diff --git a/documentation/content/en/articles/building-products/_index.adoc b/documentation/content/en/articles/building-products/_index.adoc index b444b4a41e..7f6007aa0a 100644 --- a/documentation/content/en/articles/building-products/_index.adoc +++ b/documentation/content/en/articles/building-products/_index.adoc @@ -1,401 +1,401 @@ --- title: Building Products with FreeBSD authors: - author: Joseph Koshy email: jkoshy@FreeBSD.org organizations: - organization: The FreeBSD Project description: How FreeBSD can help you build a better product trademarks: ["freebsd", "general"] tags: ["FreeBSD", "FreeBSD as base for your product"] --- = Building Products with FreeBSD :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/building-products/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract The FreeBSD project is a worldwide, volunteer based, and collaborative project, which develops a portable and high-quality operating system. The FreeBSD project distributes the source code for its product under a liberal license, with the intention of encouraging the use of its code. Collaborating with the FreeBSD project can help organizations reduce their time to market, reduce engineering costs and improve their product quality. This article examines the issues in using FreeBSD code in appliances and software products. It highlights the characteristics of FreeBSD that make it an excellent substrate for product development. The article concludes by suggesting a few "best practices" for organizations collaborating with the FreeBSD project. ''' toc::[] [[introduction]] == Introduction FreeBSD today is well-known as a high-performance server operating system. It is deployed on millions of web servers and internet-facing hosts worldwide. FreeBSD code also forms an integral part of many products, ranging from appliances such as network routers, firewalls, and storage devices, to personal computers. Portions of FreeBSD have also been used in commercial shrink-wrapped software -(see crossref:building-products[freebsd-intro]). +(see crossref:building-products[freebsd-intro, FreeBSD as a set of building blocks]). In this article we look at the link:https://www.FreeBSD.org/[FreeBSD project] as a software engineering resource-as a collection of building blocks and processes which you can use to build products. While FreeBSD's source is distributed freely to the public, to fully enjoy the benefits of the project's work, organizations need to _collaborate_ with the project. In subsequent sections of this article we discuss effective means of collaboration with the project and the pitfalls that need to be avoided while doing so. *Caveat Reader.* The author believes that the characteristics of the FreeBSD Project listed in this article were substantially true at the time the article was conceived and written (2005). However, the reader should keep in mind that the practices and processes used by open-source communities can change over time, and that the information in this article should therefore be taken as indicative rather than normative. === Target Audience This document would be of interest to the following broad groups of people: * Decision makers in product companies looking at ways to improve their product quality, reduce their time to market and lower engineering costs in the long term. * Technology consultants looking for best-practices in leveraging "open-source". * Industry observers interested in understanding the dynamics of open-source projects. * Software developers seeking to use FreeBSD and looking for ways to contribute back. === Article Goals After reading this article you should have: * An understanding of the goals of the FreeBSD Project and its organizational structure. * An understanding of its development model and release engineering processes. * An understanding of how conventional corporate software development processes differ from that used in the FreeBSD project. * Awareness of the communication channels used by the project and the level of transparency you can expect. * Awareness of optimal ways of working with the project-how best to reduce engineering costs, improve time to market, manage security vulnerabilities, and preserve future compatibility with your product as the FreeBSD project evolves. === Article Structure The rest of the article is structured as follows: -* crossref:building-products[freebsd-intro] introduces the FreeBSD project, explores its organizational structure, key technologies and release engineering processes. -* crossref:building-products[freebsd-collaboration] describes ways to collaborate with the FreeBSD project. It examines common pitfalls encountered by corporates working with voluntary projects like FreeBSD. -* crossref:building-products[conclusion] concludes. +* crossref:building-products[freebsd-intro, FreeBSD as a set of building blocks] introduces the FreeBSD project, explores its organizational structure, key technologies and release engineering processes. +* crossref:building-products[freebsd-collaboration, Collaborating with FreeBSD] describes ways to collaborate with the FreeBSD project. It examines common pitfalls encountered by corporates working with voluntary projects like FreeBSD. +* crossref:building-products[conclusion, Conclusion] concludes. [[freebsd-intro]] == FreeBSD as a set of building blocks FreeBSD makes an excellent foundation on which to build products: * FreeBSD source code is distributed under a liberal BSD license facilitating its adoption in commercial products crossref:building-products[Mon2005] with minimum hassle. * The FreeBSD project has excellent engineering practices that can be leveraged. * The project offers exceptional transparency into its workings, allowing organizations using its code to plan effectively for the future. * The culture of the FreeBSD project, carried over from the Computer Science Research Group at The University of California, Berkeley crossref:building-products[McKu1999-1], fosters high-quality work. Some features in FreeBSD define the state of the art. crossref:building-products[GoldGab2005] examines the business reasons for using open-source in greater detail. For organizations, the benefits of using FreeBSD components in their products include a shorter time to market, lower development costs and lower development risks. === Building with FreeBSD Here are a few ways organizations have used FreeBSD: * As an upstream source for tested code for libraries and utilities. + By being "downstream" of the project, organizations leverage the new features, bug fixes and testing that the upstream code receives. * As an embedded OS (for example, for an OEM router and firewall device). In this model, organizations use a customized FreeBSD kernel and application program set along with a proprietary management layer for their device. OEMs benefit from new hardware support being added by the FreeBSD project upstream, and from the testing that the base system receives. + FreeBSD ships with a self-hosting development environment that allows easy creation of such configurations. * As a Unix compatible environment for the management functions of high-end storage and networking devices, running on a separate processor "blade". + FreeBSD provides the tools for creating dedicated OS and application program images. Its implementation of a BSD unix API is mature and tested. FreeBSD can also provide a stable cross-development environment for the other components of the high-end device. * As a vehicle to get widespread testing and support from a worldwide team of developers for non-critical "intellectual property". + In this model, organizations contribute useful infrastructural frameworks to the FreeBSD project (for example, see man:netgraph[3]). The widespread exposure that the code gets helps to quickly identify performance issues and bugs. The involvement of top-notch developers also leads to useful extensions to the infrastructure that the contributing organization also benefits from. * As a development environment supporting cross-development for embedded OSes like http://www.rtems.com/[RTEMS] and http://ecos.sourceware.org/[eCOS]. + There are many full-fledged development environments in the {numports}-strong collection of applications ported and packaged with FreeBSD. * As a way to support a Unix-like API in an otherwise proprietary OS, increasing its palatability for application developers. + Here parts of FreeBSD's kernel and application programs are "ported" to run alongside other tasks in the proprietary OS. The availability of a stable and well tested Unix(TM) API implementation can reduce the effort needed to port popular applications to the proprietary OS. As FreeBSD ships with high-quality documentation for its internals and has effective vulnerability management and release engineering processes, the costs of keeping up-to-date are kept low. [[freebsd-technologies]] === Technologies There are a large number of technologies supported by the FreeBSD project. A selection of these are listed below: * A complete system that can cross-host itself for link:https://www.FreeBSD.org/platforms/[many architectures:] * A modular symmetric multiprocessing capable kernel, with loadable kernel modules and a flexible and easy to use configuration system. * Support for emulation of Linux(TM) and SVR4 binaries at near machine speeds. Support for binary Windows(TM) (NDIS) network drivers. * Libraries for many programming tasks: archivers, FTP and HTTP support, thread support, in addition to a full POSIX(TM) like programming environment. * Security features: Mandatory Access Control (man:mac[9]), jails (man:jail[2]), ACLs, and in-kernel cryptographic device support. * Networking features: firewall-ing, QoS management, high-performance TCP/IP networking with support for many extensions. + FreeBSD's in-kernel Netgraph (man:netgraph[4]) framework allows kernel networking modules to be connected together in flexible ways. * Support for storage technologies: Fibre Channel, SCSI, software and hardware RAID, ATA and SATA. + FreeBSD supports a number of filesystems, and its native UFS2 filesystem supports soft updates, snapshots and very large filesystem sizes (16TB per filesystem) crossref:building-products[McKu1999]. + FreeBSD's in-kernel GEOM (man:geom[4]) framework allows kernel storage modules to be composed in flexible ways. * Over {numports} ported applications, both commercial and open-source, managed via the FreeBSD ports collection. === Organizational Structure FreeBSD's organizational structure is non-hierarchical. There are essentially two kinds of contributors to FreeBSD, general users of FreeBSD, and developers with write access (known as _committers_ in the jargon) to the source base. There are many thousands of contributors in the first group; the vast majority of contributions to FreeBSD come from individuals in this group. Commit rights (write access) to the repository are granted to individuals who contribute consistently to the project. Commit rights come with additional responsibilities, and new committers are assigned mentors to help them learn the ropes. .FreeBSD Organization image::freebsd-organization.png[] Conflict resolution is performed by a nine member "Core Team" that is elected from the group of committers. FreeBSD does not have "corporate" committers. Individual committers are required to take responsibility for the changes they introduce to the code. The extref:{committers-guide}[FreeBSD Committer's guide] crossref:building-products[ComGuide] documents the rules and responsibilities for committers. FreeBSD's project model is examined in detail in crossref:building-products[Nik2005]. === FreeBSD Release Engineering Processes FreeBSD's release engineering processes play a major role in ensuring that its released versions are of a high quality. At any point of time, FreeBSD's volunteers support multiple code lines (crossref:building-products[fig-freebsd-branches, FreeBSD Release Branches]): * New features and disruptive code enters on the development branch, also known as the _-CURRENT_ branch. * _-STABLE_ branches are code lines that are branched from HEAD at regular intervals. Only tested code is allowed onto a -STABLE branch. New features are allowed once they have been tested and stabilized in the -CURRENT branch. * _-RELEASE_ branches are maintained by the FreeBSD security team. Only bug fixes for critical issues are permitted onto -RELEASE branches. [[fig-freebsd-branches]] .FreeBSD Release Branches image::freebsd-branches.png[] Code lines are kept alive for as long as there is user and developer interest in them. Machine architectures are grouped into "tiers"; _Tier 1_ architectures are fully supported by the project's release engineering and security teams, _Tier 2_ architectures are supported on a best effort basis, and experimental architectures comprise _Tier 3_. The list of extref:{committers-guide}[supported architectures, archs] is part of the FreeBSD documentation collection. The release engineering team publishes a link:https://www.FreeBSD.org/releng/[road map] for future releases of FreeBSD on the project's web site. The dates laid down in the road map are not deadlines; FreeBSD is released when its code and documentation are ready. FreeBSD's release engineering processes are described in crossref:building-products[RelEngDoc]. [[freebsd-collaboration]] == Collaborating with FreeBSD Open-source projects like FreeBSD offer finished code of a very high quality. While access to quality source code can reduce the cost of initial development, in the long-term the costs of managing change begin to dominate. As computing environments change over the years and new security vulnerabilities are discovered, your product too needs to change and adapt. Using open-source code is best viewed not as a one-off activity, but as an __ongoing process__. The best projects to collaborate with are the ones that are __live__; i.e., with an active community, clear goals and a transparent working style. * FreeBSD has an active developer community around it. At the time of writing there are many thousands of contributors from every populated continent in the world and over 300 individuals with write access to the project's source repositories. * The goals of the FreeBSD project are crossref:building-products[Hub1994]: ** To develop a high-quality operating system for popular computer hardware, and, ** To make our work available to all under a liberal license. * FreeBSD enjoys an open and transparent working culture. Nearly all discussion in the project happens by email, on link:https://lists.freebsd.org/[public mailing lists] that are also archived for posterity. The project's policies are link:https://www.FreeBSD.org/internal/policies/[documented] and maintained under revision control. Participation in the project is open to all. [[freebsd-org]] === Understanding FreeBSD culture To be able to work effectively with the FreeBSD project, you need to understand the project's culture. Volunteer driven projects operate under different rules than for-profit corporates. A common mistake that companies make when venturing into the open-source world is that of underplaying these differences. *Motivation.* Most contributions to FreeBSD are done voluntarily without monetary rewards entering the picture. The factors that motivate individuals are complex, ranging from altruism, to an interest in solving the kinds of problems that FreeBSD attempts to solve. In this environment, "elegance is never optional"crossref:building-products[Nor1993]. *The Long Term View.* FreeBSD traces its roots back nearly twenty years to the work of the Computer Science Research Group at the University of California Berkeley.footnote:[FreeBSD's source repository contains a history of the project since its inception, and there are CDROMs available that contain earlier code from the CSRG.] A number of the original CSRG developers remain associated with the project. The project values long-term perspectives crossref:building-products[Nor2001]. A frequent acronym encountered in the project is DTRT, which stands for "Do The Right Thing". *Development Processes.* Computer programs are tools for communication: at one level programmers communicate their intentions using a precise notation to a tool (a compiler) that translates their instructions to executable code. At another level, the same notation is used for communication of intent between two programmers. Formal specifications and design documents are seldom used in the project. Clear and well-written code and well-written change logs (crossref:building-products[fig-change-log, A sample change log entry]) are used in their place. FreeBSD development happens by "rough consensus and running code"crossref:building-products[Carp1996]. [.programlisting] .... r151864 | bde | 2005-10-29 09:34:50 -0700 (Sat, 29 Oct 2005) | 13 lines Changed paths: M /head/lib/msun/src/e_rem_pio2f.c Use double precision to simplify and optimize arg reduction for small and medium size args too: instead of conditionally subtracting a float 17+24, 17+17+24 or 17+17+17+24 bit approximation to pi/2, always subtract a double 33+53 bit one. The float version is now closer to the double version than to old versions of itself -- it uses the same 33+53 bit approximation as the simplest cases in the double version, and where the float version had to switch to the slow general case at |x| == 2^7*pi/2, it now switches at |x| == 2^19*pi/2 the same as the double version. This speeds up arg reduction by a factor of 2 for |x| between 3*pi/4 and 2^7*pi/4, and by a factor of 7 for |x| between 2^7*pi/4 and 2^19*pi/4. .... .A sample change log entry [[fig-change-log]] Communication between programmers is enhanced by the use of a common coding standard man:style[9]. *Communication Channels.* FreeBSD's contributors are spread across the world. Email (and to a lesser extent, IRC) is the preferred means of communication in the project. === Best Practices for collaborating with the FreeBSD project We now look at a few best practices for making the best use of FreeBSD in product development. Plan for the long term:: Setup processes that help in tracking the development of FreeBSD. For example: + *Track FreeBSD source code.* The project makes it easy to mirror its SVN repository using extref:{committers-guide}[svnsync, svn-advanced-use-setting-up-svnsync]. Having the complete history of the source is useful when debugging complex problems and offers valuable insight into the intentions of the original developers. Use a capable source control system that allows you to easily merge changes between the upstream FreeBSD code base and your own in-house code. + crossref:building-products[fig-svn-blame, An annotated source listing generated using `svn blame`] shows a portion of an annotated listing of the file referenced by the change log in crossref:building-products[fig-change-log, A sample change log entry]. The ancestry of each line of the source is clearly visible. Annotated listings showing the history of every file that is part of FreeBSD are https://svnweb.freebsd.org/[available on the web]. + [.programlisting] .... #REV #WHO #DATE #TEXT 176410 bde 2008-02-19 07:42:46 -0800 (Tue, 19 Feb 2008) #include 176410 bde 2008-02-19 07:42:46 -0800 (Tue, 19 Feb 2008) __FBSDID("$FreeBSD$"); 2116 jkh 1994-08-19 02:40:01 -0700 (Fri, 19 Aug 1994) 2116 jkh 1994-08-19 02:40:01 -0700 (Fri, 19 Aug 1994) /* __ieee754_rem_pio2f(x,y) 8870 rgrimes 1995-05-29 22:51:47 -0700 (Mon, 29 May 1995) * 176552 bde 2008-02-25 05:33:20 -0800 (Mon, 25 Feb 2008) * return the remainder of x rem pi/2 in *y 176552 bde 2008-02-25 05:33:20 -0800 (Mon, 25 Feb 2008) * use double precision for everything except passing x 152535 bde 2005-11-16 18:20:04 -0800 (Wed, 16 Nov 2005) * use __kernel_rem_pio2() for large x 2116 jkh 1994-08-19 02:40:01 -0700 (Fri, 19 Aug 1994) */ 2116 jkh 1994-08-19 02:40:01 -0700 (Fri, 19 Aug 1994) 176465 bde 2008-02-22 07:55:14 -0800 (Fri, 22 Feb 2008) #include 176465 bde 2008-02-22 07:55:14 -0800 (Fri, 22 Feb 2008) 2116 jkh 1994-08-19 02:40:01 -0700 (Fri, 19 Aug 1994) #include "math.h" .... .An annotated source listing generated using `svn blame` [[fig-svn-blame]] + *Use a gatekeeper.* Appoint a _gatekeeper_ to monitor FreeBSD development, to keep an eye out for changes that could potentially impact your products. + *Report bugs upstream.* If you notice bug in the FreeBSD code that you are using, file a https://www.FreeBSD.org/support/bugreports/[bug report]. This step helps ensure that you do not have to fix the bug the next time you take a code drop from upstream. Leverage FreeBSD's release engineering efforts:: Use code from a -STABLE development branch of FreeBSD. These development branches are formally supported by FreeBSD's release engineering and security teams and comprise of tested code. Donate code to reduce costs:: A major proportion of the costs associated with developing products is that of doing maintenance. By donating non-critical code to the project, you benefit by having your code see much wider exposure than it would otherwise get. This in turn leads to more bugs and security vulnerabilities being flushed out and performance anomalies being identified and fixed. Get support effectively:: For products with tight deadlines, it is recommended that you hire or enter into a consulting agreement with a developer or firm with FreeBSD experience. The {freebsd-jobs} is a useful communication channel to find talent. The FreeBSD project maintains a link:https://www.FreeBSD.org/commercial/consult_bycat/[gallery of consultants and consulting firms] undertaking FreeBSD work. The http://www.bsdcertification.org/[BSD Certification Group] offers certification for all the major BSD derived OSes. + For less critical needs, you can ask for help on the link:https://lists.freebsd.org/[project mailing lists]. A useful guide to follow when asking for help is given in crossref:building-products[Ray2004]. Publicize your involvement:: You are not required to publicize your use of FreeBSD, but doing so helps both your effort as well as that of the project. + Letting the FreeBSD community know that your company uses FreeBSD helps improve your chances of attracting high quality talent. A large roster of support for FreeBSD also means more mind share for it among developers. This in turn yields a healthier foundation for your future. Support FreeBSD developers:: Sometimes the most direct way to get a desired feature into FreeBSD is to support a developer who is already looking at a related problem. Help can range from hardware donations to direct financial assistance. In some countries, donations to the FreeBSD project enjoy tax benefits. The project has a dedicated link:https://www.FreeBSD.org/donations/[donations liaison] to assist donors. The project also maintains a web page where developers link:https://www.FreeBSD.org/donations/wantlist/[list their needs]. + As a policy the FreeBSD project extref:{contributors}[acknowledges] all contributions received on its web site. [[conclusion]] == Conclusion The FreeBSD project's goals are to create and give away the source code for a high-quality operating system. By working with the FreeBSD project you can reduce development costs and improve your time to market in a number of product development scenarios. We examined the characteristics of the FreeBSD project that make it an excellent choice for being part of an organization's product strategy. We then looked at the prevailing culture of the project and examined effective ways of interacting with its developers. The article concluded with a list of best-practices that could help organizations collaborating with the project. :sectnums!: [bibliography] == Bibliography [[Carp1996]] [Carp1996] http://www.ietf.org/rfc/rfc1958.txt[The Architectural Principles of the Internet] B. Carpenter. The Internet Architecture Board.The Internet Architecture Board. Copyright(R) 1996. [[ComGuide]] [ComGuide] extref:{committers-guide}[Committer's Guide] The FreeBSD Project. Copyright(R) 2005. [[GoldGab2005]] [GoldGab2005] http://dreamsongs.com/IHE/IHE.html[Innovation Happens Elsewhere: Open Source as Business Strategy] Ron Goldman. Richard Gabriel. Copyright(R) 2005. Morgan-Kaufmann. [[Hub1994]] [Hub1994] extref:{contributing}[Contributing to the FreeBSD Project] Jordan Hubbard. Copyright(R) 1994-2005. The FreeBSD Project. [[McKu1999]] [McKu1999] http://www.usenix.org/publications/library/proceedings/usenix99/mckusick.html[Soft Updates: A Technique for Eliminating Most Synchronous Writes in the Fast Filesystem] Kirk McKusick. Gregory Ganger. Copyright(R) 1999. [[McKu1999-1]] [McKu1999-1] http://www.oreilly.com/catalog/opensources/book/kirkmck.html[Twenty Years of Berkeley Unix: From AT&T-Owned to Freely Redistributable] Marshall Kirk McKusick. http://www.oreilly.com/catalog/opensources/book/toc.html[Open Sources: Voices from the Open Source Revolution] O'Reilly Inc.. Copyright(R) 1993. [[Mon2005]] [Mon2005] extref:{bsdl-gpl}[Why you should use a BSD style license for your Open Source Project] Bruce Montague. The FreeBSD Project. Copyright(R) 2005. [[Nik2005]] [Nik2005] extref:{dev-model}[A project model for the FreeBSD Project] Niklas Saers. Copyright(R) 2005. The FreeBSD Project. [[Nor1993]] [Nor1993] http://www.norvig.com/luv-slides.ps[Tutorial on Good Lisp Programming Style] Peter Norvig. Kent Pitman. Copyright(R) 1993. [[Nor2001]] [Nor2001] http://www.norvig.com/21-days.html[Teach Yourself Programming in Ten Years] Peter Norvig. Copyright(R) 2001. [[Ray2004]] [Ray2004] http://www.catb.org/~esr/faqs/smart-questions.html[How to ask questions the smart way] Eric Steven Raymond. Copyright(R) 2004. [[RelEngDoc]] [RelEngDoc] extref:{releng}[FreeBSD Release Engineering] Murray Stokely. Copyright(R) 2001. The FreeBSD Project. diff --git a/documentation/content/en/articles/committers-guide/_index.adoc b/documentation/content/en/articles/committers-guide/_index.adoc index 921a823a7d..ff2923c80c 100644 --- a/documentation/content/en/articles/committers-guide/_index.adoc +++ b/documentation/content/en/articles/committers-guide/_index.adoc @@ -1,3795 +1,3795 @@ --- title: Committer's Guide authors: - author: The FreeBSD Documentation Project copyright: 1999-2022 The FreeBSD Documentation Project description: Introductory information for FreeBSD committers trademarks: ["freebsd", "coverity", "git", "github", "gitlab", "ibm", "intel", "general"] weight: 25 tags: ["FreeBSD Committer's Guide", "Guide", "Community"] --- = Committer's Guide :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/committers-guide/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract This document provides information for the FreeBSD committer community. All new committers should read this document before they start, and existing committers are strongly encouraged to review it from time to time. Almost all FreeBSD developers have commit rights to one or more repositories. However, a few developers do not, and some of the information here applies to them as well. (For instance, some people only have rights to work with the Problem Report database.) -Please see crossref:committers-guide[non-committers] for more information. +Please see crossref:committers-guide[non-committers, Issues Specific to Developers Who Are Not Committers] for more information. This document may also be of interest to members of the FreeBSD community who want to learn more about how the project works. ''' toc::[] [[admin]] == Administrative Details [.informaltable] [cols="1,1", frame="none"] |=== |_Login Methods_ |man:ssh[1], protocol 2 only |_Main Shell Host_ |`freefall.FreeBSD.org` |_Reference Machines_ |`ref*.FreeBSD.org`, `universe*.freeBSD.org` (see also link:https://www.FreeBSD.org/internal/machines/[FreeBSD Project Hosts]) |_SMTP Host_ -|`smtp.FreeBSD.org:587` (see also crossref:committers-guide[smtp-setup]). +|`smtp.FreeBSD.org:587` (see also crossref:committers-guide[smtp-setup, SMTP Access Setup]). |`_src/_` Git Repository |`ssh://git@gitrepo.FreeBSD.org/src.git` |`_doc/_` Git Repository |`ssh://git@gitrepo.FreeBSD.org/doc.git` |`_ports/_` Git Repository |`ssh://git@gitrepo.FreeBSD.org/ports.git` |_Internal Mailing Lists_ |developers (technically called all-developers), doc-developers, doc-committers, ports-developers, ports-committers, src-developers, src-committers. (Each project repository has its own -developers and -committers mailing lists. Archives for these lists can be found in the files [.filename]#/local/mail/repository-name-developers-archive# and [.filename]#/local/mail/repository-name-committers-archive# on `freefall.FreeBSD.org`.) |_Core Team monthly reports_ |[.filename]#/home/core/public/reports# on the `FreeBSD.org` cluster. |_Ports Management Team monthly reports_ |[.filename]#/home/portmgr/public/monthly-reports# on the `FreeBSD.org` cluster. |_Noteworthy `src/` Git Branches:_ |`stable/n` (`n`-STABLE), `main` (-CURRENT) |=== man:ssh[1] is required to connect to the project hosts. For more information, - see crossref:committers-guide[ssh.guide]. + see crossref:committers-guide[ssh.guide, SSH Quick-Start Guide]. Useful links: * link:https://www.FreeBSD.org/internal/[FreeBSD Project Internal Pages] * link:https://www.FreeBSD.org/internal/machines/[FreeBSD Project Hosts] * link:https://www.FreeBSD.org/administration/[FreeBSD Project Administrative Groups] [[pgpkeys]] == OpenPGP Keys for FreeBSD Cryptographic keys conforming to the OpenPGP (__Pretty Good Privacy__) standard are used by the FreeBSD project to authenticate committers. Messages carrying important information like public SSH keys can be signed with the OpenPGP key to prove that they are really from the committer. See https://nostarch.com/releases/pgp_release.pdf[PGP & GPG: Email for the Practical Paranoid by Michael Lucas] and http://en.wikipedia.org/wiki/Pretty_Good_Privacy[] for more information. [[pgpkeys-creating]] === Creating a Key Existing keys can be used, but should be checked with [.filename]#documentation/tools/checkkey.sh# first. In this case, make sure the key has a FreeBSD user ID. For those who do not yet have an OpenPGP key, or need a new key to meet FreeBSD security requirements, here we show how to generate one. [[pgpkeys-create-steps]] [.procedure] ==== . Install [.filename]#security/gnupg#. Enter these lines in [.filename]#~/.gnupg/gpg.conf# to set minimum acceptable defaults for signing and new key preferences (see the link:https://www.gnupg.org/documentation/manuals/gnupg/GPG-Options.html[GnuPG options documentation] for more details): + [.programlisting] .... # Sorted list of preferred algorithms for signing (strongest to weakest). personal-digest-preferences SHA512 SHA384 SHA256 SHA224 # Default preferences for new keys default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 CAMELLIA256 AES192 CAMELLIA192 AES CAMELLIA128 CAST5 BZIP2 ZLIB ZIP Uncompressed .... . Generate a key: + [source,shell] .... % gpg --full-gen-key gpg (GnuPG) 2.1.8; Copyright (C) 2015 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Warning: using insecure memory! Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) Your selection? 1 RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (2048) 2048 <.> Requested keysize is 2048 bits Please specify how long the key should be valid. 0 = key does not expire = key expires in n days w = key expires in n weeks m = key expires in n months y = key expires in n years Key is valid for? (0) 3y <.> Key expires at Wed Nov 4 17:20:20 2015 MST Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: Chucky Daemon <.> Email address: notreal@example.com Comment: You selected this USER-ID: "Chucky Daemon " Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o You need a Passphrase to protect your secret key. .... <.> 2048-bit keys with a three-year expiration provide adequate protection at present (2022-10). <.> A three year key lifespan is short enough to obsolete keys weakened by advancing computer power, but long enough to reduce key management problems. <.> Use your real name here, preferably matching that shown on government-issued ID to make it easier for others to verify your identity. Text that may help others identify you can be entered in the `Comment` section. + After the email address is entered, a passphrase is requested. Methods of creating a secure passphrase are contentious. Rather than suggest a single way, here are some links to sites that describe various methods: https://world.std.com/~reinhold/diceware.html[], https://www.iusmentis.com/security/passphrasefaq/[], https://xkcd.com/936/[], https://en.wikipedia.org/wiki/Passphrase[]. ==== Protect the private key and passphrase. If either the private key or passphrase may have been compromised or disclosed, immediately notify mailto:accounts@FreeBSD.org[accounts@FreeBSD.org] and revoke the key. Committing the new key is shown in crossref:committers-guide[commit-steps, Steps for New Committers]. [[kerberos-ldap]] == Kerberos and LDAP web Password for FreeBSD Cluster The FreeBSD cluster requires a Kerberos password to access certain services. The Kerberos password also serves as the LDAP web password, since LDAP is proxying to Kerberos in the cluster. Some of the services which require this include: * https://bugs.freebsd.org/bugzilla[Bugzilla] * https://ci.freebsd.org[Jenkins] To create a new Kerberos account in the FreeBSD cluster, or to reset a Kerberos password for an existing account using a random password generator: [source,shell] .... % ssh kpasswd.freebsd.org .... [NOTE] ==== This must be done from a machine outside of the FreeBSD.org cluster. ==== A Kerberos password can also be set manually by logging into `freefall.FreeBSD.org` and running: [source,shell] .... % kpasswd .... [NOTE] ==== Unless the Kerberos-authenticated services of the FreeBSD.org cluster have been used previously, `Client unknown` will be shown. This error means that the `ssh kpasswd.freebsd.org` method shown above must be used first to initialize the Kerberos account. ==== [[committer.types]] == Commit Bit Types The FreeBSD repository has a number of components which, when combined, support the basic operating system source, documentation, third party application ports infrastructure, and various maintained utilities. When FreeBSD commit bits are allocated, the areas of the tree where the bit may be used are specified. Generally, the areas associated with a bit reflect who authorized the allocation of the commit bit. Additional areas of authority may be added at a later date: when this occurs, the committer should follow normal commit bit allocation procedures for that area of the tree, seeking approval from the appropriate entity and possibly getting a mentor for that area for some period of time. [.informaltable] [cols="1,1,1", frame="none"] |=== |__Committer Type__ |__Responsible__ |__Tree Components__ |src |core@ |src/ |doc |doceng@ |doc/, ports/, src/ documentation |ports |portmgr@ |ports/ |=== Commit bits allocated prior to the development of the notion of areas of authority may be appropriate for use in many parts of the tree. However, common sense dictates that a committer who has not previously worked in an area of the tree seek review prior to committing, seek approval from the appropriate responsible party, and/or work with a mentor. Since the rules regarding code maintenance differ by area of the tree, this is as much for the benefit of the committer working in an area of less familiarity as it is for others working on the tree. Committers are encouraged to seek review for their work as part of the normal development process, regardless of the area of the tree where the work is occurring. === Policy for Committer Activity in Other Trees * All committers may modify [.filename]#src/share/misc/committers-*.dot#, [.filename]#src/usr.bin/calendar/calendars/calendar.freebsd#, and [.filename]#ports/astro/xearth/files#. * doc committers may commit documentation changes to [.filename]#src# files, such as manual pages, READMEs, fortune databases, calendar files, and comment fixes without approval from a src committer, subject to the normal care and tending of commits. * Any committer may make changes to any other tree with an "Approved by" from a non-mentored committer with the appropriate bit. Mentored committers can provide a "Reviewed by" but not an "Approved by". * Committers can acquire an additional bit by the usual process of finding a mentor who will propose them to core, doceng, or portmgr, as appropriate. When approved, they will be added to 'access' and the normal mentoring period will ensue, which will involve a continuing of "Approved by" for some period. [[doc-blanket-approval]] ==== Documentation Implicit (Blanket) Approval Some types of fixes have "blanket approval" from the {doceng}, allowing any committer to fix those categories of problems on any part of the doc tree. These fixes do not need approval or review from a doc committer if the author doesn't have a doc commit bit. Blanket approval applies to these types of fixes: * Typos * Trivial fixes + Punctuation, URLs, dates, paths and file names with outdated or incorrect information, and other common mistakes that may confound the readers. Over the years, some implicit approvals were granted in the doc tree. This list shows the most common cases: * Changes in [.filename]#documentation/content/en/books/porters-handbook/versions/_index.adoc# + extref:{porters-handbook}versions/[__FreeBSD_version Values (Porter's Handbook)], mainly used for src committers. * Changes in [.filename]#doc/shared/contrib-additional.adoc# + extref:{contributors}[Additional FreeBSD Contributors, contrib-additional] maintenance. * All link:#commit-steps[Steps for New Committers], doc related * Security advisories; Errata Notices; Releases; + Used by {security-officer} and {re}. * Changes in [.filename]#website/content/en/donations/donors.adoc# + Used by {donations}. Before any commit, a build test is necessary; see the 'Overview' and 'The FreeBSD Documentation Build Process' sections of the extref:{fdp-primer}[FreeBSD Documentation Project Primer for New Contributors] for more details. [[git-primer]] == Git Primer [[git-basics]] === Git basics When one searches for "Git Primer" a number of good ones come up. Daniel Miessler's link:https://danielmiessler.com/study/git/[A git primer] and Willie Willus' link:https://gist.github.com/williewillus/068e9a8543de3a7ef80adb2938657b6b[Git - Quick Primer] are both good overviews. The Git book is also complete, but much longer https://git-scm.com/book/en/v2. There is also this website https://dangitgit.com/ for common traps and pitfalls of Git, in case you need guidance to fix things up. Finally, an introduction link:https://eagain.net/articles/git-for-computer-scientists/[targeted at computer scientists] has proven helpful to some at explaining the Git world view. This document will assume that you've read through it and will try not to belabor the basics (though it will cover them briefly). [[git-mini-primer]] === Git Mini Primer This primer is less ambitiously scoped than the old Subversion Primer, but should cover the basics. ==== Scope If you want to download FreeBSD, compile it from sources, and generally keep up to date that way, this primer is for you. It covers getting the sources, updating the sources, bisecting and touches briefly on how to cope with a few local changes. It covers the basics, and tries to give good pointers to more in-depth treatment for when the reader finds the basics insufficient. Other sections of this guide cover more advanced topics related to contributing to the project. The goal of this section is to highlight those bits of Git needed to track sources. They assume a basic understanding of Git. There are many primers for Git on the web, but the https://git-scm.com/book/en/v2[Git Book] provides one of the better treatments. [[git-mini-primer-getting-started]] ==== Getting Started For Developers This section describes the read-write access for committers to push the commits from developers or contributors. [[git-mini-daily-use]] ===== Daily use [NOTE] ==== In the examples below, replace `${repo}` with the name of the desired FreeBSD repository: `doc`, `ports`, or `src`. ==== * Clone the repository: + [source,shell] .... % git clone -o freebsd --config remote.freebsd.fetch='+refs/notes/*:refs/notes/*' https://git.freebsd.org/${repo}.git .... + Then you should have the official mirrors as your remote: + [source,shell] .... % git remote -v freebsd https://git.freebsd.org/${repo}.git (fetch) freebsd https://git.freebsd.org/${repo}.git (push) .... * Configure the FreeBSD committer data: + The commit hook in repo.freebsd.org checks the "Commit" field matches the committer's information in FreeBSD.org. The easiest way to get the suggested config is by executing `/usr/local/bin/gen-gitconfig.sh` script on freefall: + [source,shell] .... % gen-gitconfig.sh [...] % git config user.name (your name in gecos) % git config user.email (your login)@FreeBSD.org .... * Set the push URL: + [source,shell] .... % git remote set-url --push freebsd git@gitrepo.freebsd.org:${repo}.git .... + Then you should have separated fetch and push URLs as the most efficient setup: + [source,shell] .... % git remote -v freebsd https://git.freebsd.org/${repo}.git (fetch) freebsd git@gitrepo.freebsd.org:${repo}.git (push) .... + Again, note that `gitrepo.freebsd.org` has been canonicalized to `repo.freebsd.org`. * Install commit message template hook: + For doc repository: + [source,shell] .... % cd .git/hooks % ln -s ../../.hooks/prepare-commit-msg .... + For ports repository: + [source,shell] .... % git config --add core.hooksPath .hooks .... + For src repository: + [source,shell] .... % cd .git/hooks % ln -s ../../tools/tools/git/hooks/prepare-commit-msg .... [[admin-branch]] ===== "admin" branch The `access` and `mentors` files are stored in an orphan branch, `internal/admin`, in each repository. Following example is how to check out the `internal/admin` branch to a local branch named `admin`: [source,shell] .... % git config --add remote.freebsd.fetch '+refs/internal/*:refs/internal/*' % git fetch % git checkout -b admin internal/admin .... Alternatively, you can add a worktree for the `admin` branch: [source,shell] .... git worktree add -b admin ../${repo}-admin internal/admin .... For browsing `internal/admin` branch on web: `https://cgit.freebsd.org/${repo}/log/?h=internal/admin` For pushing, specify the full refspec: [source,shell] .... git push freebsd HEAD:refs/internal/admin .... ==== Keeping Current With The FreeBSD src Tree [[keeping_current]] First step: cloning a tree. This downloads the entire tree. There are two ways to download. Most people will want to do a deep clone of the repository. However, there are times when you may wish to do a shallow clone. ===== Branch Names FreeBSD-CURRENT uses the `main` branch. `main` is the default branch. For FreeBSD-STABLE, branch names include `stable/12` and `stable/13`. For FreeBSD-RELEASE, release engineering branch names include `releng/12.4` and `releng/13.2`. https://www.freebsd.org/releng/[] shows: * `main` and `stable/⋯` branches open * `releng/⋯` branches, each of which is frozen when a release is tagged. Examples: * tag https://cgit.freebsd.org/src/tag/?h=release/13.1.0[release/13.1.0] on the https://cgit.freebsd.org/src/log/?h=releng/13.1[releng/13.1] branch * tag https://cgit.freebsd.org/src/tag/?h=release/13.2.0[release/13.2.0] on the https://cgit.freebsd.org/src/log/?h=releng/13.2[releng/13.2] branch. ===== Repositories Please see the crossref:committers-guide[admin,Administrative Details] for the latest information on where to get FreeBSD sources. $URL below can be obtained from that page. Note: The project doesn't use submodules as they are a poor fit for our workflows and development model. How we track changes in third-party applications is discussed elsewhere and generally of little concern to the casual user. ===== Deep Clone A deep clone pulls in the entire tree, as well as all the history and branches. It is the easiest to do. It also allows you to use Git's worktree feature to have all your active branches checked out into separate directories but with only one copy of the repository. [source,shell] .... % git clone -o freebsd $URL -b branch [] .... -- will create a deep clone. `branch` should be one of the branches listed in the previous section. If no `branch` is given: the default (`main`) will be used. If no `` is given: the name of the new directory will match the name of the repo ([.filename]#doc#, [.filename]#ports# or [.filename]#src#). You will want a deep clone if you are interested in the history, plan on making local changes, or plan on working on more than one branch. It is the easiest to keep up to date as well. If you are interested in the history, but are working with only one branch and are short on space, you can also use --single-branch to only download the one branch (though some merge commits will not reference the merged-from branch which may be important for some users who are interested in detailed versions of history). ===== Shallow Clone A shallow clone copies just the most current code, but none or little of the history. This can be useful when you need to build a specific revision of FreeBSD, or when you are just starting out and plan to track the tree more fully. You can also use it to limit history to only so many revisions. However, see below for a significant limitation of this approach. [source,shell] .... % git clone -o freebsd -b branch --depth 1 $URL [dir] .... This clones the repository, but only has the most recent version in the repository. The rest of the history is not downloaded. Should you change your mind later, you can do `git fetch --unshallow` to get the old history. [WARNING] ==== When you make a shallow clone, you will lose the commit count in your uname output. This can make it more difficult to determine if your system needs to be updated when a security advisory is issued. ==== ===== Building Once you've downloaded, building is done as described in the handbook, e.g.: [source,shell] .... % cd src % make buildworld % make buildkernel % make installkernel % make installworld .... so that won't be covered in depth here. If you want to build a custom kernel, extref:{handbook}[the kernel config section, kernelconfig] of the FreeBSD Handbook recommends creating a file MYKERNEL under sys/${ARCH}/conf with your changes against GENERIC. To have MYKERNEL disregarded by Git, it can be added to .git/info/exclude. ===== Updating To update both types of trees uses the same commands. This pulls in all the revisions since your last update. [source,shell] .... % git pull --ff-only .... will update the tree. In Git, a 'fast forward' merge is one that only needs to set a new branch pointer and doesn't need to re-create the commits. By always doing a fast forward merge/pull, you'll ensure that you have an exact copy of the FreeBSD tree. This will be important if you want to maintain local patches. See below for how to manage local changes. The simplest is to use `--autostash` on the `git pull` command, but more sophisticated options are available. ==== Selecting a Specific Version In Git, `git checkout` checks out both branches and specific versions. Git's versions are the long hashes rather than a sequential number. When you checkout a specific version, just specify the hash you want on the command line (the git log command can help you decide which hash you might want): [source,shell] .... % git checkout 08b8197a74 .... and you have that checked out. You will be greeted with a message similar to the following: [source,shell] .... Note: checking out '08b8197a742a96964d2924391bf9fdfeb788865d'. You are in a 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b HEAD is now at 08b8197a742a hook gpiokeys.4 to the build .... where the last line is generated from the hash you are checking out and the first line of the commit message from that revision. The hash can be abbreviated to the shortest unique length. Git itself is inconsistent about how many digits it displays. ==== Bisecting Sometimes, things go wrong. The last version worked, but the one you just updated to does not. A developer may ask you to bisect the problem to track down which commit caused the regression. Git makes bisecting changes easy with a powerful `git bisect` command. Here's a brief outline of how to use it. For more information, you can view https://www.metaltoad.com/blog/beginners-guide-git-bisect-process-elimination or https://git-scm.com/docs/git-bisect for more details. The man git-bisect page is good at describing what can go wrong, what to do when versions won't build, when you want to use terms other than 'good' and 'bad', etc, none of which will be covered here. `git bisect start --first-parent` will start the bisection process. Next, you need to tell a range to go through. `git bisect good XXXXXX` will tell it the working version and `git bisect bad XXXXX` will tell it the bad version. The bad version will almost always be HEAD (a special tag for what you have checked out). The good version will be the last one you checked out. The `--first-parent` argument is necessary so that subsequent `git bisect` commands do not try to check out a vendor branch which lacks the full FreeBSD source tree. [TIP] ==== If you want to know the last version you checked out, you should use `git reflog`: [source,shell] .... 5ef0bd68b515 (HEAD -> main, freebsd/main, freebsd/HEAD) HEAD@{0}: pull --ff-only: Fast-forward a8163e165c5b (upstream/main) HEAD@{1}: checkout: moving from b6fb97efb682994f59b21fe4efb3fcfc0e5b9eeb to main ... .... shows me moving the working tree to the `main` branch (a816...) and then updating from upstream (to 5ef0...). In this case, bad would be HEAD (or 5ef0bd68b515) and good would be a8163e165c5b. As you can see from the output, HEAD@{1} also often works, but isn't foolproof if you have done other things to your Git tree after updating, but before you discover the need to bisect. ==== Set the 'good' version first, then set the bad (though the order doesn't matter). When you set the bad version, it will give you some statistics on the process: [source,shell] .... % git bisect start --first-parent % git bisect good a8163e165c5b % git bisect bad HEAD Bisecting: 1722 revisions left to test after this (roughly 11 steps) [c427b3158fd8225f6afc09e7e6f62326f9e4de7e] Fixup r361997 by balancing parens. Duh. .... You would then build/install that version. If it's good you'd type `git bisect good` otherwise `git bisect bad`. If the version doesn't compile, type `git bisect skip`. You will get a similar message to the above after each step. When you are done, report the bad version to the developer (or fix the bug yourself and send a patch). `git bisect reset` will end the process and return you back to where you started (usually tip of `main`). Again, the git-bisect manual (linked above) is a good resource for when things go wrong or for unusual cases. [[git-gpg-signing]] ==== Signing the commits, tags, and pushes, with GnuPG Git knows how to sign commits, tags, and pushes. When you sign a Git commit or a tag, you can prove that the code you submitted came from you and wasn't altered while you were transferring it. You also can prove that you submitted the code and not someone else. A more in-depth documentation on signing commits and tags can be found in the https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work[Git Tools - Signing Your Work] chapter of the Git's book. The rationale behind signing pushes can be found in the https://github.com/git/git/commit/a85b377d0419a9dfaca8af2320cc33b051cbed04[commit that introduced the feature]. The best way is to simply tell Git you always want to sign commits, tags, and pushes. You can do this by setting a few configuration variables: [source,shell] .... % git config --add user.signingKey LONG-KEY-ID % git config --add commit.gpgSign true % git config --add tag.gpgSign true % git config --add push.gpgSign if-asked .... // push.gpgSign should probably be set to `yes` once we enable it, or be set with --global, so that it is enabled for all repositories. [NOTE] ====== To avoid possible collisions, make sure you give a long key id to Git. You can get the long id with: `gpg --list-secret-keys --keyid-format LONG`. ====== [TIP] ====== To use specific subkeys, and not have GnuPG to resolve the subkey to a primary key, attach `!` to the key. For example, to encrypt for the subkey `DEADBEEF`, use `DEADBEEF!`. ====== ===== Verifying signatures Commit signatures can be verified by running either `git verify-commit `, or `git log --show-signature`. Tag signatures can be verified with `git verify-tag `, or `git tag -v `. //// Commented out for now until we decide what to do. Git pushes are a bit different, they live in a special ref in the repository. TODO: write how to verify them //// ==== Ports Considerations The ports tree operates the same way. The branch names are different and the repositories are in different locations. The cgit repository web interface for use with web browsers is at https://cgit.FreeBSD.org/ports/ . The production Git repository is at https://git.FreeBSD.org/ports.git and at ssh://anongit@git.FreeBSD.org/ports.git (or anongit@git.FreeBSD.org:ports.git). There is also a mirror on GitHub, see extref:{handbook}/mirrors[External mirrors, mirrors] for an overview. The _latest_ branch is `main`. The _quarterly_ branches are named `yyyyQn` for year 'yyyy' and quarter 'n'. [[port-commit-message-formats]] ===== Commit message formats A hook is available in the ports repository to help you write up your commit messages in https://cgit.freebsd.org/ports/tree/.hooks/prepare-commit-msg[.hooks/prepare-commit-message]. It can be enabled by running ``git config --add core.hooksPath .hooks``. The main point being that a commit message should be formatted in the following way: .... category/port: Summary. Description of why the changes where made. PR: 12345 .... [IMPORTANT] ==== The first line is the subject of the commit, it contains what port was changed, and a summary of the commit. It should contain 50 characters or less. A blank line should separate it from the rest of the commit message. The rest of the commit message should be wrapped at the 72 characters boundary. Another blank line should be added if there are any metadata fields, so that they are easily distinguishable from the commit message. ==== ==== Managing Local Changes This section addresses tracking local changes. If you have no local changes you can skip this section. One item that is important for all of them: all changes are local until pushed. Unlike Subversion, Git uses a distributed model. For users, for most things, there is very little difference. However, if you have local changes, you can use the same tool to manage them as you use to pull in changes from FreeBSD. All changes that you have not pushed are local and can easily be modified (git rebase, discussed below does this). ===== Keeping local changes The simplest way to keep local changes (especially trivial ones) is to use `git stash`. In its simplest form, you use `git stash` to record the changes (which pushes them onto the stash stack). Most people use this to save changes before updating the tree as described above. They then use `git stash apply` to re-apply them to the tree. The stash is a stack of changes that can be examined with `git stash list`. The git-stash man page (https://git-scm.com/docs/git-stash) has all the details. This method is suitable when you have tiny tweaks to the tree. When you have anything non trivial, you'll likely be better off keeping a local branch and rebasing. Stashing is also integrated with the `git pull` command: just add `--autostash` to the command line. ===== Keeping a local branch [[keeping_a_local_branch]] It is much easier to keep a local branch with Git than Subversion. In Subversion you need to merge the commit, and resolve the conflicts. This is manageable, but can lead to a convoluted history that's hard to upstream should that ever be necessary, or hard to replicate if you need to do so. Git also allows one to merge, along with the same problems. That's one way to manage the branch, but it's the least flexible. In addition to merging, Git supports the concept of 'rebasing' which avoids these issues. The `git rebase` command replays all the commits of a branch at a newer location on the parent branch. We will cover the most common scenarios that arise using it. ====== Create a branch Let's say you want to make a change to FreeBSD's ls command to never, ever do color. There are many reasons to do this, but this example will use that as a baseline. The FreeBSD ls command changes from time to time, and you'll need to cope with those changes. Fortunately, with Git rebase it usually is automatic. [source,shell] .... % cd src % git checkout main % git checkout -b no-color-ls % cd bin/ls % vi ls.c # hack the changes in % git diff # check the changes diff --git a/bin/ls/ls.c b/bin/ls/ls.c index 7378268867ef..cfc3f4342531 100644 --- a/bin/ls/ls.c +++ b/bin/ls/ls.c @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#undef COLORLS #ifdef COLORLS #include #include % # these look good, make the commit... % git commit ls.c .... The commit will pop you into an editor to describe what you've done. Once you enter that, you have your own **local** branch in the Git repo. Build and install it like you normally would, following the directions in the handbook. Git differs from other version control systems in that you have to tell it explicitly which files to commit. I have opted to do it on the commit command line, but you can also do it with `git add` which many of the more in depth tutorials cover. ====== Time to update When it is time to bring in a new version, it is almost the same as w/o the branches. You would update like you would above, but there is one extra command before you update, and one after. The following assumes you are starting with an unmodified tree. It is important to start rebasing operations with a clean tree (Git requires this). [source,shell] .... % git checkout main % git pull --ff-only % git rebase -i main no-color-ls .... This will bring up an editor that lists all the commits in it. For this example, do not change it at all. This is typically what you are doing while updating the baseline (though you also use the Git rebase command to curate the commits you have in the branch). Once you are done with the above, you have to move the commits to ls.c forward from the old version of FreeBSD to the newer one. Sometimes there are merge conflicts. That is OK. Do not panic. Instead, handle them the same as any other merge conflicts. To keep it simple, I will just describe a common issue that may arise. A pointer to a complete treatment can be found at the end of this section. Let's say the includes changes upstream in a radical shift to terminfo as well as a name change for the option. When you updated, you might see something like this: [source,shell] .... Auto-merging bin/ls/ls.c CONFLICT (content): Merge conflict in bin/ls/ls.c error: could not apply 646e0f9cda11... no color ls Resolve all conflicts manually, mark them as resolved with "git add/rm ", then run "git rebase --continue". You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 646e0f9cda11... no color ls .... which looks scary. If you bring up an editor, you will see it is a typical 3-way merge conflict resolution that you may be familiar with from other source code systems (the rest of ls.c has been omitted): [source,shell] <<<<<<< HEAD #ifdef COLORLS_NEW #include ======= #undef COLORLS #ifdef COLORLS #include >>>>>>> 646e0f9cda11... no color ls .... The new code is first, and your code is second. The right fix here is to just add a #undef COLORLS_NEW before #ifdef and then delete the old changes: [source,shell] .... #undef COLORLS_NEW #ifdef COLORLS_NEW #include .... save the file. The rebase was interrupted, so you have to complete it: [source,shell] .... % git add ls.c % git rebase --continue .... which tells Git that ls.c has been fixed and to continue the rebase operation. Since there was a conflict, you will get kicked into the editor to update the commit message if necessary. If the commit message is still accurate, just exit the editor. If you get stuck during the rebase, do not panic. git rebase --abort will take you back to a clean slate. It is important, though, to start with an unmodified tree. An aside: The above mentioned `git reflog` comes in handy here, as it will have a list of all the (intermediate) commits that you can view or inspect or cherry-pick. For more on this topic, https://www.freecodecamp.org/news/the-ultimate-guide-to-git-merge-and-git-rebase/ provides a rather extensive treatment. It is a good resource for issues that arise occasionally but are too obscure for this guide. ===== Switching to a Different FreeBSD Branch If you wish to shift from stable/12 to the current branch. If you have a deep clone, the following will suffice: [source,shell] .... % git checkout main % # build and install here... .... If you have a local branch, though, there are one or two caveats. First, rebase will rewrite history, so you will likely want to do something to save it. Second, jumping branches tends to cause more conflicts. If we pretend the example above was relative to stable/12, then to move to `main`, I'd suggest the following: [source,shell] .... % git checkout no-color-ls % git checkout -b no-color-ls-stable-12 # create another name for this branch % git rebase -i stable/12 no-color-ls --onto main .... What the above does is checkout no-color-ls. Then create a new name for it (no-color-ls-stable-12) in case you need to get back to it. Then you rebase onto the `main` branch. This will find all the commits to the current no-color-ls branch (back to where it meets up with the stable/12 branch) and then it will replay them onto the `main` branch creating a new no-color-ls branch there (which is why I had you create a place holder name). [[mfc-with-git]] === MFC (Merge From Current) Procedures ==== Summary MFC workflow can be summarized as `git cherry-pick -x` plus `git commit --amend` to adjust the commit message. For multiple commits, use `git rebase -i` to squash them together and edit the commit message. ==== Single commit MFC [source,shell] .... % git checkout stable/X % git cherry-pick -x $HASH --edit .... For MFC commits, for example a vendor import, you would need to specify one parent for cherry-pick purposes. Normally, that would be the "first parent" of the branch you are cherry-picking from, so: [source,shell] .... % git checkout stable/X % git cherry-pick -x $HASH -m 1 --edit .... If things go wrong, you'll either need to abort the cherry-pick with `git cherry-pick --abort` or fix it up and do a `git cherry-pick --continue`. Once the cherry-pick is finished, push with `git push`. If you get an error due to losing the commit race, use `git pull --rebase` and try to push again. ==== MFC to RELENG branch MFCs to branches that require approval require a bit more care. The process is the same for either a typical merge or an exceptional direct commit. * Merge or direct commit to the appropriate `stable/X` branch first before merging to the `releng/X.Y` branch. * Use the hash that's in the `stable/X` branch for the MFC to `releng/X.Y` branch. * Leave both "cherry picked from" lines in the commit message. * Be sure to add the `Approved by:` line when you are in the editor. [source,shell] .... % git checkout releng/13.0 % git cherry-pick -x $HASH --edit .... If you forget to to add the `Approved by:` line, you can do a `git commit --amend` to edit the commit message before you push the change. ==== Multiple commit MFC [source,shell] .... % git checkout -b tmp-branch stable/X % for h in $HASH_LIST; do git cherry-pick -x $h; done % git rebase -i stable/X # mark each of the commits after the first as 'squash' # Update the commit message to reflect all elements of commit, if necessary. # Be sure to retain the "cherry picked from" lines. % git push freebsd HEAD:stable/X .... If the push fails due to losing the commit race, rebase and try again: [source,shell] .... % git checkout stable/X % git pull % git checkout tmp-branch % git rebase stable/X % git push freebsd HEAD:stable/X .... Once the MFC is complete, you can delete the temporary branch: [source,shell] .... % git checkout stable/X % git branch -d tmp-branch .... ==== MFC a vendor import Vendor imports are the only thing in the tree that creates a merge commit in the `main` branch. Cherry picking merge commits into stable/XX presents an additional difficulty because there are two parents for a merge commit. Generally, you'll want the first parent's diff since that's the diff to `main` (though there may be some exceptions). [source,shell] .... % git cherry-pick -x -m 1 $HASH .... is typically what you want. This will tell cherry-pick to apply the correct diff. There are some, hopefully, rare cases where it's possible that the `main` branch was merged backwards by the conversion script. Should that be the case (and we've not found any yet), you'd change the above to `-m 2` to pickup the proper parent. Just do: [source,shell] .... % git cherry-pick --abort % git cherry-pick -x -m 2 $HASH .... to do that. The `--abort` will cleanup the failed first attempt. ==== Redoing a MFC If you do a MFC, and it goes horribly wrong and you want to start over, then the easiest way is to use `git reset --hard` like so: [source,shell] .... % git reset --hard freebsd/stable/12 .... though if you have some revs you want to keep, and others you don't, using `git rebase -i` is better. ==== Considerations when MFCing When committing source commits to stable and releng branches, we have the following goals: * Clearly mark direct commits distinct from commits that land a change from another branch. * Avoid introducing known breakage into stable and releng branches. * Allow developers to determine which changes have or have not been landed from one branch to another. With Subversion, we used the following practices to achieve these goals: * Using `MFC` and `MFS` tags to mark commits that merged changes from another branch. * Squashing fixup commits into the main commit when merging a change. * Recording mergeinfo so that `svn mergeinfo --show-revs` worked. With Git, we will need to use different strategies to achieve the same goals. This document aims to define best practices when merging source commits using Git that achieve these goals. In general, we aim to use Git's native support to achieve these goals rather than enforcing practices built on Subversion's model. One general note: due to technical differences with Git, we will not be using Git "merge commits" (created via `git merge`) in stable or releng branches. Instead, when this document refers to "merge commits", it means a commit originally made to `main` that is replicated or "landed" to a stable branch, or a commit from a stable branch that is replicated to a releng branch with some variation of `git cherry-pick`. ==== Finding Eligible Hashes to MFC Git provides some built-in support for this via the `git cherry` and `git log --cherry` commands. These commands compare the raw diffs of commits (but not other metadata such as log messages) to determine if two commits are identical. This works well when each commit from `main` is landed as a single commit to a stable branch, but it falls over if multiple commits from `main` are squashed together as a single commit to a stable branch. The project makes extensive use of `git cherry-pick -x` with all lines preserved to work around these difficulties and is working on automated tooling to take advantage of this. ==== Commit message standards ===== Marking MFCs The project has adopted the following practice for marking MFCs: * Use the `-x` flag with `git cherry-pick`. This adds a line to the commit message that includes the hash of the original commit when merging. Since it is added by Git directly, committers do not have to manually edit the commit log when merging. When merging multiple commits, keep all the "cherry picked from" lines. ===== Trim Metadata? One area that was not clearly documented with Subversion (or even CVS) is how to format metadata in log messages for MFC commits. Should it include the metadata from the original commit unchanged, or should it be altered to reflect information about the MFC commit itself? Historical practice has varied, though some of the variance is by field. For example, MFCs that are relevant to a PR generally include the PR field in the MFC so that MFC commits are included in the bug tracker's audit trail. Other fields are less clear. For example, Phabricator shows the diff of the last commit tagged to a review, so including Phabricator URLs replaces the main commit with the landed commits. The list of reviewers is also not clear. If a reviewer has approved a change to `main`, does that mean they have approved the MFC commit? Is that true if it's identical code only, or with merely trivial rework? It's clearly not true for more extensive reworks. Even for identical code what if the commit doesn't conflict but introduces an ABI change? A reviewer may have ok'd a commit for `main` due to the ABI breakage but may not approve of merging the same commit as-is. One will have to use one's best judgment until clear guidelines can be agreed upon. For MFCs regulated by re@, new metadata fields are added, such as the Approved by tag for approved commits. This new metadata will have to be added via `git commit --amend` or similar after the original commit has been reviewed and approved. We may also want to reserve some metadata fields in MFC commits such as Phabricator URLs for use by re@ in the future. Preserving existing metadata provides a very simple workflow. Developers use `git cherry-pick -x` without having to edit the log message. If instead we choose to adjust metadata in MFCs, developers will have to edit log messages explicitly via the use of `git cherry-pick --edit` or `git commit --amend`. However, as compared to svn, at least the existing commit message can be pre-populated and metadata fields can be added or removed without having to re-enter the entire commit message. The bottom line is that developers will likely need to curate their commit message for MFCs that are non-trivial. [[vendor-import-git]] === Vendor Imports with Git This section describes the vendor import procedure with Git in detail. ==== Branch naming convention All vendor branches and tags start with `vendor/`. These branches and tags are visible by default. [NOTE] ==== This chapter follows the convention that the `freebsd` origin is the origin name for the official FreeBSD Git repository. If you use a different convention, replace `freebsd` with the name you use instead in the examples below. ==== We will explore an example for updating NetBSD's mtree that is in our tree. The vendor branch for this is `vendor/NetBSD/mtree`. ==== Updating an old vendor import The vendor trees usually have only the subset of the third-party software that is appropriate to FreeBSD. These trees are usually tiny in comparison to the FreeBSD tree. Git worktrees are thus quite small and fast and the preferred method to use. Make sure that whatever directory you choose below (the `../mtree`) does not currently exist. [source,shell] .... % git worktree add ../mtree vendor/NetBSD/mtree .... ==== Update the Sources in the Vendor Branch Prepare a full, clean tree of the vendor sources. Import everything but merge only what is needed. This example assumes the NetBSD source is checked out from their GitHub mirror in `~/git/NetBSD`. Note that "upstream" might have added or removed files, so we want to make sure deletions are propagated as well. package:net/rsync[] is commonly installed, so I'll use that. [source,shell] .... % cd ../mtree % rsync -va --del --exclude=".git" ~/git/NetBSD/usr.sbin/mtree/ . % git add -A % git status ... % git diff --staged ... % git commit -m "Vendor import of NetBSD's mtree at 2020-12-11" [vendor/NetBSD/mtree 8e7aa25fcf1] Vendor import of NetBSD's mtree at 2020-12-11 7 files changed, 114 insertions(+), 82 deletions(-) % git tag -a vendor/NetBSD/mtree/20201211 .... It is critical to verify that the source code you are importing comes from a trustworthy source. Many open-source projects use cryptographic signatures to sign code changes, git tags, and/or source code tarballs. Always verify these signatures, and use isolation mechanisms like jails, chroot, in combination with a dedicated, non-privileged user account that is different from the one you regularly use (see the Updating the FreeBSD source tree section below for more details), until you are confident that the source code you are importing looks safe. Following the upstream development and occasionally reviewing the upstream code changes can greatly help in improving code quality and benefit everyone involved. It is also a good idea to examine the git diff results before importing them into the vendor area. Always run the `git diff` and `git status` commands and examine the results carefully. When in doubt, it is useful to do a `git annotate` on the vendor branch or the upstream git repository to see who and why a change was made. In the example above we used `-m` to illustrate, but you should compose a proper message in an editor (using a commit message template). It is also important to create an annotated tag using `git tag -a`, otherwise the push will be rejected. Only annotated tags are allowed to be pushed. The annotated tag gives you a chance to enter a commit message. Enter the version you are importing, along with any salient new features or fixes in that version. ==== Updating the FreeBSD Copy At this point you can push the import to `vendor` into our repo. [source,shell] .... % git push --follow-tags freebsd vendor/NetBSD/mtree .... `--follow-tags` tells `git push` to also push tags associated with the locally committed revision. ==== Updating the FreeBSD source tree Now you need to update the mtree in FreeBSD. The sources live in `contrib/mtree` since it is upstream software. From time to time, we may have to make changes to the contributed code to better satisfy FreeBSD's needs. Whenever possible, please try to contribute the local changes back to the upstream projects, this helps them to better support FreeBSD, and also saves your time for future conflict resolutions when importing updates. [source,shell] .... % cd ../src % git subtree merge -P contrib/mtree vendor/NetBSD/mtree .... This would generate a subtree merge commit of `contrib/mtree` against the local `vendor/NetBSD/mtree` branch. Examine the diff from the merge result and the contents of the upstream branch. If the merge reduced our local changes to more trivial difference like blank line or indenting changes, try amending the local changes to reduce diff against upstream, or try to contribute the remaining changes back to the upstream project. If there were conflicts, you would need to fix them before committing. Include details about the changes being merged in the merge commit message. Some open-source software includes a `configure` script that generates files used to define how the code is built; usually, these generated files like `config.h` should be updated as part of the import process. When doing this, always keep in mind that these scripts are executable code running under the current user's credentials. This process should always be run in an isolated environment, ideally inside a jail that does not have network access, and with an unprivileged account; or, at minimum, a dedicated account that is different from the user account you normally use for everyday purposes or for pushing to the FreeBSD source code repository. This minimizes the risk of encountering bugs that can cause data loss or, in worse cases, maliciously planted code. Using an isolated jail also prevents the configure scripts from detecting locally installed software packages, which may lead to unexpected results. When testing your changes, run them in a chroot or jailed environment, or even within a virtual machine first, especially for kernel or library modifications. This approach helps prevent adverse interactions with your working environment. It can be particularly beneficial for changes to libraries that many base system components use, among others. ==== Rebasing your change against latest FreeBSD source tree Because the current policy recommends against using merges, if the upstream FreeBSD `main` moved forward before you get a chance to push, you would have to redo the merge. Regular `git rebase` or `git pull --rebase` doesn't know how to rebase a merge commit **as a merge commit**, so instead of that you would have to recreate the commit. The following steps should be taken to easily recreate the merge commit as if `git rebase --merge-commits` worked properly: * cd to the top of the repo * Create a side branch `XXX` with the **contents** of the merged tree. * Update this side branch `XXX` to be merged and up-to-date with FreeBSD's `main` branch. ** In the worst case scenario, you would still have to resolve merge conflicts, if there was any, but this should be really rare. ** Resolve conflicts, and collapse multiple commits down to 1 if need be (without conflicts, there's no collapse needed) * checkout `main` * create a branch `YYY` (allows for easier unwinding if things go wrong) * Re-do the subtree merge * Instead of resolving any conflicts from the subtree merge, checkout the contents of XXX on top of it. ** The trailing `.` is important, as is being at the top level of the repo. ** Rather than switching branches to XXX, it splats the contents of XXX on top of the repo * Commit the results with the prior commit message (the example assumes there's only one merge on the XXX branch). * Make sure the branches are the same. * Do whatever review you need, including having others check it out if you think that's needed. * Push the commit, if you 'lost the race' again, just redo these steps again (see below for a recipe) * Delete the branches once the commit is upstream. They are throw-a-way. The commands one would use, following the above example of mtree, would be like so (the `#` starts a comment to help link commands to descriptions above): [source,shell] .... % cd ../src # CD to top of tree % git checkout -b XXX # create new throw-away XXX branch for merge % git fetch freebsd # Get changes from upstream from upstream % git merge freebsd/main # Merge the changes and resolve conflicts % git checkout -b YYY freebsd/main # Create new throw-away YYY branch for redo % git subtree merge -P contrib/mtree vendor/NetBSD/mtree # Redo subtree merge % git checkout XXX . # XXX branch has the conflict resolution % git commit -c XXX~1 # -c reuses the commit message from commit before rebase % git diff XXX YYY # Should be empty % git show YYY # Should only have changes you want, and be a merge commit from vendor branch .... Note: if things go wrong with the commit, you can reset the `YYY` branch by reissuing the checkout command that created it with -B to start over: [source,shell] .... % git checkout -B YYY freebsd/main # Create new throw-away YYY branch if starting over is just going to be easier .... ==== Pushing the changes Once you think you have a set of changes that are good, you can push it to a fork off GitHub or GitLab for others to review. One nice thing about Git is that it allows you to publish rough drafts of your work for others to review. While Phabricator is good for content review, publishing the updated vendor branch and merge commits lets others check the details as they will eventually appear in the repository. After review, when you are sure it is a good change, you can push it to the FreeBSD repo: [source,shell] .... % git push freebsd YYY:main # put the commit on upstream's 'main' branch % git branch -D XXX # Throw away the throw-a-way branches. % git branch -D YYY .... Note: I used `XXX` and `YYY` to make it obvious they are terrible names and should not leave your machine. If you use such names for other work, then you'll need to pick different names, or risk losing the other work. There is nothing magic about these names. Upstream will not allow you to push them, but never the less, please pay attention to the exact commands above. Some commands use syntax that differs only slightly from typical uses and that different behavior is critical to this recipe working. ==== How to redo things if need be If you've tried to do the push in the previous section and it fails, then you should do the following to 'redo' things. This sequence keeps the commit with the commit message always at XXX~1 to make committing easier. [source,shell] .... % git checkout -B XXX YYY # recreate that throw-away-branch XXX and switch to it % git merge freebsd/main # Merge the changes and resolve conflicts % git checkout -B YYY freebsd/main # Recreate new throw-away YYY branch for redo % git subtree merge -P contrib/mtree vendor/NetBSD/mtree # Redo subtree merge % git checkout XXX . # XXX branch has the conflict resolution % git commit -c XXX~1 # -c reuses the commit message from commit before rebase .... Then go check it out as above and push as above when ready. === Creating a new vendor branch There are a number of ways to create a new vendor branch. The recommended way is to create a new repository and then merge that with FreeBSD. If one is importing `glorbnitz` into the FreeBSD tree, release 3.1415. For the sake of simplicity, we will not trim this release. It is a simple user command that puts the nitz device into different magical glorb states and is small enough trimming will not save much. ==== Create the repo [source,shell] .... % cd /some/where % mkdir glorbnitz % cd glorbnitz % git init % git checkout -b vendor/glorbnitz .... At this point, you have a new repo, where all new commits will go on the `vendor/glorbnitz` branch. Git experts can also do this right in their FreeBSD clone, using `git checkout --orphan vendor/glorbnitz` if they are more comfortable with that. ==== Copy the sources in Since this is a new import, you can just cp the sources in, or use tar or even rsync as shown above. And we will add everything, assuming no dot files. [source,shell] .... % cp -r ~/glorbnitz/* . % git add * .... At this point, you should have a pristine copy of glorbnitz ready to commit. [source,shell] .... % git commit -m "Import GlorbNitz frobnosticator revision 3.1415" .... As above, I used `-m` for simplicity, but you should likely create a commit message that explains what a Glorb is and why you'd use a Nitz to get it. Not everybody will know so, for your actual commit, you should follow the crossref:committers-guide[commit-log-message,commit log message] section instead of emulating the brief style used here. ==== Now import it into our repository Now you need to import the branch into our repository. [source,shell] .... % cd /path/to/freebsd/repo/src % git remote add glorbnitz /some/where/glorbnitz % git fetch glorbnitz vendor/glorbnitz .... Note the vendor/glorbnitz branch is in the repo. At this point the `/some/where/glorbnitz` can be deleted, if you like. It was only a means to an end. // perhaps the real treasure was the friends it made along the way... ==== Tag and push Steps from here on out are much the same as they are in the case of updating a vendor branch, though without the updating the vendor branch step. [source,shell] .... % git worktree add ../glorbnitz vendor/glorbnitz % cd ../glorbnitz % git tag --annotate vendor/glorbnitz/3.1415 # Make sure the commit is good with "git show" % git push --follow-tags freebsd vendor/glorbnitz .... By 'good' we mean: . All the right files are present . None of the wrong files are present . The vendor branch points at something sensible . The tag looks good, and is annotated . The commit message for the tag has a quick summary of what's new since the last tag ==== Time to finally merge it into the base tree [source,shell] .... % cd ../src % git subtree add -P contrib/glorbnitz vendor/glorbnitz # Make sure the commit is good with "git show" % git commit --amend # one last sanity check on commit message % git push freebsd .... Here 'good' means: . All the right files, and none of the wrong ones, were merged into contrib/glorbnitz. . No other changes are in the tree. . The commit messages look crossref:committers-guide[commit-log-message,good]. It should contain a summary of what's changed since the last merge to the FreeBSD `main` branch and any caveats. . UPDATING should be updated if there is anything of note, such as user visible changes, important upgrade concerns, etc. [NOTE] ==== This hasn't connected `glorbnitz` to the build yet. How so do that is specific to the software being imported and is beyond the scope of this tutorial. ==== ===== Keeping current So, time passes. It's time now to update the tree for the latest changes upstream. When you checkout `main` make sure that you have no diffs. It's a lot easier to commit those to a branch (or use `git stash`) before doing the following. If you are used to `git pull`, we strongly recommend using the `--ff-only` option, and further setting it as the default option. Alternatively, `git pull --rebase` is useful if you have changes staged in the `main` branch. [source,shell] .... % git config --global pull.ff only .... You may need to omit the --global if you want this setting to apply to only this repository. [source,shell] .... % cd freebsd-src % git checkout main % git pull (--ff-only|--rebase) .... There is a common trap, that the combination command `git pull` will try to perform a merge, which would sometimes creates a merge commit that didn't exist before. This can be harder to recover from. The longer form is also recommended. [source,shell] .... % cd freebsd-src % git checkout main % git fetch freebsd % git merge --ff-only freebsd/main .... These commands reset your tree to the `main` branch, and then update it from where you pulled the tree from originally. It's important to switch to `main` before doing this so it moves forward. Now, it's time to move the changes forward: [source,shell] .... % git rebase -i main working .... This will bring up an interactive screen to change the defaults. For now, just exit the editor. Everything should just apply. If not, then you'll need to resolve the diffs. https://docs.github.com/en/free-pro-team@latest/github/using-git/resolving-merge-conflicts-after-a-git-rebase[This github document] can help you navigate this process. [[git-push-upstream]] ===== Time to push changes upstream First, ensure that the push URL is properly configured for the upstream repository. [source,shell] .... % git remote set-url --push freebsd ssh://git@gitrepo.freebsd.org/src.git .... Then, verify that user name and email are configured right. We require that they exactly match the passwd entry in FreeBSD cluster. Use [source,shell] .... freefall% gen-gitconfig.sh .... on freefall.freebsd.org to get a recipe that you can use directly, assuming /usr/local/bin is in the PATH. The below command merges the `working` branch into the upstream `main` branch. It's important that you curate your changes to be just like you want them in the FreeBSD source repo before doing this. This syntax pushes the `working` branch to `main`, moving the `main` branch forward. You will only be able to do this if this results in a linear change to `main` (e.g. no merges). [source,shell] .... % git push freebsd working:main .... If your push is rejected due to losing a commit race, rebase your branch before trying again: [source,shell] .... % git checkout working % git fetch freebsd % git rebase freebsd/main % git push freebsd working:main .... [[git-push-upstream-alt]] ===== Time to push changes upstream (alternative) Some people find it easier to merge their changes to their local `main` before pushing to the remote repository. Also, `git arc stage` moves changes from a branch to the local `main` when you need to do a subset of a branch. The instructions are similar to the prior section: [source,shell] .... % git checkout main % git merge --ff-only `working` % git push freebsd .... If you lose the race, then try again with [source,shell] .... % git pull --rebase % git push freebsd .... These commands will fetch the most recent `freebsd/main` and then rebase the local `main` changes on top of that, which is what you want when you lose the commit race. Note: merging vendor branch commits will not work with this technique. ===== Finding the Subversion Revision -You'll need to make sure that you've fetched the notes (see the crossref:committers-guide[git-mini-daily-use]for details). +You'll need to make sure that you've fetched the notes (see the crossref:committers-guide[git-mini-daily-use, Daily use]for details). Once you have these, notes will show up in the git log command like so: [source,shell] .... % git log .... If you have a specific version in mind, you can use this construct: [source,shell] .... % git log --grep revision=XXXX .... to find the specific revision. The hex number after 'commit' is the hash you can use to refer to this commit. [[git-faq]] === Git FAQ This section provides a number of targeted answers to questions that are likely to come up often for users and developers. [NOTE] ==== We use the common convention of having the origin for the FreeBSD repository being 'freebsd' rather than the default 'origin' to allow people to use that for their own development and to minimize "whoops" pushes to the wrong repository. ==== ==== Users ===== How do I track -current and -stable with only one copy of the repository? **Q:** Although disk space is not a huge issue, it's more efficient to use only one copy of the repository. With SVN mirroring, I could checkout multiple trees from the same repository. How do I do this with Git? **A:** You can use Git worktrees. There's a number of ways to do this, but the simplest way is to use a clone to track -current, and a worktree to track stable releases. While using a 'bare repository' has been put forward as a way to cope, it's more complicated and will not be documented here. First, you need to clone the FreeBSD repository, shown here cloning into `freebsd-current` to reduce confusion. $URL is whatever mirror works best for you: [source,shell] .... % git clone -o freebsd --config remote.freebsd.fetch='+refs/notes/*:refs/notes/*' $URL freebsd-current .... then once that's cloned, you can simply create a worktree from it: [source,shell] .... % cd freebsd-current % git worktree add ../freebsd-stable-12 stable/12 .... this will checkout `stable/12` into a directory named `freebsd-stable-12` that's a peer to the `freebsd-current` directory. Once created, it's updated very similarly to how you might expect: [source,shell] .... % cd freebsd-current % git checkout main % git pull --ff-only # changes from upstream now local and current tree updated % cd ../freebsd-stable-12 % git merge --ff-only freebsd/stable/12 # now your stable/12 is up to date too .... I recommend using `--ff-only` because it's safer and you avoid accidentally getting into a 'merge nightmare' where you have an extra change in your tree, forcing a complicated merge rather than a simple one. Here's https://adventurist.me/posts/00296[a good writeup] that goes into more detail. ==== Developers ===== Ooops! I committed to `main`, instead of another branch. **Q:** From time to time, I goof up and mistakenly commit to the `main` branch. What do I do? **A:** First, don't panic. Second, don't push. In fact, you can fix almost anything if you haven't pushed. All the answers in this section assume no push has happened. The following answer assumes you committed to `main` and want to create a branch called `issue`: [source,shell] .... % git branch issue # Create the 'issue' branch % git reset --hard freebsd/main # Reset 'main' back to the official tip % git checkout issue # Back to where you were .... ===== Ooops! I committed something to the wrong branch! **Q:** I was working on feature on the `wilma` branch, but accidentally committed a change relevant to the `fred` branch in 'wilma'. What do I do? **A:** The answer is similar to the previous one, but with cherry picking. This assumes there's only one commit on wilma, but will generalize to more complicated situations. It also assumes that it's the last commit on wilma (hence using wilma in the `git cherry-pick` command), but that too can be generalized. [source,shell] .... # We're on branch wilma % git checkout fred # move to fred branch % git cherry-pick wilma # copy the misplaced commit % git checkout wilma # go back to wilma branch % git reset --hard HEAD^ # move what wilma refers to back 1 commit .... Git experts would first rewind the wilma branch by 1 commit, switch over to fred and then use `git reflog` to see what that 1 deleted commit was and cherry-pick it over. **Q:** But what if I want to commit a few changes to `main`, but keep the rest in `wilma` for some reason? **A:** The same technique above also works if you are wanting to 'land' parts of the branch you are working on into `main` before the rest of the branch is ready (say you noticed an unrelated typo, or fixed an incidental bug). You can cherry pick those changes into `main`, then push to the parent repository. Once you've done that, cleanup couldn't be simpler: just `git rebase -i`. Git will notice you've done this and skip the common changes automatically (even if you had to change the commit message or tweak the commit slightly). There's no need to switch back to wilma to adjust it: just rebase! **Q:** I want to split off some changes from branch `wilma` into branch `fred` **A:** The more general answer would be the same as the previous. You'd checkout/create the `fred` branch, cherry pick the changes you want from `wilma` one at a time, then rebase `wilma` to remove those changes you cherry picked. `git rebase -i main wilma` will toss you into an editor, and remove the `pick` lines that correspond to the commits you copied to `fred`. If all goes well, and there are no conflicts, you're done. If not, you'll need to resolve the conflicts as you go. The other way to do this would be to checkout `wilma` and then create the branch `fred` to point to the same point in the tree. You can then `git rebase -i` both these branches, selecting the changes you want in `fred` or `wilma` by retaining the pick likes, and deleting the rest from the editor. Some people would create a tag/branch called `pre-split` before starting in case something goes wrong in the split. You can undo it with the following sequence: [source,shell] .... % git checkout pre-split # Go back % git branch -D fred # delete the fred branch % git checkout -B wilma # reset the wilma branch % git branch -d pre-split # Pretend it didn't happen .... The last step is optional. If you are going to try again to split, you'd omit it. **Q:** But I did things as I read along and didn't see your advice at the end to create a branch, and now `fred` and `wilma` are all screwed up. How do I find what `wilma` was before I started. I don't know how many times I moved things around. **A:** All is not lost. You can figure out it, so long as it hasn't been too long, or too many commits (hundreds). So I created a wilma branch and committed a couple of things to it, then decided I wanted to split it into fred and wilma. Nothing weird happened when I did that, but let's say it did. The way to look at what you've done is with the `git reflog`: [source,shell] .... % git reflog 6ff9c25 (HEAD -> wilma) HEAD@{0}: rebase -i (finish): returning to refs/heads/wilma 6ff9c25 (HEAD -> wilma) HEAD@{1}: rebase -i (start): checkout main 869cbd3 HEAD@{2}: rebase -i (start): checkout wilma a6a5094 (fred) HEAD@{3}: rebase -i (finish): returning to refs/heads/fred a6a5094 (fred) HEAD@{4}: rebase -i (pick): Encourage contributions 1ccd109 (freebsd/main, main) HEAD@{5}: rebase -i (start): checkout main 869cbd3 HEAD@{6}: rebase -i (start): checkout fred 869cbd3 HEAD@{7}: checkout: moving from wilma to fred 869cbd3 HEAD@{8}: commit: Encourage contributions ... % .... Here we see the changes I've made. You can use it to figure out where things went wrong. I'll just point out a few things here. The first one is that HEAD@{X} is a 'commitish' thing, so you can use that as an argument to a command. Although if that command commits anything to the repository, the X numbers change. You can also use the hash (first column). Next, 'Encourage contributions' was the last commit I made to `wilma` before I decided to split things up. You can also see the same hash is there when I created the `fred` branch to do that. I started by rebasing `fred` and you see the 'start', each step, and the 'finish' for that process. While we don't need it here, you can figure out exactly what happened. Fortunately, to fix this, you can follow the prior answer's steps, but with the hash `869cbd3` instead of `pre-split`. While that seems a bit verbose, it's easy to remember since you're doing one thing at a time. You can also stack: [source,shell] .... % git checkout -B wilma 869cbd3 % git branch -D fred .... and you are ready to try again. The `checkout -B` with the hash combines checking out and creating a branch for it. The `-B` instead of `-b` forces the movement of a pre-existing branch. Either way works, which is what's great (and awful) about Git. One reason I tend to use `git checkout -B xxxx hash` instead of checking out the hash, and then creating / moving the branch is purely to avoid the slightly distressing message about detached heads: [source,shell] .... % git checkout 869cbd3 M faq.md Note: checking out '869cbd3'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b HEAD is now at 869cbd3 Encourage contributions % git checkout -B wilma .... this produces the same effect, but I have to read a lot more and severed heads aren't an image I like to contemplate. ===== Ooops! I did a `git pull` and it created a merge commit, what do I do? **Q:** I was on autopilot and did a `git pull` for my development tree and that created a merge commit on `main`. How do I recover? **A:** This can happen when you invoke the pull with your development branch checked out. Right after the pull, you will have the new merge commit checked out. Git supports a `HEAD^#` syntax to examine the parents of a merge commit: [source,shell] .... git log --oneline HEAD^1 # Look at the first parent's commits git log --oneline HEAD^2 # Look at the second parent's commits .... From those logs, you can easily identify which commit is your development work. Then you simply reset your branch to the corresponding `HEAD^#`: [source,shell] .... git reset --hard HEAD^2 .... **Q:** But I also need to fix my `main` branch. How do I do that? **A:** Git keeps track of the remote repository branches in a `freebsd/` namespace. To fix your `main` branch, just make it point to the remote's `main`: [source,shell] .... git branch -f main freebsd/main .... There's nothing magical about branches in Git: they are just labels on a graph that are automatically moved forward by making commits. So the above works because you're just moving a label. There's no metadata about the branch that needs to be preserved due to this. ===== Mixing and matching branches **Q:** So I have two branches `worker` and `async` that I'd like to combine into one branch called `feature` while maintaining the commits in both. **A:** This is a job for cherry pick. [source,shell] .... % git checkout worker % git checkout -b feature # create a new branch % git cherry-pick main..async # bring in the changes .... You now have a new branch called `feature`. This branch combines commits from both branches. You can further curate it with `git rebase`. **Q:** I have a branch called `driver` and I'd like to break it up into `kernel` and `userland` so I can evolve them separately and commit each branch as it becomes ready. **A:** This takes a little bit of prep work, but `git rebase` will do the heavy lifting here. [source,shell] .... % git checkout driver # Checkout the driver % git checkout -b kernel # Create kernel branch % git checkout -b userland # Create userland branch .... Now you have two identical branches. So, it's time to separate out the commits. We'll assume first that all the commits in `driver` go into either the `kernel` or the `userland` branch, but not both. [source,shell] .... % git rebase -i main kernel .... and just include the changes you want (with a 'p' or 'pick' line) and just delete the commits you don't (this sounds scary, but if worse comes to worse, you can throw this all away and start over with the `driver` branch since you've not yet moved it). [source,shell] .... % git rebase -i main userland .... and do the same thing you did with the `kernel` branch. **Q:** Oh great! I followed the above and forgot a commit in the `kernel` branch. How do I recover? **A:** You can use the `driver` branch to find the hash of the commit is missing and cherry pick it. [source,shell] .... % git checkout kernel % git log driver % git cherry-pick $HASH .... **Q:** OK. I have the same situation as the above, but my commits are all mixed up. I need parts of one commit to go to one branch and the rest to go to the other. In fact, I have several. Your rebase method to select sounds tricky. **A:** In this situation, you'd be better off to curate the original branch to separate out the commits, and then use the above method to split the branch. So let's assume that there's just one commit with a clean tree. You can either use `git rebase` with an `edit` line, or you can use this with the commit on the tip. The steps are the same either way. The first thing we need to do is to back up one commit while leaving the changes uncommitted in the tree: [source,shell] .... % git reset HEAD^ .... Note: Do not, repeat do not, add `--hard` here since that also removes the changes from your tree. Now, if you are lucky, the change needing to be split up falls entirely along file lines. In that case you can just do the usual `git add` for the files in each group than do a `git commit`. Note: when you do this, you'll lose the commit message when you do the reset, so if you need it for some reason, you should save a copy (though `git log $HASH` can recover it). If you are not lucky, you'll need to split apart files. There's another tool to do that which you can apply one file at a time. [source,shell] .... git add -i foo/bar.c .... will step through the diffs, prompting you, one at time, whether to include or exclude the hunk. Once you're done, `git commit` and you'll have the remainder in your tree. You can run it multiple times as well, and even over multiple files (though I find it easier to do one file at a time and use the `git rebase -i` to fold the related commits together). ==== Cloning and Mirroring **Q:** I'd like to mirror the entire Git repository, how do I do that? **A:** If all you want to do is mirror, then [source,shell] .... % git clone --mirror $URL .... will do the trick. However, there are two disadvantages to this if you want to use it for anything other than a mirror you'll reclone. First, this is a 'bare repository' which has the repository database, but no checked out worktree. This is great for mirroring, but terrible for day to day work. There's a number of ways around this with `git worktree`: [source,shell] .... % git clone --mirror https://git.freebsd.org/ports.git ports.git % cd ports.git % git worktree add ../ports main % git worktree add ../quarterly branches/2020Q4 % cd ../ports .... But if you aren't using your mirror for further local clones, then it's a poor match. The second disadvantage is that Git normally rewrites the refs (branch name, tags, etc) from upstream so that your local refs can evolve independently of upstream. This means that you'll lose changes if you are committing to this repository on anything other than private project branches. **Q:** So what can I do instead? **A:** Well, you can stuff all of the upstream repository's refs into a private namespace in your local repository. Git clones everything via a 'refspec' and the default refspec is: [source,shell] .... fetch = +refs/heads/*:refs/remotes/freebsd/* .... which says just fetch the branch refs. However, the FreeBSD repository has a number of other things in it. To see those, you can add explicit refspecs for each ref namespace, or you can fetch everything. To setup your repository to do that: [source,shell] .... git config --add remote.freebsd.fetch '+refs/*:refs/freebsd/*' .... which will put everything in the upstream repository into your local repository's `refs/freebsd/` namespace. Please note, that this also grabs all the unconverted vendor branches and the number of refs associated with them is quite large. You'll need to refer to these 'refs' with their full name because they aren't in and of Git's regular namespaces. [source,shell] .... git log refs/freebsd/vendor/zlib/1.2.10 .... would look at the log for the vendor branch for zlib starting at 1.2.10. === Collaborating with others One of the keys to good software development on a project as large as FreeBSD is the ability to collaborate with others before you push your changes to the tree. The FreeBSD project's Git repositories do not, yet, allow user-created branches to be pushed to the repository, and therefore if you wish to share your changes with others you must use another mechanism, such as a hosted GitLab or GitHub, to share changes in a user-generated branch. The following instructions show how to set up a user-generated branch, based on the FreeBSD `main` branch, and push it to GitHub. Before you begin, make sure that your local Git repo is up to date and has the correct origins set crossref:committers-guide[keeping_current,as shown above]. [source,shell] ```` % git remote -v freebsd https://git.freebsd.org/src.git (fetch) freebsd ssh://git@gitrepo.freebsd.org/src.git (push) ```` The first step is to create a fork of https://github.com/freebsd/freebsd-src[FreeBSD] on GitHub following these https://docs.github.com/en/github/getting-started-with-github/fork-a-repo[guidelines]. The destination of the fork should be your own, personal, GitHub account (gvnn3 in my case). Now add a remote on your local system that points to your fork: [source,shell] .... % git remote add github git@github.com:gvnn3/freebsd-src.git % git remote -v github git@github.com:gvnn3/freebsd-src.git (fetch) github git@github.com:gvnn3/freebsd-src.git (push) freebsd https://git.freebsd.org/src.git (fetch) freebsd ssh://git@gitrepo.freebsd.org/src.git (push) .... With this in place you can create a branch crossref:committers-guide[keeping_a_local_branch,as shown above]. [source,shell] .... % git checkout -b gnn-pr2001-fix .... Make whatever modifications you wish in your branch. Build, test, and once you're ready to collaborate with others it's time to push your changes into your hosted branch. Before you can push you'll have to set the appropriate upstream, as Git will tell you the first time you try to push to your +github+ remote: [source,shell] .... % git push github fatal: The current branch gnn-pr2001-fix has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream github gnn-pr2001-fix .... Setting the push as +git+ advises allows it to succeed: [source,shell] .... % git push --set-upstream github gnn-feature Enumerating objects: 20486, done. Counting objects: 100% (20486/20486), done. Delta compression using up to 8 threads Compressing objects: 100% (12202/12202), done. Writing objects: 100% (20180/20180), 56.25 MiB | 13.15 MiB/s, done. Total 20180 (delta 11316), reused 12972 (delta 7770), pack-reused 0 remote: Resolving deltas: 100% (11316/11316), completed with 247 local objects. remote: remote: Create a pull request for 'gnn-feature' on GitHub by visiting: remote: https://github.com/gvnn3/freebsd-src/pull/new/gnn-feature remote: To github.com:gvnn3/freebsd-src.git * [new branch] gnn-feature -> gnn-feature Branch 'gnn-feature' set up to track remote branch 'gnn-feature' from 'github'. .... Subsequent changes to the same branch will push correctly by default: [source,shell] .... % git push Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Delta compression using up to 8 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 314 bytes | 1024 bytes/s, done. Total 3 (delta 1), reused 1 (delta 0), pack-reused 0 remote: Resolving deltas: 100% (1/1), completed with 1 local object. To github.com:gvnn3/freebsd-src.git 9e5243d7b659..cf6aeb8d7dda gnn-feature -> gnn-feature .... At this point your work is now in your branch on +GitHub+ and you can share the link with other collaborators. [[github-pull-land]] === Landing a github pull request This section documents how to land a GitHub pull request that's submitted against the FreeBSD Git mirrors at GitHub. While this is not an official way to submit patches at this time, sometimes good fixes come in this way and it is easiest just to bring them into a committer's tree and have them pushed into the FreeBSD's tree from there. Similar steps can be used to pull branches from other repositories and land those. When committing pull requests from others, one should take extra care to examine all the changes to ensure they are exactly as represented. Before beginning, make sure that the local Git repo is up to date and has the correct origins set crossref:committers-guide[keeping_current,as shown above]. In addition, make sure to have the following origins: [source,shell] .... % git remote -v freebsd https://git.freebsd.org/src.git (fetch) freebsd ssh://git@gitrepo.freebsd.org/src.git (push) github https://github.com/freebsd/freebsd-src (fetch) github https://github.com/freebsd/freebsd-src (fetch) .... Often pull requests are simple: requests that contain only a single commit. In this case, a streamlined approach may be used, though the approach in the prior section will also work. Here, a branch is created, the change is cherry picked, the commit message adjusted, and sanity-checked before being pushed. The branch `staging` is used in this example but it can be any name. This technique works for any number of commits in the pull request, especially when the changes apply cleanly to the FreeBSD tree. However, when there's multiple commits, especially when minor adjustments are needed, `git rebase -i` works better than `git cherry-pick`. Briefly, these commands create a branch; cherry-picks the changes from the pull request; tests it; adjusts the commit messages; and fast forward merges it back to `main`. The PR number is `$PR` below. When adjusting the message, add `Pull Request: https://github.com/freebsd-src/pull/$PR`. All pull requests committed to the FreeBSD repository should be reviewed by at least one person. This need not be the person committing it, but in that case the person committing it should trust the other reviewers competence to review the commit. Committers that do a code review of pull requests before pushing them into the repo should add a `Reviewed by:` line to the commit, because in this case it is not implicit. Add anybody that reviews and approves the commit on github to `Reviewed by:` as well. As always, care should be taken to ensure the change does what it is supposed to, and that no malicious code is present. [NOTE] ====== In addition, please check to make sure that the pull request author name is not anonymous. Github's web editing interface generates names like: [source,shell] .... Author: github-user <38923459+github-user@users.noreply.github.com> .... A polite request to the author for a better name and/or email should be made. Extra care should be taken to ensure no style issue or malicious code is introduced. ====== [source,shell] .... % git fetch github pull/$PR/head:staging % git rebase -i main staging # to move the staging branch forward, adjust commit message here % git checkout main % git pull --ff-only # to get the latest if time has passed % git checkout main % git merge --ff-only staging % git push freebsd --push-option=confirm-author .... [.procedure] ==== For complicated pull requests that have multiple commits with conflicts, follow the following outline. . checkout the pull request `git checkout github/pull/XXX` . create a branch to rebase `git checkout -b staging` . rebase the `staging` branch to the latest `main` with `git rebase -i main staging` . resolve conflicts and do whatever testing is needed . fast forward the `staging` branch into `main` as above . final sanity check of changes to make sure all is well . push to FreeBSD's Git repository. This will also work when bringing branches developed elsewhere into the local tree for committing. ==== Once finished with the pull request, close it using GitHub's web interface. It is worth noting that if your `github` origin uses `https://`, the only step you'll need a GitHub account for is closing the pull request. [[vcs-history]] == Version Control History The project has moved to crossref:committers-guide[git-primer,git]. The FreeBSD source repository switched from CVS to Subversion on May 31st, 2008. The first real SVN commit is __r179447__. The source repository switched from Subversion to Git on December 23rd, 2020. The last real svn commit is __r368820__. The first real git commit hash is __5ef5f51d2bef80b0ede9b10ad5b0e9440b60518c__. The FreeBSD `doc/www` repository switched from CVS to Subversion on May 19th, 2012. The first real SVN commit is __r38821__. The documentation repository switched from Subversion to Git on December 8th, 2020. The last SVN commit is __r54737__. The first real git commit hash is __3be01a475855e7511ad755b2defd2e0da5d58bbe__. The FreeBSD `ports` repository switched from CVS to Subversion on July 14th, 2012. The first real SVN commit is __r300894__. The ports repository switched from Subversion to Git on April 6, 2021. The last SVN commit is __r569609__ The first real git commit hash is __ed8d3eda309dd863fb66e04bccaa513eee255cbf__. [[conventions]] == Setup, Conventions, and Traditions There are a number of things to do as a new developer. The first set of steps is specific to committers only. These steps must be done by a mentor for those who are not committers. [[conventions-committers]] === For New Committers Those who have been given commit rights to the FreeBSD repositories must follow these steps. * Get mentor approval before committing each of these changes! * All [.filename]#src# commits go to FreeBSD-CURRENT first before being merged to FreeBSD-STABLE. The FreeBSD-STABLE branch must maintain ABI and API compatibility with earlier versions of that branch. Do not merge changes that break this compatibility. [[commit-steps]] [.procedure] ==== *Steps for New Committers* . Add an Author Entity + [.filename]#doc/shared/authors.adoc# - Add an author entity. Later steps depend on this entity, and missing this step will cause the [.filename]#doc/# build to fail. This is a relatively easy task, but remains a good first test of version control skills. . Update the List of Developers and Contributors + [.filename]#doc/shared/contrib-committers.adoc# - Add an entry, which will then appear in the "Developers" section of the extref:{contributors}[Contributors List, staff-committers]. Entries are sorted by last name. + [.filename]#doc/shared/contrib-additional.adoc# - _Remove_ the entry. Entries are sorted by first name. . Add a News Item + [.filename]#doc/website/data/en/news/news.toml# - Add an entry. Look for the other entries that announce new committers and follow the format. Use the date from the commit bit approval email. . Add a PGP Key + `{des}` has written a shell script ([.filename]#doc/documentation/tools/addkey.sh#) to make this easier. See the https://cgit.freebsd.org/doc/plain/documentation/static/pgpkeys/README[README] file for more information. + Use [.filename]#doc/documentation/tools/checkkey.sh# to verify that keys meet minimal best-practices standards. + After adding and checking a key, add both updated files to source control and then commit them. Entries in this file are sorted by last name. + [NOTE] ====== It is very important to have a current PGP/GnuPG key in the repository. The key may be required for positive identification of a committer. For example, the `{admins}` might need it for account recovery. A complete keyring of `FreeBSD.org` users is available for download from link:https://docs.FreeBSD.org/pgpkeys/pgpkeys.txt[https://docs.FreeBSD.org/pgpkeys/pgpkeys.txt]. ====== . Update Mentor and Mentee Information + [.filename]#src/share/misc/committers-.dot# - Add an entry to the current committers section, where _repository_ is `doc`, `ports`, or `src`, depending on the commit privileges granted. + Add an entry for each additional mentor/mentee relationship in the bottom section. . Generate a Kerberos Password + -See crossref:committers-guide[kerberos-ldap] to generate or set a Kerberos account for use with other FreeBSD services like the link:https://bugs.freebsd.org/bugzilla/[bug-tracking database] (you get a bug-tracking account as part of that step). +See crossref:committers-guide[kerberos-ldap, Kerberos and LDAP web Password for FreeBSD Cluster] to generate or set a Kerberos account for use with other FreeBSD services like the link:https://bugs.freebsd.org/bugzilla/[bug-tracking database] (you get a bug-tracking account as part of that step). . Optional: Enable Wiki Account + link:https://wiki.freebsd.org[FreeBSD Wiki] Account - A wiki account allows sharing projects and ideas. Those who do not yet have an account can follow instructions on the link:https://wiki.freebsd.org/Wiki/About[Wiki/About page] to obtain one. Contact mailto:wiki-admin@FreeBSD.org[wiki-admin@FreeBSD.org] if you need help with your Wiki account. . Optional: Update Wiki Information + Wiki Information - After gaining access to the wiki, some people add entries to the https://wiki.freebsd.org/HowWeGotHere[How We Got Here], https://wiki.freebsd.org/IRC/Nicknames[IRC Nicks], https://wiki.freebsd.org/Community/Dogs[Dogs of FreeBSD], and or https://wiki.freebsd.org/Community/Cats[Cats of FreeBSD] pages. . Optional: Update Ports with Personal Information + [.filename]#ports/astro/xearth/files/freebsd.committers.markers# and [.filename]#src/usr.bin/calendar/calendars/calendar.freebsd# - Some people add entries for themselves to these files to show where they are located or the date of their birthday. . Optional: Prevent Duplicate Mailings + Subscribers to {dev-commits-doc-all}, {dev-commits-ports-all} or {dev-commits-src-all} might wish to unsubscribe to avoid receiving duplicate copies of commit messages and followups. ==== [[conventions-everyone]] === For Everyone [[conventions-everyone-steps]] [.procedure] ==== . Introduce yourself to the other developers, otherwise no one will have any idea who you are or what you are working on. The introduction need not be a comprehensive biography, just write a paragraph or two about who you are, what you plan to be working on as a developer in FreeBSD, and who will be your mentor. Email this to the {developers-name} and you will be on your way! . Log into `freefall.FreeBSD.org` and create a [.filename]#/var/forward/user# (where _user_ is your username) file containing the e-mail address where you want mail addressed to _yourusername_@FreeBSD.org to be forwarded. This includes all of the commit messages as well as any other mail addressed to the {committers-name} and the {developers-name}. Really large mailboxes which have taken up permanent residence on `freefall` may get truncated without warning if space needs to be freed, so forward it or save it elsewhere. + [NOTE] ====== If your e-mail system uses SPF with strict rules, you should exclude `mx2.FreeBSD.org` from SPF checks. ====== + Due to the severe load dealing with SPAM places on the central mail servers that do the mailing list processing, the front-end server does do some basic checks and will drop some messages based on these checks. At the moment proper DNS information for the connecting host is the only check in place but that may change. Some people blame these checks for bouncing valid email. To have these checks turned off for your email, create a file named [.filename]#~/.spam_lover# on `freefall.FreeBSD.org`. + [NOTE] ====== Those who are developers but not committers will not be subscribed to the committers or developers mailing lists. The subscriptions are derived from the access rights. ====== ==== [[smtp-setup]] ==== SMTP Access Setup For those willing to send e-mail messages through the FreeBSD.org infrastructure, follow the instructions below: [.procedure] ==== . Point your mail client at `smtp.FreeBSD.org:587`. . Enable STARTTLS. . Ensure your `From:` address is set to `_yourusername_@FreeBSD.org`. . For authentication, you can use your FreeBSD Kerberos username and password - (see crossref:committers-guide[kerberos-ldap]). The `_yourusername_/mail` principal is preferred, as it is only valid for authenticating to mail resources. + (see crossref:committers-guide[kerberos-ldap, Kerberos and LDAP web Password for FreeBSD Cluster]). The `_yourusername_/mail` principal is preferred, as it is only valid for authenticating to mail resources. + [NOTE] ====== Do not include `@FreeBSD.org` when entering in your username. ====== + .Additional Notes [NOTE] ====== * Will only accept mail from `_yourusername_@FreeBSD.org`. If you are authenticated as one user, you are not permitted to send mail from another. * A header will be appended with the SASL username: (`Authenticated sender: _username_`). * Host has various rate limits in place to cut down on brute force attempts. ====== ==== [[smtp-setup-local-mta]] ===== Using a Local MTA to Forward Emails to the FreeBSD.org SMTP Service It is also possible to use a local MTA to forward locally sent emails to the FreeBSD.org SMTP servers. [[smtp-setup-local-postfix]] .Using Postfix [example] ==== To tell a local Postfix instance that anything from `_yourusername_@FreeBSD.org` should be forwarded to the FreeBSD.org servers, add this to your [.filename]#main.cf#: [.programlisting] .... sender_dependent_relayhost_maps = hash:/usr/local/etc/postfix/relayhost_maps smtp_sasl_auth_enable = yes smtp_sasl_security_options = noanonymous smtp_sasl_password_maps = hash:/usr/local/etc/postfix/sasl_passwd smtp_use_tls = yes .... Create [.filename]#/usr/local/etc/postfix/relayhost_maps# with the following content: [.programlisting] .... yourusername@FreeBSD.org [smtp.freebsd.org]:587 .... Create [.filename]#/usr/local/etc/postfix/sasl_passwd# with the following content: [.programlisting] .... [smtp.freebsd.org]:587 yourusername:yourpassword .... If the email server is used by other people, you may want to prevent them from sending e-mails from your address. To achieve this, add this to your [.filename]#main.cf#: [.programlisting] .... smtpd_sender_login_maps = hash:/usr/local/etc/postfix/sender_login_maps smtpd_sender_restrictions = reject_known_sender_login_mismatch .... Create [.filename]#/usr/local/etc/postfix/sender_login_maps# with the following content: [.programlisting] .... yourusername@FreeBSD.org yourlocalusername .... Where _yourlocalusername_ is the SASL username used to connect to the local instance of Postfix. ==== [[smtp-setup-local-opensmtpd]] .Using OpenSMTPD [example] ==== To tell a local OpenSMTPD instance that anything from `_yourusername_@FreeBSD.org` should be forwarded to the FreeBSD.org servers, add this to your [.filename]#smtpd.conf#: [.programlisting] .... action "freebsd" relay host smtp+tls://freebsd@smtp.freebsd.org:587 auth match from any auth yourlocalusername mail-from "_yourusername_@freebsd.org" for any action "freebsd" .... Where _yourlocalusername_ is the SASL username used to connect to the local instance of OpenSMTPD. Create [.filename]#/usr/local/etc/mail/secrets# with the following content: [.programlisting] .... freebsd yourusername:yourpassword .... ==== [[smtp-setup-local-exim]] .Using Exim [example] ==== To direct a local Exim instance to forward all mail from `_example_@FreeBSD.org` to FreeBSD.org servers, add this to Exim [.filename]#configuration#: [.programlisting] .... Routers section: (at the top of the list): freebsd_send: driver = manualroute domains = !+local_domains transport = freebsd_smtp route_data = ${lookup {${lc:$sender_address}} lsearch {/usr/local/etc/exim/freebsd_send}} Transport Section: freebsd_smtp: driver = smtp tls_certificate= tls_privatekey= tls_require_ciphers = EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+AESGCM:EECDH:EDH+AESGCM:EDH+aRSA:HIGH:!MEDIUM:!LOW:!aNULL:!eNULL:!LOW:!RC4:!MD5:!EXP:!PSK:!SRP:!DSS dkim_domain = dkim_selector = dkim_private_key= dnssec_request_domains = * hosts_require_auth = smtp.freebsd.org Authenticators: freebsd_plain: driver = plaintext public_name = PLAIN client_send = ^example/mail^examplePassword client_condition = ${if eq{$host}{smtp.freebsd.org}} .... Create [.filename]#/usr/local/etc/exim/freebsd_send# with the following content: [.programlisting] .... example@freebsd.org:smtp.freebsd.org::587 .... ==== [[mentors]] === Mentors All new developers have a mentor assigned to them for the first few months. A mentor is responsible for teaching the mentee the rules and conventions of the project and guiding their first steps in the developer community. The mentor is also personally responsible for the mentee's actions during this initial period. For committers: do not commit anything without first getting mentor approval. Document that approval with an `Approved by:` line in the commit message. When the mentor decides that a mentee has learned the ropes and is ready to commit on their own, the mentor announces it with a commit to [.filename]#mentors#. This file is in the [.filename]#admin# orphan branch of each repository. Detailed information on how to access these branches can be found in -crossref:committers-guide[admin-branch]. +crossref:committers-guide[admin-branch, "admin" branch]. [[pre-commit-review]] == Pre-Commit Review Code review is one way to increase the quality of software. The following guidelines apply to commits to the `main` (-CURRENT) branch of the `src` repository. Other branches and the `ports` and `docs` trees have their own review policies, but these guidelines generally apply to commits requiring review: * All non-trivial changes should be reviewed before they are committed to the repository. * Reviews may be conducted by email, in Bugzilla, in Phabricator, or by another mechanism. Where possible, reviews should be public. * The developer responsible for a code change is also responsible for making all necessary review-related changes. * Code review can be an iterative process, which continues until the patch is ready to be committed. Specifically, once a patch is sent out for review, it should receive an explicit "looks good" before it is committed. So long as it is explicit, this can take whatever form makes sense for the review method. * Timeouts are not a substitute for review. Sometimes code reviews will take longer than you would hope for, especially for larger features. Accepted ways to speed up review times for your patches are: * Review other people's patches. If you help out, everybody will be more willing to do the same for you; goodwill is our currency. * Ping the patch. If it is urgent, provide reasons why it is important to you to get this patch landed and ping it every couple of days. If it is not urgent, the common courtesy ping rate is one week. Remember that you are asking for valuable time from other professional developers. * Ask for help on mailing lists, IRC, etc. Others may be able to either help you directly, or suggest a reviewer. * Split your patch into multiple smaller patches that build on each other. The smaller your patch, the higher the probability that somebody will take a quick look at it. + When making large changes, it is helpful to keep this in mind from the beginning of the effort as breaking large changes into smaller ones is often difficult after the fact. Developers should participate in code reviews as both reviewers and reviewees. If someone is kind enough to review your code, you should return the favor for someone else. Note that while anyone is welcome to review and give feedback on a patch, only an appropriate subject-matter expert can approve a change. This will usually be a committer who works with the code in question on a regular basis. In some cases, no subject-matter expert may be available. In those cases, a review by an experienced developer is sufficient when coupled with appropriate testing. [[commit-log-message]] == Commit Log Messages This section contains some suggestions and traditions for how commit logs are formatted. === Why are commit messages important? When you commit a change in Git, Subversion, or another version control system (VCS), you're prompted to write some text describing the commit -- a commit message. How important is this commit message? Should you spend some significant effort writing it? Does it really matter if you write simply `fixed a bug`? Most projects have more than one developer and last for some length of time. Commit messages are a very important method of communicating with other developers, in the present and for the future. FreeBSD has hundreds of active developers and hundreds of thousands of commits spanning decades of history. Over that time the developer community has learned how valuable good commit messages are; sometimes these are hard-learned lessons. Commit messages serve at least three purposes: * Communicating with other developers + FreeBSD commits generate email to various mailing lists. These include the commit message along with a copy of the patch itself. Commit messages are also viewed through commands like git log. These serve to make other developers aware of changes that are ongoing; that other developer may want to test the change, may have an interest in the topic and will want to review in more detail, or may have their own projects underway that would benefit from interaction. * Making Changes Discoverable + In a large project with a long history it may be difficult to find changes of interest when investigating an issue or change in behaviour. Verbose, detailed commit messages allow searches for changes that might be relevant. For example, `git log --since 1year --grep 'USB timeout'`. * Providing historical documentation + Commit messages serve to document changes for future developers, perhaps years or decades later. This future developer may even be you, the original author. A change that seems obvious today may be decidedly not so much later on. The `git blame` command annotates each line of a source file with the change (hash and subject line) that brought it in. Having established the importance, here are elements of a good FreeBSD commit message: === Start with a subject line Commit messages should start with a single-line subject that briefly summarizes the change. The subject should, by itself, allow the reader to quickly determine if the change is of interest or not. === Keep subject lines short The subject line should be as short as possible while still retaining the required information. This is to make browsing Git log more efficient, and so that git log --oneline can display the short hash and subject on a single 80-column line. A good rule of thumb is to stay below 63 characters, and aim for about 50 or fewer if possible. === Prefix the subject line with a component, if applicable If the change relates to a specific component the subject line may be prefixed with that component name and a colon (:). ✓ `foo: Add -k option to keep temporary data` Include the prefix in the 63-character limit suggested above, so that `git log --oneline` avoids wrapping. === Capitalize the first letter of the subject Capitalize the first letter of the subject itself. The prefix, if any, is not capitalized unless necessary (e.g., `USB:` is capitalized). === Do not end the subject line with punctuation Do not end with a period or other punctuation. In this regard the subject line is like a newspaper headline. === Separate the subject and body with a blank line Separate the body from the subject with a blank line. Some trivial commits do not require a body, and will have only a subject. ✓ `ls: Fix typo in usage text` === Limit messages to 72 columns `git log` and `git format-patch` indent the commit message by four spaces. Wrapping at 72 columns provides a matching margin on the right edge. Limiting messages to 72 characters also keeps the commit message in formatted patches below RFC 2822's suggested email line length limit of 78 characters. This limit works well with a variety of tools that may render commit messages; line wrapping might be inconsistent with longer line length. === Use the present tense, imperative mood This facilitates short subject lines and provides consistency, including with automatically generated commit messages (e.g., as generated by git revert). This is important when reading a list of commit subjects. Think of the subject as finishing the sentence "when applied, this change will ...". ✓ `foo: Implement the -k (keep) option` + ✗ `foo: Implemented the -k option` + ✗ `This change implements the -k option in foo` + ✗ `-k option added` === Focus on what and why, not how Explain what the change accomplishes and why it is being done, rather than how. Do not assume that the reader is familiar with the issue. Explain the background and motivation for the change. Include benchmark data if you have it. If there are limitations or incomplete aspects of the change, describe them in the commit message. === Consider whether parts of the commit message could be code comments instead Sometimes while writing a commit message you may find yourself writing a sentence or two explaining some tricky or confusing aspect of the change. When this happens consider whether it would be valuable to have that explanation as a comment in the code itself. === Write commit messages for your future self While writing the commit message for a change you have all of the context in mind - what prompted the change, alternate approaches that were considered and rejected, limitations of the change, and so on. Imagine yourself revisiting the change a year or two in the future, and write the commit message in a way that would provide that necessary context. === Commit messages should stand alone You may include references to mailing list postings, benchmark result web sites, or code review links. However, the commit message should contain all of the relevant information in case these references are no longer available in the future. Similarly, a commit may refer to a previous commit, for example in the case of a bug fix or revert. In addition to the commit identifier (revision or hash), include the subject line from the referenced commit (or another suitable brief reference). With each VCS migration (from CVS to Subversion to Git) revision identifiers from previous systems may become difficult to follow. === Include appropriate metadata in a footer As well as including an informative message with each commit, some additional information may be needed. This information consists of one or more lines containing the key word or phrase, a colon, tabs for formatting, and then the additional information. The key words or phrases are: [.informaltable] [cols="20%,80%", frame="none"] |=== |`PR:` |The problem report (if any) which is affected (typically, by being closed) by this commit. Multiple PRs may be specified on one line, separated by commas or spaces. |`Reported by:` |The name and e-mail address of the person that reported the issue; for developers, just the username on the FreeBSD cluster. Typically used when there is no PR, for example if the issue was reported on a mailing list. |`Submitted by:` + (deprecated) |This has been deprecated with git; submitted patches should have the author set by using `git commit --author` with a full name and valid email. |`Reviewed by:` a| The name and e-mail address of the person or people that reviewed the change; for developers, just the username on the FreeBSD cluster. If a patch was submitted to a mailing list for review, and the review was favorable, then just include the list name. If the reviewer is not a member of the project, provide the name, email, and if ports an external role like maintainer: Reviewed by a developer: [source,shell] .... Reviewed by: username .... Reviewed by a ports maintainer that is not a developer: [source,shell] .... Reviewed by: Full Name (maintainer) .... |`Tested by:` |The name and e-mail address of the person or people that tested the change; for developers, just the username on the FreeBSD cluster. |`Approved by:` a| The name and e-mail address of the person or people that approved the change; for developers, just the username on the FreeBSD cluster. There are several cases where approval is customary: * while a new committer is under mentorship * commits to an area of the tree covered by the LOCKS file (src) * during a release cycle * committing to a repo where you do not hold a commit bit (e.g. src committer committing to docs) * committing to a port maintained by someone else While under mentorship, get mentor approval before the commit. Enter the mentor's username in this field, and note that they are a mentor: [source,shell] .... Approved by: username-of-mentor (mentor) .... If a team approved these commits then include the team name followed by the username of the approver in parentheses. For example: [source,shell] .... Approved by: re (username) .... |`Obtained from:` |The name of the project (if any) from which the code was obtained. Do not use this line for the name of an individual person. |`Fixes:` |The Git short hash and the title line of a commit that is fixed by this change as returned by `git log -n 1 --oneline GIT-COMMIT-HASH`. |`MFC after:` |To receive an e-mail reminder to MFC at a later date, specify the number of days, weeks, or months after which an MFC is planned. |`MFC to:` |If the commit should be merged to a subset of stable branches, specify the branch names. |`MFH:` |If the commit is to be merged into a ports quarterly branch name, specify the quarterly branch. For example `2021Q2`. |`Relnotes:` |If the change is a candidate for inclusion in the release notes for the next release from the branch, set to `yes`. |`Security:` |If the change is related to a security vulnerability or security exposure, include one or more references or a description of the issue. If possible, include a VuXML URL or a CVE ID. |`Event:` |The description for the event where this commit was made. If this is a recurring event, add the year or even the month to it. For example, this could be `FooBSDcon 2019`. The idea behind this line is to put recognition to conferences, gatherings, and other types of meetups and to show that these are useful to have. Please do not use the `Sponsored by:` line for this as that is meant for organizations sponsoring certain features or developers working on them. |`Sponsored by:` |Sponsoring organizations for this change, if any. Separate multiple organizations with commas. If only a portion of the work was sponsored, or different amounts of sponsorship were provided to different authors, please give appropriate credit in parentheses after each sponsor name. For example, `Example.com (alice, code refactoring), Wormulon (bob), Momcorp (cindy)` shows that Alice was sponsored by Example.com to do code refactoring, while Wormulon sponsored Bob's work and Momcorp sponsored Cindy's work. Other authors were either not sponsored or chose not to list sponsorship. |`Pull Request:` |This change was submitted as a pull request or merge request against one of FreeBSD's public read-only Git repositories. It should include the entire URL to the pull request, as these often act as code reviews for the code. For example: `https://github.com/freebsd/freebsd-src/pull/745` |`Co-authored-by:` |The name and email address of an additional author of the commit. GitHub has a detailed description of the Co-authored-by trailer at https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors. |`Signed-off-by:` |ID certifies compliance with https://developercertificate.org/ |`Differential Revision:` |The full URL of the Phabricator review. This line __must be the last line__. For example: `https://reviews.freebsd.org/D1708`. |=== .Commit Log for a Commit Based on a PR [example] ==== The commit is based on a patch from a PR submitted by John Smith. The commit message "PR" field is filled. [.programlisting] .... ... PR: 12345 .... The committer sets the author of the patch with `git commit --author "John Smith "`. ==== .Commit Log for a Commit Needing Review [example] ==== The virtual memory system is being changed. After posting patches to the appropriate mailing list (in this case, `freebsd-arch`) and the changes have been approved. [.programlisting] .... ... Reviewed by: -arch .... ==== .Commit Log for a Commit Needing Approval [example] ==== Commit a port, after working with the listed MAINTAINER, who said to go ahead and commit. [.programlisting] .... ... Approved by: abc (maintainer) .... Where _abc_ is the account name of the person who approved. ==== .Commit Log for a Commit Bringing in Code from OpenBSD [example] ==== Committing some code based on work done in the OpenBSD project. [.programlisting] .... ... Obtained from: OpenBSD .... ==== .Commit Log for a Change to FreeBSD-CURRENT with a Planned Commit to FreeBSD-STABLE to Follow at a Later Date. [example] ==== Committing some code which will be merged from FreeBSD-CURRENT into the FreeBSD-STABLE branch after two weeks. [.programlisting] .... ... MFC after: 2 weeks .... Where _2_ is the number of days, weeks, or months after which an MFC is planned. The _weeks_ option may be `day`, `days`, `week`, `weeks`, `month`, `months`. ==== It is often necessary to combine these. Consider the situation where a user has submitted a PR containing code from the NetBSD project. Looking at the PR, the developer sees it is not an area of the tree they normally work in, so they have the change reviewed by the `arch` mailing list. Since the change is complex, the developer opts to MFC after one month to allow adequate testing. The extra information to include in the commit would look something like .Example Combined Commit Log [example] ==== [.programlisting] .... PR: 54321 Reviewed by: -arch Obtained from: NetBSD MFC after: 1 month Relnotes: yes .... ==== [[pref-license]] == Preferred License for New Files The FreeBSD Project's full license policy can be found at link:https://www.FreeBSD.org/internal/software-license/[https://www.FreeBSD.org/internal/software-license]. The rest of this section is intended to help you get started. As a rule, when in doubt, ask. It is much easier to give advice than to fix the source tree. The FreeBSD Project suggests and uses this text as the preferred license scheme: [.programlisting] .... /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) [year] [your name] * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must 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. * * [id for your version control system, if any] */ .... The FreeBSD project strongly discourages the so-called "advertising clause" in new code. Due to the large number of contributors to the FreeBSD project, complying with this clause for many commercial vendors has become difficult. If you have code in the tree with the advertising clause, please consider removing it. In fact, please consider using the above license for your code. The FreeBSD project discourages completely new licenses and variations on the standard licenses. New licenses require the approval of {core-email} to reside in the `src` repository. The more different licenses that are used in the tree, the more problems that this causes to those wishing to utilize this code, typically from unintended consequences from a poorly worded license. Project policy dictates that code under some non-BSD licenses must be placed only in specific sections of the repository, and in some cases, compilation must be conditional or even disabled by default. For example, the GENERIC kernel must be compiled under only licenses identical to or substantially similar to the BSD license. GPL, APSL, CDDL, etc, licensed software must not be compiled into GENERIC. Developers are reminded that in open source, getting "open" right is just as important as getting "source" right, as improper handling of intellectual property has serious consequences. Any questions or concerns should immediately be brought to the attention of the core team. [[tracking.license.grants]] == Keeping Track of Licenses Granted to the FreeBSD Project Various software or data exist in the repositories where the FreeBSD project has been granted a special license to be able to use them. A case in point are the Terminus fonts for use with man:vt[4]. Here the author Dimitar Zhekov has allowed us to use the "Terminus BSD Console" font under a 2-clause BSD license rather than the regular Open Font License he normally uses. It is clearly sensible to keep a record of any such license grants. To that end, the {core-email} has decided to keep an archive of them. Whenever the FreeBSD project is granted a special license we require the {core-email} to be notified. Any developers involved in arranging such a license grant, please send details to the {core-email} including: * Contact details for people or organizations granting the special license. * What files, directories etc. in the repositories are covered by the license grant including the revision numbers where any specially licensed material was committed. * The date the license comes into effect from. Unless otherwise agreed, this will be the date the license was issued by the authors of the software in question. * The license text. * A note of any restrictions, limitations or exceptions that apply specifically to FreeBSD's usage of the licensed material. * Any other relevant information. Once the {core-email} is satisfied that all the necessary details have been gathered and are correct, the secretary will send a PGP-signed acknowledgment of receipt including the license details. This receipt will be persistently archived and serve as our permanent record of the license grant. The license archive should contain only details of license grants; this is not the place for any discussions around licensing or other subjects. Access to data within the license archive will be available on request to the {core-email}. [[spdx.tags]] == SPDX Tags in the tree The project uses https://spdx.dev[SPDX] tags in our source base. At present, these tags are indented to help automated tools reconstruct license requirements mechanically. All _SPDX-License-Identifier_ tags in the tree should be considered to be informative. All files in the FreeBSD source tree with these tags also have a copy of the license which governs use of that file. In the event of a discrepancy, the verbatim license is controlling. The project tries to follow the https://spdx.github.io/spdx-spec/[SPDX Specification, Version 2.2]. How to mark source files and valid algebraic expressions are found in https://spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/[Appendix IV] and https://spdx.github.io/spdx-spec/appendix-V-using-SPDX-short-identifiers-in-source-files/[Appendix V]. The project draws identifiers from SPDX's list of valid https://spdx.org/licenses/[short license identifiers]. The project uses only the _SPDX-License-Identifier_ tag. As of March 2021, approximately 25,000 out of 90,000 files in the tree have been marked. [[developer.relations]] == Developer Relations When working directly on your own code or on code which is already well established as your responsibility, then there is probably little need to check with other committers before jumping in with a commit. When working on a bug in an area of the system which is clearly orphaned (and there are a few such areas, to our shame), the same applies. When modifying parts of the system which are maintained, formally or informally, consider asking for a review just as a developer would have before becoming a committer. For ports, contact the listed `MAINTAINER` in the [.filename]#Makefile#. To determine if an area of the tree is maintained, check the MAINTAINERS file at the root of the tree. If nobody is listed, scan the revision history to see who has committed changes in the past. To list the names and email addresses of all commit authors for a given file in the last 2 years and the number of commits each has authored, ordered by descending number of commits, use: [source,shell] ---- % git -C /path/to/repo shortlog -sne --since="2 years" -- relative/path/to/file ---- If queries go unanswered or the committer otherwise indicates a lack of interest in the area affected, go ahead and commit it. [IMPORTANT] ==== Avoid sending private emails to maintainers. Other people might be interested in the conversation, not just the final output. ==== If there is any doubt about a commit for any reason at all, have it reviewed before committing. Better to have it flamed then and there rather than when it is part of the repository. If a commit does results in controversy erupting, it may be advisable to consider backing the change out again until the matter is settled. Remember, with a version control system we can always change it back. Do not impugn the intentions of others. If they see a different solution to a problem, or even a different problem, it is probably not because they are stupid, because they have questionable parentage, or because they are trying to destroy hard work, personal image, or FreeBSD, but basically because they have a different outlook on the world. Different is good. Disagree honestly. Argue your position from its merits, be honest about any shortcomings it may have, and be open to seeing their solution, or even their vision of the problem, with an open mind. Accept correction. We are all fallible. When you have made a mistake, apologize and get on with life. Do not beat up yourself, and certainly do not beat up others for your mistake. Do not waste time on embarrassment or recrimination, just fix the problem and move on. Ask for help. Seek out (and give) peer reviews. One of the ways open source software is supposed to excel is in the number of eyeballs applied to it; this does not apply if nobody will review code. [[if-in-doubt]] == If in Doubt... When unsure about something, whether it be a technical issue or a project convention be sure to ask. If you stay silent you will never make progress. If it relates to a technical issue ask on the public mailing lists. Avoid the temptation to email the individual person that knows the answer. This way everyone will be able to learn from the question and the answer. For project specific or administrative questions ask, in order: * Your mentor or former mentor. * An experienced committer on IRC, email, etc. * Any team with a "hat", as they can give you a definitive answer. * If still not sure, ask on {developers-name}. Once your question is answered, if no one pointed you to documentation that spelled out the answer to your question, document it, as others will have the same question. [[bugzilla]] == Bugzilla The FreeBSD Project utilizes Bugzilla for tracking bugs and change requests. If you commit a fix or suggestion found in the PR database, be sure to close the PR. It is also considered nice if you take time to close any other PRs associated with your commits. Committers with non-``FreeBSD.org`` Bugzilla accounts can have the old account merged with the `FreeBSD.org` account by following these steps: [.procedure] ==== . Log in using your old account. . Open new bug. Choose `Services` as the Product, and `Bug Tracker` as the Component. In bug description list accounts you wish to be merged. . Log in using `FreeBSD.org` account and post comment to newly opened bug to - confirm ownership. See crossref:committers-guide[kerberos-ldap] for more details on how to generate or set a password for your `FreeBSD.org` account. + confirm ownership. See crossref:committers-guide[kerberos-ldap, Kerberos and LDAP web Password for FreeBSD Cluster] for more details on how to generate or set a password for your `FreeBSD.org` account. . If there are more than two accounts to merge, post comments from each of them. ==== You can find out more about Bugzilla at: * extref:{pr-guidelines}[FreeBSD Problem Report Handling Guidelines] * link:https://www.FreeBSD.org/support/[https://www.FreeBSD.org/support] [[phabricator]] == Phabricator The FreeBSD Project utilizes https://reviews.freebsd.org[Phabricator] for code review requests. See the https://wiki.freebsd.org/Phabricator[Phabricator wiki page] for details. Committers with non-``FreeBSD.org`` Phabricator accounts can have the old account renamed to the ``FreeBSD.org`` account by following these steps: [.procedure] ==== . Change your Phabricator account email to your `FreeBSD.org` email. . Open new bug on our bug tracker using your `FreeBSD.org` account, see - crossref:committers-guide[bugzilla] for more information. Choose `Services` as the Product, and `Code Review` as the Component. In bug description request that your Phabricator account be renamed, and provide a link to your Phabricator user. For example, `https://reviews.freebsd.org/p/bob_example.com/` + crossref:committers-guide[bugzilla, Bugzilla] for more information. Choose `Services` as the Product, and `Code Review` as the Component. In bug description request that your Phabricator account be renamed, and provide a link to your Phabricator user. For example, `https://reviews.freebsd.org/p/bob_example.com/` ==== [IMPORTANT] ==== Phabricator accounts cannot be merged, please do not open a new account. ==== [[people]] == Who's Who Besides the repository meisters, there are other FreeBSD project members and teams whom you will probably get to know in your role as a committer. Briefly, and by no means all-inclusively, these are: `{doceng}`:: doceng is the group responsible for the documentation build infrastructure, approving new documentation committers, and ensuring that the FreeBSD website and documentation on the FTP site is up to date with respect to the Subversion tree. It is not a conflict resolution body. The vast majority of documentation related discussion takes place on the {freebsd-doc}. More details regarding the doceng team can be found in its https://www.FreeBSD.org/internal/doceng/[charter]. Committers interested in contributing to the documentation should familiarize themselves with the extref:{fdp-primer}[Documentation Project Primer]. `{re-members}`:: These are the members of the `{re}`. This team is responsible for setting release deadlines and controlling the release process. During code freezes, the release engineers have final authority on all changes to the system for whichever branch is pending release status. If there is something you want merged from FreeBSD-CURRENT to FreeBSD-STABLE (whatever values those may have at any given time), these are the people to talk to about it. `{so}`:: `{so-name}` is the link:https://www.FreeBSD.org/security/[FreeBSD Security Officer] and oversees the `{security-officer}`. {committers-name}:: {dev-src-all}, {dev-ports-all} and {dev-doc-all} are the mailing lists that the version control system uses to send commit messages to. _Never_ send email directly to these lists. Only send replies to this list when they are short and are directly related to a commit. {developers-name}:: All committers are subscribed to -developers. This list was created to be a forum for the committers "community" issues. Examples are Core voting, announcements, etc. + The {developers-name} is for the exclusive use of FreeBSD committers. To develop FreeBSD, committers must have the ability to openly discuss matters that will be resolved before they are publicly announced. Frank discussions of work in progress are not suitable for open publication and may harm FreeBSD. + All FreeBSD committers are expected not to not publish or forward messages from the {developers-name} outside the list membership without permission of all of the authors. Violators will be removed from the {developers-name}, resulting in a suspension of commit privileges. Repeated or flagrant violations may result in permanent revocation of commit privileges. + This list is _not_ intended as a place for code reviews or for any technical discussion. In fact using it as such hurts the FreeBSD Project as it gives a sense of a closed list where general decisions affecting all of the FreeBSD using community are made without being "open". Last, but not least __never, never ever, email the {developers-name} and CC:/BCC: another FreeBSD list__. Never, ever email another FreeBSD email list and CC:/BCC: the {developers-name}. Doing so can greatly diminish the benefits of this list. [[ssh.guide]] == SSH Quick-Start Guide [.procedure] ==== . If you do not wish to type your password in every time you use man:ssh[1], and you use keys to authenticate, man:ssh-agent[1] is there for your convenience. If you want to use man:ssh-agent[1], make sure that you run it before running other applications. X users, for example, usually do this from their [.filename]#.xsession# or [.filename]#.xinitrc#. See man:ssh-agent[1] for details. . Generate a key pair using man:ssh-keygen[1]. The key pair will wind up in your [.filename]#$HOME/.ssh/# directory. + [IMPORTANT] ====== Only ECDSA, Ed25519 or RSA keys are supported. ====== . Send your public key ([.filename]#$HOME/.ssh/id_ecdsa.pub#, [.filename]#$HOME/.ssh/id_ed25519.pub#, or [.filename]#$HOME/.ssh/id_rsa.pub#) to the person setting you up as a committer so it can be put into [.filename]#yourlogin# in [.filename]#/etc/ssh-keys/# on `freefall`. ==== Now man:ssh-add[1] can be used for authentication once per session. It prompts for the private key's pass phrase, and then stores it in the authentication agent (man:ssh-agent[1]). Use `ssh-add -d` to remove keys stored in the agent. Test with a simple remote command: `ssh freefall.FreeBSD.org ls /usr`. For more information, see package:security/openssh-portable[], man:ssh[1], man:ssh-add[1], man:ssh-agent[1], man:ssh-keygen[1], and man:scp[1]. For information on adding, changing, or removing man:ssh[1] keys, see https://wiki.freebsd.org/clusteradm/ssh-keys[this article]. [[coverity]] == Coverity(R) Availability for FreeBSD Committers All FreeBSD developers can obtain access to Coverity analysis results of all FreeBSD Project software. All who are interested in obtaining access to the analysis results of the automated Coverity runs, can sign up at http://scan.coverity.com/[Coverity Scan]. The FreeBSD wiki includes a mini-guide for developers who are interested in working with the Coverity(R) analysis reports: https://wiki.freebsd.org/CoverityPrevent[https://wiki.freebsd.org/CoverityPrevent]. Please note that this mini-guide is only readable by FreeBSD developers, so if you cannot access this page, you will have to ask someone to add you to the appropriate Wiki access list. Finally, all FreeBSD developers who are going to use Coverity(R) are always encouraged to ask for more details and usage information, by posting any questions to the mailing list of the FreeBSD developers. [[rules]] == The FreeBSD Committers' Big List of Rules Everyone involved with the FreeBSD project is expected to abide by the _Code of Conduct_ available from link:https://www.FreeBSD.org/internal/code-of-conduct/[https://www.FreeBSD.org/internal/code-of-conduct]. As committers, you form the public face of the project, and how you behave has a vital impact on the public perception of it. This guide expands on the parts of the _Code of Conduct_ specific to committers. . Respect other committers. . Respect other contributors. . Discuss any significant change _before_ committing. . Respect existing maintainers (if listed in the `MAINTAINER` field in [.filename]#Makefile# or in [.filename]#MAINTAINER# in the top-level directory). . Any disputed change must be backed out pending resolution of the dispute if requested by a maintainer. Security related changes may override a maintainer's wishes at the Security Officer's discretion. . Changes go to FreeBSD-CURRENT before FreeBSD-STABLE unless specifically permitted by the release engineer or unless they are not applicable to FreeBSD-CURRENT. Any non-trivial or non-urgent change which is applicable should also be allowed to sit in FreeBSD-CURRENT for at least 3 days before merging so that it can be given sufficient testing. The release engineer has the same authority over the FreeBSD-STABLE branch as outlined for the maintainer in rule #5. . Do not fight in public with other committers; it looks bad. . Respect all code freezes and read the `committers` and `developers` mailing lists in a timely manner so you know when a code freeze is in effect. . When in doubt on any procedure, ask first! . Test your changes before committing them. . Do not commit to contributed software without _explicit_ approval from the respective maintainers. As noted, breaking some of these rules can be grounds for suspension or, upon repeated offense, permanent removal of commit privileges. Individual members of core have the power to temporarily suspend commit privileges until core as a whole has the chance to review the issue. In case of an "emergency" (a committer doing damage to the repository), a temporary suspension may also be done by the repository meisters. Only a 2/3 majority of core has the authority to suspend commit privileges for longer than a week or to remove them permanently. This rule does not exist to set core up as a bunch of cruel dictators who can dispose of committers as casually as empty soda cans, but to give the project a kind of safety fuse. If someone is out of control, it is important to be able to deal with this immediately rather than be paralyzed by debate. In all cases, a committer whose privileges are suspended or revoked is entitled to a "hearing" by core, the total duration of the suspension being determined at that time. A committer whose privileges are suspended may also request a review of the decision after 30 days and every 30 days thereafter (unless the total suspension period is less than 30 days). A committer whose privileges have been revoked entirely may request a review after a period of 6 months has elapsed. This review policy is _strictly informal_ and, in all cases, core reserves the right to either act on or disregard requests for review if they feel their original decision to be the right one. In all other aspects of project operation, core is a subset of committers and is bound by the __same rules__. Just because someone is in core this does not mean that they have special dispensation to step outside any of the lines painted here; core's "special powers" only kick in when it acts as a group, not on an individual basis. As individuals, the core team members are all committers first and core second. === Details [[respect]] . Respect other committers. + This means that you need to treat other committers as the peer-group developers that they are. Despite our occasional attempts to prove the contrary, one does not get to be a committer by being stupid and nothing rankles more than being treated that way by one of your peers. Whether we always feel respect for one another or not (and everyone has off days), we still have to _treat_ other committers with respect at all times, on public forums and in private email. + Being able to work together long term is this project's greatest asset, one far more important than any set of changes to the code, and turning arguments about code into issues that affect our long-term ability to work harmoniously together is just not worth the trade-off by any conceivable stretch of the imagination. + To comply with this rule, do not send email when you are angry or otherwise behave in a manner which is likely to strike others as needlessly confrontational. First calm down, then think about how to communicate in the most effective fashion for convincing the other persons that your side of the argument is correct, do not just blow off some steam so you can feel better in the short term at the cost of a long-term flame war. Not only is this very bad "energy economics", but repeated displays of public aggression which impair our ability to work well together will be dealt with severely by the project leadership and may result in suspension or termination of your commit privileges. The project leadership will take into account both public and private communications brought before it. It will not seek the disclosure of private communications, but it will take it into account if it is volunteered by the committers involved in the complaint. + All of this is never an option which the project's leadership enjoys in the slightest, but unity comes first. No amount of code or good advice is worth trading that away. . Respect other contributors. + You were not always a committer. At one time you were a contributor. Remember that at all times. Remember what it was like trying to get help and attention. Do not forget that your work as a contributor was very important to you. Remember what it was like. Do not discourage, belittle, or demean contributors. Treat them with respect. They are our committers in waiting. They are every bit as important to the project as committers. Their contributions are as valid and as important as your own. After all, you made many contributions before you became a committer. Always remember that. + Consider the points raised under crossref:committers-guide[respect,Respect other committers] and apply them also to contributors. . Discuss any significant change _before_ committing. + The repository is not where changes are initially submitted for correctness or argued over, that happens first in the mailing lists or by use of the Phabricator service. The commit will only happen once something resembling consensus has been reached. This does not mean that permission is required before correcting every obvious syntax error or manual page misspelling, just that it is good to develop a feel for when a proposed change is not quite such a no-brainer and requires some feedback first. People really do not mind sweeping changes if the result is something clearly better than what they had before, they just do not like being _surprised_ by those changes. The very best way of making sure that things are on the right track is to have code reviewed by one or more other committers. + When in doubt, ask for review! . Respect existing maintainers if listed. + Many parts of FreeBSD are not "owned" in the sense that any specific individual will jump up and yell if you commit a change to "their" area, but it still pays to check first. One convention we use is to put a maintainer line in the [.filename]#Makefile# for any package or subtree which is being actively maintained by one or more people; see extref:{developers-handbook}[Source Tree Guidelines and Policies, policies] for documentation on this. Where sections of code have several maintainers, commits to affected areas by one maintainer need to be reviewed by at least one other maintainer. In cases where the "maintainer-ship" of something is not clear, look at the repository logs for the files in question and see if someone has been working recently or predominantly in that area. . Any disputed change must be backed out pending resolution of the dispute if requested by a maintainer. Security related changes may override a maintainer's wishes at the Security Officer's discretion. + This may be hard to swallow in times of conflict (when each side is convinced that they are in the right, of course) but a version control system makes it unnecessary to have an ongoing dispute raging when it is far easier to simply reverse the disputed change, get everyone calmed down again and then try to figure out what is the best way to proceed. If the change turns out to be the best thing after all, it can be easily brought back. If it turns out not to be, then the users did not have to live with the bogus change in the tree while everyone was busily debating its merits. People _very_ rarely call for back-outs in the repository since discussion generally exposes bad or controversial changes before the commit even happens, but on such rare occasions the back-out should be done without argument so that we can get immediately on to the topic of figuring out whether it was bogus or not. . Changes go to FreeBSD-CURRENT before FreeBSD-STABLE unless specifically permitted by the release engineer or unless they are not applicable to FreeBSD-CURRENT. Any non-trivial or non-urgent change which is applicable should also be allowed to sit in FreeBSD-CURRENT for at least 3 days before merging so that it can be given sufficient testing. The release engineer has the same authority over the FreeBSD-STABLE branch as outlined in rule #5. + This is another "do not argue about it" issue since it is the release engineer who is ultimately responsible (and gets beaten up) if a change turns out to be bad. Please respect this and give the release engineer your full cooperation when it comes to the FreeBSD-STABLE branch. The management of FreeBSD-STABLE may frequently seem to be overly conservative to the casual observer, but also bear in mind the fact that conservatism is supposed to be the hallmark of FreeBSD-STABLE and different rules apply there than in FreeBSD-CURRENT. There is also really no point in having FreeBSD-CURRENT be a testing ground if changes are merged over to FreeBSD-STABLE immediately. Changes need a chance to be tested by the FreeBSD-CURRENT developers, so allow some time to elapse before merging unless the FreeBSD-STABLE fix is critical, time sensitive or so obvious as to make further testing unnecessary (spelling fixes to manual pages, obvious bug/typo fixes, etc.) In other words, apply common sense. + Changes to the security branches (for example, `releng/9.3`) must be approved by a member of the `{security-officer}`, or in some cases, by a member of the `{re}`. . Do not fight in public with other committers; it looks bad. + This project has a public image to uphold and that image is very important to all of us, especially if we are to continue to attract new members. There will be occasions when, despite everyone's very best attempts at self-control, tempers are lost and angry words are exchanged. The best thing that can be done in such cases is to minimize the effects of this until everyone has cooled back down. Do not air angry words in public and do not forward private correspondence or other private communications to public mailing lists, mail aliases, instant messaging channels or social media sites. What people say one-to-one is often much less sugar-coated than what they would say in public, and such communications therefore have no place there - they only serve to inflame an already bad situation. If the person sending a flame-o-gram at least had the grace to send it privately, then have the grace to keep it private yourself. If you feel you are being unfairly treated by another developer, and it is causing you anguish, bring the matter up with core rather than taking it public. Core will do its best to play peace makers and get things back to sanity. In cases where the dispute involves a change to the codebase and the participants do not appear to be reaching an amicable agreement, core may appoint a mutually-agreeable third party to resolve the dispute. All parties involved must then agree to be bound by the decision reached by this third party. . Respect all code freezes and read the `committers` and `developers` mailing list on a timely basis so you know when a code freeze is in effect. + Committing unapproved changes during a code freeze is a really big mistake and committers are expected to keep up-to-date on what is going on before jumping in after a long absence and committing 10 megabytes worth of accumulated stuff. People who abuse this on a regular basis will have their commit privileges suspended until they get back from the FreeBSD Happy Reeducation Camp we run in Greenland. . When in doubt on any procedure, ask first! + Many mistakes are made because someone is in a hurry and just assumes they know the right way of doing something. If you have not done it before, chances are good that you do not actually know the way we do things and really need to ask first or you are going to completely embarrass yourself in public. There is no shame in asking "how in the heck do I do this?" We already know you are an intelligent person; otherwise, you would not be a committer. . Test your changes before committing them. + If your changes are to the kernel, make sure you can still compile both GENERIC and LINT. If your changes are anywhere else, make sure you can still make world. If your changes are to a branch, make sure your testing occurs with a machine which is running that code. If you have a change which also may break another architecture, be sure and test on all supported architectures. Please ensure your change works for crossref:committers-guide[compilers,supported toolchains]. Please refer to the https://www.FreeBSD.org/internal/[FreeBSD Internal Page] for a list of available resources. As other architectures are added to the FreeBSD supported platforms list, the appropriate shared testing resources will be made available. . Do not commit to contributed software without _explicit_ approval from the respective maintainers. + Contributed software is anything under the [.filename]#src/contrib#, [.filename]#src/crypto#, or [.filename]#src/sys/contrib# trees. + The trees mentioned above are for contributed software usually imported onto a vendor branch. Committing something there may cause unnecessary headaches when importing newer versions of the software. As a general consider sending patches upstream to the vendor. Patches may be committed to FreeBSD first with permission of the maintainer. + Reasons for modifying upstream software range from wanting strict control over a tightly coupled dependency to lack of portability in the canonical repository's distribution of their code. Regardless of the reason, effort to minimize the maintenance burden of fork is helpful to fellow maintainers. Avoid committing trivial or cosmetic changes to files since it makes every merge thereafter more difficult: such patches need to be manually re-verified every import. + If a particular piece of software lacks a maintainer, you are encouraged to take up ownership. If you are unsure of the current maintainership email {freebsd-arch} and ask. === Policy on Multiple Architectures FreeBSD has added several new architecture ports during recent release cycles and is truly no longer an i386(TM) centric operating system. In an effort to make it easier to keep FreeBSD portable across the platforms we support, core has developed this mandate: [.blockquote] Our 32-bit reference platform is i386, and our 64-bit reference platform is amd64. Major design work (including major API and ABI changes) must prove itself on at least one 32-bit and at least one 64-bit platform, preferably the primary reference platforms, before it may be committed to the source tree. Developers should also be aware of our Tier Policy for the long term support of hardware architectures. The rules here are intended to provide guidance during the development process, and are distinct from the requirements for features and architectures listed in that section. The Tier rules for feature support on architectures at release-time are more strict than the rules for changes during the development process. [[compilers]] === Policy on Multiple Compilers FreeBSD builds with both Clang and GCC. The project does this in a careful and controlled way to maximize benefits from this extra work, while keeping the extra work to a minimum. Supporting both Clang and GCC improves the flexibility our users have. These compilers have different strengths and weaknesses, and supporting both allows users to pick the best one for their needs. Clang and GCC support similar dialects of C and C++, necessitating a relatively small amount of conditional code. The project gains increased code coverage and improves the code quality by using features from both compilers. The project is able to build in more user environments and leverage more CI environments by supporting this range, increasing convenience for users and giving them more tools to test with. By carefully constraining the range of versions supported to modern versions of these compilers, the project avoids unduly increasing the testing matrix. Older and obscure compilers, as well as older dialects of the languages, have extremely limited support that allow user programs to build with them, but without constraining the base system to being built with them. The exact balance continues to evolve to ensure the benefits of extra work remain greater than the burdens it imposes. The project used to support really old Intel compilers or old GCC versions, but we traded supporting those obsolete compilers for a carefully selected range of modern compilers. This section documents where we use different compilers, and the expectations around that. The FreeBSD project provides an in-tree Clang compiler. Due to being in the tree, this compiler is the most supported compiler. All changes must compile with it, prior to commit. Complete testing, as appropriate for the change, should be done with this compiler. At any moment in time, the FreeBSD project also supports one or more out-of-tree compilers. At present, this is GCC 12.x. Ideally, committers should test compile with this compiler, especially for large or risky changes. This compiler is available as the `${TARGET_ARCH}-gcc${VERSION}` package, such as package:devel/freebsd-gcc12@aarch64[aarch64-gcc12] or package:devel/freebsd-gcc12@riscv64[riscv64-gcc12]. The project runs automated CI jobs to build everything with these compilers. Committers are expected to fix the jobs they break with their changes. Committers may test build with, for example `CROSS_TOOLCHAIN=aarch64-gcc12` or `CROSS_TOOLCHAIN=llvm15` where necessary. The FreeBSD project also has some CI pipelines on github. For pull requests on github and some branches pushed to the github forks, a number of cross compilation jobs run. These test FreeBSD building using a version of Clang that sometimes lags the in-tree compiler by a major version for a time. The FreeBSD project is also upgrading compilers. Both Clang and GCC are fast moving targets. Some work to change things in the tree, for example removing the old-style K&R function declarations and definitions, will land in the tree prior to the compiler landing. Committers should try to be mindful about this and be receptive to looking into problems with their code or changes with these new compilers. Also, just after a new compiler version hits the tree, people may need to compile things with the old version if there was an undetected regression suspected. In addition to the compiler, LLVM's LLD and GNU's binutils are used indirectly by the compiler. Committers should be mindful of variations in assembler syntax and features of the linkers and ensure both variants work. These components will be tested as part of FreeBSD's CI jobs for Clang or GCC. The FreeBSD project provides headers and libraries that allow other compilers to be used to build software not in the base system. These headers have support for making the environment as strict as the standard, supporting prior dialects of ANSI-C back to C89, and other edge cases our large ports collection has uncovered. This support constrains retirement of older standards in places like header files, but does not constrain updating the base system to newer dialects. Nor does it require the base system to compile with these older standards as a whole. Breaking this support will cause packages in the ports collection to fail, so should be avoided where possible, and promptly fixed when it is easy to do so. The FreeBSD build system currently accommodates these different environments. As new warnings are added to compilers, the project tries to fix them. However, sometimes these warnings require extensive rework, so are suppressed in some way by using make variables that evaluate to the proper thing depending on the compiler version. Developers should be mindful of this, and ensure any compiler specific flags are properly conditionalized. ==== Current Compiler Versions The in-tree compiler is currently Clang 15.x. Currently, GCC 12 and Clang 12, 13, 14 and 15 are tested in the github and project's CI jenkins jobs. Work is underway to get the tree ready for Clang 16. The oldest project supported branch has Clang 12, so the bootstrap portions of the build must work for Clang major versions 12 to 15. === Other Suggestions When committing documentation changes, use a spell checker before committing. For all XML docs, verify that the formatting directives are correct by running `make lint` and package:textproc/igor[]. For manual pages, run package:sysutils/manck[] and package:textproc/igor[] over the manual page to verify all of the cross references and file references are correct and that the man page has all of the appropriate `MLINKS` installed. Do not mix style fixes with new functionality. A style fix is any change which does not modify the functionality of the code. Mixing the changes obfuscates the functionality change when asking for differences between revisions, which can hide any new bugs. Do not include whitespace changes with content changes in commits to [.filename]#doc/#. The extra clutter in the diffs makes the translators' job much more difficult. Instead, make any style or whitespace changes in separate commits that are clearly labeled as such in the commit message. === Deprecating Features When it is necessary to remove functionality from software in the base system, follow these guidelines whenever possible: . Mention is made in the manual page and possibly the release notes that the option, utility, or interface is deprecated. Use of the deprecated feature generates a warning. . The option, utility, or interface is preserved until the next major (point zero) release. . The option, utility, or interface is removed and no longer documented. It is now obsolete. It is also generally a good idea to note its removal in the release notes. === Privacy and Confidentiality . Most FreeBSD business is done in public. + FreeBSD is an _open_ project. Which means that not only can anyone use the source code, but that most of the development process is open to public scrutiny. . Certain sensitive matters must remain private or held under embargo. + There unfortunately cannot be complete transparency. As a FreeBSD developer you will have a certain degree of privileged access to information. Consequently you are expected to respect certain requirements for confidentiality. Sometimes the need for confidentiality comes from external collaborators or has a specific time limit. Mostly though, it is a matter of not releasing private communications. . The Security Officer has sole control over the release of security advisories. + Where there are security problems that affect many different operating systems, FreeBSD frequently depends on early access to be able to prepare advisories for coordinated release. Unless FreeBSD developers can be trusted to maintain security, such early access will not be made available. The Security Officer is responsible for controlling pre-release access to information about vulnerabilities, and for timing the release of all advisories. He may request help under condition of confidentiality from any developer with relevant knowledge to prepare security fixes. . Communications with Core are kept confidential for as long as necessary. + Communications to core will initially be treated as confidential. Eventually however, most of Core's business will be summarized into the monthly or quarterly core reports. Care will be taken to avoid publicising any sensitive details. Records of some particularly sensitive subjects may not be reported on at all and will be retained only in Core's private archives. . Non-disclosure Agreements may be required for access to certain commercially sensitive data. + Access to certain commercially sensitive data may only be available under a Non-Disclosure Agreement. The FreeBSD Foundation legal staff must be consulted before any binding agreements are entered into. . Private communications must not be made public without permission. + Beyond the specific requirements above there is a general expectation not to publish private communications between developers without the consent of all parties involved. Ask permission before forwarding a message onto a public mailing list, or posting it to a forum or website that can be accessed by other than the original correspondents. . Communications on project-only or restricted access channels must be kept private. + Similarly to personal communications, certain internal communications channels, including FreeBSD Committer only mailing lists and restricted access IRC channels are considered private communications. Permission is required to publish material from these sources. . Core may approve publication. + Where it is impractical to obtain permission due to the number of correspondents or where permission to publish is unreasonably withheld, Core may approve release of such private matters that merit more general publication. [[archs]] == Support for Multiple Architectures FreeBSD is a highly portable operating system intended to function on many different types of hardware architectures. Maintaining clean separation of Machine Dependent (MD) and Machine Independent (MI) code, as well as minimizing MD code, is an important part of our strategy to remain agile with regards to current hardware trends. Each new hardware architecture supported by FreeBSD adds substantially to the cost of code maintenance, toolchain support, and release engineering. It also dramatically increases the cost of effective testing of kernel changes. As such, there is strong motivation to differentiate between classes of support for various architectures while remaining strong in a few key architectures that are seen as the FreeBSD "target audience". === Statement of General Intent The FreeBSD Project targets "production quality commercial off-the-shelf (COTS) workstation, server, and high-end embedded systems". By retaining a focus on a narrow set of architectures of interest in these environments, the FreeBSD Project is able to maintain high levels of quality, stability, and performance, as well as minimize the load on various support teams on the project, such as the ports team, documentation team, security officer, and release engineering teams. Diversity in hardware support broadens the options for FreeBSD consumers by offering new features and usage opportunities, but these benefits must always be carefully considered in terms of the real-world maintenance cost associated with additional platform support. The FreeBSD Project differentiates platform targets into four tiers. Each tier includes a list of guarantees consumers may rely on as well as obligations by the Project and developers to fulfill those guarantees. These lists define the minimum guarantees for each tier. The Project and developers may provide additional levels of support beyond the minimum guarantees for a given tier, but such additional support is not guaranteed. Each platform target is assigned to a specific tier for each stable branch. As a result, a platform target might be assigned to different tiers on concurrent stable branches. === Platform Targets Support for a hardware platform consists of two components: kernel support and userland Application Binary Interfaces (ABIs). Kernel platform support includes things needed to run a FreeBSD kernel on a hardware platform such as machine-dependent virtual memory management and device drivers. A userland ABI specifies an interface for user processes to interact with a FreeBSD kernel and base system libraries. A userland ABI includes system call interfaces, the layout and semantics of public data structures, and the layout and semantics of arguments passed to subroutines. Some components of an ABI may be defined by specifications such as the layout of C++ exception objects or calling conventions for C functions. A FreeBSD kernel also uses an ABI (sometimes referred to as the Kernel Binary Interface (KBI)) which includes the semantics and layouts of public data structures and the layout and semantics of arguments to public functions within the kernel itself. A FreeBSD kernel may support multiple userland ABIs. For example, FreeBSD's amd64 kernel supports FreeBSD amd64 and i386 userland ABIs as well as Linux x86_64 and i386 userland ABIs. A FreeBSD kernel should support a "native" ABI as the default ABI. The native "ABI" generally shares certain properties with the kernel ABI such as the C calling convention, sizes of basic types, etc. Tiers are defined for both kernels and userland ABIs. In the common case, a platform's kernel and FreeBSD ABIs are assigned to the same tier. ==== Tier 1: Fully-Supported Architectures Tier 1 platforms are the most mature FreeBSD platforms. They are supported by the security officer, release engineering, and Ports Management Team. Tier 1 architectures are expected to be Production Quality with respect to all aspects of the FreeBSD operating system, including installation and development environments. The FreeBSD Project provides the following guarantees to consumers of Tier 1 platforms: * Official FreeBSD release images will be provided by the release engineering team. * Binary updates and source patches for Security Advisories and Errata Notices will be provided for supported releases. * Source patches for Security Advisories will be provided for supported branches. * Binary updates and source patches for cross-platform Security Advisories will typically be provided at the time of the announcement. * Changes to userland ABIs will generally include compatibility shims to ensure correct operation of binaries compiled against any stable branch where the platform is Tier 1. These shims might not be enabled in the default install. If compatibility shims are not provided for an ABI change, the lack of shims will be clearly documented in the release notes. * Changes to certain portions of the kernel ABI will include compatibility shims to ensure correct operation of kernel modules compiled against the oldest supported release on the branch. Note that not all parts of the kernel ABI are protected. * Official binary packages for third party software will be provided by the ports team. For embedded architectures, these packages may be cross-built from a different architecture. * Most relevant ports should either build or have the appropriate filters to prevent inappropriate ones from building. * New features which are not inherently platform-specific will be fully functional on all Tier 1 architectures. * Features and compatibility shims used by binaries compiled against older stable branches may be removed in newer major versions. Such removals will be clearly documented in the release notes. * Tier 1 platforms should be fully documented. Basic operations will be documented in the FreeBSD Handbook. * Tier 1 platforms will be included in the source tree. * Tier 1 platforms should be self-hosting either via the in-tree toolchain or an external toolchain. If an external toolchain is required, official binary packages for an external toolchain will be provided. To maintain maturity of Tier 1 platforms, the FreeBSD Project will maintain the following resources to support development: * Build and test automation support either in the FreeBSD.org cluster or some other location easily available for all developers. Embedded platforms may substitute an emulator available in the FreeBSD.org cluster for actual hardware. * Inclusion in the `make universe` and `make tinderbox` targets. * Dedicated hardware in one of the FreeBSD clusters for package building (either natively or via qemu-user). Collectively, developers are required to provide the following to maintain the Tier 1 status of a platform: * Changes to the source tree should not knowingly break the build of a Tier 1 platform. * Tier 1 architectures must have a mature, healthy ecosystem of users and active developers. * Developers should be able to build packages on commonly available, non-embedded Tier 1 systems. This can mean either native builds if non-embedded systems are commonly available for the platform in question, or it can mean cross-builds hosted on some other Tier 1 architecture. * Changes cannot break the userland ABI. If an ABI change is required, ABI compatibility for existing binaries should be provided via use of symbol versioning or shared library version bumps. * Changes merged to stable branches cannot break the protected portions of the kernel ABI. If a kernel ABI change is required, the change should be modified to preserve functionality of existing kernel modules. ==== Tier 2: Developmental and Niche Architectures Tier 2 platforms are functional, but less mature FreeBSD platforms. They are not supported by the security officer, release engineering, and Ports Management Team. Tier 2 platforms may be Tier 1 platform candidates that are still under active development. Architectures reaching end of life may also be moved from Tier 1 status to Tier 2 status as the availability of resources to continue to maintain the system in a Production Quality state diminishes. Well-supported niche architectures may also be Tier 2. The FreeBSD Project provides the following guarantees to consumers of Tier 2 platforms: * The ports infrastructure should include basic support for Tier 2 architectures sufficient to support building ports and packages. This includes support for basic packages such as ports-mgmt/pkg, but there is no guarantee that arbitrary ports will be buildable or functional. * New features which are not inherently platform-specific should be feasible on all Tier 2 architectures if not implemented. * Tier 2 platforms will be included in the source tree. * Tier 2 platforms should be self-hosting either via the in-tree toolchain or an external toolchain. If an external toolchain is required, official binary packages for an external toolchain will be provided. * Tier 2 platforms should provide functional kernels and userlands even if an official release distribution is not provided. To maintain maturity of Tier 2 platforms, the FreeBSD Project will maintain the following resources to support development: * Inclusion in the `make universe` and `make tinderbox` targets. Collectively, developers are required to provide the following to maintain the Tier 2 status of a platform: * Changes to the source tree should not knowingly break the build of a Tier 2 platform. * Tier 2 architectures must have an active ecosystem of users and developers. * While changes are permitted to break the userland ABI, the ABI should not be broken gratuitously. Significant userland ABI changes should be restricted to major versions. * New features that are not yet implemented on Tier 2 architectures should provide a means of disabling them on those architectures. ==== Tier 3: Experimental Architectures Tier 3 platforms have at least partial FreeBSD support. They are _not_ supported by the security officer, release engineering, and Ports Management Team. Tier 3 platforms are architectures in the early stages of development, for non-mainstream hardware platforms, or which are considered legacy systems unlikely to see broad future use. Initial support for Tier 3 platforms may exist in a separate repository rather than the main source repository. The FreeBSD Project provides no guarantees to consumers of Tier 3 platforms and is not committed to maintaining resources to support development. Tier 3 platforms may not always be buildable, nor are any kernel or userland ABIs considered stable. ==== Unsupported Architectures Other platforms are not supported in any form by the project. The project previously described these as Tier 4 systems. After a platform transitions to unsupported, all support for the platform is removed from the source, ports and documentation trees. Note that ports support should remain as long as the platform is supported in a branch supported by ports. === Policy on Changing the Tier of an Architecture Systems may only be moved from one tier to another by approval of the FreeBSD Core Team, which shall make that decision in collaboration with the Security Officer, Release Engineering, and ports management teams. For a platform to be promoted to a higher tier, any missing support guarantees must be satisfied before the promotion is completed. [[ports]] == Ports Specific FAQ [[ports-qa-adding]] === Adding a New Port [[ports-qa-add-new]] ==== How do I add a new port? Adding a port to the tree is relatively simple. Once the port is ready to be added, as explained later crossref:committers-guide[ports-qa-add-new-extra,here], you need to add the port's directory entry in the category's [.filename]#Makefile#. In this [.filename]#Makefile#, ports are listed in alphabetical order and added to the `SUBDIR` variable, like this: [.programlisting] .... SUBDIR += newport .... Once the port and its category's Makefile are ready, the new port can be committed: [source,shell] .... % git add category/Makefile category/newport % git commit % git push .... [TIP] ==== Don't forget to crossref:committers-guide[port-commit-message-formats,setup git hooks for the ports tree as explained here]; a specific hook has been developed to verify the category's [.filename]#Makefile#. ==== [[ports-qa-add-new-extra]] ==== Any other things I need to know when I add a new port? Check the port, preferably to make sure it compiles and packages correctly. The extref:{porters-handbook}testing[Porters Handbook's Testing Chapter] contains more detailed instructions. See the extref:{porters-handbook}testing[Portclippy / Portfmt, testing-portclippy] and the extref:{porters-handbook}testing[poudriere, testing-poudriere] sections. You do not necessarily have to eliminate all warnings but make sure you have fixed the simple ones. If the port came from a submitter who has not contributed to the Project before, add that person's name to the extref:{contributors}[Additional Contributors, contrib-additional] section of the FreeBSD Contributors List. Close the PR if the port came in as a PR. To close a PR, change the state to `Issue Resolved` and the resolution as `Fixed`. [NOTE] ==== If for some reason using extref:{porters-handbook}testing[poudriere, testing-poudriere] to test the new port is not possible, the bare minimum of testing includes this sequence: [source,shell] .... # make install # make package # make deinstall # pkg add package you built above # make deinstall # make reinstall # make package .... Note that poudriere is the reference for package building, it the port does not build in poudriere, it will be removed. ==== [[ports-qa-removing]] === Removing an Existing Port [[ports-qa-remove-one]] ==== How do I remove an existing port? First, please read the section about repository copies. Before you remove the port, you have to verify there are no other ports depending on it. * Make sure there is no dependency on the port in the ports collection: ** The port's PKGNAME appears in exactly one line in a recent INDEX file. ** No other ports contains any reference to the port's directory or PKGNAME in their Makefiles + [TIP] ==== When using Git, consider using man:git-grep[1], it is much faster than `grep -r`. ==== + * Then, remove the port: + [.procedure] ==== * Remove the port's files and directory with `git rm`. * Remove the `SUBDIR` listing of the port in the parent directory [.filename]#Makefile#. * Add an entry to [.filename]#ports/MOVED#. * Remove the port from [.filename]#ports/LEGAL# if it is there. ==== Alternatively, you can use the rmport script, from [.filename]#ports/Tools/scripts#. This script was written by {vd}. When sending questions about this script to the {freebsd-ports}, please also CC {crees}, the current maintainer. [[ports-qa-move-port]] === How do I move a port to a new location? [.procedure] ==== . Perform a thorough check of the ports collection for any dependencies on the old port location/name, and update them. Running `grep` on [.filename]#INDEX# is not enough because some ports have dependencies enabled by compile-time options. A full man:git-grep[1] of the ports collection is recommended. . Remove the `SUBDIR` entry from the old category Makefile and add a `SUBDIR` entry to the new category Makefile. . Add an entry to [.filename]#ports/MOVED#. . Search for entries in xml files inside [.filename]#ports/security/vuxml# and adjust them accordingly. In particular, check for previous packages with the new name which version could include the new port. . Move the port with `git mv`. . Commit the changes. ==== [[ports-qa-copy-port]] === How do I copy a port to a new location? [.procedure] ==== . Copy port with `cp -R old-cat/old-port new-cat/new-port`. . Add the new port to the [.filename]#new-cat/Makefile#. . Change stuff in [.filename]#new-cat/new-port#. . Commit the changes. ==== [[ports-qa-freeze]] === Ports Freeze [[ports-qa-freeze-what]] ==== What is a “ports freeze”? A “ports freeze” was a restricted state the ports tree was put in before a release. It was used to ensure a higher quality for the packages shipped with a release. It usually lasted a couple of weeks. During that time, build problems were fixed, and the release packages were built. This practice is no longer used, as the packages for the releases are built from the current stable, quarterly branch. For more information on how to merge commits to the quarterly branch, see -crossref:committers-guide[ports-qa-misc-request-mfh]. +crossref:committers-guide[ports-qa-misc-request-mfh, What is the procedure to request authorization for merging a commit to the quarterly branch?]. [[ports-qa-quarterly]] === Quarterly Branches [[ports-qa-misc-request-mfh]] ==== What is the procedure to request authorization for merging a commit to the quarterly branch? As of November 30, 2020, there is no need to seek explicit approval to commit to the quarterly branch. [[ports-qa-misc-commit-mfh]] ==== What is the procedure for merging commits to the quarterly branch? Merging commits to the quarterly branch (a process we call MFH for a historical reason) is very similar to MFC'ing a commit in the src repository, so basically: [source,shell] .... % git checkout 2021Q2 % git cherry-pick -x $HASH (verify everything is OK, for example by doing a build test) % git push .... where `$HASH` is the hash of the commit you want to copy over to the quarterly branch. The `-x` parameter ensures the hash `$HASH` of the `main` branch is included in the new commit message of the quarterly branch. [[ports-qa-new-category]] === Creating a New Category [[ports-qa-new-category-how]] ==== What is the procedure for creating a new category? Please see extref:{porters-handbook}[Proposing a New Category, proposing-categories] in the Porter's Handbook. Once that procedure has been followed and the PR has been assigned to the {portmgr}, it is their decision whether or not to approve it. If they do, it is their responsibility to: [.procedure] ==== . Perform any needed moves. (This only applies to physical categories.) . Update the `VALID_CATEGORIES` definition in [.filename]#ports/Mk/bsd.port.mk#. . Assign the PR back to you. ==== [[ports-qa-new-category-physical]] ==== What do I need to do to implement a new physical category? [.procedure] ==== . Upgrade each moved port's [.filename]#Makefile#. Do not connect the new category to the build yet. + To do this, you will need to: + [.procedure] ====== . Change the port's `CATEGORIES` (this was the point of the exercise, remember?) The new category is listed first. This will help to ensure that the PKGORIGIN is correct. . Run a `make describe`. Since the top-level `make index` that you will be running in a few steps is an iteration of `make describe` over the entire ports hierarchy, catching any errors here will save you having to re-run that step later on. . If you want to be really thorough, now might be a good time to run man:portlint[1]. ====== + . Check that the ``PKGORIGIN``s are correct. The ports system uses each port's `CATEGORIES` entry to create its `PKGORIGIN`, which is used to connect installed packages to the port directory they were built from. If this entry is wrong, common port tools like man:pkg-version[8] and man:portupgrade[1] fail. + To do this, use the [.filename]#chkorigin.sh# tool: `env PORTSDIR=/path/to/ports sh -e /path/to/ports/Tools/scripts/chkorigin.sh`. This will check every port in the ports tree, even those not connected to the build, so you can run it directly after the move operation. Hint: do not forget to look at the ``PKGORIGIN``s of any slave ports of the ports you just moved! . On your own local system, test the proposed changes: first, comment out the SUBDIR entries in the old ports' categories' [.filename]##Makefile##s; then enable building the new category in [.filename]#ports/Makefile#. Run make checksubdirs in the affected category directories to check the SUBDIR entries. Next, in the [.filename]#ports/# directory, run make index. This can take over 40 minutes on even modern systems; however, it is a necessary step to prevent problems for other people. . Once this is done, you can commit the updated [.filename]#ports/Makefile# to connect the new category to the build and also commit the [.filename]#Makefile# changes for the old category or categories. . Add appropriate entries to [.filename]#ports/MOVED#. . Update the documentation by modifying: ** the extref:{porters-handbook}[list of categories, PORTING-CATEGORIES] in the Porter's Handbook + . Only once all the above have been done, and no one is any longer reporting problems with the new ports, should the old ports be deleted from their previous locations in the repository. ==== ==== What do I need to do to implement a new virtual category? This is much simpler than a physical category. Only a few modifications are needed: * the extref:{porters-handbook}[list of categories, PORTING-CATEGORIES] in the Porter's Handbook [[ports-qa-misc-questions]] === Miscellaneous Questions [[ports-qa-misc-blanket-approval]] ==== Are there changes that can be committed without asking the maintainer for approval? Blanket approval for most ports applies to these types of fixes: * Most infrastructure changes to a port (that is, modernizing, but not changing the functionality). For example, the blanket covers converting to new `USES` macros, enabling verbose builds, and switching to new ports system syntaxes. * Trivial and _tested_ build and runtime fixes. * Documentations or metadata changes to ports, like [.filename]#pkg-descr# or `COMMENT`. [IMPORTANT] ==== Exceptions to this are anything maintained by the {portmgr}, or the {security-officer}. No unauthorized commits may ever be made to ports maintained by those groups. ==== [[ports-qa-misc-correctly-building]] ==== How do I know if my port is building correctly or not? The packages are built multiple times each week. If a port fails, the maintainer will receive an email from `pkg-fallout@FreeBSD.org`. Reports for all the package builds (official, experimental, and non-regression) are aggregated at link:pkg-status.FreeBSD.org[pkg-status.FreeBSD.org]. [[ports-qa-misc-INDEX]] ==== I added a new port. Do I need to add it to the [.filename]#INDEX#? No. The file can either be generated by running `make index`, or a pre-generated version can be downloaded with `make fetchindex`. [[ports-qa-misc-no-touch]] ==== Are there any other files I am not allowed to touch? Any file directly under [.filename]#ports/#, or any file under a subdirectory that starts with an uppercase letter ([.filename]#Mk/#, [.filename]#Tools/#, etc.). In particular, the {portmgr} is very protective of [.filename]#ports/Mk/bsd.port*.mk# so do not commit changes to those files unless you want to face their wrath. [[ports-qa-misc-updated-distfile]] ==== What is the proper procedure for updating the checksum for a port distfile when the file changes without a version change? When the checksum for a distribution file is updated due to the author updating the file without changing the port revision, the commit message includes a summary of the relevant diffs between the original and new distfile to ensure that the distfile has not been corrupted or maliciously altered. If the current version of the port has been in the ports tree for a while, a copy of the old distfile will usually be available on the ftp servers; otherwise the author or maintainer should be contacted to find out why the distfile has changed. [[ports-exp-run]] ==== How can an experimental test build of the ports tree (exp-run) be requested? An exp-run must be completed before patches with a significant ports impact are committed. The patch can be against the ports tree or the base system. Full package builds will be done with the patches provided by the submitter, and the submitter is required to fix detected problems _(fallout)_ before commit. [.procedure] ==== . Go to the link:https://bugs.freebsd.org/submit[Bugzilla new PR page]. . Select the product your patch is about. . Fill in the bug report as normal. Remember to attach the patch. . If at the top it says “Show Advanced Fields” click on it. It will now say “Hide Advanced Fields”. Many new fields will be available. If it already says “Hide Advanced Fields”, no need to do anything. . In the “Flags” section, set the “exp-run” one to `?`. As for all other fields, hovering the mouse over any field shows more details. . Submit. Wait for the build to run. . {portmgr} will reply with a possible fallout. . Depending on the fallout: ** If there is no fallout, the procedure stops here, and the change can be committed, pending any other approval required. ... If there is fallout, it _must_ be fixed, either by fixing the ports directly in the ports tree, or adding to the submitted patch. ... When this is done, go back to step 6 saying the fallout was fixed and wait for the exp-run to be run again. Repeat as long as there are broken ports. ==== [[non-committers]] == Issues Specific to Developers Who Are Not Committers A few people who have access to the FreeBSD machines do not have commit bits. Almost all of this document will apply to these developers as well (except things specific to commits and the mailing list memberships that go with them). In particular, we recommend that you read: -* crossref:committers-guide[admin] -* crossref:committers-guide[conventions-everyone] +* crossref:committers-guide[admin, Administrative Details] +* crossref:committers-guide[conventions-everyone, For Everyone] + [NOTE] ==== Get your mentor to add you to the "Additional Contributors" ([.filename]#doc/shared/contrib-additional.adoc#), if you are not already listed there. ==== -* crossref:committers-guide[developer.relations] -* crossref:committers-guide[ssh.guide] -* crossref:committers-guide[rules] +* crossref:committers-guide[developer.relations, Developer Relations] +* crossref:committers-guide[ssh.guide, SSH Quick-Start Guide] +* crossref:committers-guide[rules, The FreeBSD Committers' Big List of Rules] [[google-analytics]] == Information About Google Analytics As of December 12, 2012, Google Analytics was enabled on the FreeBSD Project website to collect anonymized usage statistics regarding usage of the site. [NOTE] ==== As of March 3, 2022, Google Analytics was removed from the FreeBSD Project. ==== [[misc]] == Miscellaneous Questions === How do I access people.FreeBSD.org to put up personal or project information? `people.FreeBSD.org` is the same as `freefall.FreeBSD.org`. Just create a [.filename]#public_html# directory. Anything you place in that directory will automatically be visible under https://people.FreeBSD.org/[https://people.FreeBSD.org/]. === Where are the mailing list archives stored? The mailing lists are archived under [.filename]#/local/mail# on `freefall.FreeBSD.org`. === I would like to mentor a new committer. What process do I need to follow? See the https://www.freebsd.org/internal/new-account/[New Account Creation Procedure] document on the internal pages. [[benefits]] == Benefits and Perks for FreeBSD Committers [[benefits-recognition]] === Recognition Recognition as a competent software engineer is the longest lasting value. In addition, getting a chance to work with some of the best people that every engineer would dream of meeting is a great perk! [[benefits-freebsdmall]] === FreeBSD Mall FreeBSD committers can get a free 4-CD or DVD set at conferences from http://www.freebsdmall.com[FreeBSD Mall, Inc.]. [[benefits-gandi]] === `Gandi.net` https://gandi.net[Gandi] provides website hosting, cloud computing, domain registration, and X.509 certificate services. Gandi offers an E-rate discount to all FreeBSD developers. To streamline the process of getting the discount first set up a Gandi account, fill in the billing information and select the currency. Then send an mail to mailto:non-profit@gandi.net[non-profit@gandi.net] using your `@freebsd.org` mail address, and indicate your Gandi handle. [[benefits-rsync]] === `rsync.net` https://rsync.net[rsync.net] provides cloud storage for offsite backup that is optimized for UNIX users. Their service runs entirely on FreeBSD and ZFS. rsync.net offers a free-forever 500 GB account to FreeBSD developers. Simply sign up at https://www.rsync.net/freebsd.html[https://www.rsync.net/freebsd.html] using your `@freebsd.org` address to receive this free account. diff --git a/documentation/content/en/articles/contributing/_index.adoc b/documentation/content/en/articles/contributing/_index.adoc index 10bdcf03e5..a5b872383a 100644 --- a/documentation/content/en/articles/contributing/_index.adoc +++ b/documentation/content/en/articles/contributing/_index.adoc @@ -1,649 +1,649 @@ --- title: Contributing to FreeBSD authors: - author: Jordan Hubbard - author: Sam Lawrance - author: Mark Linimon description: How to contribute to the FreeBSD Project trademarks: ["freebsd", "ieee", "general"] weight: 15 tags: ["Contributing", "FreeBSD", "Non-Programmer Tasks", "Programmer Tasks"] --- = Contributing to FreeBSD :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/contributing/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] pass:[] [.abstract-title] Abstract This article describes the different ways in which an individual or organization may contribute to the FreeBSD Project. ''' toc::[] So you want to contribute to FreeBSD? That is great! FreeBSD _relies_ on the contributions of its user base to survive. Your contributions are not only appreciated, they are vital to FreeBSD's continued growth. A large and growing number of international contributors, of greatly varying ages and areas of technical expertise, develop FreeBSD. There is always more work to be done than there are people available to do it, and more help is always appreciated. As a volunteer, what you do is limited only by what you want to do. However, we do ask that you are aware of what other members of the FreeBSD community will expect of you. You may want to take this into account before deciding to volunteer. The FreeBSD project is responsible for an entire operating system environment, rather than just a kernel or a few scattered utilities. As such, our [.filename]#TODO# lists span a very wide range of tasks: from documentation, beta testing and presentation, to the system installer and highly specialized types of kernel development. People of any skill level, in almost any area, can almost certainly help the project. Commercial entities engaged in FreeBSD-related enterprises are also encouraged to contact us. Do you need a special extension to make your product work? You will find us receptive to your requests, given that they are not too outlandish. Are you working on a value-added product? Please let us know! We may be able to work cooperatively on some aspect of it. The free software world is challenging many existing assumptions about how software is developed, sold, and maintained, and we urge you to at least give it a second look. [[contrib-what]] == What Is Needed The following list of tasks and sub-projects represents something of an amalgam of various [.filename]#TODO# lists and user requests. [[non-programmer-tasks]] === Ongoing Non-Programmer Tasks Many people who are involved in FreeBSD are not programmers. The Project includes documentation writers, Web designers, and support people. All that these people need to contribute is an investment of time and a willingness to learn. . Read through the FAQ and Handbook periodically. If anything is poorly explained, ambiguous, out of date or incorrect, let us know. Even better, send us a fix (AsciiDoc is not difficult to learn, but there is no objection to plain text submissions). . Help translate FreeBSD documentation into your native language. If documentation already exists for your language, you can help translate additional documents or verify that the translations are up-to-date and correct. First take a look at the extref:{fdp-primer}[Translations FAQ, translations] in the FreeBSD Documentation Project Primer. You are not committing yourself to translating every single FreeBSD document by doing this - as a volunteer, you can do as much or as little translation as you desire. Once someone begins translating, others almost always join the effort. If you only have the time or energy to translate one part of the documentation, please translate the installation instructions. . Read the {freebsd-questions} occasionally (or even regularly). It can be very satisfying to share your expertise and help people solve their problems; sometimes you may even learn something new yourself! These forums can also be a source of ideas for things to improve upon. [[ongoing-programmer-tasks]] === Ongoing Programmer Tasks Most of the tasks listed here may require a considerable investment of time, an in-depth knowledge of the FreeBSD kernel, or both. However, there are also many useful tasks which are suitable for "weekend hackers". . If you run FreeBSD-CURRENT and have a good Internet connection, there is a machine `current.FreeBSD.org` which builds a full release once a day-every now and again, try to install the latest release from it and report any failures in the process. . Read the {freebsd-bugs}. There may be a problem you can comment constructively on or with patches you can test. Or you could even try to fix one of the problems yourself. . If you know of any bug fixes which have been successfully applied to -CURRENT but have not been merged into -STABLE after a decent interval (normally a couple of weeks), send the committer a polite reminder. . Move contributed software to [.filename]#src/contrib# in the source tree. . Make sure code in [.filename]#src/contrib# is up to date. . Build the source tree (or just part of it) with extra warnings enabled and clean up the warnings. A list of build warnings can also be found from our https://ci.freebsd.org[CI] by selecting a build and checking "LLVM/Clang Warnings". . Fix warnings for ports which do deprecated things like using `gets()` or including [.filename]#malloc.h#. . If you have contributed any ports and you had to make FreeBSD-specific changes, send your patches back to the original authors (this will make your life easier when they bring out the next version). . Get copies of formal standards like POSIX(R). Compare FreeBSD's behavior to that required by the standard. If the behavior differs, particularly in subtle or obscure corners of the specification, send in a PR about it. If you are able, figure out how to fix it and include a patch in the PR. If you think the standard is wrong, ask the standards body to consider the question. . Suggest further tasks for this list! === Work through the PR Database The https://bugs.FreeBSD.org/search/[FreeBSD PR list] shows all the current active problem reports and requests for enhancement that have been submitted by FreeBSD users. The PR database includes both programmer and non-programmer tasks. Look through the open PRs, and see if anything there takes your interest. Some of these might be very simple tasks that just need an extra pair of eyes to look over them and confirm that the fix in the PR is a good one. Others might be much more complex, or might not even have a fix included at all. Start with the PRs that have not been assigned to anyone else. If a PR is assigned to someone else, but it looks like something you can handle, email the person it is assigned to and ask if you can work on it-they might already have a patch ready to be tested, or further ideas that you can discuss with them. === Ongoing Ports Tasks The Ports Collection is a perpetual work in progress. We want to provide our users with an easy to use, up to date, high quality repository of third party software. We need people to donate some of their time and effort to help us achieve this goal. Anyone can get involved, and there are lots of different ways to do so. Contributing to ports is an excellent way to help "give back" something to the project. Whether you are looking for an ongoing role, or a fun challenge for a rainy day, we would love to have your help! There are a number of easy ways you can contribute to keeping the ports tree up to date and in good working order: * Find some cool or useful software and extref:{porters-handbook}[create a port] for it. * There are a large number of ports that have no maintainer. -Become a maintainer and crossref:contributing[adopt-port]. -* If you have created or adopted a port, be aware of crossref:contributing[maintain-port]. -* When you are looking for a quick challenge you could crossref:contributing[fix-broken]. +Become a maintainer and crossref:contributing[adopt-port, Adopting an unmaintained port]. +* If you have created or adopted a port, be aware of crossref:contributing[maintain-port, The challenge for port maintainers]. +* When you are looking for a quick challenge you could crossref:contributing[fix-broken, Finding and fixing a broken port]. === Pick one of the items from the Ideas page The https://wiki.freebsd.org/IdeasPage[FreeBSD list of projects and ideas for volunteers] is also available for people willing to contribute to the FreeBSD project. The list is being regularly updated and contains items for both programmers and non-programmers with information about each project. [[contrib-how]] == How to Contribute Contributions to the system generally fall into one or more of the following 5 categories: [[contrib-general]] === Bug Reports and General Commentary An idea or suggestion of _general_ technical interest should be mailed to the {freebsd-hackers}. Likewise, people with an interest in such things (and a tolerance for a _high_ volume of mail!) may subscribe to the {freebsd-hackers}. See extref:{handbook}[The FreeBSD Handbook, eresources-mail] for more information about this and other mailing lists. If you are submitting a simple patch to the src repo, please consider submitting it to the project's GitHub mirror as https://github.com/freebsd/freebsd-src/pulls[a pull request]. Suitable submissions should: * It is ready or nearly ready to be committed. A committer should be able to land this patch with less than 10 minutes of additional work. * It passes all the GitHub CI jobs. * You can respond to feedback quickly. * It touches fewer than about 10 files and the changes are less than about 200 lines. Changes larger than this may be OK, or you may be asked to submit multiple pull requests of a more manageable size. * Each logical change is a separate commit within the pull request. Commit messages for each change should follow extref:{committers-guide}#commit-log-message[commit log guide]. * All commits have your name and valid email address as you'd like to see them in the FreeBSD repository as the author. Fake github.com addresses cannot be used. * The scope of the pull request should not change during review. If the review suggests changes that expand the scope, please create an independent pull request. * Fixup commits should be squashed with the commit they are fixing. Each commit in your branch should be suitable for FreeBSD's repository. * Commits should include one or more `Signed-off-by:` lines with full name and email address certifying https://developercertificate.org/[Developer Certificate of Origin]. When updating pull request, please rebase with a forced push rather than a merge commit. More complex changes may be submitted as pull requests, but they may be closed if they are too large, too unwieldy, become inactive, need further discussion in the community, or need extensive revision. Please avoid creating large, wide-ranging cleanup patches: they are too large and lack the focus needed for a good review. Misdirected patches may be redirected to a more appropriate forum for the patch to be resolved. Pull requests submitted to the ports repository may or may not see action, based on the whims of developers. For now, you will have a better experience if you follow the ports submission -process crossref:contributing[ports-contributing]. +process crossref:contributing[ports-contributing, Contributing to ports]. The docs team also accepts pull requests via GitHub, but has not established any policy for them yet. If you find a bug or are submitting a specific change, please report it using the https://bugs.FreeBSD.org/submit/[bug submission form]. Try to fill-in each field of the bug report. Unless they exceed 65KB, include any patches directly in the report. If the patch is suitable to be applied to the source tree put `[PATCH]` in the synopsis of the report. When including patches, _do not_ use cut-and-paste because cut-and-paste turns tabs into spaces and makes them unusable. When patches are a lot larger than 20KB, consider compressing them (for example with man:gzip[1] or man:bzip2[1]) prior to uploading them. After filing a report, you should receive confirmation along with a tracking number. Keep this tracking number so that you can update us with details about the problem. See also extref:{problem-reports}[this article] on how to write good problem reports. === Changes to the Documentation Changes to the documentation are overseen by the {freebsd-doc}. Please look at the extref:{fdp-primer}[FreeBSD Documentation Project Primer] for complete instructions. Send submissions and changes (even small ones are welcome!) using the same method as any other bug report. === Changes to Existing Source Code An addition or change to the existing source code is a somewhat trickier affair and depends a lot on how far out of date you are with the current state of FreeBSD development. There is a special on-going release of FreeBSD known as "FreeBSD-CURRENT" which is made available in a variety of ways for the convenience of developers working actively on the system. See extref:{handbook}[The FreeBSD Handbook, current-stable] for more information about getting and using FreeBSD-CURRENT. Working from older sources unfortunately means that your changes may sometimes be too obsolete or too divergent for easy re-integration into FreeBSD. Chances of this can be minimized somewhat by subscribing to the {freebsd-announce} and the {freebsd-current} lists, where discussions on the current state of the system take place. Assuming that you can manage to secure fairly up-to-date sources to base your changes on, the next step is to produce a set of diffs to send to the FreeBSD maintainers. This is done with the man:diff[1] command. The preferred man:diff[1] format for submitting patches is the unified output format generated by `diff -u`. [source,shell] .... % diff -u oldfile newfile .... or [source,shell] .... % diff -u -r -N olddir newdir .... would generate a set of unified diffs for the given source file or directory hierarchy. See man:diff[1] for more information. Once you have a set of diffs (which you may test with the man:patch[1] command), you should submit them for inclusion with FreeBSD as a bug report. _Do not_ just send the diffs to the {freebsd-hackers} or they will get lost! We greatly appreciate your submission (this is a volunteer project!); because we are busy, we may not be able to address it immediately, but it will remain in the PR database until we do. Indicate your submission by including `[PATCH]` in the synopsis of the report. If you feel it appropriate (for example you have added, deleted, or renamed files), bundle your changes into a `tar` file. Archives created with man:shar[1] are also welcome. If your change is of a potentially sensitive nature, such as if you are unsure of copyright issues governing its further distribution then you should send it to {core-email} directly rather than submitting as a bug report. The {core-email} reaches a much smaller group of people who do much of the day-to-day work on FreeBSD. Note that this group is also _very busy_ and so you should only send mail to them where it is truly necessary. Please refer to man:intro[9] and man:style[9] for some information on coding style. We would appreciate it if you were at least aware of this information before submitting code. === New Code or Major Value-Added Packages In the case of a significant contribution of a large body work, or the addition of an important new feature to FreeBSD, it becomes almost always necessary to either send changes as tar files or upload them to a web or FTP site for other people to access. If you do not have access to a web or FTP site, ask on an appropriate FreeBSD mailing list for someone to host the changes for you. When working with large amounts of code, the touchy subject of copyrights also invariably comes up. FreeBSD prefers free software licenses such as BSD or ISC. Copyleft licenses such as GPLv2 are sometimes permitted. The complete listing can be found on the link:https://www.FreeBSD.org/internal/software-license/[core team licensing policy] page. === Money or Hardware We are always very happy to accept donations to further the cause of the FreeBSD Project and, in a volunteer effort like ours, a little can go a long way! Donations of hardware are also very important to expanding our list of supported peripherals since we generally lack the funds to buy such items ourselves. [[donations]] ==== Donating Funds The https://www.freebsdfoundation.org[FreeBSD Foundation] is a non-profit, tax-exempt foundation established to further the goals of the FreeBSD Project. As a 501(c)3 entity, the Foundation is generally exempt from US federal income tax as well as Colorado State income tax. Donations to a tax-exempt entity are often deductible from taxable federal income. Donations may be sent in check form to: [.address] **** The FreeBSD Foundation + 3980 Broadway Street + STE #103-107 + Boulder CO 80304 + USA **** The FreeBSD Foundation is also able to accept https://www.freebsdfoundation.org/donate/[online donations] through various payment options. More information about the FreeBSD Foundation can be found in https://people.FreeBSD.org/~jdp/foundation/announcement.html[The FreeBSD Foundation -- an Introduction]. To contact the Foundation by email, write to mailto:info@FreeBSDFoundation.org[info@FreeBSDFoundation.org]. ==== Donating Hardware The FreeBSD Project happily accepts donations of hardware that it can find good use for. If you are interested in donating hardware, please contact the link:https://www.FreeBSD.org/donations/[Donations Liaison Office]. [[ports-contributing]] == Contributing to ports [[adopt-port]] === Adopting an unmaintained port ==== Choosing an unmaintained port Taking over maintainership of ports that are unmaintained is a great way to get involved. Unmaintained ports are only updated and fixed when somebody volunteers to work on them. There are a large number of unmaintained ports. It is a good idea to start with adopting a port that you use regularly. Unmaintained ports have their `MAINTAINER` set to `ports@FreeBSD.org`. Many unmaintained ports can have pending updates, this can be seen at the https://portscout.freebsd.org/ports@freebsd.org.html[FreeBSD Ports distfile scanner]. On https://portsfallout.com/fallout?port=&maintainer=ports%40FreeBSD.org[PortsFallout] can be seen a list of unmaintained ports with errors. Some ports affect a large number of others due to dependencies and secondary port relationships. Generally, we want people to have some experience before they maintain such ports. You can find out whether or not a port has dependencies or secondary ports by looking at a primary index of ports called [.filename]#INDEX#. (The name of the file varies by release of FreeBSD; for instance, [.filename]#INDEX-13#.) Some ports have conditional dependencies that are not included in a default [.filename]#INDEX# build. We expect you to be able to recognize such ports by looking through other ports' [.filename]#Makefile#'s. ==== How to adopt the port -First make sure you understand your crossref:contributing[maintain-port]. +First make sure you understand your crossref:contributing[maintain-port, The challenge for port maintainers]. Also read the extref:{porters-handbook}[Porter's Handbook]. _Please do not commit yourself to more than you feel you can comfortably handle._ You may request maintainership of any unmaintained port as soon as you wish. Simply set `MAINTAINER` to your own email address and send a PR (Problem Report) with the change. If the port has build errors or needs updating, you may wish to include any other changes in the same PR. This will help because many committers are less willing to assign maintainership to someone who does not have a known track record with FreeBSD. Submitting PRs that fix build errors or update ports are the best ways to establish one. File your PR with Product `Ports & Packages`. A committer will examine your PR, commit the changes, and finally close the PR. Sometimes this process can take a little while (committers are volunteers, too :). [[maintain-port]] === The challenge for port maintainers This section will give you an idea of why ports need to be maintained and outline the responsibilities of a port maintainer. [[why-maintenance]] ==== Why ports require maintenance Creating a port is a once-off task. Ensuring that a port is up to date and continues to build and run requires an ongoing maintenance effort. Maintainers are the people who dedicate some of their time to meeting these goals. The foremost reason ports need maintenance is to bring the latest and greatest in third party software to the FreeBSD community. An additional challenge is to keep individual ports working within the Ports Collection framework as it evolves. As a maintainer, you will need to manage the following challenges: * *New software versions and updates.* New versions and updates of existing ported software become available all the time, and these need to be incorporated into the Ports Collection to provide up-to-date software. * *Changes to dependencies.* If significant changes are made to the dependencies of your port, it may need to be updated so that it will continue to work correctly. * *Changes affecting dependent ports.* If other ports depend on a port that you maintain, changes to your port may require coordination with other maintainers. * *Interaction with other users, maintainers and developers.* Part of being a maintainer is taking on a support role. You are not expected to provide general support (but we welcome it if you choose to do so). What you should provide is a point of coordination for FreeBSD-specific issues regarding your ports. * *Bug hunting.* A port may be affected by bugs which are specific to FreeBSD. You will need to investigate, find, and fix these bugs when they are reported. Thoroughly testing a port to identify problems before they make their way into the Ports Collection is even better. * *Changes to ports infrastructure and policy.* Occasionally the systems that are used to build ports and packages are updated or a new recommendation affecting the infrastructure is made. You should be aware of these changes in case your ports are affected and require updating. * *Changes to the base system.* FreeBSD is under constant development. Changes to software, libraries, the kernel or even policy changes can cause flow-on change requirements to ports. ==== Maintainer responsibilities ===== Keep your ports up to date This section outlines the process to follow to keep your ports up to date. This is an overview. More information about upgrading a port is available in the extref:{porters-handbook}[Porter's Handbook]. [.procedure] ==== . Watch for updates + Monitor the upstream vendor for new versions, updates and security fixes for the software. Announcement mailing lists or news web pages are useful for doing this. Sometimes users will contact you and ask when your port will be updated. If you are busy with other things or for any reason just cannot update it at the moment, ask if they will help you by submitting an update. + You may also receive automated email from the `FreeBSD Ports Version Check` informing you that a newer version of your port's distfile is available. More information about that system (including how to stop future emails) will be provided in the message. . Incorporate changes + When they become available, incorporate the changes into the port. You need to be able to generate a patch between the original port and your updated port. . Review and test + Thoroughly review and test your changes: ** Build, install and test your port on as many platforms and architectures as you can. It is common for a port to work on one branch or platform and fail on another. ** Make sure your port's dependencies are complete. The recommended way of doing this is by installing your own ports tinderbox. -See crossref:contributing[resources] for more information. +See crossref:contributing[resources, Resources for ports maintainers and contributors] for more information. ** Check that the packing list is up to date. This involves adding in any new files and directories and removing unused entries. ** Verify your port using man:portlint[1] as a guide. -See crossref:contributing[resources] for important information about using portlint. +See crossref:contributing[resources, Resources for ports maintainers and contributors] for important information about using portlint. ** Consider whether changes to your port might cause any other ports to break. If this is the case, coordinate the changes with the maintainers of those ports. This is especially important if your update changes the shared library version; in this case, at the very least, the dependent ports will need to get a `PORTREVISION` bump so that they will automatically be upgraded by automated tools such as package:ports-mgmt/poudriere[]. . Submit changes + Send your update by submitting a PR with an explanation of the changes and a patch containing the differences between the original port and the updated one. Please refer to extref:{problem-reports}[Writing FreeBSD Problem Reports] for information on how to write a really good PR. + [NOTE] ====== Please do not submit a man:shar[1] archive of the entire port; instead, use man:git-format-patch[1] or man:diff[1] `-ruN`. In this way, committers can much more easily see exactly what changes are being made. The Porter's Handbook section on extref:{porters-handbook}[Upgrading, port-upgrading] has more information. ====== . Wait + At some stage a committer will deal with your PR. It may take minutes, or it may take one or two weeks - so please be patient. If it takes any longer, please seek for help on mailing lists ({freebsd-ports}), IRC: #bsdports on EFNet or #freebsd-ports on Libera for example. . Give feedback + If a committer finds a problem with your changes, they will most likely refer it back to you. A prompt response will help get your PR committed faster, and is better for maintaining a thread of conversation when trying to resolve any problems. . And Finally + Your changes will be committed and your port will have been updated. The PR will then be closed by the committer. That is it! ==== ===== Ensure your ports continue to build correctly This section is about discovering and fixing problems that stop your ports from building correctly. FreeBSD only guarantees that the Ports Collection works on the `-STABLE` branches. In theory, you should be able to get by with running the latest release of each stable branch (since the ABIs are not supposed to change) but if you can run the branch, that is even better. Since the majority of FreeBSD installations run on PC-compatible machines (what is termed the `i386` architecture), we expect you to keep the port working on that architecture. We prefer that ports also work on the `amd64` architecture running native. It is completely fair to ask for help if you do not have one of these machines. [NOTE] ==== The usual failure modes for non-`x86` machines are that the original programmers assumed that, for instance, pointers are `int`-s, or that a relatively lax older gcc compiler was being used. More and more, application authors are reworking their code to remove these assumptions - but if the author is not actively maintaining their code, you may need to do this yourself. ==== These are the tasks you need to perform to ensure your port is able to be built: [.procedure] ==== . Watch for build failures + Check your mail for mail from `pkg-fallout@FreeBSD.org` and the http://portscout.FreeBSD.org[distfiles scanner] to see if any of the port which are failing to build are out of date. . Collect information + Once you are aware of a problem, collect information to help you fix it. Build errors reported by `pkg-fallout` are accompanied by logs which will show you where the build failed. If the failure was reported to you by a user, ask them to send you information which may help in diagnosing the problem, such as: ** Build logs ** The commands and options used to build the port (including options set in [.filename]#/etc/make.conf#) ** A list of packages installed on their system as shown by man:pkg-info[8] ** The version of FreeBSD they are running as shown by man:uname[1] `-a` ** When their ports collection was last updated ** When their ports tree and [.filename]#INDEX# was last updated . Investigate and find a solution + Unfortunately there is no straightforward process to follow to do this. Remember, though: if you are stuck, ask for help! The {freebsd-ports} is a good place to start, and the upstream developers are often very helpful. . Submit changes + Just as with updating a port, you should now incorporate changes, review and test, submit your changes in a PR, and provide feedback if required. . Send patches to upstream authors + In some cases, you will have to make patches to the port to make it run on FreeBSD. Some (but not all) upstream authors will accept such patches back into their code for the next release. If so, this may even help their users on other BSD-based systems as well and perhaps save duplicated effort. Please consider sending any applicable patches to the authors as a courtesy. ==== ===== Investigate bug reports and PRs related to your port This section is about discovering and fixing bugs. FreeBSD-specific bugs are generally caused by assumptions about the build and runtime environments that do not apply to FreeBSD. You are less likely to encounter a problem of this type, but it can be more subtle and difficult to diagnose. These are the tasks you need to perform to ensure your port continues to work as intended: [.procedure] ==== . Respond to bug reports + Bugs may be reported to you through email via the https://bugs.FreeBSD.org/search/[Problem Report database]. Bugs may also be reported directly to you by users. + You should respond to PRs and other reports within 14 days, but please try not to take that long. Try to respond as soon as possible, even if it is just to say you need some more time before you can work on the PR. + If you have not responded after 14 days, any committer may commit from a PR that you have not responded to via a `maintainer-timeout`. . Collect information + If the person reporting the bug has not also provided a fix, you need to collect the information that will allow you to generate one. + If the bug is reproducible, you can collect most of the required information yourself. If not, ask the person who reported the bug to collect the information for you, such as: ** A detailed description of their actions, expected program behavior and actual behavior ** Copies of input data used to trigger the bug ** Information about their build and execution environment - for example, a list of installed packages and the output of man:env[1] ** Core dumps ** Stack traces . Eliminate incorrect reports + Some bug reports may be incorrect. For example, the user may have simply misused the program; or their installed packages may be out of date and require updating. Sometimes a reported bug is not specific to FreeBSD. In this case report the bug to the upstream developers. If the bug is within your capabilities to fix, you can also patch the port so that the fix is applied before the next upstream release. . Find a solution + As with build errors, you will need to sort out a fix to the problem. Again, remember to ask if you are stuck! . Submit or approve changes + Just as with updating a port, you should now incorporate changes, review and test, and submit your changes in a PR (or send a follow-up if a PR already exists for the problem). If another user has submitted changes in the PR, you can also send a follow-up saying whether or not you approve the changes. ==== ===== Providing support Part of being a maintainer is providing support - not for the software in general - but for the port and any FreeBSD-specific quirks and problems. Users may contact you with questions, suggestions, problems and patches. Most of the time their correspondence will be specific to FreeBSD. Occasionally you may have to invoke your skills in diplomacy, and kindly point users seeking general support to the appropriate resources. Less frequently you will encounter a person asking why the `RPMS` are not up to date or how can they get the software to run under Foo Linux. Take the opportunity to tell them that your port is up to date (if it is, of course!), and suggest that they try FreeBSD. Sometimes users and developers will decide that you are a busy person whose time is valuable and do some of the work for you. For example, they might: * submit a PR or send you patches to update your port, * investigate and perhaps provide a fix to a PR, or * otherwise submit changes to your port. In these cases your main obligation is to respond in a timely manner. Again, the timeout for non-responsive maintainers is 14 days. After this period changes may be committed unapproved. They have taken the trouble to do this for you; so please try to at least respond promptly. Then review, approve, modify or discuss their changes with them as soon as possible. If you can make them feel that their contribution is appreciated (and it should be) you will have a better chance persuading them to do more things for you in the future :-). [[fix-broken]] === Finding and fixing a broken port There are some really good places to find a port that needs some attention. You can use the https://bugs.freebsd.org/search[web interface] to the Problem Report database to search through and view unresolved PRs. The majority of ports PRs are updates, but with a little searching and skimming over synopses you should be able to find something interesting to work on. https://portsfallout.com/[PortsFallout] shows port issues gathered from the FreeBSD package building. It is OK to send changes for a maintained port as well, but remember to ask the maintainer in case they are already working on the problem. Once you have found a bug or problem, collect information, investigate and fix! If there is an existing PR, follow up to that. Otherwise create a new PR. Your changes will be reviewed and, if everything checks out, committed. [[mortal-coil]] === When to call it quits As your interests and commitments change, you may find that you no longer have time to continue some (or all) of your ports contributions. That is fine! Please let us know if you are no longer using a port or have otherwise lost time or interest in being a maintainer. In this way we can go ahead and allow other people to try to work on existing problems with the port without waiting for your response. Remember, FreeBSD is a volunteer project, so if maintaining a port is no fun any more, it is probably time to let someone else do it! In any case, the Ports Management Team (`portmgr`) reserves the right to reset your maintainership if you have not actively maintained your port in some time. (Currently, this is set to 3 months.) By this, we mean that there are unresolved problems or pending updates that have not been worked on during that time. [[resources]] === Resources for ports maintainers and contributors The extref:{porters-handbook}[Porter's Handbook] is your hitchhiker's guide to the ports system. Keep it handy! extref:{problem-reports}[Writing FreeBSD Problem Reports] describes how to best formulate and submit a PR. In 2005 more than eleven thousand ports PRs were submitted! Following this article will greatly assist us in reducing the time needed to handle your PRs. The https://bugs.freebsd.org/bugzilla/query.cgi[Problem Report database]. The http://portscout.FreeBSD.org[FreeBSD Ports distfile scanner (portscout)] can show you ports for which the distfiles are not fetchable. You can check on your own ports or use it to find ports that need their `MASTER_SITES` updated. package:ports-mgmt/poudriere[] is the most thorough way to test a port through the entire cycle of installation, packaging, and deinstallation. Documentation is located at the https://github.com/freebsd/poudriere[poudriere GitHub repository] man:portlint[1] is an application which can be used to verify that your port conforms to many important stylistic and functional guidelines. portlint is a simple heuristic application, so you should use it __only as a guide__. If portlint suggests changes which seem unreasonable, consult the extref:{porters-handbook}[Porter's Handbook] or ask for advice. The {freebsd-ports} is for general ports-related discussion. It is a good place to ask for help. You can link:https://lists.freebsd.org/[subscribe, or read and search the list archives]. Reading the archives of the {freebsd-ports-bugs} and the {svn-ports-head} may also be of interest. https://portsfallout.com/[PortsFallout] is a place to help in searching for the https://lists.freebsd.org/archives/freebsd-pkg-fallout/[FreeBSD package-fallout archive]. [[ideas-contributing]] == Getting Started in Other Areas Looking for something interesting to get started that is not mentioned elsewhere in this article? The FreeBSD Project has several Wiki pages containing areas within which new contributors can get ideas on how to get started. The https://wiki.freebsd.org/JuniorJobs[Junior Jobs] page has a list of projects that might be of interest to people just getting started in FreeBSD, and want to work on interesting things to get their feet wet. The https://wiki.freebsd.org/IdeasPage[Ideas Page] contains various "nice to have" or "interesting" things to work on in the Project. diff --git a/documentation/content/en/articles/freebsd-releng/_index.adoc b/documentation/content/en/articles/freebsd-releng/_index.adoc index 27c467b1a0..60460d3c92 100644 --- a/documentation/content/en/articles/freebsd-releng/_index.adoc +++ b/documentation/content/en/articles/freebsd-releng/_index.adoc @@ -1,794 +1,794 @@ --- title: FreeBSD Release Engineering authors: - author: Glen Barber email: gjb@FreeBSD.org organizations: - organization: The FreeBSD Foundation webpage: https://www.freebsdfoundation.org/ - organization: Rubicon Communications, LLC (Netgate) webpage: https://www.netgate.com/ description: Describes the approach used by the FreeBSD release engineering team to make production quality releases of the FreeBSD Operating System. It describes the tools available for those interested in producing customized FreeBSD releases for corporate rollouts or commercial productization trademarks: ["freebsd", "intel", "general", "git"] tags: ["releases", "engineering", "process", "FreeBSD"] --- = FreeBSD Release Engineering :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :teamBugmeister: FreeBSD Bugmeister Team :teamDoceng: FreeBSD Documentation Engineering Team :teamPortmgr: FreeBSD Ports Management Team :teamPostmaster: FreeBSD Postmaster Team :teamRe: FreeBSD Release Engineering Team :teamSecteam: FreeBSD Security Team :branchHead: main :branchStable: stable/ :branchStablex: stable/13 :branchReleng: releng/ :branchRelengx: releng/13.0 :tagReleasex: release/13.0.0 :branchRevision: 13.0 :images-path: articles/freebsd-releng/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract This article describes the release engineering process of the FreeBSD Project. ''' toc::[] [[introduction]] == Introduction to the FreeBSD Release Engineering Process Development of FreeBSD has a very specific workflow. In general, all changes to the FreeBSD base system are committed to the {branchHead} branch, which reflects the top of the source tree. After a reasonable testing period, changes can then be merged to the {branchStable} branches. The default minimum timeframe before merging to {branchStable} branches is three (3) days. Although a general rule to wait a minimum of three days before merging from {branchHead}, there are a few special circumstances where an immediate merge may be necessary, such as a critical security fix, or a bug fix that directly inhibits the release build process. After several months, and the number of changes in the {branchStable} branch have grown significantly, it is time to release the next version of FreeBSD. These releases have been historically referred to as "point" releases. In between releases from the {branchStable} branches, approximately every two (2) years, a release will be cut directly from {branchHead}. These releases have been historically referred to as "dot-zero" releases. This article will highlight the workflow and responsibilities of the {teamRe} for both "dot-zero" and "point"' releases. The following sections of this article describe: -crossref:freebsd-releng[releng-prep]:: +crossref:freebsd-releng[releng-prep, General Information and Preparation]:: General information and preparation before starting the release cycle. -crossref:freebsd-releng[releng-website]:: +crossref:freebsd-releng[releng-website, Website Changes During the Release Cycle]:: Website Changes During the Release Cycle -crossref:freebsd-releng[releng-terms]:: +crossref:freebsd-releng[releng-terms, Release Engineering Terminology]:: Terminology and general information, such as the "code slush" and "code freeze", used throughout this document. -crossref:freebsd-releng[releng-head]:: +crossref:freebsd-releng[releng-head, Release from {branchHead}]:: The Release Engineering process for a "dot-zero" release. -crossref:freebsd-releng[releng-stable]:: +crossref:freebsd-releng[releng-stable, Release from {branchStable}]:: The Release Engineering process for a "point" release. -crossref:freebsd-releng[releng-building]:: +crossref:freebsd-releng[releng-building, Building FreeBSD Installation Media]:: Information related to the specific procedures to build installation medium. -crossref:freebsd-releng[releng-mirrors]:: +crossref:freebsd-releng[releng-mirrors, Publishing FreeBSD Installation Media to Project Mirrors]:: Procedures to publish installation medium. -crossref:freebsd-releng[releng-wrapup]:: +crossref:freebsd-releng[releng-wrapup, Wrapping up the Release Cycle]:: Wrapping up the release cycle. [[releng-prep]] == General Information and Preparation Approximately two months before the start of the release cycle, the {teamRe} decides on a schedule for the release. The schedule includes the various milestone points of the release cycle, such as freeze dates, branch dates, and build dates. For example: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | Milestone | Anticipated Date |{branchHead} slush: |May 27, 2016 |{branchHead} freeze: |June 10, 2016 |{branchHead} KBI freeze: |June 24, 2016 |`doc/` tree slush [1]: |June 24, 2016 |Ports quarterly branch [2]: |July 1, 2016 |{branchStablex} branch: |July 8, 2016 |`doc/` tree tag [3]: |July 8, 2016 |BETA1 build starts: |July 8, 2016 |{branchHead} thaw: |July 9, 2016 |BETA2 build starts: |July 15, 2016 |BETA3 build starts [*]: |July 22, 2016 |{branchRelengx} branch: |July 29, 2016 |RC1 build starts: |July 29, 2016 |{branchStablex} thaw: |July 30, 2016 |RC2 build starts: |August 5, 2016 |Final Ports package builds [4]: |August 6, 2016 |Ports release tag: |August 12, 2016 |RC3 build starts [*]: |August 12, 2016 |RELEASE build starts: |August 19, 2016 |RELEASE announcement: |September 2, 2016 |=== [NOTE] ==== Items marked with "[*]" are "as needed". ==== . The `doc/` tree slush is coordinated by the {teamDoceng}. . The Ports quarterly branch used is determined by when the final `RC` build is planned. A new quarterly branch is created on the first day of the quarter, so this metric should be used when taking the release cycle milestones into account. The quarterly branch is created by the {teamPortmgr}. . The `doc/` tree is tagged by the {teamDoceng}. . The final Ports package build is done by the {teamPortmgr} after the final (or what is expected to be final) `RC` build. [NOTE] ==== If the release is being created from an existing {branchStable} branch, the KBI freeze date can be excluded, since the KBI is already considered frozen on established {branchStable} branches. ==== When writing the release cycle schedule, a number of things need to be taken into consideration, in particular milestones where the target date depends on predefined milestones upon which there is a dependency. For example, the Ports Collection release tag originates from the active quarterly branch at the time of the last `RC`. This in part defines which quarterly branch is used, when the release tag can happen, and what revision of the ports tree is used for the final `RELEASE` build. After general agreement on the schedule, the {teamRe} emails the schedule to the FreeBSD Developers. It is somewhat typical that many developers will inform the {teamRe} about various works-in-progress. In some cases, an extension for the in-progress work will be requested, and in other cases, a request for "blanket approval" to a particular subset of the tree will be made. When such requests are made, it is important to make sure timelines (even if estimated) are discussed. For blanket approvals, the length of time for the blanket approval should be made clear. For example, a FreeBSD developer may request blanket approvals from the start of the code slush until the start of the `RC` builds. [NOTE] ==== To keep track of blanket approvals, the {teamRe} uses an internal repository to keep a running log of such requests, which defines the area upon which a blanket approval was granted, the author(s), when the blanket approval expires, and the reason the approval was granted. One example of this is granting blanket approval to [.filename]#release/doc/# to all {teamRe} members until the final `RC` to update the release notes and other release-related documentation. ==== [NOTE] ==== The {teamRe} also uses this repository to track pending approval requests that are received just prior to starting various builds during the release cycle, which the Release Engineer specifies the cutoff period with an email to the FreeBSD developers. ==== Depending on the underlying set of code in question, and the overall impact the set of code has on FreeBSD as a whole, such requests may be approved or denied by the {teamRe}. The same applies to work-in-progress extensions. For example, in-progress work for a new device driver that is otherwise isolated from the rest of the tree may be granted an extension. A new scheduler, however, may not be feasible, especially if such dramatic changes do not exist in another branch. The schedule is also added to the Project website, in the `doc/` repository, in [.filename]#~/website/content/en/releases/{branchRevision}R/schedule.adoc#. This file is continuously updated as the release cycle progresses. [NOTE] ==== In most cases, the [.filename]#schedule.adoc# can be copied from a prior release and updated accordingly. ==== In addition to adding [.filename]#schedule.adoc# to the website, [.filename]#~/shared/releases.adoc# is also updated to add the link to the schedule to various subpages, as well as enabling the link to the schedule on the Project website index page. The schedule is also linked from [.filename]#~/website/content/en/releng/_index.adoc#. Approximately one month prior to the scheduled "code slush", the {teamRe} sends a reminder email to the FreeBSD Developers. [[releng-terms]] == Release Engineering Terminology This section describes some of the terminology used throughout the rest of this document. [[releng-terms-code-slush]] === The Code Slush Although the code slush is not a hard freeze on the tree, the {teamRe} requests that bugs in the existing code base take priority over new features. The code slush does not enforce commit approvals to the branch. [[releng-terms-code-freeze]] === The Code Freeze The code freeze marks the point in time where all commits to the branch require explicit approval from the {teamRe}. The FreeBSD Git repository contains several hooks to perform sanity checks before any commit is actually committed to the tree. One of these hooks will evaluate if committing to a particular branch requires specific approval. To enforce commit approvals by the {teamRe}, the Release Engineering Team must approve any changes to the branch, in which case the commit log must include an `Approved by: re (login)` line, where "login" is the login ID of the approver. [NOTE] ==== During the code freeze, FreeBSD committers are urged to follow the link:https://wiki.freebsd.org/Releng/ChangeRequestGuidelines[Change Request Guidelines]. ==== [[releng-terms-kbi-freeze]] === The KBI/KPI Freeze KBI/KPI stability implies that the caller of a function across two different releases of software that implement the function results in the same end state. The caller, whether it is a process, thread, or function, expects the function to operate in a certain way, otherwise the KBI/KPI stability on the branch is broken. [[releng-website]] == Website Changes During the Release Cycle This section describes the changes to the website that should occur as the release cycle progresses. [NOTE] ==== The files specified throughout this section are relative to the `{branchHead}` branch of the `doc` repository. ==== [[releng-website-prerelease]] === Website Changes Before the Release Cycle Begins When the release cycle schedule is available, these files need to be updated to enable different functionalities on the FreeBSD Project website: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | File to Edit | What to Change |[.filename]#~/shared/releases.adoc# |Change `beta-upcoming` from `IGNORE` to `INCLUDE` |[.filename]#~/shared/releases.adoc# |Change `beta-testing` from `IGNORE` to `INCLUDE` |=== [[releng-website-beta-rc]] === Website Changes During `BETA` or `RC` When transitioning from `PRERELEASE` to `BETA`, these files need to be updated to enable the "Help Test" block on the download page. All files are relative to [.filename]#head/# in the `doc` repository: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | File to Edit | What to Change |[.filename]#~/shared/releases.adoc# |Update `betarel-vers` to `BETA__1__` |[.filename]#~/website/data/en/news/news.toml# |Add an entry announcing the `BETA` |[.filename]#~/website/static/security/advisory-template.txt# |Add the new `BETA`, `RC`, or final `RELEASE` to the template |[.filename]#~/website/static/security/errata-template.txt# |Add the new `BETA`, `RC`, or final `RELEASE` to the template |=== Once the {branchRelengx} branch is created, the various release-related documents need to be added to the `doc/` repository. [NOTE] ==== The relevant release-related documents exist in the [.filename]#doc# repository for FreeBSD 12.x and later. ==== [[releng-ports-beta-rc]] === Ports Changes During `BETA`, `RC`, and the Final `RELEASE` For each build during the release cycle, the `MANIFEST` files containing the `SHA256` of the various distribution sets, such as `base.txz`, `kernel.txz`, and so on, are added to the package:misc/freebsd-release-manifests[] port. This allows utilities other than , such as package:ports-mgmt/poudriere[], to safely use these distribution sets by providing a mechanism through which the checksums can be verified. [[releng-head]] == Release from {branchHead} This section describes the general procedures of the FreeBSD release cycle from the {branchHead} branch. [[releng-head-builds-alpha]] === FreeBSD "`ALPHA`" Builds Starting with the FreeBSD 10.0-RELEASE cycle, the notion of "`ALPHA`" builds was introduced. Unlike the `BETA` and `RC` builds, `ALPHA` builds are not included in the FreeBSD Release schedule. The idea behind `ALPHA` builds is to provide regular FreeBSD-provided builds before the creation of the {branchStable} branch. FreeBSD `ALPHA` snapshots should be built approximately once a week. For the first `ALPHA` build, the `BRANCH` value in [.filename]#sys/conf/newvers.sh# needs to be changed from `CURRENT` to `ALPHA1`. For subsequent `ALPHA` builds, increment each `ALPHA__N__` value by one. -See crossref:freebsd-releng[releng-building] for information on building the `ALPHA` images. +See crossref:freebsd-releng[releng-building, Building FreeBSD Installation Media] for information on building the `ALPHA` images. [[releng-head-branching]] === Creating the {branchStablex} Branch When creating the {branchStable} branch, several changes are required in both the new {branchStable} branch and the {branchHead} branch. The files listed are relative to the repository root. To create the new {branchStablex} branch in Git: [NOTE] ==== Make sure that you are in the {branchHead} branch ==== [source,shell,subs="attributes"] .... % git checkout -b {branchStablex} .... Once the {branchStablex} branch has been created, make the following edits: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | File to Edit | What to Change |[.filename]#UPDATING# |Update the FreeBSD version, and remove the notice about `WITNESS` |[.filename]#contrib/jemalloc/include/jemalloc/jemalloc_FreeBSD.h# a| [source,shell,subs="attributes"] .... #ifndef MALLOC_PRODUCTION #define MALLOC_PRODUCTION #endif .... |[.filename]#lib/clang/llvm.build.mk# |Uncomment `-DNDEBUG` |[.filename]#sys/\*/conf/GENERIC*# |Remove debugging support |[.filename]#sys/*/conf/MINIMAL# |Remove debugging support |[.filename]#release/release.conf.sample# |Update `SRCBRANCH` |[.filename]#sys/*/conf/GENERIC-NODEBUG# |Remove these kernel configurations |[.filename]#sys/arm/conf/std.arm*# |Remove debugging options |[.filename]#sys/conf/newvers.sh# |Update the `BRANCH` value to reflect `BETA1` |[.filename]#share/mk/src.opts.mk# |Move `REPRODUCIBLE_BUILD` from `\__DEFAULT_NO_OPTIONS` to `__DEFAULT_YES_OPTIONS` |[.filename]#share/mk/src.opts.mk# |Move `LLVM_ASSERTIONS` from `\__DEFAULT_YES_OPTIONS` to `__DEFAULT_NO_OPTIONS` |[.filename]#libexec/rc/rc.conf# |Set `dumpdev` from `AUTO` to `NO` (it is configurable via for those that want it enabled by default) |[.filename]#release/Makefile# |Remove the `debug.witness.trace` entries |=== Then in the {branchHead} branch, which will now become a new major version: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | File to Edit | What to Change |[.filename]#UPDATING# |Update the FreeBSD version |[.filename]#sys/conf/newvers.sh# |Update the `BRANCH` value to reflect `CURRENT`, and increment `REVISION` |[.filename]#Makefile.inc1# |Update `TARGET_TRIPLE` and `MACHINE_TRIPLE` |[.filename]#sys/sys/param.h# |Update `__FreeBSD_version` |[.filename]#gnu/usr.bin/cc/cc_tools/freebsd-native.h# |Update `FBSD_MAJOR` and `FBSD_CC_VER` |[.filename]#contrib/gcc/config.gcc# |Append the `freebsdversion.h` section |[.filename]#lib/clang/llvm.build.mk# |Update the value of `OS_VERSION` |[.filename]#lib/clang/freebsd_cc_version.h# |Update `FREEBSD_CC_VERSION` |[.filename]#lib/clang/include/lld/Common/Version.inc# |Update `LLD_REVISION_STRING` |[.filename]#Makefile.libcompat# |Update `LIB32CPUFLAGS` |=== [[releng-stable]] == Release from {branchStable} This section describes the general procedures of the FreeBSD release cycle from an extablished {branchStable} branch. [[releng-stable-slush]] === FreeBSD `stable` Branch Code Slush In preparation for the code freeze on a `stable` branch, several files need to be updated to reflect the release cycle is officially in progress. These files are all relative to the top-most level of the stable branch: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | File to Edit | What to Change |[.filename]#sys/conf/newvers.sh# |Update the `BRANCH` value to reflect `PRERELEASE` |[.filename]#Makefile.inc1# |Update `TARGET_TRIPLE` |[.filename]#lib/clang/llvm.build.mk# |Update `OS_VERSION` |[.filename]#Makefile.libcompat# |Update `LIB32CPUFLAGS` |=== [[releng-stable-builds-beta]] === FreeBSD `BETA` Builds Following the code slush, the next phase of the release cycle is the code freeze. This is the point at which all commits to the stable branch require explicit approval from the {teamRe}. This is enforced by {git-admin-email} who handles the repository. [NOTE] ==== There are two general exceptions to requiring commit approval during the release cycle. The first is any change that needs to be committed by the Release Engineer to proceed with the day-to-day workflow of the release cycle, the other is security fixes that may occur during the release cycle. ==== Once the code freeze is in effect, the next build from the branch is labeled `BETA1`. This is done by updating the `BRANCH` value in [.filename]#sys/conf/newvers.sh# from `PRERELEASE` to `BETA1`. Once this is done, the first set of `BETA` builds are started. Subsequent `BETA` builds do not require updates to any files other than [.filename]#sys/conf/newvers.sh#, incrementing the `BETA` build number. [[releng-stable-branching]] === Creating the {branchRelengx} Branch When the first `RC` (Release Candidate) build is ready to begin, the {branchReleng} branch is created. This is a multi-step process that must be done in a specific order, to avoid anomalies such as overlaps with `__FreeBSD_version` values, for example. The paths listed below are relative to the repository root. The order of commits and what to change are: [NOTE] ==== Make sure that you are in the {branchStablex} branch ==== [source,shell,subs="attributes"] .... % git checkout -b {branchRelengx} .... [.informaltable] [cols="1,1", frame="none", options="header"] |=== | File to Edit | What to Change |[.filename]#sys/conf/newvers.sh# |Change `BETA__X__` to `RC1` |[.filename]#sys/sys/param.h# |Update `__FreeBSD_version` |[.filename]#sys/conf/kern.opts.mk# |Move `REPRODUCIBLE_BUILD` from `__DEFAULT_NO_OPTIONS` to `__DEFAULT_YES_OPTIONS` |[.filename]#etc/pkg/FreeBSD.conf# |Replace `latest` with `quarterly` as the default package repository location |[.filename]#release/pkg_repos/release-dvd.conf# |Replace `latest` with `quarterly` as the default package repository location |[.filename]#sys/conf/newvers.sh# |Update `BETA__X__` with `PRERELEASE` |[.filename]#sys/sys/param.h# |Update `__FreeBSD_version` |=== Then, {git-admin-email} adds new approvers for the releng branch as did for the stable branch. [source,shell,subs="attributes"] .... % git add . % git commit .... Now that two new `__FreeBSD_version` values exist, also update [.filename]#~/documentation/content/en/books/porters-handbook/versions/chapter.adoc# in the Documentation Project repository. After the first `RC` build has completed and tested, the {branchStable} branch can be "thawed" by {git-admin-email}. Following the availability of the first `RC`, {teamBugmeister} should be emailed to add the new FreeBSD `-RELEASE` to the `versions` available in the drop-down menu shown in the bug tracker. [[releng-building]] == Building FreeBSD Installation Media This section describes the general procedures producing FreeBSD development snapshots and releases. [[releng-build-scripts]] === Release Build Scripts Prior to FreeBSD 9.0-RELEASE, [.filename]#src/release/Makefile# was updated to support , and the [.filename]#src/release/generate-release.sh# script was introduced as a wrapper to automate invoking the targets. Prior to FreeBSD 9.2-RELEASE, [.filename]#src/release/release.sh# was introduced, which heavily based on [.filename]#src/release/generate-release.sh# included support to specify configuration files to override various options and environment variables. Support for configuration files provided support for cross building each architecture for a release by specifying a separate configuration file for each invocation. As a brief example of using [.filename]#src/release/release.sh# to build a single release in [.filename]#/scratch#: [source,shell,subs="attributes"] .... # /bin/sh /usr/src/release/release.sh .... As a brief example of using [.filename]#src/release/release.sh# to build a single, cross-built release using a different target directory, create a custom [.filename]#release.conf# containing: [.programlisting,subs="attributes"] .... # release.sh configuration for powerpc/powerpc64 CHROOTDIR="/scratch-powerpc64" TARGET="powerpc" TARGET_ARCH="powerpc64" KERNEL="GENERIC64" .... Then invoke [.filename]#src/release/release.sh# as: [source,shell,subs="attributes"] .... # /bin/sh /usr/src/release/release.sh -c $HOME/release.conf .... See and [.filename]#src/release/release.conf.sample# for more details and example usage. [[releng-build-release]] === Building FreeBSD Releases During the release cycle, a copy of [.filename]#CHECKSUM.SHA512# and [.filename]#CHECKSUM.SHA256# for each architecture are stored in the {teamRe} internal repository in addition to being included in the various announcement emails. Each [.filename]#MANIFEST# containing the hashes of [.filename]#base.txz#, [.filename]#kernel.txz#, etc. are added to package:misc/freebsd-release-manifests[] in the Ports Collection, as well. In preparation for the release build, several files need to be updated: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | File to Edit | What to Change |[.filename]#sys/conf/newvers.sh# |Update the `BRANCH` value to `RELEASE` |[.filename]#UPDATING# |Add the anticipated announcement date |[.filename]#lib/csu/common/crtbrand.S# |Replace `__FreeBSD_version` with the value in [.filename]#sys/sys/param.h# |=== After building the final `RELEASE`, the {branchRelengx} branch is tagged as {tagReleasex} using the revision from which the `RELEASE` was built. Similar to creating the {branchStablex} and {branchRelengx} branches, this is done with `git tag`. From the repository root: [NOTE] ==== Make sure that you are in the {branchRelengx} branch ==== [source,shell,subs="attributes"] .... % git tag {tagReleasex} .... [[releng-mirrors]] == Publishing FreeBSD Installation Media to Project Mirrors This section describes the procedure to publish FreeBSD development snapshots and releases to the Project mirrors. [[releng-mirrors-staging]] === Staging FreeBSD Installation Media Images Staging FreeBSD snapshots and releases is a two part process: * Creating the directory structure to match the hierarchy on `ftp-master` + If `EVERYTHINGISFINE` is defined in the build configuration files, [.filename]#main.conf# in the case of the build scripts referenced above, this happens automatically in the after the build is complete, creating the directory structure in [.filename]#${DESTDIR}/R/ftp-stage# with a path structure matching what is expected on `ftp-master`. This is equivalent to running the following in the directly: + [source,shell,subs="attributes"] .... # make -C /usr/src/release -f Makefile.mirrors EVERYTHINGISFINE=1 ftp-stage .... + After each architecture is built, [.filename]#thermite.sh# will rsync the [.filename]#${DESTDIR}/R/ftp-stage# from the build to [.filename]#/snap/ftp/snapshots# or [.filename]#/snap/ftp/releases# on the build host, respectively. * Copying the files to a staging directory on `ftp-master` before moving the files into [.filename]#pub/# to begin propagation to the Project mirrors + Once all builds have finished, [.filename]#/snap/ftp/snapshots#, or [.filename]#/snap/ftp/releases# for a release, is polled by `ftp-master` using rsync to [.filename]#/archive/tmp/snapshots# or [.filename]#/archive/tmp/releases#, respectively. + [NOTE] ==== On `ftp-master` in the FreeBSD Project infrastructure, this step requires `root` level access, as this step must be executed as the `archive` user. ==== [[releng-mirrors-publishing]] === Publishing FreeBSD Installation Media Once the images are staged in [.filename]#/archive/tmp/#, they are ready to be made public by putting them in [.filename]#/archive/pub/FreeBSD#. To reduce propagation time, is used to create hard links from [.filename]#/archive/tmp# to [.filename]#/archive/pub/FreeBSD#. [NOTE] ==== For this to be effective, both [.filename]#/archive/tmp# and [.filename]#/archive/pub# must reside on the same logical filesystem. ==== There is a caveat, however, where rsync must be used after to correct the symbolic links in [.filename]#pub/FreeBSD/snapshots/ISO-IMAGES# which will replace with a hard link, increasing the propagation time. [NOTE] ==== As with the staging steps, this requires `root` level access, as this step must be executed as the `archive` user. ==== As the `archive` user: [source,shell,subs="attributes"] .... % cd /archive/tmp/snapshots % pax -r -w -l . /archive/pub/FreeBSD/snapshots % /usr/local/bin/rsync -avH /archive/tmp/snapshots/* /archive/pub/FreeBSD/snapshots/ .... Replace _snapshots_ with _releases_ as appropriate. [[releng-wrapup]] == Wrapping up the Release Cycle This section describes general post-release tasks. [[releng-wrapup-en]] === Post-Release Errata Notices As the release cycle approaches conclusion, it is common to have several EN (Errata Notice) candidates to address issues that were discovered late in the cycle. Following the release, the {teamRe} and the {teamSecteam} revisit changes that were not approved prior to the final release, and depending on the scope of the change in question, may issue an EN. [NOTE] ==== The actual process of issuing ENs is handled by the {teamSecteam}. ==== To request an Errata Notice after a release cycle has completed, a developer should fill out the https://www.freebsd.org/security/errata-template.txt[Errata Notice template], in particular the `Background`, `Problem Description`, `Impact`, and if applicable, `Workaround` sections. The completed Errata Notice template should be emailed together with either a patch against the {branchReleng} branch or a list of revisions from the {branchStable} branch. For Errata Notice requests immediately following the release, the request should be emailed to both the {teamRe} and the {teamSecteam}. Once the {branchReleng} branch has been handed over to the {teamSecteam} as -described in crossref:freebsd-releng[releng-wrapup-handoff], Errata Notice requests should be sent to the {teamSecteam}. +described in crossref:freebsd-releng[releng-wrapup-handoff, Handoff to the {teamSecteam}], Errata Notice requests should be sent to the {teamSecteam}. [[releng-wrapup-handoff]] === Handoff to the {teamSecteam} Roughly two weeks following the release, the Release Engineer updates the Git repository changing the approver from the Release engineering team to the security officer for the {branchRelengx} branch. [[releng-eol]] == Release End-of-Life This section describes the website-related files to update when a release reaches EoL (End-of-Life). [[releng-eol-website]] === Website Updates for End-of-Life When a release reaches End-of-Life, references to that release should be removed and/or updated on the website: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | File | What to Change |[.filename]#~/website/themes/beastie/layouts/index.html# |Remove `u-relXXX-announce` and `u-relXXX-announce` references. |[.filename]#~/website/content/en/releases/_index.adoc# |Move the `u-relXXX-*` variables from the supported release list to the Legacy Releases list. |[.filename]#~/website/content/en/releng/_index.adoc# |Update the appropriate releng branch to reflect the branch is no longer supported. |[.filename]#~/website/content/en/security/_index.adoc# |Remove the branch from the supported branch list. |[.filename]#~/website/content/en/security/unsupported.adoc# |Add the branch to the unsupported branch list. |[.filename]#~/website/content/en/where.adoc# |Remove the URLs for the release. |[.filename]#~/website/themes/beastie/layouts/partials/sidenav.html# |Remove `u-relXXX-announce` and `u-relXXX-announce` references. |[.filename]#~/website/static/security/advisory-template.txt# |Remove references to the release and releng branch. |[.filename]#~/website/static/security/errata-template.txt# |Remove references to the release and releng branch. |=== diff --git a/documentation/content/en/articles/gjournal-desktop/_index.adoc b/documentation/content/en/articles/gjournal-desktop/_index.adoc index 774bcf29f3..1f8c15f843 100644 --- a/documentation/content/en/articles/gjournal-desktop/_index.adoc +++ b/documentation/content/en/articles/gjournal-desktop/_index.adoc @@ -1,510 +1,510 @@ --- title: Implementing UFS Journaling on a Desktop PC authors: - author: Manolis Kiagias email: manolis@FreeBSD.org description: Implementing UFS Journaling on a Desktop PC trademarks: ["freebsd", "general"] tags: ["UFS", "Journaling" , "Desktop", "FreeBSD"] --- = Implementing UFS Journaling on a Desktop PC :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/gjournal-desktop/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract A journaling file system uses a log to record all transactions that take place in the file system, and preserves its integrity in the event of a system crash or power failure. Although it is still possible to lose unsaved changes to files, journaling almost completely eliminates the possibility of file system corruption caused by an unclean shutdown. It also shortens to a minimum the time required for after-failure file system checking. Although the UFS file system employed by FreeBSD does not implement journaling itself, the new journal class of the GEOM framework in FreeBSD 7._X_ can be used to provide file system independent journaling. This article explains how to implement UFS journaling on a typical desktop PC scenario. ''' toc::[] [[introduction]] == Introduction While professional servers are usually well protected from unforeseen shutdowns, the typical desktop is at the mercy of power failures, accidental resets, and other user related incidents that can lead to unclean shutdowns. Soft Updates usually protect the file system efficiently in such cases, although most of the times a lengthy background check is required. On rare occasions, file system corruption reaches a point where user intervention is required and data may be lost. The new journaling capability provided by GEOM can greatly assist in such scenarios, by virtually eliminating the time required for file system checking, and ensuring that the file system is quickly restored to a consistent state. This article describes a procedure for implementing UFS journaling on a typical desktop PC scenario (one hard disk used for both operating system and data). It should be followed during a fresh installation of FreeBSD. The steps are simple enough and do not require overly complex interaction with the command line. After reading this article, you will know: * How to reserve space for journaling during a new installation of FreeBSD. * How to load and enable the `geom_journal` module (or build support for it in your custom kernel). * How to convert your existing file systems to utilize journaling, and what options to use in [.filename]#/etc/fstab# to mount them. * How to implement journaling in new (empty) partitions. * How to troubleshoot common problems associated with journaling. Before reading this article, you should be able to: * Understand basic UNIX(R) and FreeBSD concepts. * Be familiar with the installation procedure of FreeBSD and the sysinstall utility. [WARNING] ==== The procedure described here is intended for preparing a new installation where no actual user data is stored on the disk yet. While it is possible to modify and extend this procedure for systems already in production, you should _backup_ all important data before doing so. Messing around with disks and partitions at a low level can lead to fatal mistakes and data loss. ==== [[understanding-journaling]] == Understanding Journaling in FreeBSD The journaling provided by GEOM in FreeBSD 7._X_ is not file system specific (unlike for example the ext3 file system in Linux(R)) but is functioning at the block level. Though this means it can be applied to different file systems, for FreeBSD 7.0-RELEASE, it can only be used on UFS2. This functionality is provided by loading the [.filename]#geom_journal.ko# module into the kernel (or building it into a custom kernel) and using the `gjournal` command to configure the file systems. In general, you would like to journal large file systems, like [.filename]#/usr#. You will need however (see the following section) to reserve some free disk space. When a file system is journaled, some disk space is needed to keep the journal itself. The disk space that holds the actual data is referred to as the __data provider__, while the one that holds the journal is referred to as the __journal provider__. The data and journal providers need to be on different partitions when journaling an existing (non-empty) partition. When journaling a new partition, you have the option to use a single provider for both data and journal. In any case, the `gjournal` command combines both providers to create the final journaled file system. For example: * You wish to journal your [.filename]#/usr# file system, stored in [.filename]#/dev/ad0s1f# (which already contains data). * You reserved some free disk space in a partition in [.filename]#/dev/ad0s1g#. * Using `gjournal`, a new [.filename]#/dev/ad0s1f.journal# device is created where [.filename]#/dev/ad0s1f# is the data provider, and [.filename]#/dev/ad0s1g# is the journal provider. This new device is then used for all subsequent file operations. The amount of disk space you need to reserve for the journal provider depends on the usage load of the file system and not on the size of the data provider. For example on a typical office desktop, a 1 GB journal provider for the [.filename]#/usr# file system will suffice, while a machine that deals with heavy disk I/O (i.e. video editing) may need more. A kernel panic will occur if the journal space is exhausted before it has a chance to be committed. [NOTE] ==== The journal sizes suggested here, are highly unlikely to cause problems in typical desktop use (such as web browsing, word processing and playback of media files). If your workload includes intense disk activity, use the following rule for maximum reliability: Your RAM size should fit in 30% of the journal provider's space. For example, if your system has 1 GB RAM, create an approximately 3.3 GB journal provider. (Multiply your RAM size with 3.3 to obtain the size of the journal). ==== For more information about journaling, please read the manual page of man:gjournal[8]. [[reserve-space]] == Steps During the Installation of FreeBSD === Reserving Space for Journaling A typical desktop machine usually has one hard disk that stores both the OS and user data. Arguably, the default partitioning scheme selected by sysinstall is more or less suitable: A desktop machine does not need a large [.filename]#/var# partition, while [.filename]#/usr# is allocated the bulk of the disk space, since user data and a lot of packages are installed into its subdirectories. The default partitioning (the one obtained by pressing kbd:[A] at the FreeBSD partition editor, called Disklabel) does not leave any unallocated space. Each partition that will be journaled, requires another partition for the journal. Since the [.filename]#/usr# partition is the largest, it makes sense to shrink this partition slightly, to obtain the space required for journaling. In our example, an 80 GB disk is used. The following screenshot shows the default partitions created by Disklabel during installation: image::disklabel1.png[] If this is more or less what you need, it is very easy to adjust for journaling. Simply use the arrow keys to move the highlight to the [.filename]#/usr# partition and press kbd:[D] to delete it. Now, move the highlight to the disk name at the top of the screen and press kbd:[C] to create a new partition for [.filename]#/usr#. This new partition should be smaller by 1 GB (if you intend to journal [.filename]#/usr# only), or 2 GB (if you intend to journal both [.filename]#/usr# and [.filename]#/var#). From the pop-up that appears, opt to create a file system, and type [.filename]#/usr# as the mount point. [NOTE] ==== Should you journal the [.filename]#/var# partition? Normally, journaling makes sense on quite large partitions. You may decide not to journal [.filename]#/var#, although doing so on a typical desktop will cause no harm. If the file system is lightly used (quite probable for a desktop) you may wish to allocate less disk space for its journal. In our example, we journal both [.filename]#/usr# and [.filename]#/var#. You may of course adjust the procedure to your own needs. ==== To keep things as easy going as possible, we are going to use sysinstall to create the partitions required for journaling. However, during installation, sysinstall insists on asking a mount point for each partition you create. At this point, you do not have any mount points for the partitions that will hold the journals, and in reality you __do not even need them__. These are not partitions that we are ever going to mount somewhere. To avoid these problems with sysinstall, we are going to create the journal partitions as swap space. Swap is never mounted, and sysinstall has no problem creating as many swap partitions as needed. After the first reboot, [.filename]#/etc/fstab# will have to be edited, and the extra swap space entries removed. To create the swap, again use the arrow keys to move the highlight to the top of Disklabel screen, so that the disk name itself is highlighted. Then press kbd:[N], enter the desired size (_1024M_), and select "swap space" from the pop-up menu that appears. Repeat for every journal you wish to create. In our example, we create two partitions to provide for the journals of [.filename]#/usr# and [.filename]#/var#. The final result is shown in the following screenshot: image::disklabel2.png[] When you have completed creating the partitions, we suggest you write down the partition names, and mount points, so you can easily refer to this information during the configuration phase. This will help alleviate mistakes that may damage your installation. The following table shows our notes for the sample configuration: .Partitions and Journals [cols="1,1,1", options="header"] |=== | Partition | Mount Point | Journal |ad0s1d |/var |ad0s1h |ad0s1f |/usr |ad0s1g |=== Continue the installation as you would normally do. We would however suggest you postpone installation of third party software (packages) until you have completely setup journaling. [[first-boot]] === Booting for the first time Your system will come up normally, but you will need to edit [.filename]#/etc/fstab# and remove the extra swap partitions you created for the journals. Normally, the swap partition you will actually use is the one with the "b" suffix (i.e. ad0s1b in our example). Remove all other swap space entries and reboot so that FreeBSD will stop using them. When the system comes up again, we will be ready to configure journaling. [[configure-journal]] == Setting Up Journaling [[running-gjournal]] === Executing `gjournal` Having prepared all the required partitions, it is quite easy to configure journaling. We will need to switch to single user mode, so login as `root` and type: [source,shell] .... # shutdown now .... Press kbd:[Enter] to get the default shell. We will need to unmount the partitions that will be journaled, in our example [.filename]#/usr# and [.filename]#/var#: [source,shell] .... # umount /usr /var .... Load the module required for journaling: [source,shell] .... # gjournal load .... Now, use your notes to determine which partition will be used for each journal. In our example, [.filename]#/usr# is [.filename]#ad0s1f# and its journal will be [.filename]#ad0s1g#, while [.filename]#/var# is [.filename]#ad0s1d# and will be journaled to [.filename]#ad0s1h#. The following commands are required: [source,shell] .... # gjournal label ad0s1f ad0s1g GEOM_JOURNAL: Journal 2948326772: ad0s1f contains data. GEOM_JOURNAL: Journal 2948326772: ad0s1g contains journal. # gjournal label ad0s1d ad0s1h GEOM_JOURNAL: Journal 3193218002: ad0s1d contains data. GEOM_JOURNAL: Journal 3193218002: ad0s1h contains journal. .... [NOTE] ==== If the last sector of either partition is used, `gjournal` will return an error. You will have to run the command using the `-f` flag to force an overwrite, i.e.: [source,shell] .... # gjournal label -f ad0s1d ad0s1h .... Since this is a new installation, it is highly unlikely that anything will be actually overwritten. ==== At this point, two new devices are created, namely [.filename]#ad0s1d.journal# and [.filename]#ad0s1f.journal#. These represent the [.filename]#/var# and [.filename]#/usr# partitions we have to mount. Before mounting, we must however set the journal flag on them and clear the Soft Updates flag: [source,shell] .... # tunefs -J enable -n disable ad0s1d.journal tunefs: gjournal set tunefs: soft updates cleared # tunefs -J enable -n disable ad0s1f.journal tunefs: gjournal set tunefs: soft updates cleared .... Now, mount the new devices manually at their respective places (note that we can now use the `async` mount option): [source,shell] .... # mount -o async /dev/ad0s1d.journal /var # mount -o async /dev/ad0s1f.journal /usr .... Edit [.filename]#/etc/fstab# and update the entries for [.filename]#/usr# and [.filename]#/var#: [.programlisting] .... /dev/ad0s1f.journal /usr ufs rw,async 2 2 /dev/ad0s1d.journal /var ufs rw,async 2 2 .... [WARNING] ==== Make sure the above entries are correct, or you will have trouble starting up normally after you reboot! ==== Finally, edit [.filename]#/boot/loader.conf# and add the following line so the man:gjournal[8] module is loaded at every boot: [.programlisting] .... geom_journal_load="YES" .... Congratulations! Your system is now set for journaling. You can either type `exit` to return to multi-user mode, or reboot to test your configuration (recommended). During the boot you will see messages like the following: [source,shell] .... ad0: 76293MB XEC XE800JD-00HBC0 08.02D08 at ata0-master SATA150 GEOM_JOURNAL: Journal 2948326772: ad0s1g contains journal. GEOM_JOURNAL: Journal 3193218002: ad0s1h contains journal. GEOM_JOURNAL: Journal 3193218002: ad0s1d contains data. GEOM_JOURNAL: Journal ad0s1d clean. GEOM_JOURNAL: Journal 2948326772: ad0s1f contains data. GEOM_JOURNAL: Journal ad0s1f clean. .... After an unclean shutdown, the messages will vary slightly, i.e.: [source,shell] .... GEOM_JOURNAL: Journal ad0s1d consistent. .... This usually means that man:gjournal[8] used the information in the journal provider to return the file system to a consistent state. [[gjournal-new]] === Journaling Newly Created Partitions While the above procedure is necessary for journaling partitions that already contain data, journaling an empty partition is somewhat easier, since both the data and the journal provider can be stored in the same partition. For example, assume a new disk was installed, and a new partition [.filename]#/dev/ad1s1d# was created. Creating the journal would be as simple as: [source,shell] .... # gjournal label ad1s1d .... The journal size will be 1 GB by default. You may adjust it by using the `-s` option. The value can be given in bytes, or appended by `K`, `M` or `G` to denote Kilobytes, Megabytes or Gigabytes respectively. Note that `gjournal` will not allow you to create unsuitably small journal sizes. For example, to create a 2 GB journal, you could use the following command: [source,shell] .... # gjournal label -s 2G ad1s1d .... You can then create a file system on your new partition, and enable journaling using the `-J` option: [source,shell] .... # newfs -J /dev/ad1s1d.journal .... [[configure-kernel]] === Building Journaling into Your Custom Kernel If you do not wish to load `geom_journal` as a module, you can build its functions right into your kernel. Edit your custom kernel configuration file, and make sure it includes these two lines: [.programlisting] .... options UFS_GJOURNAL # Note: This is already in GENERIC options GEOM_JOURNAL # You will have to add this one .... Rebuild and reinstall your kernel following the relevant extref:{handbook}[instructions in the FreeBSD Handbook., kernelconfig] Do not forget to remove the relevant "load" entry from [.filename]#/boot/loader.conf# if you have previously used it. [[troubleshooting-gjournal]] == Troubleshooting Journaling The following section covers frequently asked questions regarding problems related to journaling. === I am getting kernel panics during periods of high disk activity. How is this related to journaling? The journal probably fills up before it has a chance to get committed (flushed) to disk. Keep in mind the size of the journal depends on the usage load, and not the size of the data provider. If your disk activity is high, you need a larger partition for the journal. -See the note in the crossref:gjournal-desktop[understanding-journaling] section. +See the note in the crossref:gjournal-desktop[understanding-journaling, Understanding Journaling in FreeBSD] section. === I made some mistake during configuration, and I cannot boot normally now. Can this be fixed some way? You either forgot (or misspelled) the entry in [.filename]#/boot/loader.conf#, or there are errors in your [.filename]#/etc/fstab# file. These are usually easy to fix. Press kbd:[Enter] to get to the default single user shell. Then locate the root of the problem: [source,shell] .... # cat /boot/loader.conf .... If the `geom_journal_load` entry is missing or misspelled, the journaled devices are never created. Load the module manually, mount all partitions, and continue with multi-user boot: [source,shell] .... # gjournal load GEOM_JOURNAL: Journal 2948326772: ad0s1g contains journal. GEOM_JOURNAL: Journal 3193218002: ad0s1h contains journal. GEOM_JOURNAL: Journal 3193218002: ad0s1d contains data. GEOM_JOURNAL: Journal ad0s1d clean. GEOM_JOURNAL: Journal 2948326772: ad0s1f contains data. GEOM_JOURNAL: Journal ad0s1f clean. # mount -a # exit (boot continues) .... If, on the other hand, this entry is correct, have a look at [.filename]#/etc/fstab#. You will probably find a misspelled or missing entry. In this case, mount all remaining partitions by hand and continue with the multi-user boot. === Can I remove journaling and return to my standard file system with Soft Updates? Sure. Use the following procedure, which reverses the changes. The partitions you created for the journal providers can then be used for other purposes, if you so wish. Login as `root` and switch to single user mode: [source,shell] .... # shutdown now .... Unmount the journaled partitions: [source,shell] .... # umount /usr /var .... Synchronize the journals: [source,shell] .... # gjournal sync .... Stop the journaling providers: [source,shell] .... # gjournal stop ad0s1d.journal # gjournal stop ad0s1f.journal .... Clear journaling metadata from all the devices used: [source,shell] .... # gjournal clear ad0s1d # gjournal clear ad0s1f # gjournal clear ad0s1g # gjournal clear ad0s1h .... Clear the file system journaling flag, and restore the Soft Updates flag: [source,shell] .... # tunefs -J disable -n enable ad0s1d tunefs: gjournal cleared tunefs: soft updates set # tunefs -J disable -n enable ad0s1f tunefs: gjournal cleared tunefs: soft updates set .... Remount the old devices by hand: [source,shell] .... # mount -o rw /dev/ad0s1d /var # mount -o rw /dev/ad0s1f /usr .... Edit [.filename]#/etc/fstab# and restore it to its original state: [.programlisting] .... /dev/ad0s1f /usr ufs rw 2 2 /dev/ad0s1d /var ufs rw 2 2 .... Finally, edit [.filename]#/boot/loader.conf#, remove the entry that loads the `geom_journal` module and reboot. [[further-reading]] == Further Reading Journaling is a fairly new feature of FreeBSD, and as such, it is not very well documented yet. You may however find the following additional references useful: * A extref:{handbook}[new section on journaling, geom-gjournal] is now part of the FreeBSD Handbook. * https://lists.freebsd.org/pipermail/freebsd-current/2006-June/064043.html[This post] in {freebsd-current} by man:gjournal[8]'s developer, `{pjd}`. * https://lists.freebsd.org/pipermail/freebsd-questions/2008-April/173501.html[This post] in {freebsd-questions} by `{ivoras}`. * The manual pages of man:gjournal[8] and man:geom[8]. diff --git a/documentation/content/en/articles/hubs/_index.adoc b/documentation/content/en/articles/hubs/_index.adoc index 3269322e7a..1ddbe3065a 100644 --- a/documentation/content/en/articles/hubs/_index.adoc +++ b/documentation/content/en/articles/hubs/_index.adoc @@ -1,420 +1,420 @@ --- title: Mirroring FreeBSD authors: - author: Jun Kuriyama email: kuriyama@FreeBSD.org - author: Valentino Vaschetto email: logo@FreeBSD.org - author: Daniel Lang email: dl@leo.org - author: Ken Smith email: kensmith@FreeBSD.org description: The all in one guide for mirroring the FreeBSD website, FTP servers, and more trademarks: ["freebsd", "general"] tags: ["Mirroring", "FreeBSD", "Hub"] --- = Mirroring FreeBSD :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/hubs/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract An in-progress article on how to mirror FreeBSD, aimed at hub administrators. ''' toc::[] [NOTE] ==== We are not accepting new community mirrors at this time. ==== [[mirror-contact]] == Contact Information The Mirror System Coordinators can be reached through email at mailto:mirror-admin@FreeBSD.org[mirror-admin@FreeBSD.org]. There is also a {freebsd-hubs}. [[mirror-requirements]] == Requirements for FreeBSD Mirrors [[mirror-diskspace]] === Disk Space Disk space is one of the most important requirements. Depending on the set of releases, architectures, and degree of completeness you want to mirror, a huge amount of disk space may be consumed. Also keep in mind that _official_ mirrors are probably required to be complete. The web pages should always be mirrored completely. Also note that the numbers stated here are reflecting the current state (at {rel120-current}-RELEASE/{rel113-current}-RELEASE). Further development and releases will only increase the required amount. Also make sure to keep some (ca. 10-20%) extra space around just to be sure. Here are some approximate figures: * Full FTP Distribution: 1.4 TB * CTM deltas: 10 GB * Web pages: 1GB The current disk usage of FTP Distribution can be found at link:ftp://ftp.FreeBSD.org/pub/FreeBSD/dir.sizes[ftp://ftp.FreeBSD.org/pub/FreeBSD/dir.sizes]. [[mirror-bandwidth]] === Network Connection/Bandwidth Of course, you need to be connected to the Internet. The required bandwidth depends on your intended use of the mirror. If you just want to mirror some parts of FreeBSD for local use at your site/intranet, the demand may be much smaller than if you want to make the files publicly available. If you intend to become an official mirror, the bandwidth required will be even higher. We can only give rough estimates here: * Local site, no public access: basically no minimum, but < 2 Mbps could make syncing too slow. * Unofficial public site: 34 Mbps is probably a good start. * Official site: > 100 Mbps is recommended, and your host should be connected as close as possible to your border router. [[mirror-system]] === System Requirements, CPU, RAM One thing this depends on the expected number of clients, which is determined by the server's policy. It is also affected by the types of services you want to offer. Plain FTP or HTTP services may not require a huge amount of resources. Watch out if you provide rsync. This can have a huge impact on CPU and memory requirements as it is considered a memory hog. The following are just examples to give you a very rough hint. For a moderately visited site that offers rsync, you might consider a current CPU with around 800MHz - 1 GHz, and at least 512MB RAM. This is probably the minimum you want for an _official_ site. For a frequently used site you definitely need more RAM (consider 2GB as a good start) and possibly more CPU, which could also mean that you need to go for a SMP system. You also want to consider a fast disk subsystem. Operations on the SVN repository require a fast disk subsystem (RAID is highly advised). A SCSI controller that has a cache of its own can also speed up things since most of these services incur a large number of small modifications to the disk. [[mirror-services]] === Services to Offer Every mirror site is required to have a set of core services available. In addition to these required services, there are a number of optional services that server administrators may choose to offer. This section explains which services you can provide and how to go about implementing them. [[mirror-serv-ftp]] ==== FTP (required for FTP Fileset) This is one of the most basic services, and it is required for each mirror offering public FTP distributions. FTP access must be anonymous, and no upload/download ratios are allowed (a ridiculous thing anyway). Upload capability is not required (and _must_ never be allowed for the FreeBSD file space). Also the FreeBSD archive should be available under the path [.filename]#/pub/FreeBSD#. There is a lot of software available which can be set up to allow anonymous FTP (in alphabetical order). * `/usr/libexec/ftpd`: FreeBSD's own ftpd can be used. Be sure to read man:ftpd[8]. * package:ftp/ncftpd[]: A commercial package, free for educational use. * package:ftp/oftpd[]: An ftpd designed with security as a main focus. * package:ftp/proftpd[]: A modular and very flexible ftpd. * package:ftp/pure-ftpd[]: Another ftpd developed with security in mind. * package:ftp/twoftpd[]: As above. * package:ftp/vsftpd[]: The "very secure" ftpd. FreeBSD's `ftpd`, `proftpd` and maybe `ncftpd` are among the most commonly used FTPds. The others do not have a large userbase among mirror sites. One thing to consider is that you may need flexibility in limiting how many simultaneous connections are allowed, thus limiting how much network bandwidth and system resources are consumed. [[mirror-serv-rsync]] ==== Rsync (optional for FTP Fileset) Rsync is often offered for access to the contents of the FTP area of FreeBSD, so other mirror sites can use your system as their source. The protocol is different from FTP in many ways. It is much more bandwidth friendly, as only differences between files are transferred instead of whole files when they change. Rsync does require a significant amount of memory for each instance. The size depends on the size of the synced module in terms of the number of directories and files. Rsync can use `rsh` and `ssh` (now default) as a transport, or use its own protocol for stand-alone access (this is the preferred method for public rsync servers). Authentication, connection limits, and other restrictions may be applied. There is just one software package available: * package:net/rsync[] [[mirror-serv-http]] ==== HTTP (required for Web Pages, Optional for FTP Fileset) If you want to offer the FreeBSD web pages, you will need to install a web server. You may optionally offer the FTP fileset via HTTP. The choice of web server software is left up to the mirror administrator. Some of the most popular choices are: * package:www/apache24[]: Apache is still one of the most widely deployed web servers on the Internet. It is used extensively by the FreeBSD Project. * package:www/boa[]: Boa is a single-tasking HTTP server. Unlike traditional web servers, it does not fork for each incoming connection, nor does it fork many copies of itself to handle multiple connections. Although, it should provide considerably great performance for purely static content. * package:www/cherokee[]: Cherokee is a very fast, flexible and easy to configure web server. It supports the widespread technologies nowadays: FastCGI, SCGI, PHP, CGI, SSL/TLS encrypted connections, vhosts, users authentication, on the fly encoding and load balancing. It also generates Apache compatible log files. * package:www/lighttpd[]: lighttpd is a secure, fast, compliant and very flexible web server which has been optimized for high-performance environments. It has a very low memory footprint compared to other web servers and takes care of cpu-load. * package:www/nginx[]: nginx is a high performance edge web server with a low memory footprint and key features to build a modern and efficient web infrastructure. Features include a HTTP server, HTTP and mail reverse proxy, caching, load balancing, compression, request throttling, connection multiplexing and reuse, SSL offload and HTTP media streaming. * package:www/thttpd[]: If you are going to be serving a large amount of static content you may find that using an application such as thttpd is more efficient than others. It is also optimized for excellent performance on FreeBSD. [[mirror-howto]] == How to Mirror FreeBSD Ok, now you know the requirements and how to offer the services, but not how to get it. :-) This section explains how to actually mirror the various parts of FreeBSD, what tools to use, and where to mirror from. [[mirror-ftp-rsync]] === Mirroring the FTP Site The FTP area is the largest amount of data that needs to be mirrored. It includes the _distribution sets_ required for network installation, the _branches_ which are actually snapshots of checked-out source trees, the _ISO Images_ to write CD-ROMs with the installation distribution, a live file system, and a snapshot of the ports tree. All of course for various FreeBSD versions, and various architectures. The best way to mirror the FTP area is rsync. You can install the port package:net/rsync[] and then use rsync to sync with your upstream host. -rsync is already mentioned in crossref:hubs[mirror-serv-rsync]. +rsync is already mentioned in crossref:hubs[mirror-serv-rsync, Rsync (optional for FTP Fileset)]. Since rsync access is not required, your preferred upstream site may not allow it. You may need to hunt around a little bit to find a site that allows rsync access. [NOTE] ==== Since the number of rsync clients will have a significant impact on the server machine, most admins impose limitations on their server. For a mirror, you should ask the site maintainer you are syncing from about their policy, and maybe an exception for your host (since you are a mirror). ==== A command line to mirror FreeBSD might look like: [source,shell] .... % rsync -vaHz --delete rsync://ftp4.de.FreeBSD.org/FreeBSD/ /pub/FreeBSD/ .... Consult the documentation for rsync, which is also available at http://rsync.samba.org/[http://rsync.samba.org/], about the various options to be used with rsync. If you sync the whole module (unlike subdirectories), be aware that the module-directory (here "FreeBSD") will not be created, so you cannot omit the target directory. Also you might want to set up a script framework that calls such a command via man:cron[8]. [[mirror-www]] === Mirroring the WWW Pages [WARNING] ==== Since doc migration to Hugo/Asciidoctor on 2021-01-25, mirroring the website with rsync no longer works. ==== There are ongoing studies to implement a website mirror with the extref:{handbook}mirrors/[official infrastructure]. For the former website mirrors, a way to achieve mirroring the website today is building the website locally with the corresponding address it will be hosted. [source,shell] .... % cd website && env HUGO_baseURL="https://www.XX.freebsd.org/" make .... Check for more details about the build tools on extref:{fdp-primer}overview/[FreeBSD Documentation Project Primer for New Contributors, overview-quick-start] book. //// [source,shell] .... % rsync -vaHz --delete rsync://bit0.us-west.freebsd.org/FreeBSD-www-data/ /usr/local/www/ .... //// [NOTE] ==== Notice the website was split into www.FreeBSD.org and docs.FreeBSD.org, and there are links between them; plus, at this moment, `HUGO_baseURL` variable won't cover all links, this way, mirroring the website is discouraged. ==== [[mirror-pkgs]] === Mirroring Packages Due to very high requirements of bandwidth, storage and administration the FreeBSD Project has decided not to allow public mirrors of packages. For sites with lots of machines, it might be advantagous to run a caching HTTP proxy for the man:pkg[8] process. Alternatively specific packages and their dependencies can be fetched by running something like the following: [source,shell] .... % pkg fetch -d -o /usr/local/mirror vim .... Once those packages have been fetched, the repository metadata must be generated by running: [source,shell] .... % pkg repo /usr/local/mirror .... Once the packages have been fetched and the metadata for the repository has been generated, serve the packages up to the client machines via HTTP. For additional information see the man pages for man:pkg[8], specifically the man:pkg-repo[8] page. [[mirror-how-often]] === How Often Should I Mirror? Every mirror should be updated at a minimum of once per day. Certainly a script with locking to prevent multiple runs happening at the same time will be needed to run from man:cron[8]. Since nearly every admin does this in their own way, specific instructions cannot be provided. It could work something like this: [.procedure] ==== . Put the command to run your mirroring application in a script. Use of a plain `/bin/sh` script is recommended. . Add some output redirections so diagnostic messages are logged to a file. . Test if your script works. Check the logs. . Use man:crontab[1] to add the script to the appropriate user's man:crontab[5]. This should be a different user than what your FTP daemon runs as so that if file permissions inside your FTP area are not world-readable those files cannot be accessed by anonymous FTP. This is used to "stage" releases - making sure all of the official mirror sites have all of the necessary release files on release day. ==== Here are some recommended schedules: * FTP fileset: daily * WWW pages: daily [[mirror-where]] == Where to Mirror From This is an important issue. So this section will spend some effort to explain the backgrounds. We will say this several times: under no circumstances should you mirror from `ftp.FreeBSD.org`. [[mirror-where-organization]] === A few Words About the Organization Mirrors are organized by country. All official mirrors have a DNS entry of the form `ftpN.CC.FreeBSD.org`. _CC_ (i.e., country code) is the _top level domain_ (TLD) of the country where this mirror is located. _N_ is a number, telling that the host would be the _Nth_ mirror in that country. (Same applies to `wwwN.CC.FreeBSD.org`, etc.) There are mirrors with no _CC_ part. These are the mirror sites that are very well connected and allow a large number of concurrent users. `ftp.FreeBSD.org` is actually two machines, one currently located in Denmark and the other in the United States. It is _NOT_ a master site and should never be used to mirror from. Lots of online documentation leads "interactive"users to `ftp.FreeBSD.org` so automated mirroring systems should find a different machine to mirror from. Additionally there exists a hierarchy of mirrors, which is described in terms of __tiers__. The master sites are not referred to but can be described as __Tier-0__. Mirrors that mirror from these sites can be considered __Tier-1__, mirrors of __Tier-1__-mirrors, are __Tier-2__, etc. Official sites are encouraged to be of a low __tier__, but the lower the tier the higher the requirements in terms as described in -crossref:hubs[mirror-requirements]. +crossref:hubs[mirror-requirements, Requirements for FreeBSD Mirrors]. Also access to low-tier-mirrors may be restricted, and access to master sites is definitely restricted. The __tier__-hierarchy is not reflected by DNS and generally not documented anywhere except for the master sites. However, official mirrors with low numbers like 1-4, are usually _Tier-1_ (this is just a rough hint, and there is no rule). [[mirror-where-where]] === Ok, but Where Should I get the Stuff Now? Under no circumstances should you mirror from `ftp.FreeBSD.org`. The short answer is: from the site that is closest to you in Internet terms, or gives you the fastest access. [[mirror-where-simple]] ==== I Just Want to Mirror from Somewhere! If you have no special intentions or requirements, the statement in -crossref:hubs[mirror-where-where] applies. +crossref:hubs[mirror-where-where, Ok, but Where Should I get the Stuff Now?] applies. This means: [.procedure] ==== . Check for those which provide fastest access (number of hops, round-trip-times) and offer the services you intend to use (like rsync). . Contact the administrators of your chosen site stating your request, and asking about their terms and policies. . Set up your mirror as described above. ==== [[mirror-where-official]] ==== I am an Official Mirror, What is the Right Site for Me? -In general the description in crossref:hubs[mirror-where-simple] still applies. +In general the description in crossref:hubs[mirror-where-simple, I Just Want to Mirror from Somewhere!] still applies. Of course you may want to put some weight on the fact that your upstream should be of a low tier. There are some other considerations about _official_ mirrors that are described -in crossref:hubs[mirror-official]. +in crossref:hubs[mirror-official, Official Mirrors]. [[mirror-where-master]] ==== I Want to Access the Master Sites! If you have good reasons and good prerequisites, you may want and get access to one of the master sites. Access to these sites is generally restricted, and there are special policies for access. If you are already an _official_ mirror, this certainly helps you getting access. In any other case make sure your country really needs another mirror. If it already has three or more, ask the "zone administrator" (mailto:hostmaster@CC.FreeBSD.org[hostmaster@CC.FreeBSD.org]) or {freebsd-hubs} first. Whoever helped you become, an _official_ should have helped you gain access to an appropriate upstream host, either one of the master sites or a suitable Tier-1 site. If not, you can send email to mailto:mirror-admin@FreeBSD.org[mirror-admin@FreeBSD.org] to request help with that. There is one master site for the FTP fileset. [[mirror-where-master-ftp]] ===== ftp-master.FreeBSD.org This is the master site for the FTP fileset. `ftp-master.FreeBSD.org` provides rsync access, in addition to FTP. -Refer to crossref:hubs[mirror-ftp-rsync]. +Refer to crossref:hubs[mirror-ftp-rsync, Mirroring the FTP Site]. Mirrors are also encouraged to allow rsync access for the FTP contents, since they are __Tier-1__-mirrors. [[mirror-official]] == Official Mirrors Official mirrors are mirrors that * a) have a `FreeBSD.org` DNS entry (usually a CNAME). * b) are listed as an official mirror in the FreeBSD documentation (like handbook). So far to distinguish official mirrors. Official mirrors are not necessarily __Tier-1__-mirrors. However you probably will not find a __Tier-1__-mirror, that is not also official. [[mirror-official-requirements]] === Special Requirements for Official (tier-1) Mirrors It is not so easy to state requirements for all official mirrors, since the project is sort of tolerant here. It is more easy to say, what _official tier-1 mirrors_ are required to. All other official mirrors can consider this a big __should__. Tier-1 mirrors are required to: * carry the complete fileset * allow access to other mirror sites * provide FTP and rsync access Furthermore, admins should be subscribed to the {freebsd-hubs}. See extref:{handbook}[this link, eresources-mail] for details, how to subscribe. [IMPORTANT] ==== It is _very_ important for a hub administrator, especially Tier-1 hub admins, to check the https://www.FreeBSD.org/releng/[release schedule] for the next FreeBSD release. This is important because it will tell you when the next release is scheduled to come out, and thus giving you time to prepare for the big spike of traffic which follows it. It is also important that hub administrators try to keep their mirrors as up-to-date as possible (again, even more crucial for Tier-1 mirrors). If Mirror1 does not update for a while, lower tier mirrors will begin to mirror old data from Mirror1 and thus begins a downward spiral... Keep your mirrors up to date! ==== [[mirror-official-become]] === How to Become Official Then? Please contact the Cluster Administrators as documented at https://www.FreeBSD.org/administration/#t-clusteradm. [[mirror-statpages]] == Some Statistics from Mirror Sites Here are links to the stat pages of your favorite mirrors (aka the only ones who feel like providing stats). [[mirror-statpagesftp]] === FTP Site Statistics * ftp.is.FreeBSD.org - mailto:hostmaster@is.FreeBSD.org[hostmaster@is.FreeBSD.org] - http://www.rhnet.is/status/draupnir/draupnir.html[ (Bandwidth)] http://www.rhnet.is/status/ftp/ftp-notendur.html[(FTP processes)] http://www.rhnet.is/status/ftp/http-notendur.html[(HTTP processes)] * ftp2.ru.FreeBSD.org - mailto:mirror@macomnet.ru[mirror@macomnet.ru] - http://mirror.macomnet.net/mrtg/mirror.macomnet.net_195.128.64.25.html[(Bandwidth)] http://mirror.macomnet.net/mrtg/mirror.macomnet.net_proc.html[(HTTP and FTP users)] diff --git a/documentation/content/en/articles/ipsec-must/_index.adoc b/documentation/content/en/articles/ipsec-must/_index.adoc index 025d16ca7f..361b6c007c 100644 --- a/documentation/content/en/articles/ipsec-must/_index.adoc +++ b/documentation/content/en/articles/ipsec-must/_index.adoc @@ -1,295 +1,295 @@ --- title: Independent Verification of IPsec Functionality in FreeBSD authors: - author: David Honig email: honig@sprynet.com description: Independent Verification of IPsec Functionality in FreeBSD trademarks: ["freebsd", "opengroup", "general"] tags: ["IPsec", "verification", "FreeBSD"] --- = Independent Verification of IPsec Functionality in FreeBSD :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/ipsec-must/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract You installed IPsec and it seems to be working. How do you know? I describe a method for experimentally verifying that IPsec is working. ''' toc::[] [[problem]] == The Problem -First, lets assume you have crossref::ipsec-must[ipsec-install]. -How do you know it is crossref::ipsec-must[caveat]? Sure, your connection will not work if it is misconfigured, and it will work when you finally get it right. +First, lets assume you have crossref::ipsec-must[ipsec-install, Installing IPsec]. +How do you know it is crossref::ipsec-must[caveat, Caveat]? Sure, your connection will not work if it is misconfigured, and it will work when you finally get it right. man:netstat[1] will list it. But can you independently confirm it? [[solution]] == The Solution First, some crypto-relevant info theory: . Encrypted data is uniformly distributed, i.e., has maximal entropy per symbol; . Raw, uncompressed data is typically redundant, i.e., has sub-maximal entropy. Suppose you could measure the entropy of the data to- and from- your network interface. Then you could see the difference between unencrypted data and encrypted data. This would be true even if some of the data in "encrypted mode" was not encrypted---as the outermost IP header must be if the packet is to be routable. [[MUST]] === MUST Ueli Maurer's "Universal Statistical Test for Random Bit Generators"(https://web.archive.org/web/20011115002319/http://www.geocities.com/SiliconValley/Code/4704/universal.pdf[MUST]) quickly measures the entropy of a sample. It uses a compression-like algorithm. -crossref::ipsec-must[code] for a variant which measures successive (~quarter megabyte) chunks of a file. +crossref::ipsec-must[code, Maurer's Universal Statistical Test (for block size8 bits)] for a variant which measures successive (~quarter megabyte) chunks of a file. [[tcpdump]] === Tcpdump We also need a way to capture the raw network data. A program called man:tcpdump[1] lets you do this, if you have enabled the _Berkeley Packet Filter_ interface in your crossref::ipsec-must[kernel]. The command: [source,shell] .... tcpdump -c 4000 -s 10000 -w dumpfile.bin .... will capture 4000 raw packets to _dumpfile.bin_. Up to 10,000 bytes per packet will be captured in this example. [[experiment]] == The Experiment Here is the experiment: [.procedure] ==== . Open a window to an IPsec host and another window to an insecure host. -. Now start crossref::ipsec-must[tcpdump]. +. Now start crossref::ipsec-must[tcpdump, Tcpdump]. . In the "secure" window, run the UNIX(R) command man:yes[1], which will stream the `y` character. After a while, stop this. Switch to the insecure window, and repeat. After a while, stop. -. Now run crossref::ipsec-must[code] on the captured packets. You should see something like the following. The important thing to note is that the secure connection has 93% (6.7) of the expected value (7.18), and the "normal" connection has 29% (2.1) of the expected value. +. Now run crossref::ipsec-must[code, Maurer's Universal Statistical Test (for block size8 bits)] on the captured packets. You should see something like the following. The important thing to note is that the secure connection has 93% (6.7) of the expected value (7.18), and the "normal" connection has 29% (2.1) of the expected value. + [source,shell] .... % tcpdump -c 4000 -s 10000 -w ipsecdemo.bin % uliscan ipsecdemo.bin Uliscan 21 Dec 98 L=8 256 258560 Measuring file ipsecdemo.bin Init done Expected value for L=8 is 7.1836656 6.9396 -------------------------------------------------------- 6.6177 ----------------------------------------------------- 6.4100 --------------------------------------------------- 2.1101 ----------------- 2.0838 ----------------- 2.0983 ----------------- .... ==== [[caveat]] == Caveat This experiment shows that IPsec _does_ seem to be distributing the payload data __uniformly__, as encryption should. However, the experiment described here _cannot_ detect many possible flaws in a system (none of which do I have any evidence for). These include poor key generation or exchange, data or keys being visible to others, use of weak algorithms, kernel subversion, etc. Study the source; know the code. [[IPsec]] == IPsec---Definition Internet Protocol security extensions to IPv4; required for IPv6. A protocol for negotiating encryption and authentication at the IP (host-to-host) level. SSL secures only one application socket; SSH secures only a login; PGP secures only a specified file or message. IPsec encrypts everything between two hosts. [[ipsec-install]] == Installing IPsec Most of the modern versions of FreeBSD have IPsec support in their base source. So you will need to include the `IPSEC` option in your kernel config and, after kernel rebuild and reinstall, configure IPsec connections using man:setkey[8] command. A comprehensive guide on running IPsec on FreeBSD is provided in extref:{handbook}[FreeBSD Handbook, ipsec]. [[kernel]] == src/sys/i386/conf/KERNELNAME This needs to be present in the kernel config file to capture network data with man:tcpdump[1]. Be sure to run man:config[8] after adding this, and rebuild and reinstall. [.programlisting] .... device bpf .... [[code]] == Maurer's Universal Statistical Test (for block size=8 bits) You can find the same code at https://web.archive.org/web/20031204230654/http://www.geocities.com:80/SiliconValley/Code/4704/uliscanc.txt[this link]. [.programlisting] .... /* ULISCAN.c ---blocksize of 8 1 Oct 98 1 Dec 98 21 Dec 98 uliscan.c derived from ueli8.c This version has // comments removed for Sun cc This implements Ueli M Maurer's "Universal Statistical Test for Random Bit Generators" using L=8 Accepts a filename on the command line; writes its results, with other info, to stdout. Handles input file exhaustion gracefully. Ref: J. Cryptology v 5 no 2, 1992 pp 89-105 also on the web somewhere, which is where I found it. -David Honig honig@sprynet.com Usage: ULISCAN filename outputs to stdout */ #define L 8 #define V (1< #include int main(argc, argv) int argc; char **argv; { FILE *fptr; int i,j; int b, c; int table[V]; double sum = 0.0; int iproduct = 1; int run; extern double log(/* double x */); printf("Uliscan 21 Dec 98 \nL=%d %d %d \n", L, V, MAXSAMP); if (argc < 2) { printf("Usage: Uliscan filename\n"); exit(-1); } else { printf("Measuring file %s\n", argv[1]); } fptr = fopen(argv[1],"rb"); if (fptr == NULL) { printf("Can't find %s\n", argv[1]); exit(-1); } for (i = 0; i < V; i++) { table[i] = 0; } for (i = 0; i < Q; i++) { b = fgetc(fptr); table[b] = i; } printf("Init done\n"); printf("Expected value for L=8 is 7.1836656\n"); run = 1; while (run) { sum = 0.0; iproduct = 1; if (run) for (i = Q; run && i < Q + K; i++) { j = i; b = fgetc(fptr); if (b < 0) run = 0; if (run) { if (table[b] > j) j += K; sum += log((double)(j-table[b])); table[b] = i; } } if (!run) printf("Premature end of file; read %d blocks.\n", i - Q); sum = (sum/((double)(i - Q))) / log(2.0); printf("%4.4f ", sum); for (i = 0; i < (int)(sum*8.0 + 0.50); i++) printf("-"); printf("\n"); /* refill initial table */ if (0) { for (i = 0; i < Q; i++) { b = fgetc(fptr); if (b < 0) { run = 0; } else { table[b] = i; } } } } } .... diff --git a/documentation/content/en/articles/ldap-auth/_index.adoc b/documentation/content/en/articles/ldap-auth/_index.adoc index 37e46cb731..edffbd10ea 100644 --- a/documentation/content/en/articles/ldap-auth/_index.adoc +++ b/documentation/content/en/articles/ldap-auth/_index.adoc @@ -1,804 +1,804 @@ --- title: LDAP Authentication authors: - author: Toby Burress email: kurin@causa-sui.net copyright: 2007-2008 The FreeBSD Documentation Project description: Guide for the configuration of an LDAP server for authentication on FreeBSD trademarks: ["freebsd", "general"] tags: ["LDAP", "Authentication", "OpenLDAP", "configuration", "guide", "tutorial", "FreeBSD"] --- = LDAP Authentication :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/ldap-auth/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract This document is intended as a guide for the configuration of an LDAP server (principally an OpenLDAP server) for authentication on FreeBSD. This is useful for situations where many servers need the same user accounts, for example as a replacement for NIS. ''' toc::[] [[preface]] == Preface This document is intended to give the reader enough of an understanding of LDAP to configure an LDAP server. This document will attempt to provide an explanation of package:net/nss_ldap[] and package:security/pam_ldap[] for use with client machines services for use with the LDAP server. When finished, the reader should be able to configure and deploy a FreeBSD server that can host an LDAP directory, and to configure and deploy a FreeBSD server which can authenticate against an LDAP directory. This article is not intended to be an exhaustive account of the security, robustness, or best practice considerations for configuring LDAP or the other services discussed herein. While the author takes care to do everything correctly, they do not address security issues beyond a general scope. This article should be considered to lay the theoretical groundwork only, and any actual implementation should be accompanied by careful requirement analysis. [[ldap]] == Configuring LDAP LDAP stands for "Lightweight Directory Access Protocol" and is a subset of the X.500 Directory Access Protocol. Its most recent specifications are in http://www.ietf.org/rfc/rfc4510.txt[RFC4510] and friends. Essentially it is a database that expects to be read from more often than it is written to. The LDAP server http://www.openldap.org/[OpenLDAP] will be used in the examples in this document; while the principles here should be generally applicable to many different servers, most of the concrete administration is OpenLDAP-specific. There are several server versions in ports, for example package:net/openldap26-server[]. Client servers will need the corresponding package:net/openldap26-client[] libraries. There are (basically) two areas of the LDAP service which need configuration. The first is setting up a server to receive connections properly, and the second is adding entries to the server's directory so that FreeBSD tools know how to interact with it. [[ldap-connect]] === Setting Up the Server for Connections [NOTE] ==== This section is specific to OpenLDAP. If you are using another server, you will need to consult that server's documentation. ==== [[ldap-connect-install]] ==== Installing OpenLDAP First, install OpenLDAP: [[oldap-install]] .Installing OpenLDAP [example] ==== [source,shell] .... # cd /usr/ports/net/openldap26-server # make install clean .... ==== This installs the `slapd` and `slurpd` binaries, along with the required OpenLDAP libraries. [[ldap-connect-config]] ==== Configuring OpenLDAP Next we must configure OpenLDAP. You will want to require encryption in your connections to the LDAP server; otherwise your users' passwords will be transferred in plain text, which is considered insecure. The tools we will be using support two very similar kinds of encryption, SSL and TLS. TLS stands for "Transportation Layer Security". Services that employ TLS tend to connect on the _same_ ports as the same services without TLS; thus an SMTP server which supports TLS will listen for connections on port 25, and an LDAP server will listen on 389. SSL stands for "Secure Sockets Layer", and services that implement SSL do _not_ listen on the same ports as their non-SSL counterparts. Thus SMTPS listens on port 465 (not 25), HTTPS listens on 443, and LDAPS on 636. The reason SSL uses a different port than TLS is because a TLS connection begins as plain text, and switches to encrypted traffic after the `STARTTLS` directive. SSL connections are encrypted from the beginning. Other than that there are no substantial differences between the two. [NOTE] ==== We will adjust OpenLDAP to use TLS, as SSL is considered deprecated. ==== Once OpenLDAP is installed via ports, the following configuration parameters in [.filename]#/usr/local/etc/openldap/slapd.conf# will enable TLS: [.programlisting] .... security ssf=128 TLSCertificateFile /path/to/your/cert.crt TLSCertificateKeyFile /path/to/your/cert.key TLSCACertificateFile /path/to/your/cacert.crt .... Here, `ssf=128` tells OpenLDAP to require 128-bit encryption for all connections, both search and update. This parameter may be configured based on the security needs of your site, but rarely you need to weaken it, as most LDAP client libraries support strong encryption. The [.filename]#cert.crt#, [.filename]#cert.key#, and [.filename]#cacert.crt# files are necessary for clients to authenticate _you_ as the valid LDAP server. If you simply want a server that runs, you can create a self-signed certificate with OpenSSL: [[genrsa]] .Generating an RSA Key [example] ==== [source,shell] .... % openssl genrsa -out cert.key 1024 Generating RSA private key, 1024 bit long modulus ....................++++++ ...++++++ e is 65537 (0x10001) % openssl req -new -key cert.key -out cert.csr .... ==== At this point you should be prompted for some values. You may enter whatever values you like; however, it is important the "Common Name" value be the fully qualified domain name of the OpenLDAP server. In our case, and the examples here, the server is _server.example.org_. Incorrectly setting this value will cause clients to fail when making connections. This can the cause of great frustration, so ensure that you follow these steps closely. Finally, the certificate signing request needs to be signed: [[self-sign]] .Self-signing the Certificate [example] ==== [source,shell] .... % openssl x509 -req -in cert.csr -days 365 -signkey cert.key -out cert.crt Signature ok subject=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd Getting Private key .... ==== This will create a self-signed certificate that can be used for the directives in [.filename]#slapd.conf#, where [.filename]#cert.crt# and [.filename]#cacert.crt# are the same file. If you are going to use many OpenLDAP servers (for replication via `slurpd`) you -will want to see crossref:ldap-auth[ssl-ca] to generate a CA key and use it to sign individual server certificates. +will want to see crossref:ldap-auth[ssl-ca, OpenSSL Certificates for LDAP] to generate a CA key and use it to sign individual server certificates. Once this is done, put the following in [.filename]#/etc/rc.conf#: [.programlisting] .... slapd_enable="YES" .... Then run `/usr/local/etc/rc.d/slapd start`. This should start OpenLDAP. Confirm that it is listening on 389 with [source,shell] .... % sockstat -4 -p 389 ldap slapd 3261 7 tcp4 *:389 *:* .... [[ldap-connect-client]] ==== Configuring the Client Install the package:net/openldap26-client[] port for the OpenLDAP libraries. The client machines will always have OpenLDAP libraries since that is all package:security/pam_ldap[] and package:net/nss_ldap[] support, at least for the moment. The configuration file for the OpenLDAP libraries is [.filename]#/usr/local/etc/openldap/ldap.conf#. Edit this file to contain the following values: [.programlisting] .... base dc=example,dc=org uri ldap://server.example.org/ ssl start_tls tls_cacert /path/to/your/cacert.crt .... [NOTE] ==== It is important that your clients have access to [.filename]#cacert.crt#, otherwise they will not be able to connect. ==== [NOTE] ==== There are two files called [.filename]#ldap.conf#. The first is this file, which is for the OpenLDAP libraries and defines how to talk to the server. The second is [.filename]#/usr/local/etc/ldap.conf#, and is for pam_ldap. ==== At this point you should be able to run `ldapsearch -Z` on the client machine; `-Z` means "use TLS". If you encounter an error, then something is configured wrong; most likely it is your certificates. Use man:openssl[1]'s `s_client` and `s_server` to ensure you have them configured and signed properly. [[ldap-database]] === Entries in the Database Authentication against an LDAP directory is generally accomplished by attempting to bind to the directory as the connecting user. This is done by establishing a "simple" bind on the directory with the user name supplied. If there is an entry with the `uid` equal to the user name and that entry's `userPassword` attribute matches the password supplied, then the bind is successful. The first thing we have to do is figure out is where in the directory our users will live. The base entry for our database is `dc=example,dc=org`. The default location for users that most clients seem to expect is something like `ou=people,_base_`, so that is what will be used here. However keep in mind that this is configurable. So the ldif entry for the `people` organizational unit will look like: [.programlisting] .... dn: ou=people,dc=example,dc=org objectClass: top objectClass: organizationalUnit ou: people .... All users will be created as subentries of this organizational unit. Some thought might be given to the object class your users will belong to. Most tools by default will use `people`, which is fine if you simply want to provide entries against which to authenticate. However, if you are going to store user information in the LDAP database as well, you will probably want to use `inetOrgPerson`, which has many useful attributes. In either case, the relevant schemas need to be loaded in [.filename]#slapd.conf#. For this example we will use the `person` object class. If you are using `inetOrgPerson`, the steps are basically identical, except that the `sn` attribute is required. To add a test-user named `tuser`, the ldif would be: [.programlisting] .... dn: uid=tuser,ou=people,dc=example,dc=org objectClass: person objectClass: posixAccount objectClass: shadowAccount objectClass: top uidNumber: 10000 gidNumber: 10000 homeDirectory: /home/tuser loginShell: /bin/csh uid: tuser cn: tuser .... I start my LDAP users' UIDs at 10000 to avoid collisions with system accounts; you can configure whatever number you wish here, as long as it is less than 65536. We also need group entries. They are as configurable as user entries, but we will use the defaults below: [.programlisting] .... dn: ou=groups,dc=example,dc=org objectClass: top objectClass: organizationalUnit ou: groups dn: cn=tuser,ou=groups,dc=example,dc=org objectClass: posixGroup objectClass: top gidNumber: 10000 cn: tuser .... To enter these into your database, you can use `slapadd` or `ldapadd` on a file containing these entries. Alternatively, you can use package:sysutils/ldapvi[]. The `ldapsearch` utility on the client machine should now return these entries. If it does, your database is properly configured to be used as an LDAP authentication server. [[client]] == Client Configuration The client should already have OpenLDAP libraries from crossref:ldap-auth[ldap-connect-client], but if you are installing several client machines you will need to install package:net/openldap26-client[] on each of them. FreeBSD requires two ports to be installed to authenticate against an LDAP server, package:security/pam_ldap[] and package:net/nss_ldap[]. [[client-auth]] === Authentication package:security/pam_ldap[] is configured via [.filename]#/usr/local/etc/ldap.conf#. [NOTE] ==== This is a _different file_ than the OpenLDAP library functions' configuration file, [.filename]#/usr/local/etc/openldap/ldap.conf#; however, it takes many of the same options; in fact it is a superset of that file. For the rest of this section, references to [.filename]#ldap.conf# will mean [.filename]#/usr/local/etc/ldap.conf#. ==== Thus, we will want to copy all of our original configuration parameters from [.filename]#openldap/ldap.conf# to the new [.filename]#ldap.conf#. Once this is done, we want to tell package:security/pam_ldap[] what to look for on the directory server. We are identifying our users with the `uid` attribute. To configure this (though it is the default), set the `pam_login_attribute` directive in [.filename]#ldap.conf#: [[set-pam-login-attr]] .Setting `pam_login_attribute` [example] ==== [.programlisting] .... pam_login_attribute uid .... ==== With this set, package:security/pam_ldap[] will search the entire LDAP directory under `base` for the value `uid=_username_`. If it finds one and only one entry, it will attempt to bind as that user with the password it was given. If it binds correctly, then it will allow access. Otherwise it will fail. Users whose shell is not in [.filename]#/etc/shells# will not be able to log in. This is particularly important when Bash is set as the user shell on the LDAP server. Bash is not included with a default installation of FreeBSD. When installed from a package or port, it is located at [.filename]#/usr/local/bin/bash#. Verify that the path to the shell on the server is set correctly: [source,shell] .... % getent passwd username .... There are two choices when the output shows `/bin/bash` in the last column. The first is to change the user's entry on the LDAP server to [.filename]#/usr/local/bin/bash#. The second option is to create a symlink on the LDAP client computer so Bash is found at the correct location: [source,shell] .... # ln -s /usr/local/bin/bash /bin/bash .... Make sure that [.filename]#/etc/shells# contains entries for both `/usr/local/bin/bash` and `/bin/bash`. The user will then be able to log in to the system with Bash as their shell. [[client-auth-pam]] ==== PAM PAM, which stands for "Pluggable Authentication Modules", is the method by which FreeBSD authenticates most of its sessions. To tell FreeBSD we wish to use an LDAP server, we will have to add a line to the appropriate PAM file. Most of the time the appropriate PAM file is [.filename]#/etc/pam.d/sshd#, if you want to use SSH (remember to set the relevant options in [.filename]#/etc/ssh/sshd_config#, otherwise SSH will not use PAM). To use PAM for authentication, add the line [.programlisting] .... auth sufficient /usr/local/lib/pam_ldap.so no_warn .... Exactly where this line shows up in the file and which options appear in the fourth column determine the exact behavior of the authentication mechanism; see man:pam[d] With this configuration you should be able to authenticate a user against an LDAP directory. PAM will perform a bind with your credentials, and if successful will tell SSH to allow access. However it is not a good idea to allow _every_ user in the directory into _every_ client machine. With the current configuration, all that a user needs to log into a machine is an LDAP entry. Fortunately there are a few ways to restrict user access. [.filename]#ldap.conf# supports a `pam_groupdn` directive; every account that connects to this machine needs to be a member of the group specified here. For example, if you have [.programlisting] .... pam_groupdn cn=servername,ou=accessgroups,dc=example,dc=org .... in [.filename]#ldap.conf#, then only members of that group will be able to log in. There are a few things to bear in mind, however. Members of this group are specified in one or more `memberUid` attributes, and each attribute must have the full distinguished name of the member. So `memberUid: someuser` will not work; it must be: [.programlisting] .... memberUid: uid=someuser,ou=people,dc=example,dc=org .... Additionally, this directive is not checked in PAM during authentication, it is checked during account management, so you will need a second line in your PAM files under `account`. This will require, in turn, _every_ user to be listed in the group, which is not necessarily what we want. To avoid blocking users that are not in LDAP, you should enable the `ignore_unknown_user` attribute. Finally, you should set the `ignore_authinfo_unavail` option so that you are not locked out of every computer when the LDAP server is unavailable. Your [.filename]#pam.d/sshd# might then end up looking like this: [[pam]] .Sample [.filename]#pam.d/sshd# [example] ==== [.programlisting] .... auth required pam_nologin.so no_warn auth sufficient pam_opie.so no_warn no_fake_prompts auth requisite pam_opieaccess.so no_warn allow_local auth sufficient /usr/local/lib/pam_ldap.so no_warn auth required pam_unix.so no_warn try_first_pass account required pam_login_access.so account required /usr/local/lib/pam_ldap.so no_warn ignore_authinfo_unavail ignore_unknown_user .... ==== [NOTE] ==== Since we are adding these lines specifically to [.filename]#pam.d/sshd#, this will only have an effect on SSH sessions. LDAP users will be unable to log in at the console. To change this behavior, examine the other files in [.filename]#/etc/pam.d# and modify them accordingly. ==== [[client-nss]] === Name Service Switch NSS is the service that maps attributes to names. So, for example, if a file is owned by user `1001`, an application will query NSS for the name of `1001`, and it might get `bob` or `ted` or whatever the user's name is. Now that our user information is kept in LDAP, we need to tell NSS to look there when queried. The package:net/nss_ldap[] port does this. It uses the same configuration file as package:security/pam_ldap[], and should not need any extra parameters once it is installed. Instead, what is left is simply to edit [.filename]#/etc/nsswitch.conf# to take advantage of the directory. Simply replace the following lines: [.programlisting] .... group: compat passwd: compat .... with [.programlisting] .... group: files ldap passwd: files ldap .... This will allow you to map usernames to UIDs and UIDs to usernames. Congratulations! You should now have working LDAP authentication. [[caveats]] === Caveats Unfortunately, as of the time this was written FreeBSD did not support changing user passwords with man:passwd[1]. As a result of this, most administrators are left to implement a solution themselves. I provide some examples here. Note that if you write your own password change script, there are some security -issues you should be made aware of; see crossref:ldap-auth[security-passwd] +issues you should be made aware of; see crossref:ldap-auth[security-passwd, Password Storage] [[chpw-shell]] .Shell Script for Changing Passwords [example] ==== [.programlisting] .... #!/bin/sh stty -echo read -p "Old Password: " oldp; echo read -p "New Password: " np1; echo read -p "Retype New Password: " np2; echo stty echo if [ "$np1" != "$np2" ]; then echo "Passwords do not match." exit 1 fi ldappasswd -D uid="$USER",ou=people,dc=example,dc=org \ -w "$oldp" \ -a "$oldp" \ -s "$np1" .... ==== [CAUTION] ==== This script does hardly any error checking, but more important it is very cavalier about how it stores your passwords. If you do anything like this, at least adjust the `security.bsd.see_other_uids` sysctl value: [source,shell] .... # sysctl security.bsd.see_other_uids=0 .... ==== A more flexible (and probably more secure) approach can be used by writing a custom program, or even a web interface. The following is part of a Ruby library that can change LDAP passwords. It sees use both on the command line, and on the web. [[chpw-ruby]] .Ruby Script for Changing Passwords [example] ==== [.programlisting] .... require 'ldap' require 'base64' require 'digest' require 'password' # ruby-password ldap_server = "ldap.example.org" luser = "uid=#{ENV['USER']},ou=people,dc=example,dc=org" # get the new password, check it, and create a salted hash from it def get_password pwd1 = Password.get("New Password: ") pwd2 = Password.get("Retype New Password: ") raise if pwd1 != pwd2 pwd1.check # check password strength salt = rand.to_s.gsub(/0\./, '') pass = pwd1.to_s hash = "{SSHA}"+Base64.encode64(Digest::SHA1.digest("#{pass}#{salt}")+salt).chomp! return hash end oldp = Password.get("Old Password: ") newp = get_password # We'll just replace it. That we can bind proves that we either know # the old password or are an admin. replace = LDAP::Mod.new(LDAP::LDAP_MOD_REPLACE | LDAP::LDAP_MOD_BVALUES, "userPassword", [newp]) conn = LDAP::SSLConn.new(ldap_server, 389, true) conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3) conn.bind(luser, oldp) conn.modify(luser, [replace]) .... ==== Although not guaranteed to be free of security holes (the password is kept in memory, for example) this is cleaner and more flexible than a simple `sh` script. [[secure]] == Security Considerations Now that your machines (and possibly other services) are authenticating against your LDAP server, this server needs to be protected at least as well as [.filename]#/etc/master.passwd# would be on a regular server, and possibly even more so since a broken or cracked LDAP server would break every client service. Remember, this section is not exhaustive. You should continually review your configuration and procedures for improvements. [[secure-readonly]] === Setting Attributes Read-only Several attributes in LDAP should be read-only. If left writable by the user, for example, a user could change his `uidNumber` attribute to `0` and get `root` access! To begin with, the `userPassword` attribute should not be world-readable. By default, anyone who can connect to the LDAP server can read this attribute. To disable this, put the following in [.filename]#slapd.conf#: [[hide-userpass]] .Hide Passwords [example] ==== [.programlisting] .... access to dn.subtree="ou=people,dc=example,dc=org" attrs=userPassword by self write by anonymous auth by * none access to * by self write by * read .... ==== This will disallow reading of the `userPassword` attribute, while still allowing users to change their own passwords. Additionally, you'll want to keep users from changing some of their own attributes. By default, users can change any attribute (except for those which the LDAP schemas themselves deny changes), such as `uidNumber`. To close this hole, modify the above to [[attrib-readonly]] .Read-only Attributes [example] ==== [.programlisting] .... access to dn.subtree="ou=people,dc=example,dc=org" attrs=userPassword by self write by anonymous auth by * none access to attrs=homeDirectory,uidNumber,gidNumber by * read access to * by self write by * read .... ==== This will stop users from being able to masquerade as other users. [[secure-root]] === `root` Account Definition Often the `root` or manager account for the LDAP service will be defined in the configuration file. OpenLDAP supports this, for example, and it works, but it can lead to trouble if [.filename]#slapd.conf# is compromised. It may be better to use this only to bootstrap yourself into LDAP, and then define a `root` account there. Even better is to define accounts that have limited permissions, and omit a `root` account entirely. For example, users that can add or remove user accounts are added to one group, but they cannot themselves change the membership of this group. Such a security policy would help mitigate the effects of a leaked password. [[manager-acct]] ==== Creating a Management Group Say you want your IT department to be able to change home directories for users, but you do not want all of them to be able to add or remove users. The way to do this is to add a group for these admins: [[manager-acct-dn]] .Creating a Management Group [example] ==== [.programlisting] .... dn: cn=homemanagement,dc=example,dc=org objectClass: top objectClass: posixGroup cn: homemanagement gidNumber: 121 # required for posixGroup memberUid: uid=tuser,ou=people,dc=example,dc=org memberUid: uid=user2,ou=people,dc=example,dc=org .... ==== And then change the permissions attributes in [.filename]#slapd.conf#: [[management-acct-acl]] .ACLs for a Home Directory Management Group [example] ==== [.programlisting] .... access to dn.subtree="ou=people,dc=example,dc=org" attr=homeDirectory by dn="cn=homemanagement,dc=example,dc=org" dnattr=memberUid write .... ==== Now `tuser` and `user2` can change other users' home directories. In this example we have given a subset of administrative power to certain users without giving them power in other domains. The idea is that soon no single user account has the power of a `root` account, but every power root had is had by at least one user. The `root` account then becomes unnecessary and can be removed. [[security-passwd]] === Password Storage By default OpenLDAP will store the value of the `userPassword` attribute as it stores any other data: in the clear. Most of the time it is base 64 encoded, which provides enough protection to keep an honest administrator from knowing your password, but little else. It is a good idea, then, to store passwords in a more secure format, such as SSHA (salted SHA). This is done by whatever program you use to change users' passwords. :sectnums!: [appendix] [[useful]] == Useful Aids There are a few other programs that might be useful, particularly if you have many users and do not want to configure everything manually. package:security/pam_mkhomedir[] is a PAM module that always succeeds; its purpose is to create home directories for users which do not have them. If you have dozens of client servers and hundreds of users, it is much easier to use this and set up skeleton directories than to prepare every home directory. package:sysutils/ldapvi[] is a great utility for editing LDAP values in an LDIF-like syntax. The directory (or subsection of the directory) is presented in the editor chosen by the `EDITOR` environment variable. This makes it easy to enable large-scale changes in the directory without having to write a custom tool. package:security/openssh-portable[] has the ability to contact an LDAP server to verify SSH keys. This is extremely nice if you have many servers and do not want to copy your public keys across all of them. :sectnums!: [appendix] [[ssl-ca]] == OpenSSL Certificates for LDAP If you are hosting two or more LDAP servers, you will probably not want to use self-signed certificates, since each client will have to be configured to work with each certificate. While this is possible, it is not nearly as simple as creating your own certificate authority, and signing your servers' certificates with that. The steps here are presented as they are with very little attempt at explaining what is going on-further explanation can be found in man:openssl[1] and its friends. To create a certificate authority, we simply need a self-signed certificate and key. The steps for this again are [[make-cert]] .Creating a Certificate [example] ==== [source,shell] .... % openssl genrsa -out root.key 1024 % openssl req -new -key root.key -out root.csr % openssl x509 -req -days 1024 -in root.csr -signkey root.key -out root.crt .... ==== These will be your root CA key and certificate. You will probably want to encrypt the key and store it in a cool, dry place; anyone with access to it can masquerade as one of your LDAP servers. Next, using the first two steps above create a key [.filename]#ldap-server-one.key# and certificate signing request [.filename]#ldap-server-one.csr#. Once you sign the signing request with [.filename]#root.key#, you will be able to use [.filename]#ldap-server-one.*# on your LDAP servers. [NOTE] ==== Do not forget to use the fully qualified domain name for the "common name" attribute when generating the certificate signing request; otherwise clients will reject a connection with you, and it can be very tricky to diagnose. ==== To sign the key, use `-CA` and `-CAkey` instead of `-signkey`: [[ca-sign]] .Signing as a Certificate Authority [example] ==== [source,shell] .... % openssl x509 -req -days 1024 \ -in ldap-server-one.csr -CA root.crt -CAkey root.key \ -out ldap-server-one.crt .... ==== The resulting file will be the certificate that you can use on your LDAP servers. Finally, for clients to trust all your servers, distribute [.filename]#root.crt# (the __certificate__, not the key!) to each client, and specify it in the `TLSCACertificateFile` directive in [.filename]#ldap.conf#. diff --git a/documentation/content/en/articles/pam/_index.adoc b/documentation/content/en/articles/pam/_index.adoc index 23dbb861c4..307690be04 100644 --- a/documentation/content/en/articles/pam/_index.adoc +++ b/documentation/content/en/articles/pam/_index.adoc @@ -1,686 +1,686 @@ --- title: Pluggable Authentication Modules authors: - author: Dag-Erling Smørgrav copyright: 2001-2003 Networks Associates Technology, Inc. description: A guide to the PAM system and modules under FreeBSD trademarks: ["pam", "freebsd", "linux", "opengroup", "sun", "general"] tags: ["pam", "introduction", "authentication", "modules", "FreeBSD"] --- //// Copyright (c) 2001-2003 Networks Associates Technology, Inc. All rights reserved. This software was developed for the FreeBSD Project by ThinkSec AS and Network Associates Laboratories, the Security Research Division of Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research program. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED 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. //// = Pluggable Authentication Modules :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/pam/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} :include-path: static/source/articles/pam/ endif::[] ifdef::backend-pdf,backend-epub3[] :include-path: ../../../../static/source/articles/pam/ include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] :include-path: ../../../../static/source/articles/pam/ include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract This article describes the underlying principles and mechanisms of the Pluggable Authentication Modules (PAM) library, and explains how to configure PAM, how to integrate PAM into applications, and how to write PAM modules. ''' toc::[] [[pam-intro]] == Introduction The Pluggable Authentication Modules (PAM) library is a generalized API for authentication-related services which allows a system administrator to add new authentication methods simply by installing new PAM modules, and to modify authentication policies by editing configuration files. PAM was defined and developed in 1995 by Vipin Samar and Charlie Lai of Sun Microsystems, and has not changed much since. In 1997, the Open Group published the X/Open Single Sign-on (XSSO) preliminary specification, which standardized the PAM API and added extensions for single (or rather integrated) sign-on. At the time of this writing, this specification has not yet been adopted as a standard. Although this article focuses primarily on FreeBSD 5.x, which uses OpenPAM, it should be equally applicable to FreeBSD 4.x, which uses Linux-PAM, and other operating systems such as Linux and Solaris(TM). [[pam-terms]] == Terms and Conventions [[pam-definitions]] === Definitions The terminology surrounding PAM is rather confused. Neither Samar and Lai's original paper nor the XSSO specification made any attempt at formally defining terms for the various actors and entities involved in PAM, and the terms that they do use (but do not define) are sometimes misleading and ambiguous. The first attempt at establishing a consistent and unambiguous terminology was a whitepaper written by Andrew G. Morgan (author of Linux-PAM) in 1999. While Morgan's choice of terminology was a huge leap forward, it is in this author's opinion by no means perfect. What follows is an attempt, heavily inspired by Morgan, to define precise and unambiguous terms for all actors and entities involved in PAM. account:: The set of credentials the applicant is requesting from the arbitrator. applicant:: The user or entity requesting authentication. arbitrator:: The user or entity who has the privileges necessary to verify the applicant's credentials and the authority to grant or deny the request. chain:: A sequence of modules that will be invoked in response to a PAM request. The chain includes information about the order in which to invoke the modules, what arguments to pass to them, and how to interpret the results. client:: The application responsible for initiating an authentication request on behalf of the applicant and for obtaining the necessary authentication information from him. facility:: One of the four basic groups of functionality provided by PAM: authentication, account management, session management and authentication token update. module:: A collection of one or more related functions implementing a particular authentication facility, gathered into a single (normally dynamically loadable) binary file and identified by a single name. policy:: The complete set of configuration statements describing how to handle PAM requests for a particular service. A policy normally consists of four chains, one for each facility, though some services do not use all four facilities. server:: The application acting on behalf of the arbitrator to converse with the client, retrieve authentication information, verify the applicant's credentials and grant or deny requests. service:: A class of servers providing similar or related functionality and requiring similar authentication. PAM policies are defined on a per-service basis, so all servers that claim the same service name will be subject to the same policy. session:: The context within which service is rendered to the applicant by the server. One of PAM's four facilities, session management, is concerned exclusively with setting up and tearing down this context. token:: A chunk of information associated with the account, such as a password or passphrase, which the applicant must provide to prove his identity. transaction:: A sequence of requests from the same applicant to the same instance of the same server, beginning with authentication and session set-up and ending with session tear-down. [[pam-usage-examples]] === Usage Examples This section aims to illustrate the meanings of some of the terms defined above by way of a handful of simple examples. ==== Client and Server Are One This simple example shows `alice` man:su[1]'ing to `root`. [source,shell] .... % whoami alice % ls -l `which su` -r-sr-xr-x 1 root wheel 10744 Dec 6 19:06 /usr/bin/su % su - Password: xi3kiune # whoami root .... * The applicant is `alice`. * The account is `root`. * The man:su[1] process is both client and server. * The authentication token is `xi3kiune`. * The arbitrator is `root`, which is why man:su[1] is setuid `root`. ==== Client and Server Are Separate The example below shows `eve` try to initiate an man:ssh[1] connection to `login.example.com`, ask to log in as `bob`, and succeed. Bob should have chosen a better password! [source,shell] .... % whoami eve % ssh bob@login.example.com bob@login.example.com's password: % god Last login: Thu Oct 11 09:52:57 2001 from 192.168.0.1 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD 4.4-STABLE (LOGIN) 4: Tue Nov 27 18:10:34 PST 2001 Welcome to FreeBSD! % .... * The applicant is `eve`. * The client is Eve's man:ssh[1] process. * The server is the man:sshd[8] process on `login.example.com` * The account is `bob`. * The authentication token is `god`. * Although this is not shown in this example, the arbitrator is `root`. ==== Sample Policy The following is FreeBSD's default policy for `sshd`: [.programlisting] .... sshd auth required pam_nologin.so no_warn sshd auth required pam_unix.so no_warn try_first_pass sshd account required pam_login_access.so sshd account required pam_unix.so sshd session required pam_lastlog.so no_fail sshd password required pam_permit.so .... * This policy applies to the `sshd` service (which is not necessarily restricted to the man:sshd[8] server.) * `auth`, `account`, `session` and `password` are facilities. * [.filename]#pam_nologin.so#, [.filename]#pam_unix.so#, [.filename]#pam_login_access.so#, [.filename]#pam_lastlog.so# and [.filename]#pam_permit.so# are modules. It is clear from this example that [.filename]#pam_unix.so# provides at least two facilities (authentication and account management.) [[pam-essentials]] == PAM Essentials [[pam-facilities-primitives]] === Facilities and Primitives The PAM API offers six different authentication primitives grouped in four facilities, which are described below. `auth`:: _Authentication._ This facility concerns itself with authenticating the applicant and establishing the account credentials. It provides two primitives: ** man:pam_authenticate[3] authenticates the applicant, usually by requesting an authentication token and comparing it with a value stored in a database or obtained from an authentication server. ** man:pam_setcred[3] establishes account credentials such as user ID, group membership and resource limits. `account`:: _Account management._ This facility handles non-authentication-related issues of account availability, such as access restrictions based on the time of day or the server's work load. It provides a single primitive: ** man:pam_acct_mgmt[3] verifies that the requested account is available. `session`:: _Session management._ This facility handles tasks associated with session set-up and tear-down, such as login accounting. It provides two primitives: ** man:pam_open_session[3] performs tasks associated with session set-up: add an entry in the [.filename]#utmp# and [.filename]#wtmp# databases, start an SSH agent, etc. ** man:pam_close_session[3] performs tasks associated with session tear-down: add an entry in the [.filename]#utmp# and [.filename]#wtmp# databases, stop the SSH agent, etc. `password`:: _Password management._ This facility is used to change the authentication token associated with an account, either because it has expired or because the user wishes to change it. It provides a single primitive: ** man:pam_chauthtok[3] changes the authentication token, optionally verifying that it is sufficiently hard to guess, has not been used previously, etc. [[pam-modules]] === Modules Modules are a very central concept in PAM; after all, they are the "M" in "PAM". A PAM module is a self-contained piece of program code that implements the primitives in one or more facilities for one particular mechanism; possible mechanisms for the authentication facility, for instance, include the UNIX(R) password database, NIS, LDAP and Radius. [[pam-module-naming]] ==== Module Naming FreeBSD implements each mechanism in a single module, named `pam_mechanism.so` (for instance, `pam_unix.so` for the UNIX(R) mechanism.) Other implementations sometimes have separate modules for separate facilities, and include the facility name as well as the mechanism name in the module name. To name one example, Solaris(TM) has a `pam_dial_auth.so.1` module which is commonly used to authenticate dialup users. [[pam-module-versioning]] ==== Module Versioning FreeBSD's original PAM implementation, based on Linux-PAM, did not use version numbers for PAM modules. This would commonly cause problems with legacy applications, which might be linked against older versions of the system libraries, as there was no way to load a matching version of the required modules. OpenPAM, on the other hand, looks for modules that have the same version number as the PAM library (currently 2), and only falls back to an unversioned module if no versioned module could be loaded. Thus legacy modules can be provided for legacy applications, while allowing new (or newly built) applications to take advantage of the most recent modules. Although Solaris(TM) PAM modules commonly have a version number, they are not truly versioned, because the number is a part of the module name and must be included in the configuration. [[pam-chains-policies]] === Chains and Policies When a server initiates a PAM transaction, the PAM library tries to load a policy for the service specified in the man:pam_start[3] call. The policy specifies how authentication requests should be processed, and is defined in a configuration file. This is the other central concept in PAM: the possibility for the admin to tune the system security policy (in the wider sense of the word) simply by editing a text file. A policy consists of four chains, one for each of the four PAM facilities. Each chain is a sequence of configuration statements, each specifying a module to invoke, some (optional) parameters to pass to the module, and a control flag that describes how to interpret the return code from the module. Understanding the control flags is essential to understanding PAM configuration files. There are four different control flags: `binding`:: If the module succeeds and no earlier module in the chain has failed, the chain is immediately terminated and the request is granted. If the module fails, the rest of the chain is executed, but the request is ultimately denied. + This control flag was introduced by Sun in Solaris(TM) 9 (SunOS(TM) 5.9), and is also supported by OpenPAM. `required`:: If the module succeeds, the rest of the chain is executed, and the request is granted unless some other module fails. If the module fails, the rest of the chain is also executed, but the request is ultimately denied. `requisite`:: If the module succeeds, the rest of the chain is executed, and the request is granted unless some other module fails. If the module fails, the chain is immediately terminated and the request is denied. `sufficient`:: If the module succeeds and no earlier module in the chain has failed, the chain is immediately terminated and the request is granted. If the module fails, the module is ignored and the rest of the chain is executed. + As the semantics of this flag may be somewhat confusing, especially when it is used for the last module in a chain, it is recommended that the `binding` control flag be used instead if the implementation supports it. `optional`:: The module is executed, but its result is ignored. If all modules in a chain are marked `optional`, all requests will always be granted. When a server invokes one of the six PAM primitives, PAM retrieves the chain for the facility the primitive belongs to, and invokes each of the modules listed in the chain, in the order they are listed, until it reaches the end, or determines that no further processing is necessary (either because a `binding` or `sufficient` module succeeded, or because a `requisite` module failed.) The request is granted if and only if at least one module was invoked, and all non-optional modules succeeded. Note that it is possible, though not very common, to have the same module listed several times in the same chain. For instance, a module that looks up user names and passwords in a directory server could be invoked multiple times with different parameters specifying different directory servers to contact. PAM treat different occurrences of the same module in the same chain as different, unrelated modules. [[pam-transactions]] === Transactions The lifecycle of a typical PAM transaction is described below. Note that if any of these steps fails, the server should report a suitable error message to the client and abort the transaction. . If necessary, the server obtains arbitrator credentials through a mechanism independent of PAM-most commonly by virtue of having been started by `root`, or of being setuid `root`. . The server calls man:pam_start[3] to initialize the PAM library and specify its service name and the target account, and register a suitable conversation function. . The server obtains various information relating to the transaction (such as the applicant's user name and the name of the host the client runs on) and submits it to PAM using man:pam_set_item[3]. . The server calls man:pam_authenticate[3] to authenticate the applicant. . The server calls man:pam_acct_mgmt[3] to verify that the requested account is available and valid. If the password is correct but has expired, man:pam_acct_mgmt[3] will return `PAM_NEW_AUTHTOK_REQD` instead of `PAM_SUCCESS`. . If the previous step returned `PAM_NEW_AUTHTOK_REQD`, the server now calls man:pam_chauthtok[3] to force the client to change the authentication token for the requested account. . Now that the applicant has been properly authenticated, the server calls man:pam_setcred[3] to establish the credentials of the requested account. It is able to do this because it acts on behalf of the arbitrator, and holds the arbitrator's credentials. . Once the correct credentials have been established, the server calls man:pam_open_session[3] to set up the session. . The server now performs whatever service the client requested-for instance, provide the applicant with a shell. . Once the server is done serving the client, it calls man:pam_close_session[3] to tear down the session. . Finally, the server calls man:pam_end[3] to notify the PAM library that it is done and that it can release whatever resources it has allocated in the course of the transaction. [[pam-config]] == PAM Configuration [[pam-config-file]] === PAM Policy Files [[pam-config-pam.conf]] ==== The [.filename]#/etc/pam.conf# The traditional PAM policy file is [.filename]#/etc/pam.conf#. This file contains all the PAM policies for your system. Each line of the file describes one step in a chain, as shown below: [.programlisting] .... login auth required pam_nologin.so no_warn .... The fields are, in order: service name, facility name, control flag, module name, and module arguments. Any additional fields are interpreted as additional module arguments. A separate chain is constructed for each service / facility pair, so while the order in which lines for the same service and facility appear is significant, the order in which the individual services and facilities are listed is not. The examples in the original PAM paper grouped configuration lines by facility, and the Solaris(TM) stock [.filename]#pam.conf# still does that, but FreeBSD's stock configuration groups configuration lines by service. Either way is fine; either way makes equal sense. [[pam-config-pam.d]] ==== The [.filename]#/etc/pam.d# OpenPAM and Linux-PAM support an alternate configuration mechanism, which is the preferred mechanism in FreeBSD. In this scheme, each policy is contained in a separate file bearing the name of the service it applies to. These files are stored in [.filename]#/etc/pam.d/#. These per-service policy files have only four fields instead of [.filename]#pam.conf#'s five: the service name field is omitted. Thus, instead of the sample [.filename]#pam.conf# line from the previous section, one would have the following line in [.filename]#/etc/pam.d/login#: [.programlisting] .... auth required pam_nologin.so no_warn .... As a consequence of this simplified syntax, it is possible to use the same policy for multiple services by linking each service name to a same policy file. For instance, to use the same policy for the `su` and `sudo` services, one could do as follows: [source,shell] .... # cd /etc/pam.d # ln -s su sudo .... This works because the service name is determined from the file name rather than specified in the policy file, so the same file can be used for multiple differently-named services. Since each service's policy is stored in a separate file, the [.filename]#pam.d# mechanism also makes it very easy to install additional policies for third-party software packages. [[pam-config-file-order]] ==== The Policy Search Order As we have seen above, PAM policies can be found in a number of places. What happens if policies for the same service exist in multiple places? It is essential to understand that PAM's configuration system is centered on chains. [[pam-config-breakdown]] === Breakdown of a Configuration Line As explained in crossref:pam[pam-config-file], each line in [.filename]#/etc/pam.conf# consists of four or more fields: the service name, the facility name, the control flag, the module name, and zero or more module arguments. The service name is generally (though not always) the name of the application the statement applies to. If you are unsure, refer to the individual application's documentation to determine what service name it uses. Note that if you use [.filename]#/etc/pam.d/# instead of [.filename]#/etc/pam.conf#, the service name is specified by the name of the policy file, and omitted from the actual configuration lines, which then start with the facility name. The facility is one of the four facility keywords described in -crossref:pam[pam-facilities-primitives]. +crossref:pam[pam-facilities-primitives, Facilities and Primitives]. Likewise, the control flag is one of the four keywords described in - crossref:pam[pam-chains-policies], describing how to interpret the return code from the module. + crossref:pam[pam-chains-policies, Chains and Policies], describing how to interpret the return code from the module. Linux-PAM supports an alternate syntax that lets you specify the action to associate with each possible return code, but this should be avoided as it is non-standard and closely tied in with the way Linux-PAM dispatches service calls (which differs greatly from the way Solaris(TM) and OpenPAM do it.) Unsurprisingly, OpenPAM does not support this syntax. [[pam-policies]] === Policies To configure PAM correctly, it is essential to understand how policies are interpreted. When an application calls man:pam_start[3], the PAM library loads the policy for the specified service and constructs four module chains (one for each facility.) If one or more of these chains are empty, the corresponding chains from the policy for the `other` service are substituted. When the application later calls one of the six PAM primitives, the PAM library retrieves the chain for the corresponding facility and calls the appropriate service function in each module listed in the chain, in the order in which they were listed in the configuration. After each call to a service function, the module type and the error code returned by the service function are used to determine what happens next. With a few exceptions, which we discuss below, the following table applies: .PAM Chain Execution Summary [cols="1,1,1,1", options="header"] |=== | | PAM_SUCCESS | PAM_IGNORE | other |binding |if (!fail) break; |- |fail = true; |required |- |- |fail = true; |requisite |- |- |fail = true; break; |sufficient |if (!fail) break; |- |- |optional |- |- |- |=== If `fail` is true at the end of a chain, or when a "break" is reached, the dispatcher returns the error code returned by the first module that failed. Otherwise, it returns `PAM_SUCCESS`. The first exception of note is that the error code `PAM_NEW_AUTHTOK_REQD` is treated like a success, except that if no module failed, and at least one module returned `PAM_NEW_AUTHTOK_REQD`, the dispatcher will return `PAM_NEW_AUTHTOK_REQD`. The second exception is that man:pam_setcred[3] treats `binding` and `sufficient` modules as if they were `required`. The third and final exception is that man:pam_chauthtok[3] runs the entire chain twice (once for preliminary checks and once to actually set the password), and in the preliminary phase it treats `binding` and `sufficient` modules as if they were `required`. [[pam-freebsd-modules]] == FreeBSD PAM Modules [[pam-modules-deny]] === man:pam_deny[8] The man:pam_deny[8] module is one of the simplest modules available; it responds to any request with `PAM_AUTH_ERR`. It is useful for quickly disabling a service (add it to the top of every chain), or for terminating chains of `sufficient` modules. [[pam-modules-echo]] === man:pam_echo[8] The man:pam_echo[8] module simply passes its arguments to the conversation function as a `PAM_TEXT_INFO` message. It is mostly useful for debugging, but can also serve to display messages such as "Unauthorized access will be prosecuted" before starting the authentication procedure. [[pam-modules-exec]] === man:pam_exec[8] The man:pam_exec[8] module takes its first argument to be the name of a program to execute, and the remaining arguments are passed to that program as command-line arguments. One possible application is to use it to run a program at login time which mounts the user's home directory. [[pam-modules-ftpusers]] === man:pam_ftpusers[8] The man:pam_ftpusers[8] module [[pam-modules-group]] === man:pam_group[8] The man:pam_group[8] module accepts or rejects applicants on the basis of their membership in a particular file group (normally `wheel` for man:su[1]). It is primarily intended for maintaining the traditional behavior of BSD man:su[1], but has many other uses, such as excluding certain groups of users from a particular service. [[pam-modules-guest]] === man:pam_guest[8] The man:pam_guest[8] module allows guest logins using fixed login names. Various requirements can be placed on the password, but the default behavior is to allow any password as long as the login name is that of a guest account. The man:pam_guest[8] module can easily be used to implement anonymous FTP logins. [[pam-modules-krb5]] === man:pam_krb5[8] The man:pam_krb5[8] module [[pam-modules-ksu]] === man:pam_ksu[8] The man:pam_ksu[8] module [[pam-modules-lastlog]] === man:pam_lastlog[8] The man:pam_lastlog[8] module [[pam-modules-login-access]] === man:pam_login_access[8] The man:pam_login_access[8] module provides an implementation of the account management primitive which enforces the login restrictions specified in the man:login.access[5] table. [[pam-modules-nologin]] === man:pam_nologin[8] The man:pam_nologin[8] module refuses non-root logins when [.filename]#/var/run/nologin# exists. This file is normally created by man:shutdown[8] when less than five minutes remain until the scheduled shutdown time. [[pam-modules-passwdqc]] === man:pam_passwdqc[8] The man:pam_passwdqc[8] module [[pam-modules-permit]] === man:pam_permit[8] The man:pam_permit[8] module is one of the simplest modules available; it responds to any request with `PAM_SUCCESS`. It is useful as a placeholder for services where one or more chains would otherwise be empty. [[pam-modules-radius]] === man:pam_radius[8] The man:pam_radius[8] module [[pam-modules-rhosts]] === man:pam_rhosts[8] The man:pam_rhosts[8] module [[pam-modules-rootok]] === man:pam_rootok[8] The man:pam_rootok[8] module reports success if and only if the real user id of the process calling it (which is assumed to be run by the applicant) is 0. This is useful for non-networked services such as man:su[1] or man:passwd[1], to which the `root` should have automatic access. [[pam-modules-securetty]] === man:pam_securetty[8] The man:pam_securetty[8] module [[pam-modules-self]] === man:pam_self[8] The man:pam_self[8] module reports success if and only if the names of the applicant matches that of the target account. It is most useful for non-networked services such as man:su[1], where the identity of the applicant can be easily verified. [[pam-modules-ssh]] === man:pam_ssh[8] The man:pam_ssh[8] module provides both authentication and session services. The authentication service allows users who have passphrase-protected SSH secret keys in their [.filename]#~/.ssh# directory to authenticate themselves by typing their passphrase. The session service starts man:ssh-agent[1] and preloads it with the keys that were decrypted in the authentication phase. This feature is particularly useful for local logins, whether in X (using man:xdm[8] or another PAM-aware X login manager) or at the console. [[pam-modules-tacplus]] === man:pam_tacplus[8] The man:pam_tacplus[8] module [[pam-modules-unix]] === man:pam_unix[8] The man:pam_unix[8] module implements traditional UNIX(R) password authentication, using man:getpwnam[3] to obtain the target account's password and compare it with the one provided by the applicant. It also provides account management services (enforcing account and password expiration times) and password-changing services. This is probably the single most useful module, as the great majority of admins will want to maintain historical behavior for at least some services. [[pam-appl-prog]] == PAM Application Programming This section has not yet been written. [[pam-module-prog]] == PAM Module Programming This section has not yet been written. :sectnums!: [appendix] [[pam-sample-appl]] == Sample PAM Application The following is a minimal implementation of man:su[1] using PAM. Note that it uses the OpenPAM-specific man:openpam_ttyconv[3] conversation function, which is prototyped in [.filename]#security/openpam.h#. If you wish build this application on a system with a different PAM library, you will have to provide your own conversation function. A robust conversation function is surprisingly difficult to implement; -the one presented in crossref:pam[pam-sample-conv] is a good starting point, but should not be used in real-world applications. +the one presented in crossref:pam[pam-sample-conv, Sample PAM Conversation Function] is a good starting point, but should not be used in real-world applications. [.programlisting] .... include::{include-path}su.c[] .... :sectnums!: [appendix] [[pam-sample-module]] == Sample PAM Module The following is a minimal implementation of man:pam_unix[8], offering only authentication services. It should build and run with most PAM implementations, but takes advantage of OpenPAM extensions if available: note the use of man:pam_get_authtok[3], which enormously simplifies prompting the user for a password. [.programlisting] .... include::{include-path}pam_unix.c[] .... :sectnums!: [appendix] [[pam-sample-conv]] == Sample PAM Conversation Function The conversation function presented below is a greatly simplified version of OpenPAM's man:openpam_ttyconv[3]. It is fully functional, and should give the reader a good idea of how a conversation function should behave, but it is far too simple for real-world use. Even if you are not using OpenPAM, feel free to download the source code and adapt man:openpam_ttyconv[3] to your uses; we believe it to be as robust as a tty-oriented conversation function can reasonably get. [.programlisting] .... include::{include-path}converse.c[] .... :sectnums!: [[pam-further]] == Further Reading === Papers Making Login Services Independent of Authentication Technologies Vipin Samar. Charlie Lai. Sun Microsystems. _link:https://pubs.opengroup.org/onlinepubs/8329799/toc.htm[X/Open Single Sign-on Preliminary Specification]_. The Open Group. 1-85912-144-6. June 1997. _link:https://mirrors.kernel.org/pub/linux/libs/pam/pre/doc/draft-morgan-pam-07.txt[Pluggable Authentication Modules]_. Andrew G. Morgan. 1999-10-06. === User Manuals _link:https://docs.oracle.com/cd/E26505_01/html/E27224/pam-1.html[PAM Administration]_. Sun Microsystems. === Related Web Pages _link:https://www.openpam.org/[OpenPAM homepage]_ Dag-Erling Smørgrav. ThinkSec AS. _link:http://www.kernel.org/pub/linux/libs/pam/[Linux-PAM homepage]_ Andrew Morgan. _Solaris PAM homepage_. Sun Microsystems. diff --git a/documentation/content/en/articles/pr-guidelines/_index.adoc b/documentation/content/en/articles/pr-guidelines/_index.adoc index 85f3ab4546..b6729150cd 100644 --- a/documentation/content/en/articles/pr-guidelines/_index.adoc +++ b/documentation/content/en/articles/pr-guidelines/_index.adoc @@ -1,515 +1,515 @@ --- title: Problem Report Handling Guidelines authors: - author: Dag-Erling Smørgrav - author: Hiten Pandya description: These guidelines describe recommended handling practices for FreeBSD Problem Reports (PRs). trademarks: ["freebsd", "general"] tags: ["PR", "guideline", "bugs", "maintenance", "BugZilla", "FreeBSD"] --- = Problem Report Handling Guidelines :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/pr-guidelines/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract These guidelines describe recommended handling practices for FreeBSD Problem Reports (PRs). Whilst developed for the FreeBSD PR Database Maintenance Team mailto:freebsd-bugbusters@FreeBSD.org[freebsd-bugbusters@FreeBSD.org], these guidelines should be followed by anyone working with FreeBSD PRs. ''' toc::[] [[intro]] == Introduction Bugzilla is an issue management system used by the FreeBSD Project. As accurate tracking of outstanding software defects is important to FreeBSD's quality, the correct use of the software is essential to the forward progress of the Project. Access to Bugzilla is available to the entire FreeBSD community. In order to maintain consistency within the database and provide a consistent user experience, guidelines have been established covering common aspects of bug management such as presenting followup, handling close requests, and so forth. [[pr-lifecycle]] == Problem Report Life-cycle * The Reporter submits a bug report on the website. The bug is in the `Needs Triage` state. * Jane Random BugBuster confirms that the bug report has sufficient information to be reproducible. If not, she goes back and forth with the reporter to obtain the needed information. At this point the bug is set to the `Open` state. * Joe Random Committer takes interest in the PR and assigns it to himself, or Jane Random BugBuster decides that Joe is best suited to handle it and assigns it to him. The bug should be set to the `In Discussion` state. * Joe has a brief exchange with the originator (making sure it all goes into the audit trail) and determines the cause of the problem. * Joe pulls an all-nighter and whips up a patch that he thinks fixes the problem, and submits it in a follow-up, asking the originator to test it. He then sets the PRs state to `Patch Ready`. * A couple of iterations later, both Joe and the originator are satisfied with the patch, and Joe commits it to `-CURRENT` (or directly to `-STABLE` if the problem does not exist in `-CURRENT`), making sure to reference the Problem Report in his commit log (and credit the originator if they submitted all or part of the patch) and, if appropriate, start an MFC countdown. The bug is set to the `Needs MFC` state. * If the patch does not need MFCing, Joe then closes the PR as `Issue Resolved`. [NOTE] ==== Many PRs are submitted with very little information about the problem, and some are either very complex to solve, or just scratch the surface of a larger problem; in these cases, it is very important to obtain all the necessary information needed to solve the problem. If the problem contained within cannot be solved, or has occurred again, it is necessary to re-open the PR. ==== [[pr-states]] == Problem Report State It is important to update the state of a PR when certain actions are taken. The state should accurately reflect the current state of work on the PR. .A small example on when to change PR state [example] ==== When a PR has been worked on and the developer(s) responsible feel comfortable about the fix, they will submit a followup to the PR and change its state to "feedback". At this point, the originator should evaluate the fix in their context and respond indicating whether the defect has indeed been remedied. ==== A Problem Report may be in one of the following states: open:: Initial state; the problem has been pointed out and it needs reviewing. analyzed:: The problem has been reviewed and a solution is being sought. feedback:: Further work requires additional information from the originator or the community; possibly information regarding the proposed solution. patched:: A patch has been committed, but something (MFC, or maybe confirmation from originator) is still pending. suspended:: The problem is not being worked on, due to lack of information or resources. This is a prime candidate for somebody who is looking for a project to take on. If the problem cannot be solved at all, it will be closed, rather than suspended. The documentation project uses suspended for wish-list items that entail a significant amount of work which no one currently has time for. closed:: A problem report is closed when any changes have been integrated, documented, and tested, or when fixing the problem is abandoned. [NOTE] ==== The "patched" state is directly related to feedback, so you may go directly to "closed" state if the originator cannot test the patch, and it works in your own testing. ==== [[pr-types]] == Types of Problem Reports While handling problem reports, either as a developer who has direct access to the Problem Reports database or as a contributor who browses the database and submits followups with patches, comments, suggestions or change requests, you will come across several different types of PRs. -* crossref:pr-guidelines[pr-unassigned] -* crossref:pr-guidelines[pr-assigned] -* crossref:pr-guidelines[pr-dups] -* crossref:pr-guidelines[pr-stale] -* crossref:pr-guidelines[pr-misfiled-notpr] +* crossref:pr-guidelines[pr-unassigned, Unassigned PRs] +* crossref:pr-guidelines[pr-assigned, Assigned PRs] +* crossref:pr-guidelines[pr-dups, Duplicate PRs] +* crossref:pr-guidelines[pr-stale, Stale PRs] +* crossref:pr-guidelines[pr-misfiled-notpr, Non-Bug PRs] The following sections describe what each different type of PRs is used for, when a PR belongs to one of these types, and what treatment each different type receives. [[pr-unassigned]] == Unassigned PRs When PRs arrive, they are initially assigned to a generic (placeholder) assignee. These are always prepended with `freebsd-`. The exact value for this default depends on the category; in most cases, it corresponds to a specific FreeBSD mailing list. Here is the current list, with the most common ones listed first: [[default-assignees-common]] .Default Assignees - most common [cols="1,1,1", options="header"] |=== | Type | Categories | Default Assignee |base system |bin, conf, gnu, kern, misc |freebsd-bugs |architecture-specific |alpha, amd64, arm, i386, ia64, powerpc, sparc64 |freebsd-_arch_ |ports collection |ports |freebsd-ports-bugs |documentation shipped with the system |docs |freebsd-doc |FreeBSD web pages (not including docs) |Website |freebsd-www |=== [[default-assignees-other]] .Default Assignees - other [cols="1,1,1", options="header"] |=== | Type | Categories | Default Assignee |advocacy efforts |advocacy |freebsd-advocacy |Java Virtual Machine(TM) problems |java |freebsd-java |standards compliance |standards |freebsd-standards |threading libraries |threads |freebsd-threads |man:usb[4] subsystem |usb |freebsd-usb |=== Do not be surprised to find that the submitter of the PR has assigned it to the wrong category. If you fix the category, do not forget to fix the assignment as well. (In particular, our submitters seem to have a hard time understanding that just because their problem manifested on an i386 system, that it might be generic to all of FreeBSD, and thus be more appropriate for `kern`. The converse is also true, of course.) Certain PRs may be reassigned away from these generic assignees by anyone. There are several types of assignees: specialized mailing lists; mail aliases (used for certain limited-interest items); and individuals. For assignees which are mailing lists, please use the long form when making the assignment (e.g., `freebsd-foo` instead of `foo`); this will avoid duplicate emails sent to the mailing list. [NOTE] ==== Since the list of individuals who have volunteered to be the default assignee for certain types of PRs changes so often, it is much more suitable for https://wiki.freebsd.org/AssigningPRs[the FreeBSD wiki]. ==== Here is a sample list of such entities; it is probably not complete. [[common-assignees-base]] .Common Assignees - base system [cols="1,1,1,1", options="header"] |=== | Type | Suggested Category | Suggested Assignee | Assignee Type |problem specific to the ARM(R) architecture |arm |freebsd-arm |mailing list |problem specific to the MIPS(R) architecture |kern |freebsd-mips |mailing list |problem specific to the PowerPC(R) architecture |kern |freebsd-ppc |mailing list |problem with Advanced Configuration and Power Management (man:acpi[4]) |kern |freebsd-acpi |mailing list |problem with Asynchronous Transfer Mode (ATM) drivers |kern |freebsd-atm |mailing list |problem with embedded or small-footprint FreeBSD systems (e.g., NanoBSD/PicoBSD/FreeBSD-arm) |kern |freebsd-embedded |mailing list |problem with FireWire(R) drivers |kern |freebsd-firewire |mailing list |problem with the filesystem code |kern |freebsd-fs |mailing list |problem with the man:geom[4] subsystem |kern |freebsd-geom |mailing list |problem with the man:ipfw[4] subsystem |kern |freebsd-ipfw |mailing list |problem with Integrated Services Digital Network (ISDN) drivers |kern |freebsd-isdn |mailing list |man:jail[8] subsystem |kern |freebsd-jail |mailing list |problem with Linux(R) or SVR4 emulation |kern |freebsd-emulation |mailing list |problem with the networking stack |kern |freebsd-net |mailing list |problem with the man:pf[4] subsystem |kern |freebsd-pf |mailing list |problem with the man:scsi[4] subsystem |kern |freebsd-scsi |mailing list |problem with the man:sound[4] subsystem |kern |freebsd-multimedia |mailing list |problems with the man:wlan[4] subsystem and wireless drivers |kern |freebsd-wireless |mailing list |problem with man:sysinstall[8] or man:bsdinstall[8] |bin |freebsd-sysinstall |mailing list |problem with the system startup scripts (man:rc[8]) |kern |freebsd-rc |mailing list |problem with VIMAGE or VNET functionality and related code |kern |freebsd-virtualization |mailing list |problem with Xen emulation |kern |freebsd-xen |mailing list |=== [[common-assignees-ports]] .Common Assignees - Ports Collection [cols="1,1,1,1", options="header"] |=== | Type | Suggested Category | Suggested Assignee | Assignee Type |problem with the ports framework (__not__ with an individual port!) |ports |portmgr |alias |port which is maintained by apache@FreeBSD.org |ports |apache |mailing list |port which is maintained by autotools@FreeBSD.org |ports |autotools |alias |port which is maintained by doceng@FreeBSD.org |ports |doceng |alias |port which is maintained by eclipse@FreeBSD.org |ports |freebsd-eclipse |mailing list |port which is maintained by gecko@FreeBSD.org |ports |gecko |mailing list |port which is maintained by gnome@FreeBSD.org |ports |gnome |mailing list |port which is maintained by hamradio@FreeBSD.org |ports |hamradio |alias |port which is maintained by haskell@FreeBSD.org |ports |haskell |alias |port which is maintained by java@FreeBSD.org |ports |freebsd-java |mailing list |port which is maintained by kde@FreeBSD.org |ports |kde |mailing list |port which is maintained by mono@FreeBSD.org |ports |mono |mailing list |port which is maintained by office@FreeBSD.org |ports |freebsd-office |mailing list |port which is maintained by perl@FreeBSD.org |ports |perl |mailing list |port which is maintained by python@FreeBSD.org |ports |freebsd-python |mailing list |port which is maintained by ruby@FreeBSD.org |ports |freebsd-ruby |mailing list |port which is maintained by secteam@FreeBSD.org |ports |secteam |alias |port which is maintained by vbox@FreeBSD.org |ports |vbox |alias |port which is maintained by x11@FreeBSD.org |ports |freebsd-x11 |mailing list |=== Ports PRs which have a maintainer who is a ports committer may be reassigned by anyone (but note that not every FreeBSD committer is necessarily a ports committer, so you cannot simply go by the email address alone.) For other PRs, please do not reassign them to individuals (other than yourself) unless you are certain that the assignee really wants to track the PR. This will help to avoid the case where no one looks at fixing a particular problem because everyone assumes that the assignee is already working on it. [[common-assignees-other]] .Common Assignees - Other [cols="1,1,1,1", options="header"] |=== | Type | Suggested Category | Suggested Assignee | Assignee Type |problem with PR database |bin |bugmeister |alias |problem with Bugzilla https://bugs.freebsd.org/submit/[web form]. |doc |bugmeister |alias |=== [[pr-assigned]] == Assigned PRs If a PR has the `responsible` field set to the username of a FreeBSD developer, it means that the PR has been handed over to that particular person for further work. Assigned PRs should not be touched by anyone but the assignee or bugmeister. If you have comments, submit a followup. If for some reason you think the PR should change state or be reassigned, send a message to the assignee. If the assignee does not respond within two weeks, unassign the PR and do as you please. [[pr-dups]] == Duplicate PRs If you find more than one PR that describe the same issue, choose the one that contains the largest amount of useful information and close the others, stating clearly the number of the superseding PR. If several PRs contain non-overlapping useful information, submit all the missing information to one in a followup, including references to the others; then close the other PRs (which are now completely superseded). [[pr-stale]] == Stale PRs A PR is considered stale if it has not been modified in more than six months. Apply the following procedure to deal with stale PRs: * If the PR contains sufficient detail, try to reproduce the problem in `-CURRENT` and `-STABLE`. If you succeed, submit a followup detailing your findings and try to find someone to assign it to. Set the state to "analyzed" if appropriate. * If the PR describes an issue which you know is the result of a usage error (incorrect configuration or otherwise), submit a followup explaining what the originator did wrong, then close the PR with the reason "User error" or "Configuration error". * If the PR describes an error which you know has been corrected in both `-CURRENT` and `-STABLE`, close it with a message stating when it was fixed in each branch. * If the PR describes an error which you know has been corrected in `-CURRENT`, but not in `-STABLE`, try to find out when the person who corrected it is planning to MFC it, or try to find someone else (maybe yourself?) to do it. Set the state to "patched" and assign it to whomever will do the MFC. * In other cases, ask the originator to confirm if the problem still exists in newer versions. If the originator does not reply within a month, close the PR with the notation "Feedback timeout". [[pr-misfiled-notpr]] == Non-Bug PRs Developers that come across PRs that look like they should have been posted to {freebsd-bugs} or some other list should close the PR, informing the submitter in a comment why this is not really a PR and where the message should be posted. The email addresses that Bugzilla listens to for incoming PRs have been published as part of the FreeBSD documentation, have been announced and listed on the web-site. This means that spammers found them. Whenever you close one of these PRs, please do the following: * Set the component to `junk` (under `Supporting Services`. * Set Responsible to `nobody@FreeBSD.org`. * Set State to `Issue Resolved`. Setting the category to `junk` makes it obvious that there is no useful content within the PR, and helps to reduce the clutter within the main categories. [[references]] == Further Reading This is a list of resources relevant to the proper writing and processing of problem reports. It is by no means complete. * extref:{problem-reports}[How to Write FreeBSD Problem Reports]-guidelines for PR originators. diff --git a/documentation/content/en/articles/releng/_index.adoc b/documentation/content/en/articles/releng/_index.adoc index b54952577c..f19ccb2bdd 100644 --- a/documentation/content/en/articles/releng/_index.adoc +++ b/documentation/content/en/articles/releng/_index.adoc @@ -1,447 +1,447 @@ --- title: Legacy FreeBSD Release Engineering authors: - author: Murray Stokely email: murray@FreeBSD.org webpage: https://people.FreeBSD.org/~murray/ description: This paper describes the approach previously used by the FreeBSD release engineering team to make production quality releases of the FreeBSD Operating System trademarks: ["freebsd", "intel", "general"] tags: ["Release", "Engineering", "Historical", "FreeBSD"] --- = FreeBSD Release Engineering :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/releng/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract [NOTE] ==== This document is outdated and does not accurately describe the current release procedures of the FreeBSD Release Engineering team. It is retained for historical purposes. The current procedures used by the FreeBSD Release Engineering team are available in the extref:{freebsd-releng}[FreeBSD Release Engineering] article. ==== This paper describes the approach used by the FreeBSD release engineering team to make production quality releases of the FreeBSD Operating System. It details the methodology used for the official FreeBSD releases and describes the tools available for those interested in producing customized FreeBSD releases for corporate rollouts or commercial productization. ''' toc::[] [[introduction]] == Introduction The development of FreeBSD is a very open process. FreeBSD is comprised of contributions from thousands of people around the world. The FreeBSD Project provides Subversion footnote:[Subversion, http://subversion.apache.org] access to the general public so that others can have access to log messages, diffs (patches) between development branches, and other productivity enhancements that formal source code management provides. This has been a huge help in attracting more talented developers to FreeBSD. However, I think everyone would agree that chaos would soon manifest if write access to the main repository was opened up to everyone on the Internet. Therefore only a "select" group of nearly 300 people are given write access to the Subversion repository. These extref:{contributors}[FreeBSD committers, staff-committers]footnote:[extref:{contributors}[FreeBSD committers, staff-committers]] are usually the people who do the bulk of FreeBSD development. An elected link:https://www.FreeBSD.org/administration/#t-core[Core Team]footnote:[link:https://www.FreeBSD.org/administration/#t-core[FreeBSD Core Team]] of developers provide some level of direction over the project. The rapid pace of `FreeBSD` development makes the main development branch unsuitable for the everyday use by the general public. In particular, stabilizing efforts are required for polishing the development system into a production quality release. To solve this conflict, development continues on several parallel tracks. The main development branch is the _HEAD_ or _trunk_ of our Subversion tree, known as "FreeBSD-CURRENT" or "-CURRENT" for short. A set of more stable branches are maintained, known as "FreeBSD-STABLE" or "-STABLE" for short. All branches live in a master Subversion repository maintained by the FreeBSD Project. FreeBSD-CURRENT is the "bleeding-edge" of FreeBSD development where all new changes first enter the system. FreeBSD-STABLE is the development branch from which major releases are made. Changes go into this branch at a different pace, and with the general assumption that they have first gone into FreeBSD-CURRENT and have been thoroughly tested by our user community. The term _stable_ in the name of the branch refers to the presumed Application Binary Interface stability, which is promised by the project. This means that a user application compiled on an older version of the system from the same branch works on a newer system from the same branch. The ABI stability has improved greatly from the compared to previous releases. In most cases, binaries from the older _STABLE_ systems run unmodified on newer systems, including __HEAD__, assuming that the system management interfaces are not used. In the interim period between releases, weekly snapshots are built automatically by the FreeBSD Project build machines and made available for download from `https:/download.FreeBSD.org/snapshots/`. The widespread availability of binary release snapshots, and the tendency of our user community to keep up with -STABLE development with Subversion and "`make buildworld`" footnote:[extref:{handbook}[Rebuilding world, makeworld]] helps to keep FreeBSD-STABLE in a very reliable condition even before the quality assurance activities ramp up pending a major release. In addition to installation ISO snapshots, weekly virtual machine images are also provided for use with VirtualBox, qemu, or other popular emulation software. The virtual machine images can be downloaded from `https://download.FreeBSD.org/snapshots/VM-IMAGES/`. The virtual machine images are approximately 150MB man:xz[1] compressed, and contain a 10GB sparse filesystem when attached to a virtual machine. Bug reports and feature requests are continuously submitted by users throughout the release cycle. Problems reports are entered into our Bugzilla database through the web interface provided at https://www.freebsd.org/support/bugreports/[https://www.freebsd.org/support/bugreports/]. To service our most conservative users, individual release branches were introduced with FreeBSD 4.3. These release branches are created shortly before a final release is made. After the release goes out, only the most critical security fixes and additions are merged onto the release branch. In addition to source updates via Subversion, binary patchkits are available to keep systems on the _releng/X.Y_ branches updated. === What This Article Describes The following sections of this article describe: -crossref:releng[release-proc]:: +crossref:releng[release-proc, Release Process]:: The different phases of the release engineering process leading up to the actual system build. -crossref:releng[release-build]:: +crossref:releng[release-build, Release Building]:: The actual build process. -crossref:releng[extensibility]:: +crossref:releng[extensibility, Extensibility]:: How the base release may be extended by third parties. -crossref:releng[lessons-learned]:: +crossref:releng[lessons-learned, Lessons Learned from FreeBSD 4.4]:: Some of the lessons learned through the release of FreeBSD 4.4. -crossref:releng[future]:: +crossref:releng[future, Future Directions]:: Future directions of development. [[release-proc]] == Release Process New releases of FreeBSD are released from the -STABLE branch at approximately four month intervals. The FreeBSD release process begins to ramp up 70-80 days before the anticipated release date when the release engineer sends an email to the development mailing lists to remind developers that they only have 15 days to integrate new changes before the code freeze. During this time, many developers perform what have become known as "MFC sweeps". MFC stands for "Merge From CURRENT" and it describes the process of merging a tested change from our -CURRENT development branch to our -STABLE branch. Project policy requires any change to be first applied to trunk, and merged to the -STABLE branches after sufficient external testing was done by -CURRENT users (developers are expected to extensively test the change before committing to -CURRENT, but it is impossible for a person to exercise all usages of the general-purpose operating system). Minimal MFC period is 3 days, which is typically used only for trivial or critical bugfixes. === Code Review Sixty days before the anticipated release, the source repository enters a "code freeze". During this time, all commits to the -STABLE branch must be approved by `{re}`. The approval process is technically enforced by a pre-commit hook. The kinds of changes that are allowed during this period include: * Bug fixes. * Documentation updates. * Security-related fixes of any kind. * Minor changes to device drivers, such as adding new Device IDs. * Driver updates from the vendors. * Any additional change that the release engineering team feels is justified, given the potential risk. Shortly after the code freeze is started, a _BETA1_ image is built and released for widespread testing. During the code freeze, at least one beta image or release candidate is released every two weeks until the final release is ready. During the days preceding the final release, the release engineering team is in constant communication with the security-officer team, the documentation maintainers, and the port maintainers to ensure that all of the different components required for a successful release are available. After the quality of the BETA images is satisfying enough, and no large and potentially risky changes are planned, the release branch is created and _Release Candidate_ (RC) images are built from the release branch, instead of the BETA images from the STABLE branch. Also, the freeze on the STABLE branch is lifted and release branch enters a "hard code freeze" where it becomes much harder to justify new changes to the system unless a serious bug-fix or security issue is involved. === Final Release Checklist When several BETA images have been made available for widespread testing and all major issues have been resolved, the final release "polishing" can begin. [[rel-branch]] ==== Creating the Release Branch [NOTE] ==== In all examples below, `$FSVN` refers to the location of the FreeBSD Subversion repository, `svn+ssh://svn.FreeBSD.org/base/`. ==== The layout of FreeBSD branches in Subversion is described in the extref:{committers-guide}[Committer's Guide, subversion-primer-base-layout]. The first step in creating a branch is to identify the revision of the `stable/_X_` sources that you want to branch _from_. [source,shell] .... # svn log -v $FSVN/stable/9 .... The next step is to create the _release branch_ [source,shell] .... # svn cp $FSVN/stable/9@REVISION $FSVN/releng/9.2 .... This branch can be checked out: [source,shell] .... # svn co $FSVN/releng/9.2 src .... [NOTE] ==== Creating the `releng` branch and `release` tags is done by the link:https://www.FreeBSD.org/administration/#t-re[Release Engineering Team]. ==== image::branches-head.png[FreeBSD Development Branch] image::branches-releng3.png[FreeBSD 3.x STABLE Branch] image::branches-releng4.png[FreeBSD 4.x STABLE Branch] image::branches-releng5.png[FreeBSD 5.x STABLE Branch] image::branches-releng6.png[FreeBSD 6.x STABLE Branch] image::branches-releng7.png[FreeBSD 7.x STABLE Branch] image::branches-releng8.png[FreeBSD 8.x STABLE Branch] image::branches-releng9.png[FreeBSD 9.x STABLE Branch] [[versionbump]] ==== Bumping up the Version Number Before the final release can be tagged, built, and released, the following files need to be modified to reflect the correct version of FreeBSD: * [.filename]#doc/en_US.ISO8859-1/books/handbook/mirrors/chapter.xml# * [.filename]#doc/en_US.ISO8859-1/books/porters-handbook/book.xml# * [.filename]#doc/en_US.ISO8859-1/htdocs/cgi/ports.cgi# * [.filename]#ports/Tools/scripts/release/config# * [.filename]#doc/shared/xml/freebsd.ent# * [.filename]#src/Makefile.inc1# * [.filename]#src/UPDATING# * [.filename]#src/gnu/usr.bin/groff/tmac/mdoc.local# * [.filename]#src/release/Makefile# * [.filename]#src/release/doc/en_US.ISO8859-1/shared/xml/release.dsl# * [.filename]#src/release/doc/shared/examples/Makefile.relnotesng# * [.filename]#src/release/doc/shared/xml/release.ent# * [.filename]#src/sys/conf/newvers.sh# * [.filename]#src/sys/sys/param.h# * [.filename]#src/usr.sbin/pkg_install/add/main.c# * [.filename]#doc/en_US.ISO8859-1/htdocs/search/opensearch/man.xml# The release notes and errata files also need to be adjusted for the new release (on the release branch) and truncated appropriately (on the stable/current branch): * [.filename]#src/release/doc/en_US.ISO8859-1/relnotes/common/new.xml# * [.filename]#src/release/doc/en_US.ISO8859-1/errata/article.xml# Sysinstall should be updated to note the number of available ports and the amount of disk space required for the Ports Collection. footnote:[FreeBSD Ports Collection https://ports.FreeBSD.org] This information is currently kept in [.filename]#src/usr.sbin/bsdinstall/dist.c#. After the release has been built, a number of files should be updated to announce the release to the world. These files are relative to `head/` within the `doc/` subversion tree. * [.filename]#share/images/articles/releng/branches-relengX.pic# * [.filename]#head/shared/xml/release.ent# * [.filename]#en_US.ISO8859-1/htdocs/releases/*# * [.filename]#en_US.ISO8859-1/htdocs/releng/index.xml# * [.filename]#share/xml/news.xml# Additionally, update the "BSD Family Tree" file: * [.filename]#src/shared/misc/bsd-family-tree# ==== Creating the Release Tag When the final release is ready, the following command will create the `release/9.2.0` tag. [source,shell] .... # svn cp $FSVN/releng/9.2 $FSVN/release/9.2.0 .... The Documentation and Ports managers are responsible for tagging their respective trees with the `tags/RELEASE_9_2_0` tag. When the Subversion `svn cp` command is used to create a __release tag__, this identifies the source at a specific point in time. By creating tags, we ensure that future release builders will always be able to use the same source we used to create the official FreeBSD Project releases. [[release-build]] == Release Building FreeBSD "releases" can be built by anyone with a fast machine and access to a source repository. (That should be everyone, since we offer Subversion access! See the extref:{handbook}[Subversion section in the Handbook, svn] for details.) The _only_ special requirement is that the man:md[4] device must be available. If the device is not loaded into your kernel, then the kernel module should be automatically loaded when man:mdconfig[8] is executed during the boot media creation phase. All of the tools necessary to build a release are available from the Subversion repository in [.filename]#src/release#. These tools aim to provide a consistent way to build FreeBSD releases. A complete release can actually be built with only a single command, including the creation of ISO images suitable for burning to CDROM or DVD, and an FTP install directory. man:release[7] fully documents the `src/release/generate-release.sh` script which is used to build a release. `generate-release.sh` is a wrapper around the Makefile target: `make release`. === Building a Release man:release[7] documents the exact commands required to build a FreeBSD release. The following sequences of commands can build an 9.2.0 release: [source,shell] .... # cd /usr/src/release # sh generate-release.sh release/9.2.0 /local3/release .... After running these commands, all prepared release files are available in [.filename]#/local3/release/R# directory. The release [.filename]#Makefile# can be broken down into several distinct steps. * Creation of a sanitized system environment in a separate directory hierarchy with "`make installworld`". * Checkout from Subversion of a clean version of the system source, documentation, and ports into the release build hierarchy. * Population of [.filename]#/etc# and [.filename]#/dev# in the chrooted environment. * chroot into the release build hierarchy, to make it harder for the outside environment to taint this build. * `make world` in the chrooted environment. * Build of Kerberos-related binaries. * Build [.filename]#GENERIC# kernel. * Creation of a staging directory tree where the binary distributions will be built and packaged. * Build and installation of the documentation toolchain needed to convert the documentation source (SGML) into HTML and text documents that will accompany the release. * Build and installation of the actual documentation (user manuals, tutorials, release notes, hardware compatibility lists, and so on.) * Package up distribution tarballs of the binaries and sources. * Create FTP installation hierarchy. * _(optionally)_ Create ISO images for CDROM/DVD media. For more information about the release build infrastructure, please see man:release[7]. [NOTE] ==== It is important to remove any site-specific settings from [.filename]#/etc/make.conf#. For example, it would be unwise to distribute binaries that were built on a system with `CPUTYPE` set to a specific processor. ==== === Contributed Software ("ports") The https://ports.FreeBSD.org[FreeBSD Ports collection] is a collection of over {numports} third-party software packages available for FreeBSD. The `{portmgr}` is responsible for maintaining a consistent ports tree that can be used to create the binary packages that accompany official FreeBSD releases. === Release ISOs Starting with FreeBSD 4.4, the FreeBSD Project decided to release all four ISO images that were previously sold on the _BSDi/Wind River Systems/FreeBSD Mall_ "official" CDROM distributions. Each of the four discs must contain a [.filename]#README.TXT# file that explains the contents of the disc, a [.filename]#CDROM.INF# file that provides meta-data for the disc so that man:bsdinstall[8] can validate and use the contents, and a [.filename]#filename.txt# file that provides a manifest for the disc. This _manifest_ can be created with a simple command: [source,shell] .... /stage/cdrom# find . -type f | sed -e 's/^\.\///' | sort > filename.txt .... The specific requirements of each CD are outlined below. ==== Disc 1 The first disc is almost completely created by `make release`. The only changes that should be made to the [.filename]#disc1# directory are the addition of a [.filename]#tools# directory, and as many popular third party software packages as will fit on the disc. The [.filename]#tools# directory contains software that allow users to create installation floppies from other operating systems. This disc should be made bootable so that users of modern PCs do not need to create installation floppy disks. If a custom kernel of FreeBSD is to be included, then man:bsdinstall[8] and man:release[7] must be updated to include installation instructions. The relevant code is contained in [.filename]#src/release# and [.filename]#src/usr.sbin/bsdinstall#. Specifically, the file [.filename]#src/release/Makefile#, and [.filename]#dist.c#, [.filename]#dist.h#, [.filename]#menus.c#, [.filename]#install.c#, and [.filename]#Makefile# will need to be updated under [.filename]#src/usr.sbin/bsdinstall#. Optionally, you may choose to update [.filename]#bsdinstall.8#. ==== Disc 2 The second disc is also largely created by `make release`. This disc contains a "live filesystem" that can be used from man:bsdinstall[8] to troubleshoot a FreeBSD installation. This disc should be bootable and should also contain a compressed copy of the CVS repository in the [.filename]#CVSROOT# directory and commercial software demos in the [.filename]#commerce# directory. ==== Multi-volume Support Sysinstall supports multiple volume package installations. This requires that each disc have an [.filename]#INDEX# file containing all of the packages on all volumes of a set, along with an extra field that indicates which volume that particular package is on. Each volume in the set must also have the `CD_VOLUME` variable set in the [.filename]#cdrom.inf# file so that bsdinstall can tell which volume is which. When a user attempts to install a package that is not on the current disc, bsdinstall will prompt the user to insert the appropriate one. [[distribution]] == Distribution [[dist-ftp]] === FTP Sites When the release has been thoroughly tested and packaged for distribution, the master FTP site must be updated. The official FreeBSD public FTP sites are all mirrors of a master server that is open only to other FTP sites. This site is known as `ftp-master`. When the release is ready, the following files must be modified on `ftp-master`: [.filename]#/pub/FreeBSD/releases/arch/X.Y-RELEASE/#:: The installable FTP directory as output from `make release`. [.filename]#/pub/FreeBSD/ports/arch/packages-X.Y-release/#:: The complete package build for this release. [.filename]#/pub/FreeBSD/releases/arch/X.Y-RELEASE/tools#:: A symlink to [.filename]#../../../tools#. [.filename]#/pub/FreeBSD/releases/arch/X.Y-RELEASE/packages#:: A symlink to [.filename]#../../../ports/arch/packages-X.Y-release#. [.filename]#/pub/FreeBSD/releases/arch/ISO-IMAGES/X.Y/X.Y-RELEASE-arch-*.iso#:: The ISO images. The "*" is [.filename]#disc1#, [.filename]#disc2#, etc. Only if there is a [.filename]#disc1# and there is an alternative first installation CD (for example a stripped-down install with no windowing system) there may be a [.filename]#mini# as well. For more information about the distribution mirror architecture of the FreeBSD FTP sites, please see the extref:{hubs}[Mirroring FreeBSD] article. It may take many hours to two days after updating `ftp-master` before a majority of the Tier-1 FTP sites have the new software depending on whether or not a package set got loaded at the same time. It is imperative that the release engineers coordinate with the {mirror-announce} before announcing the general availability of new software on the FTP sites. Ideally the release package set should be loaded at least four days prior to release day. The release bits should be loaded between 24 and 48 hours before the planned release time with "other" file permissions turned off. This will allow the mirror sites to download it but the general public will not be able to download it from the mirror sites. Mail should be sent to {mirror-announce} at the time the release bits get posted saying the release has been staged and giving the time that the mirror sites should begin allowing access. Be sure to include a time zone with the time, for example make it relative to GMT. [[dist-cdrom]] === CD-ROM Replication Coming soon: Tips for sending FreeBSD ISOs to a replicator and quality assurance measures to be taken. [[extensibility]] == Extensibility Although FreeBSD forms a complete operating system, there is nothing that forces you to use the system exactly as we have packaged it up for distribution. We have tried to design the system to be as extensible as possible so that it can serve as a platform that other commercial products can be built on top of. The only "rule" we have about this is that if you are going to distribute FreeBSD with non-trivial changes, we encourage you to document your enhancements! The FreeBSD community can only help support users of the software we provide. We certainly encourage innovation in the form of advanced installation and administration tools, for example, but we cannot be expected to answer questions about it. === Scripting `bsdinstall` The FreeBSD system installation and configuration tool, man:bsdinstall[8], can be scripted to provide automated installs for large sites. This functionality can be used in conjunction with Intel(R) PXE footnote:[extref:{handbook}[Diskless Operation with PXE, network-diskless]] to bootstrap systems from the network. [[lessons-learned]] == Lessons Learned from FreeBSD 4.4 The release engineering process for 4.4 formally began on August 1st, 2001. After that date all commits to the `RELENG_4` branch of FreeBSD had to be explicitly approved by the `{re}`. The first release candidate for the x86 architecture was released on August 16, followed by 4 more release candidates leading up to the final release on September 18th. The security officer was very involved in the last week of the process as several security issues were found in the earlier release candidates. A total of over _500_ emails were sent to the `{re}` in little over a month. Our user community has made it very clear that the security and stability of a FreeBSD release should not be sacrificed for any self-imposed deadlines or target release dates. The FreeBSD Project has grown tremendously over its lifetime and the need for standardized release engineering procedures has never been more apparent. This will become even more important as FreeBSD is ported to new platforms. [[future]] == Future Directions It is imperative for our release engineering activities to scale with our growing userbase. Along these lines we are working very hard to document the procedures involved in producing FreeBSD releases. * _Parallelism_ - Certain portions of the release build are actually "embarrassingly parallel". Most of the tasks are very I/O intensive, so having multiple high-speed disk drives is actually more important than using multiple processors in speeding up the `make release` process. If multiple disks are used for different hierarchies in the man:chroot[2] environment, then the CVS checkout of the [.filename]#ports# and [.filename]#doc# trees can be happening simultaneously as the `make world` on another disk. Using a RAID solution (hardware or software) can significantly decrease the overall build time. * _Cross-building releases_ - Building IA-64 or Alpha release on x86 hardware? `make TARGET=ia64 release`. * _Regression Testing_ - We need better automated correctness testing for FreeBSD. * _Installation Tools_ - Our installation program has long since outlived its intended life span. Several projects are under development to provide a more advanced installation mechanism. The libh project was one such project that aimed to provide an intelligent new package framework and GUI installation program. [[ackno]] == Acknowledgements I would like to thank Jordan Hubbard for giving me the opportunity to take on some of the release engineering responsibilities for FreeBSD 4.4 and also for all of his work throughout the years making FreeBSD what it is today. Of course the release would not have been possible without all of the release-related work done by `{asami}`, `{steve}`, `{bmah}`, `{nik}`, `{obrien}`, `{kris}`, `{jhb}` and the rest of the FreeBSD development community. I would also like to thank `{rgrimes}`, `{phk}`, and others who worked on the release engineering tools in the very early days of FreeBSD. This article was influenced by release engineering documents from the CSRG footnote:[Marshall Kirk McKusick, Michael J. Karels, and Keith Bostic: link:http://docs.FreeBSD.org/44doc/papers/releng.html[The Release Engineering of 4.3BSD]] , the NetBSD Project, footnote:[NetBSD Developer Documentation: Release Engineering http://www.NetBSD.org/developers/releng/index.html] , and John Baldwin's proposed release engineering process notes. footnote:[John Baldwin's FreeBSD Release Engineering Proposal https://people.FreeBSD.org/~jhb/docs/releng.txt] diff --git a/documentation/content/en/articles/remote-install/_index.adoc b/documentation/content/en/articles/remote-install/_index.adoc index 3883615121..ba9bf48256 100644 --- a/documentation/content/en/articles/remote-install/_index.adoc +++ b/documentation/content/en/articles/remote-install/_index.adoc @@ -1,395 +1,395 @@ --- title: Remote Installation of the FreeBSD Operating System Without a Remote Console authors: - author: Daniel Gerzo email: danger@FreeBSD.org copyright: 2008-2021 The FreeBSD Documentation Project description: Describes the remote installation of the FreeBSD operating system when the console of the remote system is unavailable trademarks: ["freebsd", "general"] tags: ["Remote", "Installation", "FreeBSD"] --- = Remote Installation of the FreeBSD Operating System Without a Remote Console :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/remote-install/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract This article documents the remote installation of the FreeBSD operating system when the console of the remote system is unavailable. The main idea behind this article is the result of a collaboration with `{mm}` with valuable input provided by `{pjd}`. ''' toc::[] [[background]] == Background There are many server hosting providers in the world, but very few of them are officially supporting FreeBSD. They usually provide support for a Linux(R) distribution to be installed on the servers they offer. In some cases, these companies will install your preferred Linux(R) distribution if you request it. Using this option, we will attempt to install FreeBSD. In other cases, they may offer a rescue system which would be used in an emergency. It is possible to use this for our purposes as well. This article covers the basic installation and configuration steps required to bootstrap a remote installation of FreeBSD with RAID-1 and ZFS capabilities. [[intro]] == Introduction This section will summarize the purpose of this article and better explain what is covered herein. The instructions included in this article will benefit those using services provided by colocation facilities not supporting FreeBSD. [.procedure] ==== -. As we have mentioned in the crossref:remote-install[background] section, many of the reputable server hosting companies provide some kind of rescue system, which is booted from their LAN and accessible over SSH. They usually provide this support to help their customers fix broken operating systems. As this article will explain, it is possible to install FreeBSD with the help of these rescue systems. +. As we have mentioned in the crossref:remote-install[background, Background] section, many of the reputable server hosting companies provide some kind of rescue system, which is booted from their LAN and accessible over SSH. They usually provide this support to help their customers fix broken operating systems. As this article will explain, it is possible to install FreeBSD with the help of these rescue systems. + . The next section of this article will describe how to configure, and build minimalistic FreeBSD on the local machine. That version will eventually be running on the remote machine from a ramdisk, which will allow us to install a complete FreeBSD operating system from an FTP mirror using the sysinstall utility. . The rest of this article will describe the installation procedure itself, as well as the configuration of the ZFS file system. ==== [[requirements]] === Requirements To continue successfully, you must: * Have a network accessible operating system with SSH access * Understand the FreeBSD installation process * Be familiar with the man:sysinstall[8] utility * Have the FreeBSD installation SO image or CD handy [[preparation]] == Preparation - mfsBSD Before FreeBSD may be installed on the target system, it is necessary to build the minimal FreeBSD operating system image which will boot from the hard drive. This way the new system can be accessed from the network, and the rest of the installation can be done without remote access to the system console. The mfsBSD tool-set can be used to build a tiny FreeBSD image. As the name of mfsBSD suggests ("mfs" means "memory file system"), the resulting image runs entirely from a ramdisk. Thanks to this feature, the manipulation of hard drives will not be limited, therefore it will be possible to install a complete FreeBSD operating system. The mfsBSD http://mfsbsd.vx.sk/[home page] includes pointers to the latest release of the toolset. Please note that the internals of mfsBSD and how it all fits together is beyond the scope of this article. The interested reader should consult the original documentation of mfsBSD for more details. Download and extract the latest mfsBSD release and change your working directory to the directory where the mfsBSD scripts will reside: [source,shell] .... # fetch http://mfsbsd.vx.sk/release/mfsbsd-2.1.tar.gz # tar xvzf mfsbsd-2.1.tar.gz # cd mfsbsd-2.1/ .... [[mfsbsd-config]] === Configuration of mfsBSD Before booting mfsBSD, a few important configuration options have to be set. The most important that we have to get right is, naturally, the network setup. The most suitable method to configure networking options depends on whether we know beforehand the type of the network interface we will use, and the network interface driver to be loaded for our hardware. We will see how mfsBSD can be configured in either case. Another important thing to set is the `root` password. This can be done by editing [.filename]#conf/loader.conf#. Please see the included comments. ==== The [.filename]#conf/interfaces.conf# method When the installed network interface card is unknown, it is possible to use the auto-detection features of mfsBSD. The startup scripts of mfsBSD can detect the correct driver to use, based on the MAC address of the interface, if we set the following options in [.filename]#conf/interfaces.conf#: [.programlisting] .... mac_interfaces="ext1" ifconfig_ext1_mac="00:00:00:00:00:00" ifconfig_ext1="inet 192.168.0.2/24" .... Do not forget to add the `defaultrouter` information to [.filename]#conf/rc.conf#: [.programlisting] .... defaultrouter="192.168.0.1" .... ==== The [.filename]#conf/rc.conf# Method When the network interface driver is known, it is more convenient to use [.filename]#conf/rc.conf# for networking options. The syntax of this file is the same as the one used in the standard man:rc.conf[5] file of FreeBSD. For example, if you know that a man:re[4] network interface is going to be available, you can set the following options in [.filename]#conf/rc.conf#: [.programlisting] .... defaultrouter="192.168.0.1" ifconfig_re0="inet 192.168.0.2/24" .... [[mfsbsd-build]] === Building an mfsBSD Image The process of building an mfsBSD image is pretty straightforward. The first step is to mount the FreeBSD installation CD, or the installation ISO image to [.filename]#/cdrom#. For the sake of example, in this article we will assume that you have downloaded the FreeBSD 10.1-RELEASE ISO. Mounting this ISO image to the [.filename]#/cdrom# directory is easy with the man:mdconfig[8] utility: [source,shell] .... # mdconfig -a -t vnode -u 10 -f FreeBSD-10.1-RELEASE-amd64-disc1.iso # mount_cd9660 /dev/md10 /cdrom .... Since the recent FreeBSD releases do not contain regular distribution sets, it is required to extract the FreeBSD distribution files from the distribution archives located on the ISO image: [source,shell] .... # mkdir DIST # tar -xvf /cdrom/usr/freebsd-dist/base.txz -C DIST # tar -xvf /cdrom/usr/freebsd-dist/kernel.txz -C DIST .... Next, build the bootable mfsBSD image: [source,shell] .... # make BASE=DIST .... [NOTE] ==== The above `make` has to be run from the top level of the mfsBSD directory tree, for example [.filename]#~/mfsbsd-2.1/#. ==== === Booting mfsBSD Now that the mfsBSD image is ready, it must be uploaded to the remote system running a live rescue system or pre-installed Linux(R) distribution. The most suitable tool for this task is scp: [source,shell] .... # scp disk.img root@192.168.0.2:. .... To boot mfsBSD image properly, it must be placed on the first (bootable) device of the given machine. This may be accomplished using this example providing that [.filename]#sda# is the first bootable disk device: [source,shell] .... # dd if=/root/disk.img of=/dev/sda bs=1m .... If all went well, the image should now be in the MBR of the first device and the machine can be rebooted. Watch for the machine to boot up properly with the man:ping[8] tool. Once it has came back on-line, it should be possible to access it over man:ssh[1] as user `root` with the configured password. [[installation]] == Installation of the FreeBSD Operating System The mfsBSD has been successfully booted and it should be possible to log in through man:ssh[1]. This section will describe how to create and label slices, set up `gmirror` for RAID-1, and how to use `sysinstall` to install a minimal distribution of the FreeBSD operating system. === Preparation of Hard Drives The first task is to allocate disk space for FreeBSD, i.e.: to create slices and partitions. Obviously, the currently running system is fully loaded in system memory and therefore there will be no problems with manipulating hard drives. To complete this task, it is possible to use either `sysinstall` or man:fdisk[8] in conjunction to man:bsdlabel[8]. At the start, mark all system disks as empty. Repeat the following command for each hard drive: [source,shell] .... # dd if=/dev/zero of=/dev/ad0 count=2 .... Next, create slices and label them with your preferred tool. While it is considered easier to use `sysinstall`, a powerful and also probably less buggy method will be to use standard text-based UNIX(R) tools, such as man:fdisk[8] and man:bsdlabel[8], which will also be covered in this section. The former option is well documented in the extref:{handbook}[Installing FreeBSD, install-steps] chapter of the FreeBSD Handbook. As it was mentioned in the introduction, this article will present how to set up a system with RAID-1 and ZFS capabilities. Our set up will consist of a small man:gmirror[8] mirrored [.filename]#/# (root), [.filename]#/usr# and [.filename]#/var# dataset, and the rest of the disk space will be allocated for a man:zpool[8] mirrored ZFS file system. Please note, that the ZFS file system will be configured after the FreeBSD operating system is successfully installed and booted. The following example will describe how to create slices and labels, initialize man:gmirror[8] on each partition and how to create a UFS2 file system in each mirrored partition: [source,shell] .... # fdisk -BI /dev/ad0 <.> # fdisk -BI /dev/ad1 # bsdlabel -wB /dev/ad0s1 <.> # bsdlabel -wB /dev/ad1s1 # bsdlabel -e /dev/ad0s1 <.> # bsdlabel /dev/ad0s1 > /tmp/bsdlabel.txt && bsdlabel -R /dev/ad1s1 /tmp/bsdlabel.txt <.> # gmirror label root /dev/ad[01]s1a <.> # gmirror label var /dev/ad[01]s1d # gmirror label usr /dev/ad[01]s1e # gmirror label -F swap /dev/ad[01]s1b <.> # newfs /dev/mirror/root <.> # newfs /dev/mirror/var # newfs /dev/mirror/usr .... <.> Create a slice covering the entire disk and initialize the boot code contained in sector 0 of the given disk. Repeat this command for all hard drives in the system. <.> Write a standard label for each disk including the bootstrap code. <.> Now, manually edit the label of the given disk. Refer to the man:bsdlabel[8] manual page to find out how to create partitions. Create partitions `a` for [.filename]#/# (root) file system, `b` for swap, `d` for [.filename]#/var#, `e` for [.filename]#/usr# and finally `f` which will later be used for ZFS. <.> Import the recently created label for the second hard drive, so both hard drives will be labeled in the same way. <.> Initialize man:gmirror[8] on each partition. <.> Note that `-F` is used for the swap partition. This instructs man:gmirror[8] to assume that the device is in the consistent state after the power/system failure. <.> Create a UFS2 file system on each mirrored partition. === System Installation This is the most important part. This section will describe how to actually install the minimal distribution of FreeBSD on the hard drives that we have prepared in the previous section. To accomplish this goal, all file systems need to be mounted so `sysinstall` may write the contents of FreeBSD to the hard drives: [source,shell] .... # mount /dev/mirror/root /mnt # mkdir /mnt/var /mnt/usr # mount /dev/mirror/var /mnt/var # mount /dev/mirror/usr /mnt/usr .... When you are done, start man:sysinstall[8]. Select the [.guimenuitem]#Custom# installation from the main menu. Select [.guimenuitem]#Options# and press kbd:[Enter]. With the help of arrow keys, move the cursor on the `Install Root` item, press kbd:[Space] and change it to [.filename]#/mnt#. Press kbd:[Enter] to submit your changes and exit the [.guimenuitem]#Options# menu by pressing kbd:[q]. [WARNING] ==== Note that this step is very important and if skipped, `sysinstall` will be unable to install FreeBSD. ==== Go to the [.guimenuitem]#Distributions# menu, move the cursor with the arrow keys to `Minimal`, and check it by pressing kbd:[Space]. This article uses the Minimal distribution to save network traffic, because the system itself will be installed over ftp. Exit this menu by choosing `Exit`. [NOTE] ==== The [.guimenuitem]#Partition# and [.guimenuitem]#Label# menus will be skipped, as these are useless now. ==== In the [.guimenuitem]#Media# menu, select `FTP`. Select the nearest mirror and let `sysinstall` assume that the network is already configured. You will be returned back to the [.guimenuitem]#Custom# menu. Finally, perform the system installation by selecting the last option, [.guimenuitem]#Commit#. Exit `sysinstall` when it finishes the installation. === Post Installation Steps The FreeBSD operating system should be installed now; however, the process is not finished yet. It is necessary to perform some post installation steps to allow FreeBSD to boot in the future and to be able to log in to the system. You must now man:chroot[8] into the freshly installed system to finish the installation. Use the following command: [source,shell] .... # chroot /mnt .... To complete our goal, perform these steps: * Copy the `GENERIC` kernel to the [.filename]#/boot/kernel# directory: + [source,shell] .... # cp -Rp /boot/GENERIC/* /boot/kernel .... * Create the [.filename]#/etc/rc.conf#, [.filename]#/etc/resolv.conf# and [.filename]#/etc/fstab# files. Do not forget to properly set the network information and to enable sshd in [.filename]#/etc/rc.conf#. The contents of [.filename]#/etc/fstab# will be similar to the following: + [.programlisting] .... # Device Mountpoint FStype Options Dump Pass# /dev/mirror/swap none swap sw 0 0 /dev/mirror/root / ufs rw 1 1 /dev/mirror/usr /usr ufs rw 2 2 /dev/mirror/var /var ufs rw 2 2 /dev/cd0 /cdrom cd9660 ro,noauto 0 0 .... * Create [.filename]#/boot/loader.conf# with the following contents: + [.programlisting] .... geom_mirror_load="YES" zfs_load="YES" .... * Perform the following command, which will make ZFS available on the next boot: + [source,shell] .... # sysrc zfs_enable="YES" .... * Add additional users to the system using the man:adduser[8] tool. Do not forget to add a user to the `wheel` group so you may obtain root access after the reboot. * Double-check all your settings. The system should now be ready for the next boot. Use the man:reboot[8] command to reboot your system. [[zfs]] == ZFS If your system survived the reboot, it should now be possible to log in. Welcome to the fresh FreeBSD installation, performed remotely without the use of a remote console! The only remaining step is to configure man:zpool[8] and create some man:zfs[8] file systems. Creating and administering ZFS is very straightforward. First, create a mirrored pool: [source,shell] .... # zpool create tank mirror /dev/ad[01]s1f .... Next, create some file systems: [source,shell] .... # zfs create tank/ports # zfs create tank/src # zfs set compression=gzip tank/ports # zfs set compression=on tank/src # zfs set mountpoint=/usr/ports tank/ports # zfs set mountpoint=/usr/src tank/src .... That is all. If you are interested in more details about ZFS on FreeBSD, please refer to the https://wiki.freebsd.org/ZFS[ZFS] section of the FreeBSD Wiki. diff --git a/documentation/content/en/articles/solid-state/_index.adoc b/documentation/content/en/articles/solid-state/_index.adoc index 40088623e3..3ea3224636 100644 --- a/documentation/content/en/articles/solid-state/_index.adoc +++ b/documentation/content/en/articles/solid-state/_index.adoc @@ -1,327 +1,327 @@ --- title: FreeBSD and Solid State Devices authors: - author: John Kozubik email: john@kozubik.com copyright: 2001 - 2021 The FreeBSD Documentation Project description: The use of solid state disk devices in FreeBSD trademarks: ["freebsd", "general"] tags: ["Solid State", "embedded", "FreeBSD"] --- = FreeBSD and Solid State Devices :doctype: article :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :source-highlighter: rouge :experimental: :images-path: articles/solid-state/ ifdef::env-beastie[] ifdef::backend-html5[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] :imagesdir: ../../../images/{images-path} endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [.abstract-title] Abstract This article covers the use of solid state disk devices in FreeBSD to create embedded systems. Embedded systems have the advantage of increased stability due to the lack of integral moving parts (hard drives). Account must be taken, however, for the generally low disk space available in the system and the durability of the storage medium. Specific topics to be covered include the types and attributes of solid state media suitable for disk use in FreeBSD, kernel options that are of interest in such an environment, the [.filename]#rc.initdiskless# mechanisms that automate the initialization of such systems and the need for read-only filesystems, and building filesystems from scratch. The article will conclude with some general strategies for small and read-only FreeBSD environments. ''' toc::[] [[intro]] == Solid State Disk Devices The scope of this article will be limited to solid state disk devices made from flash memory. Flash memory is a solid state memory (no moving parts) that is non-volatile (the memory maintains data even after all power sources have been disconnected). Flash memory can withstand tremendous physical shock and is reasonably fast (the flash memory solutions covered in this article are slightly slower than a EIDE hard disk for write operations, and much faster for read operations). One very important aspect of flash memory, the ramifications of which will be discussed later in this article, is that each sector has a limited rewrite capacity. You can only write, erase, and write again to a sector of flash memory a certain number of times before the sector becomes permanently unusable. Although many flash memory products automatically map bad blocks, and although some even distribute write operations evenly throughout the unit, the fact remains that there exists a limit to the amount of writing that can be done to the device. Competitive units have between 1,000,000 and 10,000,000 writes per sector in their specification. This figure varies due to the temperature of the environment. Specifically, we will be discussing ATA compatible compact-flash units, which are quite popular as storage media for digital cameras. Of particular interest is the fact that they pin out directly to the IDE bus and are compatible with the ATA command set. Therefore, with a very simple and low-cost adaptor, these devices can be attached directly to an IDE bus in a computer. Once implemented in this manner, operating systems such as FreeBSD see the device as a normal hard disk (albeit small). Other solid state disk solutions do exist, but their expense, obscurity, and relative unease of use places them beyond the scope of this article. [[kernel]] == Kernel Options A few kernel options are of specific interest to those creating an embedded FreeBSD system. All embedded FreeBSD systems that use flash memory as system disk will be interested in memory disks and memory filesystems. As a result of the limited number of writes that can be done to flash memory, the disk and the filesystems on the disk will most likely be mounted read-only. In this environment, filesystems such as [.filename]#/tmp# and [.filename]#/var# are mounted as memory filesystems to allow the system to create logs and update counters and temporary files. Memory filesystems are a critical component to a successful solid state FreeBSD implementation. You should make sure the following lines exist in your kernel configuration file: [.programlisting] .... options MD_ROOT # md device usable as a potential root device .... [[ro-fs]] == The `rc` Subsystem and Read-Only Filesystems The post-boot initialization of an embedded FreeBSD system is controlled by [.filename]#/etc/rc.initdiskless#. [.filename]#/etc/rc.d/var# mounts [.filename]#/var# as a memory filesystem, makes a configurable list of directories in [.filename]#/var# with the man:mkdir[1] command, and changes modes on some of those directories. In the execution of [.filename]#/etc/rc.d/var#, one other [.filename]#rc.conf# variable comes into play - `varsize`. A [.filename]#/var# partition is created by [.filename]#/etc/rc.d/var# based on the value of this variable in [.filename]#rc.conf#: [.programlisting] .... varsize=8192 .... Remember that this value is in sectors by default. The fact that [.filename]#/var# is a read-write filesystem is an important distinction, as the [.filename]#/# partition (and any other partitions you may have on your flash media) should be mounted read-only. -Remember that in crossref:solid-state[intro] we detailed the limitations of flash memory - specifically the limited write capability. +Remember that in crossref:solid-state[intro, Solid State Disk Devices] we detailed the limitations of flash memory - specifically the limited write capability. The importance of not mounting filesystems on flash media read-write, and the importance of not using a swap file, cannot be overstated. A swap file on a busy system can burn through a piece of flash media in less than one year. Heavy logging or temporary file creation and destruction can do the same. Therefore, in addition to removing the `swap` entry from your [.filename]#/etc/fstab#, you should also change the Options field for each filesystem to `ro` as follows: [.programlisting] .... # Device Mountpoint FStype Options Dump Pass# /dev/ad0s1a / ufs ro 1 1 .... A few applications in the average system will immediately begin to fail as a result of this change. For instance, cron will not run properly as a result of missing cron tabs in the [.filename]#/var# created by [.filename]#/etc/rc.d/var#, and syslog and dhcp will encounter problems as well as a result of the read-only filesystem and missing items in the [.filename]#/var# that [.filename]#/etc/rc.d/var# has created. These are only temporary problems though, and are addressed, along with solutions to the execution of other common software packages in -crossref:solid-state[strategies]. +crossref:solid-state[strategies, System Strategies for Small and Read Only Environments]. An important thing to remember is that a filesystem that was mounted read-only with [.filename]#/etc/fstab# can be made read-write at any time by issuing the command: [source,shell] .... # /sbin/mount -uw partition .... and can be toggled back to read-only with the command: [source,shell] .... # /sbin/mount -ur partition .... == Building a File System from Scratch Since ATA compatible compact-flash cards are seen by FreeBSD as normal IDE hard drives, you could theoretically install FreeBSD from the network using the kern and mfsroot floppies or from a CD. However, even a small installation of FreeBSD using normal installation procedures can produce a system in size of greater than 200 megabytes. Most people will be using smaller flash memory devices (128 megabytes is considered fairly large - 32 or even 16 megabytes is common), so an installation using normal mechanisms is not possible-there is simply not enough disk space for even the smallest of conventional installations. The easiest way to overcome this space limitation is to install FreeBSD using conventional means to a normal hard disk. After the installation is complete, pare down the operating system to a size that will fit onto your flash media, then tar the entire filesystem. The following steps will guide you through the process of preparing a piece of flash memory for your tarred filesystem. Remember, because a normal installation is not being performed, operations such as partitioning, labeling, file-system creation, etc. need to be performed by hand. In addition to the kern and mfsroot floppy disks, you will also need to use the fixit floppy. [.procedure] ==== . Partitioning Your Flash Media Device + After booting with the kern and mfsroot floppies, choose `custom` from the installation menu. In the custom installation menu, choose `partition`. In the partition menu, you should delete all existing partitions using kbd:[d]. After deleting all existing partitions, create a partition using kbd:[c] and accept the default value for the size of the partition. When asked for the type of the partition, make sure the value is set to `165`. Now write this partition table to the disk by pressing kbd:[w] (this is a hidden option on this screen). If you are using an ATA compatible compact flash card, you should choose the FreeBSD Boot Manager. Now press kbd:[q] to quit the partition menu. You will be shown the boot manager menu once more - repeat the choice you made earlier. . Creating Filesystems on Your Flash Memory Device + Exit the custom installation menu, and from the main installation menu choose the `fixit` option. After entering the fixit environment, enter the following command: + [source,shell] .... # disklabel -e /dev/ad0c .... + At this point you will have entered the vi editor under the auspices of the disklabel command. Next, you need to add an `a:` line at the end of the file. This `a:` line should look like: + [.programlisting] .... a: 123456 0 4.2BSD 0 0 .... + Where _123456_ is a number that is exactly the same as the number in the existing `c:` entry for size. Basically you are duplicating the existing `c:` line as an `a:` line, making sure that fstype is `4.2BSD`. Save the file and exit. + [source,shell] .... # disklabel -B -r /dev/ad0c # newfs /dev/ad0a .... . Placing Your Filesystem on the Flash Media + Mount the newly prepared flash media: + [source,shell] .... # mount /dev/ad0a /flash .... + Bring this machine up on the network so we may transfer our tar file and explode it onto our flash media filesystem. One example of how to do this is: + [source,shell] .... # ifconfig xl0 192.168.0.10 netmask 255.255.255.0 # route add default 192.168.0.1 .... + Now that the machine is on the network, transfer your tar file. You may be faced with a bit of a dilemma at this point - if your flash memory part is 128 megabytes, for instance, and your tar file is larger than 64 megabytes, you cannot have your tar file on the flash media at the same time as you explode it - you will run out of space. One solution to this problem, if you are using FTP, is to untar the file while it is transferred over FTP. If you perform your transfer in this manner, you will never have the tar file and the tar contents on your disk at the same time: + [source,shell] .... ftp> get tarfile.tar "| tar xvf -" .... + If your tarfile is gzipped, you can accomplish this as well: + [source,shell] .... ftp> get tarfile.tar "| zcat | tar xvf -" .... + After the contents of your tarred filesystem are on your flash memory filesystem, you can unmount the flash memory and reboot: + [source,shell] .... # cd / # umount /flash # exit .... + Assuming that you configured your filesystem correctly when it was built on the normal hard disk (with your filesystems mounted read-only, and with the necessary options compiled into the kernel) you should now be successfully booting your FreeBSD embedded system. ==== [[strategies]] == System Strategies for Small and Read Only Environments -In crossref:solid-state[ro-fs], it was pointed out that the [.filename]#/var# filesystem constructed by [.filename]#/etc/rc.d/var# and the presence of a read-only root filesystem causes problems with many common software packages used with FreeBSD. +In crossref:solid-state[ro-fs, The `rc` Subsystem and Read-Only Filesystems], it was pointed out that the [.filename]#/var# filesystem constructed by [.filename]#/etc/rc.d/var# and the presence of a read-only root filesystem causes problems with many common software packages used with FreeBSD. In this article, suggestions for successfully running cron, syslog, ports installations, and the Apache web server will be provided. === Cron Upon boot, [.filename]#/var# gets populated by [.filename]#/etc/rc.d/var# using the list from [.filename]#/etc/mtree/BSD.var.dist#, so the [.filename]#cron#, [.filename]#cron/tabs#, [.filename]#at#, and a few other standard directories get created. However, this does not solve the problem of maintaining cron tabs across reboots. When the system reboots, the [.filename]#/var# filesystem that is in memory will disappear and any cron tabs you may have had in it will also disappear. Therefore, one solution would be to create cron tabs for the users that need them, mount your [.filename]#/# filesystem as read-write and copy those cron tabs to somewhere safe, like [.filename]#/etc/tabs#, then add a line to the end of [.filename]#/etc/rc.initdiskless# that copies those crontabs into [.filename]#/var/cron/tabs# after that directory has been created during system initialization. You may also need to add a line that changes modes and permissions on the directories you create and the files you copy with [.filename]#/etc/rc.initdiskless#. === Syslog [.filename]#syslog.conf# specifies the locations of certain log files that exist in [.filename]#/var/log#. These files are not created by [.filename]#/etc/rc.d/var# upon system initialization. Therefore, somewhere in [.filename]#/etc/rc.d/var#, after the section that creates the directories in [.filename]#/var#, you will need to add something like this: [source,shell] .... # touch /var/log/security /var/log/maillog /var/log/cron /var/log/messages # chmod 0644 /var/log/* .... === Ports Installation Before discussing the changes necessary to successfully use the ports tree, a reminder is necessary regarding the read-only nature of your filesystems on the flash media. Since they are read-only, you will need to temporarily mount them read-write -using the mount syntax shown in crossref:solid-state[ro-fs]. +using the mount syntax shown in crossref:solid-state[ro-fs, The `rc` Subsystem and Read-Only Filesystems]. You should always remount those filesystems read-only when you are done with any maintenance - unnecessary writes to the flash media could considerably shorten its lifespan. To make it possible to enter a ports directory and successfully run `make install`, we must create a packages directory on a non-memory filesystem that will keep track of our packages across reboots. As it is necessary to mount your filesystems as read-write for the installation of a package anyway, it is sensible to assume that an area on the flash media can also be used for package information to be written to. First, create a package database directory. This is normally in [.filename]#/var/db/pkg#, but we cannot place it there as it will disappear every time the system is booted. [source,shell] .... # mkdir /etc/pkg .... Now, add a line to [.filename]#/etc/rc.d/var# that links the [.filename]#/etc/pkg# directory to [.filename]#/var/db/pkg#. An example: [source,shell] .... # ln -s /etc/pkg /var/db/pkg .... Now, any time that you mount your filesystems as read-write and install a package, the `make install` will work, and package information will be written successfully to [.filename]#/etc/pkg# (because the filesystem will, at that time, be mounted read-write) which will always be available to the operating system as [.filename]#/var/db/pkg#. === Apache Web Server [NOTE] ==== The steps in this section are only necessary if Apache is set up to write its pid or log information outside of [.filename]#/var#. By default, Apache keeps its pid file in [.filename]#/var/run/httpd.pid# and its log files in [.filename]#/var/log#. ==== It is now assumed that Apache keeps its log files in a directory [.filename]#apache_log_dir# outside of [.filename]#/var#. When this directory lives on a read-only filesystem, Apache will not be able to save any log files, and may have problems working. If so, it is necessary to add a new directory to the list of directories in [.filename]#/etc/rc.d/var# to create in [.filename]#/var#, and to link [.filename]#apache_log_dir# to [.filename]#/var/log/apache#. It is also necessary to set permissions and ownership on this new directory. First, add the directory `log/apache` to the list of directories to be created in [.filename]#/etc/rc.d/var#. Second, add these commands to [.filename]#/etc/rc.d/var# after the directory creation section: [source,shell] .... # chmod 0774 /var/log/apache # chown nobody:nobody /var/log/apache .... Finally, remove the existing [.filename]#apache_log_dir# directory, and replace it with a link: [source,shell] .... # rm -rf apache_log_dir # ln -s /var/log/apache apache_log_dir .... diff --git a/documentation/content/en/books/arch-handbook/mac/_index.adoc b/documentation/content/en/books/arch-handbook/mac/_index.adoc index 73a27cdf0e..961774e323 100644 --- a/documentation/content/en/books/arch-handbook/mac/_index.adoc +++ b/documentation/content/en/books/arch-handbook/mac/_index.adoc @@ -1,5397 +1,5397 @@ --- title: Chapter 6. The TrustedBSD MAC Framework authors: - author: Chris Costello email: chris@FreeBSD.org - author: Robert Watson email: rwatson@FreeBSD.org prev: books/arch-handbook/sysinit next: books/arch-handbook/vm description: The TrustedBSD MAC Framework tags: ["TrustedBSD", "MAC"] showBookMenu: true weight: 7 path: "/books/arch-handbook/mac/" --- [[mac]] = The TrustedBSD MAC Framework :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 6 :partnums: :source-highlighter: rouge :experimental: :images-path: books/arch-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[mac-copyright]] == MAC Documentation Copyright This documentation was developed for the FreeBSD Project by Chris Costello at Safeport Network Services and Network Associates Laboratories, the Security Research Division of Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research program. Redistribution and use in source (SGML DocBook) and 'compiled' forms (SGML, HTML, PDF, PostScript, RTF and so forth) with or without modification, are permitted provided that the following conditions are met: . Redistributions of source code (SGML DocBook) must retain the above copyright notice, this list of conditions and the following disclaimer as the first lines of this file unmodified. . Redistributions in compiled form (transformed to other DTDs, converted to PDF, PostScript, RTF and other formats) must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. [IMPORTANT] ==== THIS DOCUMENTATION IS PROVIDED BY THE NETWORKS ASSOCIATES TECHNOLOGY, INC "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NETWORKS ASSOCIATES TECHNOLOGY, INC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==== [[mac-synopsis]] == Synopsis FreeBSD includes experimental support for several mandatory access control policies, as well as a framework for kernel security extensibility, the TrustedBSD MAC Framework. The MAC Framework is a pluggable access control framework, permitting new security policies to be easily linked into the kernel, loaded at boot, or loaded dynamically at run-time. The framework provides a variety of features to make it easier to implement new security policies, including the ability to easily tag security labels (such as confidentiality information) onto system objects. This chapter introduces the MAC policy framework and provides documentation for a sample MAC policy module. [[mac-introduction]] == Introduction The TrustedBSD MAC framework provides a mechanism to allow the compile-time or run-time extension of the kernel access control model. New system policies may be implemented as kernel modules and linked to the kernel; if multiple policy modules are present, their results will be composed. The MAC Framework provides a variety of access control infrastructure services to assist policy writers, including support for transient and persistent policy-agnostic object security labels. This support is currently considered experimental. This chapter provides information appropriate for developers of policy modules, as well as potential consumers of MAC-enabled environments, to learn about how the MAC Framework supports access control extension of the kernel. [[mac-background]] == Policy Background Mandatory Access Control (MAC), refers to a set of access control policies that are mandatorily enforced on users by the operating system. MAC policies may be contrasted with Discretionary Access Control (DAC) protections, by which non-administrative users may (at their discretion) protect objects. In traditional UNIX systems, DAC protections include file permissions and access control lists; MAC protections include process controls preventing inter-user debugging and firewalls. A variety of MAC policies have been formulated by operating system designers and security researches, including the Multi-Level Security (MLS) confidentiality policy, the Biba integrity policy, Role-Based Access Control (RBAC), Domain and Type Enforcement (DTE), and Type Enforcement (TE). Each model bases decisions on a variety of factors, including user identity, role, and security clearance, as well as security labels on objects representing concepts such as data sensitivity and integrity. The TrustedBSD MAC Framework is capable of supporting policy modules that implement all of these policies, as well as a broad class of system hardening policies, which may use existing security attributes, such as user and group IDs, as well as extended attributes on files, and other system properties. In addition, despite the name, the MAC Framework can also be used to implement purely discretionary policies, as policy modules are given substantial flexibility in how they authorize protections. [[mac-framework-kernel-arch]] == MAC Framework Kernel Architecture The TrustedBSD MAC Framework permits kernel modules to extend the operating system security policy, as well as providing infrastructure functionality required by many access control modules. If multiple policies are simultaneously loaded, the MAC Framework will usefully (for some definition of useful) compose the results of the policies. [[mac-framework-kernel-arch-elements]] === Kernel Elements The MAC Framework contains a number of kernel elements: * Framework management interfaces * Concurrency and synchronization primitives. * Policy registration * Extensible security label for kernel objects * Policy entry point composition operators * Label management primitives * Entry point API invoked by kernel services * Entry point API to policy modules * Entry points implementations (policy life cycle, object life cycle/label management, access control checks). * Policy-agnostic label-management system calls * `mac_syscall()` multiplex system call * Various security policies implemented as MAC policy modules [[mac-framework-kernel-arch-management]] === Framework Management Interfaces The TrustedBSD MAC Framework may be directly managed using sysctl's, loader tunables, and system calls. In most cases, sysctl's and loader tunables of the same name modify the same parameters, and control behavior such as enforcement of protections relating to various kernel subsystems. In addition, if MAC debugging support is compiled into the kernel, several counters will be maintained tracking label allocation. It is generally advisable that per-subsystem enforcement controls not be used to control policy behavior in production environments, as they broadly impact the operation of all active policies. Instead, per-policy controls should be preferred, as they provide greater granularity and greater operational consistency for policy modules. Loading and unloading of policy modules is performed using the system module management system calls and other system interfaces, including boot loader variables; policy modules will have the opportunity to influence load and unload events, including preventing undesired unloading of the policy. [[mac-framework-kernel-arch-synchronization]] === Policy List Concurrency and Synchronization As the set of active policies may change at run-time, and the invocation of entry points is non-atomic, synchronization is required to prevent loading or unloading of policies while an entry point invocation is in progress, freezing the set of active policies for the duration. This is accomplished by means of a framework busy count: whenever an entry point is entered, the busy count is incremented; whenever it is exited, the busy count is decremented. While the busy count is elevated, policy list changes are not permitted, and threads attempting to modify the policy list will sleep until the list is not busy. The busy count is protected by a mutex, and a condition variable is used to wake up sleepers waiting on policy list modifications. One side effect of this synchronization model is that recursion into the MAC Framework from within a policy module is permitted, although not generally used. Various optimizations are used to reduce the overhead of the busy count, including avoiding the full cost of incrementing and decrementing if the list is empty or contains only static entries (policies that are loaded before the system starts, and cannot be unloaded). A compile-time option is also provided which prevents any change in the set of loaded policies at run-time, which eliminates the mutex locking costs associated with supporting dynamically loaded and unloaded policies as synchronization is no longer required. As the MAC Framework is not permitted to block in some entry points, a normal sleep lock cannot be used; as a result, it is possible for the load or unload attempt to block for a substantial period of time waiting for the framework to become idle. [[mac-framework-kernel-arch-label-synchronization]] === Label Synchronization As kernel objects of interest may generally be accessed from more than one thread at a time, and simultaneous entry of more than one thread into the MAC Framework is permitted, security attribute storage maintained by the MAC Framework is carefully synchronized. In general, existing kernel synchronization on kernel object data is used to protect MAC Framework security labels on the object: for example, MAC labels on sockets are protected using the existing socket mutex. Likewise, semantics for concurrent access are generally identical to those of the container objects: for credentials, copy-on-write semantics are maintained for label contents as with the remainder of the credential structure. The MAC Framework asserts necessary locks on objects when invoked with an object reference. Policy authors must be aware of these synchronization semantics, as they will sometimes limit the types of accesses permitted on labels: for example, when a read-only reference to a credential is passed to a policy via an entry point, only read operations are permitted on the label state attached to the credential. [[mac-framework-kernel-arch-policy-synchronization]] === Policy Synchronization and Concurrency Policy modules must be written to assume that many kernel threads may simultaneously enter one more policy entry points due to the parallel and preemptive nature of the FreeBSD kernel. If the policy module makes use of mutable state, this may require the use of synchronization primitives within the policy to prevent inconsistent views on that state resulting in incorrect operation of the policy. Policies will generally be able to make use of existing FreeBSD synchronization primitives for this purpose, including mutexes, sleep locks, condition variables, and counting semaphores. However, policies should be written to employ these primitives carefully, respecting existing kernel lock orders, and recognizing that some entry points are not permitted to sleep, limiting the use of primitives in those entry points to mutexes and wakeup operations. When policy modules call out to other kernel subsystems, they will generally need to release any in-policy locks in order to avoid violating the kernel lock order or risking lock recursion. This will maintain policy locks as leaf locks in the global lock order, helping to avoid deadlock. [[mac-framework-kernel-arch-registration]] === Policy Registration The MAC Framework maintains two lists of active policies: a static list, and a dynamic list. The lists differ only with regards to their locking semantics: an elevated reference count is not required to make use of the static list. When kernel modules containing MAC Framework policies are loaded, the policy module will use `SYSINIT` to invoke a registration function; when a policy module is unloaded, `SYSINIT` will likewise invoke a de-registration function. Registration may fail if a policy module is loaded more than once, if insufficient resources are available for the registration (for example, the policy might require labeling and insufficient labeling state might be available), or other policy prerequisites might not be met (some policies may only be loaded prior to boot). Likewise, de-registration may fail if a policy is flagged as not unloadable. [[mac-framework-kernel-arch-entrypoints]] === Entry Points Kernel services interact with the MAC Framework in two ways: they invoke a series of APIs to notify the framework of relevant events, and they provide a policy-agnostic label structure pointer in security-relevant objects. The label pointer is maintained by the MAC Framework via label management entry points, and permits the Framework to offer a labeling service to policy modules through relatively non-invasive changes to the kernel subsystem maintaining the object. For example, label pointers have been added to processes, process credentials, sockets, pipes, vnodes, Mbufs, network interfaces, IP reassembly queues, and a variety of other security-relevant structures. Kernel services also invoke the MAC Framework when they perform important security decisions, permitting policy modules to augment those decisions based on their own criteria (possibly including data stored in security labels). Most of these security critical decisions will be explicit access control checks; however, some affect more general decision functions such as packet matching for sockets and label transition at program execution. [[mac-framework-kernel-arch-composition]] === Policy Composition When more than one policy module is loaded into the kernel at a time, the results of the policy modules will be composed by the framework using a composition operator. This operator is currently hard-coded, and requires that all active policies must approve a request for it to return success. As policies may return a variety of error conditions (success, access denied, object does not exist, ...), a precedence operator selects the resulting error from the set of errors returned by policies. In general, errors indicating that an object does not exist will be preferred to errors indicating that access to an object is denied. While it is not guaranteed that the resulting composition will be useful or secure, we have found that it is for many useful selections of policies. For example, traditional trusted systems often ship with two or more policies using a similar composition. [[mac-framework-kernel-arch-labels]] === Labeling Support As many interesting access control extensions rely on security labels on objects, the MAC Framework provides a set of policy-agnostic label management system calls covering a variety of user-exposed objects. Common label types include partition identifiers, sensitivity labels, integrity labels, compartments, domains, roles, and types. By policy agnostic, we mean that policy modules are able to completely define the semantics of meta-data associated with an object. Policy modules participate in the internalization and externalization of string-based labels provides by user applications, and can expose multiple label elements to applications if desired. In-memory labels are stored in slab-allocated `struct label`, which consists of a fixed-length array of unions, each holding a `void *` pointer and a `long`. Policies registering for label storage will be assigned a "slot" identifier, which may be used to dereference the label storage. The semantics of the storage are left entirely up to the policy module: modules are provided with a variety of entry points associated with the kernel object life cycle, including initialization, association/creation, and destruction. Using these interfaces, it is possible to implement reference counting and other storage models. Direct access to the object structure is generally not required by policy modules to retrieve a label, as the MAC Framework generally passes both a pointer to the object and a direct pointer to the object's label into entry points. The primary exception to this rule is the process credential, which must be manually dereferenced to access the credential label. This may change in future revisions of the MAC Framework. Initialization entry points frequently include a sleeping disposition flag indicating whether or not an initialization is permitted to sleep; if sleeping is not permitted, a failure may be returned to cancel allocation of the label (and hence object). This may occur, for example, in the network stack during interrupt handling, where sleeping is not permitted, or while the caller holds a mutex. Due to the performance cost of maintaining labels on in-flight network packets (Mbufs), policies must specifically declare a requirement that Mbuf labels be allocated. Dynamically loaded policies making use of labels must be able to handle the case where their init function has not been called on an object, as objects may already exist when the policy is loaded. The MAC Framework guarantees that uninitialized label slots will hold a 0 or NULL value, which policies may use to detect uninitialized values. However, as allocation of Mbuf labels is conditional, policies must also be able to handle a NULL label pointer for Mbufs if they have been loaded dynamically. In the case of file system labels, special support is provided for the persistent storage of security labels in extended attributes. Where available, extended attribute transactions are used to permit consistent compound updates of security labels on vnodes--currently this support is present only in the UFS2 file system. Policy authors may choose to implement multilabel file system object labels using one (or more) extended attributes. For efficiency reasons, the vnode label (`v_label`) is a cache of any on-disk label; policies are able to load values into the cache when the vnode is instantiated, and update the cache as needed. As a result, the extended attribute need not be directly accessed with every access control check. [NOTE] ==== Currently, if a labeled policy permits dynamic unloading, its state slot cannot be reclaimed, which places a strict (and relatively low) bound on the number of unload-reload operations for labeled policies. ==== [[mac-framework-kernel-arch-syscalls]] === System Calls The MAC Framework implements a number of system calls: most of these calls support the policy-agnostic label retrieval and manipulation APIs exposed to user applications. The label management calls accept a label description structure, `struct mac`, which contains a series of MAC label elements. Each element contains a character string name, and character string value. Each policy will be given the chance to claim a particular element name, permitting policies to expose multiple independent elements if desired. Policy modules perform the internalization and externalization between kernel labels and user-provided labels via entry points, permitting a variety of semantics. Label management system calls are generally wrapped by user library functions to perform memory allocation and error handling, simplifying user applications that must manage labels. The following MAC-related system calls are present in the FreeBSD kernel: * `mac_get_proc()` may be used to retrieve the label of the current process. * `mac_set_proc()` may be used to request a change in the label of the current process. * `mac_get_fd()` may be used to retrieve the label of an object (file, socket, pipe, ...) referenced by a file descriptor. * `mac_get_file()` may be used to retrieve the label of an object referenced by a file system path. * `mac_set_fd()` may be used to request a change in the label of an object (file, socket, pipe, ...) referenced by a file descriptor. * `mac_set_file()` may be used to request a change in the label of an object referenced by a file system path. * `mac_syscall()` permits policy modules to create new system calls without modifying the system call table; it accepts a target policy name, operation number, and opaque argument for use by the policy. * `mac_get_pid()` may be used to request the label of another process by process id. * `mac_get_link()` is identical to `mac_get_file()`, only it will not follow a symbolic link if it is the final entry in the path, so may be used to retrieve the label on a symlink. * `mac_set_link()` is identical to `mac_set_file()`, only it will not follow a symbolic link if it is the final entry in a path, so may be used to manipulate the label on a symlink. * `mac_execve()` is identical to the `execve()` system call, only it also accepts a requested label to set the process label to when beginning execution of a new program. This change in label on execution is referred to as a "transition". * `mac_get_peer()`, actually implemented via a socket option, retrieves the label of a remote peer on a socket, if available. In addition to these system calls, the `SIOCSIGMAC` and `SIOCSIFMAC` network interface ioctls permit the labels on network interfaces to be retrieved and set. [[mac-policy-architecture]] == MAC Policy Architecture Security policies are either linked directly into the kernel, or compiled into loadable kernel modules that may be loaded at boot, or dynamically using the module loading system calls at runtime. Policy modules interact with the system through a set of declared entry points, providing access to a stream of system events and permitting the policy to influence access control decisions. Each policy contains a number of elements: * Optional configuration parameters for policy. * Centralized implementation of the policy logic and parameters. * Optional implementation of policy life cycle events, such as initialization and destruction. * Optional support for initializing, maintaining, and destroying labels on selected kernel objects. * Optional support for user process inspection and modification of labels on selected objects. * Implementation of selected access control entry points that are of interest to the policy. * Declaration of policy identity, module entry points, and policy properties. [[mac-policy-declaration]] === Policy Declaration Modules may be declared using the `MAC_POLICY_SET()` macro, which names the policy, provides a reference to the MAC entry point vector, provides load-time flags determining how the policy framework should handle the policy, and optionally requests the allocation of label state by the framework. [.programlisting] .... static struct mac_policy_ops mac_policy_ops = { .mpo_destroy = mac_policy_destroy, .mpo_init = mac_policy_init, .mpo_init_bpfdesc_label = mac_policy_init_bpfdesc_label, .mpo_init_cred_label = mac_policy_init_label, /* ... */ .mpo_check_vnode_setutimes = mac_policy_check_vnode_setutimes, .mpo_check_vnode_stat = mac_policy_check_vnode_stat, .mpo_check_vnode_write = mac_policy_check_vnode_write, }; .... The MAC policy entry point vector, `mac__policy__ops` in this example, associates functions defined in the module with specific entry points. A complete listing of available entry points and their prototypes may be found in the MAC entry point reference section. Of specific interest during module registration are the .mpo_destroy and .mpo_init entry points. .mpo_init will be invoked once a policy is successfully registered with the module framework but prior to any other entry points becoming active. This permits the policy to perform any policy-specific allocation and initialization, such as initialization of any data or locks. .mpo_destroy will be invoked when a policy module is unloaded to permit releasing of any allocated memory and destruction of locks. Currently, these two entry points are invoked with the MAC policy list mutex held to prevent any other entry points from being invoked: this will be changed, but in the mean time, policies should be careful about what kernel primitives they invoke so as to avoid lock ordering or sleeping problems. The policy declaration's module name field exists so that the module may be uniquely identified for the purposes of module dependencies. An appropriate string should be selected. The full string name of the policy is displayed to the user via the kernel log during load and unload events, and also exported when providing status information to userland processes. [[mac-policy-flags]] === Policy Flags The policy declaration flags field permits the module to provide the framework with information about its capabilities at the time the module is loaded. Currently, three flags are defined: MPC_LOADTIME_FLAG_UNLOADOK:: This flag indicates that the policy module may be unloaded. If this flag is not provided, then the policy framework will reject requests to unload the module. This flag might be used by modules that allocate label state and are unable to free that state at runtime. MPC_LOADTIME_FLAG_NOTLATE:: This flag indicates that the policy module must be loaded and initialized early in the boot process. If the flag is specified, attempts to register the module following boot will be rejected. The flag may be used by policies that require pervasive labeling of all system objects, and cannot handle objects that have not been properly initialized by the policy. MPC_LOADTIME_FLAG_LABELMBUFS:: This flag indicates that the policy module requires labeling of Mbufs, and that memory should always be allocated for the storage of Mbuf labels. By default, the MAC Framework will not allocate label storage for Mbufs unless at least one loaded policy has this flag set. This measurably improves network performance when policies do not require Mbuf labeling. A kernel option, `MAC_ALWAYS_LABEL_MBUF`, exists to force the MAC Framework to allocate Mbuf label storage regardless of the setting of this flag, and may be useful in some environments. [NOTE] ==== Policies using the `MPC_LOADTIME_FLAG_LABELMBUFS` without the `MPC_LOADTIME_FLAG_NOTLATE` flag set must be able to correctly handle `NULL` Mbuf label pointers passed into entry points. This is necessary as in-flight Mbufs without label storage may persist after a policy enabling Mbuf labeling has been loaded. If a policy is loaded before the network subsystem is active (i.e., the policy is not being loaded late), then all Mbufs are guaranteed to have label storage. ==== [[mac-policy-entry-points]] === Policy Entry Points Four classes of entry points are offered to policies registered with the framework: entry points associated with the registration and management of policies, entry points denoting initialization, creation, destruction, and other life cycle events for kernel objects, events associated with access control decisions that the policy module may influence, and calls associated with the management of labels on objects. In addition, a `mac_syscall()` entry point is provided so that policies may extend the kernel interface without registering new system calls. Policy module writers should be aware of the kernel locking strategy, as well as what object locks are available during which entry points. Writers should attempt to avoid deadlock scenarios by avoiding grabbing non-leaf locks inside of entry points, and also follow the locking protocol for object access and modification. In particular, writers should be aware that while necessary locks to access objects and their labels are generally held, sufficient locks to modify an object or its label may not be present for all entry points. Locking information for arguments is documented in the MAC framework entry point document. Policy entry points will pass a reference to the object label along with the object itself. This permits labeled policies to be unaware of the internals of the object yet still make decisions based on the label. The exception to this is the process credential, which is assumed to be understood by policies as a first class security object in the kernel. [[mac-entry-point-reference]] == MAC Policy Entry Point Reference [[mac-mpo-general]] === General-Purpose Module Entry Points [[mac-mpo-init]] ==== `mpo_init` [source,c] ---- void mpo_init(struct mac_policy_conf *conf); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`conf` |MAC policy definition | |=== Policy load event. The policy list mutex is held, so sleep operations cannot be performed, and calls out to other kernel subsystems must be made with caution. If potentially sleeping memory allocations are required during policy initialization, they should be made using a separate module SYSINIT(). [[mpo-destroy]] ==== `mpo_destroy` [source,c] ---- void mpo_destroy(struct mac_policy_conf *conf); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`conf` |MAC policy definition | |=== Policy load event. The policy list mutex is held, so caution should be applied. [[mac-mpo-syscall]] ==== `mpo_syscall` [source,c] ---- int mpo_syscall(struct thread *td, int call, void *arg); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`td` |Calling thread | |`call` |Policy-specific syscall number | |`arg` |Pointer to syscall arguments | |=== This entry point provides a policy-multiplexed system call so that policies may provide additional services to user processes without registering specific system calls. The policy name provided during registration is used to demultiplexer calls from userland, and the arguments will be forwarded to this entry point. When implementing new services, security modules should be sure to invoke appropriate access control checks from the MAC framework as needed. For example, if a policy implements an augmented signal functionality, it should call the necessary signal access control checks to invoke the MAC framework and other registered policies. [NOTE] ==== Modules must currently perform the `copyin()` of the syscall data on their own. ==== [[mac-mpo-thread-userret]] ==== `mpo_thread_userret` [source,c] ---- void mpo_thread_userret(struct thread *td); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`td` |Returning thread | |=== This entry point permits policy modules to perform MAC-related events when a thread returns to user space, via a system call return, trap return, or otherwise. This is required for policies that have floating process labels, as it is not always possible to acquire the process lock at arbitrary points in the stack during system call processing; process labels might represent traditional authentication data, process history information, or other data. To employ this mechanism, intended changes to the process credential label may be stored in the `p_label` protected by a per-policy spin lock, and then set the per-thread `TDF_ASTPENDING` flag and per-process `PS_MACPENDM` flag to schedule a call to the `userret` entry point. From this entry point, the policy may create a replacement credential with less concern about the locking context. Policy writers are cautioned that event ordering relating to scheduling an AST and the AST being performed may be complex and interlaced in multithreaded applications. [[mac-label-ops]] === Label Operations [[mac-mpo-init-bpfdesc]] ==== `mpo_init_bpfdesc_label` [source,c] ---- void mpo_init_bpfdesc_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |New label to apply | |=== Initialize the label on a newly instantiated bpfdesc (BPF descriptor). Sleeping is permitted. [[mac-mpo-init-cred-label]] ==== `mpo_init_cred_label` [source,c] ---- void mpo_init_cred_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |New label to initialize | |=== Initialize the label for a newly instantiated user credential. Sleeping is permitted. [[mac-mpo-init-devfsdirent]] ==== `mpo_init_devfsdirent_label` [source,c] ---- void mpo_init_devfsdirent_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |New label to apply | |=== Initialize the label on a newly instantiated devfs entry. Sleeping is permitted. [[mac-mpo-init-ifnet]] ==== `mpo_init_ifnet_label` [source,c] ---- void mpo_init_ifnet_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |New label to apply | |=== Initialize the label on a newly instantiated network interface. Sleeping is permitted. [[mac-mpo-init-ipq]] ==== `mpo_init_ipq_label` [source,c] ---- void mpo_init_ipq_label(struct label *label, int flag); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |New label to apply | |`flag` |Sleeping/non-sleeping man:malloc[9]; see below | |=== Initialize the label on a newly instantiated IP fragment reassembly queue. The `flag` field may be one of M_WAITOK and M_NOWAIT, and should be employed to avoid performing a sleeping man:malloc[9] during this initialization call. IP fragment reassembly queue allocation frequently occurs in performance sensitive environments, and the implementation should be careful to avoid sleeping or long-lived operations. This entry point is permitted to fail resulting in the failure to allocate the IP fragment reassembly queue. [[mac-mpo-init-mbuf]] ==== `mpo_init_mbuf_label` [source,c] ---- void mpo_init_mbuf_label(int flag, struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`flag` |Sleeping/non-sleeping man:malloc[9]; see below | |`label` |Policy label to initialize | |=== Initialize the label on a newly instantiated mbuf packet header (`mbuf`). The `flag` field may be one of M_WAITOK and M_NOWAIT, and should be employed to avoid performing a sleeping man:malloc[9] during this initialization call. Mbuf allocation frequently occurs in performance sensitive environments, and the implementation should be careful to avoid sleeping or long-lived operations. This entry point is permitted to fail resulting in the failure to allocate the mbuf header. [[mac-mpo-init-mount]] ==== `mpo_init_mount_label` [source,c] ---- void mpo_init_mount_label(struct label *mntlabel, struct label *fslabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`mntlabel` |Policy label to be initialized for the mount itself | |`fslabel` |Policy label to be initialized for the file system | |=== Initialize the labels on a newly instantiated mount point. Sleeping is permitted. [[mac-mpo-init-mount-fs-label]] ==== `mpo_init_mount_fs_label` [source,c] ---- void mpo_init_mount_fs_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be initialized | |=== Initialize the label on a newly mounted file system. Sleeping is permitted [[mac-mpo-init-pipe-label]] ==== `mpo_init_pipe_label` [source,c] ---- void mpo_init_pipe_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be filled in | |=== Initialize a label for a newly instantiated pipe. Sleeping is permitted. [[mac-mpo-init-socket]] ==== `mpo_init_socket_label` [source,c] ---- void mpo_init_socket_label(struct label *label, int flag); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |New label to initialize | |`flag` |man:malloc[9] flags | |=== Initialize a label for a newly instantiated socket. The `flag` field may be one of M_WAITOK and M_NOWAIT, and should be employed to avoid performing a sleeping man:malloc[9] during this initialization call. [[mac-mpo-init-socket-peer-label]] ==== `mpo_init_socket_peer_label` [source,c] ---- void mpo_init_socket_peer_label(struct label *label, int flag); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |New label to initialize | |`flag` |man:malloc[9] flags | |=== Initialize the peer label for a newly instantiated socket. The `flag` field may be one of M_WAITOK and M_NOWAIT, and should be employed to avoid performing a sleeping man:malloc[9] during this initialization call. [[mac-mpo-init-proc-label]] ==== `mpo_init_proc_label` [source,c] ---- void mpo_init_proc_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |New label to initialize | |=== Initialize the label for a newly instantiated process. Sleeping is permitted. [[mac-mpo-init-vnode]] ==== `mpo_init_vnode_label` [source,c] ---- void mpo_init_vnode_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |New label to initialize | |=== Initialize the label on a newly instantiated vnode. Sleeping is permitted. [[mac-mpo-destroy-bpfdesc]] ==== `mpo_destroy_bpfdesc_label` [source,c] ---- void mpo_destroy_bpfdesc_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |bpfdesc label | |=== Destroy the label on a BPF descriptor. In this entry point a policy should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-cred]] ==== `mpo_destroy_cred_label` [source,c] ---- void mpo_destroy_cred_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label being destroyed | |=== Destroy the label on a credential. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-devfsdirent]] ==== `mpo_destroy_devfsdirent_label` [source,c] ---- void mpo_destroy_devfsdirent_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label being destroyed | |=== Destroy the label on a devfs entry. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-ifnet-label]] ==== `mpo_destroy_ifnet_label` [source,c] ---- void mpo_destroy_ifnet_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label being destroyed | |=== Destroy the label on a removed interface. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-ipq-label]] ==== `mpo_destroy_ipq_label` [source,c] ---- void mpo_destroy_ipq_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label being destroyed | |=== Destroy the label on an IP fragment queue. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-mbuf-label]] ==== `mpo_destroy_mbuf_label` [source,c] ---- void mpo_destroy_mbuf_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label being destroyed | |=== Destroy the label on an mbuf header. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-mount-label]] ==== `mpo_destroy_mount_label` [source,c] ---- void mpo_destroy_mount_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Mount point label being destroyed | |=== Destroy the labels on a mount point. In this entry point, a policy module should free the internal storage associated with `mntlabel` so that they may be destroyed. [[mac-mpo-destroy-mount]] ==== `mpo_destroy_mount_label` [source,c] ---- void mpo_destroy_mount_label(struct label *mntlabel, struct label *fslabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`mntlabel` |Mount point label being destroyed | |`fslabel` |File system label being destroyed> | |=== Destroy the labels on a mount point. In this entry point, a policy module should free the internal storage associated with `mntlabel` and `fslabel` so that they may be destroyed. [[mac-mpo-destroy-socket]] ==== `mpo_destroy_socket_label` [source,c] ---- void mpo_destroy_socket_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Socket label being destroyed | |=== Destroy the label on a socket. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-socket-peer-label]] ==== `mpo_destroy_socket_peer_label` [source,c] ---- void mpo_destroy_socket_peer_label(struct label *peerlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`peerlabel` |Socket peer label being destroyed | |=== Destroy the peer label on a socket. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-pipe-label]] ==== `mpo_destroy_pipe_label` [source,c] ---- void mpo_destroy_pipe_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Pipe label | |=== Destroy the label on a pipe. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-proc-label]] ==== `mpo_destroy_proc_label` [source,c] ---- void mpo_destroy_proc_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Process label | |=== Destroy the label on a process. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-destroy-vnode-label]] ==== `mpo_destroy_vnode_label` [source,c] ---- void mpo_destroy_vnode_label(struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Process label | |=== Destroy the label on a vnode. In this entry point, a policy module should free any internal storage associated with `label` so that it may be destroyed. [[mac-mpo-copy-mbuf-label]] ==== `mpo_copy_mbuf_label` [source,c] ---- void mpo_copy_mbuf_label(struct label *src, struct label *dest); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`src` |Source label | |`dest` |Destination label | |=== Copy the label information in `src` into `dest`. [[mac-mpo-copy-pipe-label]] ==== `mpo_copy_pipe_label` [source,c] ---- void mpo_copy_pipe_label(struct label *src, struct label *dest); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`src` |Source label | |`dest` |Destination label | |=== Copy the label information in `src` into `dest`. [[mac-mpo-copy-vnode-label]] ==== `mpo_copy_vnode_label` [source,c] ---- void mpo_copy_vnode_label(struct label *src, struct label *dest); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`src` |Source label | |`dest` |Destination label | |=== Copy the label information in `src` into `dest`. [[mac-mpo-externalize-cred-label]] ==== `mpo_externalize_cred_label` [source,c] ---- int mpo_externalize_cred_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be externalized | |`element_name` |Name of the policy whose label should be externalized | |`sb` |String buffer to be filled with a text representation of label | |`claimed` |Should be incremented when `element_data` can be filled in. | |=== Produce an externalized label based on the label structure passed. An externalized label consists of a text representation of the label contents that can be used with userland applications and read by the user. Currently, all policies' `externalize` entry points will be called, so the implementation should check the contents of `element_name` before attempting to fill in `sb`. If `element_name` does not match the name of your policy, simply return 0. Only return nonzero if an error occurs while externalizing the label data. Once the policy fills in `element_data`, `*claimed` should be incremented. [[mac-mpo-externalize-ifnet-label]] ==== `mpo_externalize_ifnet_label` [source,c] ---- int mpo_externalize_ifnet_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be externalized | |`element_name` |Name of the policy whose label should be externalized | |`sb` |String buffer to be filled with a text representation of label | |`claimed` |Should be incremented when `element_data` can be filled in. | |=== Produce an externalized label based on the label structure passed. An externalized label consists of a text representation of the label contents that can be used with userland applications and read by the user. Currently, all policies' `externalize` entry points will be called, so the implementation should check the contents of `element_name` before attempting to fill in `sb`. If `element_name` does not match the name of your policy, simply return 0. Only return nonzero if an error occurs while externalizing the label data. Once the policy fills in `element_data`, `*claimed` should be incremented. [[mac-mpo-externalize-pipe-label]] ==== `mpo_externalize_pipe_label` [source,c] ---- int mpo_externalize_pipe_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be externalized | |`element_name` |Name of the policy whose label should be externalized | |`sb` |String buffer to be filled with a text representation of label | |`claimed` |Should be incremented when `element_data` can be filled in. | |=== Produce an externalized label based on the label structure passed. An externalized label consists of a text representation of the label contents that can be used with userland applications and read by the user. Currently, all policies' `externalize` entry points will be called, so the implementation should check the contents of `element_name` before attempting to fill in `sb`. If `element_name` does not match the name of your policy, simply return 0. Only return nonzero if an error occurs while externalizing the label data. Once the policy fills in `element_data`, `*claimed` should be incremented. [[mac-mpo-externalize-socket-label]] ==== `mpo_externalize_socket_label` [source,c] ---- int mpo_externalize_socket_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be externalized | |`element_name` |Name of the policy whose label should be externalized | |`sb` |String buffer to be filled with a text representation of label | |`claimed` |Should be incremented when `element_data` can be filled in. | |=== Produce an externalized label based on the label structure passed. An externalized label consists of a text representation of the label contents that can be used with userland applications and read by the user. Currently, all policies' `externalize` entry points will be called, so the implementation should check the contents of `element_name` before attempting to fill in `sb`. If `element_name` does not match the name of your policy, simply return 0. Only return nonzero if an error occurs while externalizing the label data. Once the policy fills in `element_data`, `*claimed` should be incremented. [[mac-mpo-externalize-socket-peer-label]] ==== `mpo_externalize_socket_peer_label` [source,c] ---- int mpo_externalize_socket_peer_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be externalized | |`element_name` |Name of the policy whose label should be externalized | |`sb` |String buffer to be filled with a text representation of label | |`claimed` |Should be incremented when `element_data` can be filled in. | |=== Produce an externalized label based on the label structure passed. An externalized label consists of a text representation of the label contents that can be used with userland applications and read by the user. Currently, all policies' `externalize` entry points will be called, so the implementation should check the contents of `element_name` before attempting to fill in `sb`. If `element_name` does not match the name of your policy, simply return 0. Only return nonzero if an error occurs while externalizing the label data. Once the policy fills in `element_data`, `*claimed` should be incremented. [[mac-mpo-externalize-vnode-label]] ==== `mpo_externalize_vnode_label` [source,c] ---- int mpo_externalize_vnode_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be externalized | |`element_name` |Name of the policy whose label should be externalized | |`sb` |String buffer to be filled with a text representation of label | |`claimed` |Should be incremented when `element_data` can be filled in. | |=== Produce an externalized label based on the label structure passed. An externalized label consists of a text representation of the label contents that can be used with userland applications and read by the user. Currently, all policies' `externalize` entry points will be called, so the implementation should check the contents of `element_name` before attempting to fill in `sb`. If `element_name` does not match the name of your policy, simply return 0. Only return nonzero if an error occurs while externalizing the label data. Once the policy fills in `element_data`, `*claimed` should be incremented. [[mac-mpo-internalize-cred-label]] ==== `mpo_internalize_cred_label` [source,c] ---- int mpo_internalize_cred_label(struct label *label, char *element_name, char *element_data, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be filled in | |`element_name` |Name of the policy whose label should be internalized | |`element_data` |Text data to be internalized | |`claimed` |Should be incremented when data can be successfully internalized. | |=== Produce an internal label structure based on externalized label data in text format. Currently, all policies' `internalize` entry points are called when internalization is requested, so the implementation should compare the contents of `element_name` to its own name in order to be sure it should be internalizing the data in `element_data`. Just as in the `externalize` entry points, the entry point should return 0 if `element_name` does not match its own name, or when data can successfully be internalized, in which case `*claimed` should be incremented. [[mac-mpo-internalize-ifnet-label]] ==== `mpo_internalize_ifnet_label` [source,c] ---- int mpo_internalize_ifnet_label(struct label *label, char *element_name, char *element_data, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be filled in | |`element_name` |Name of the policy whose label should be internalized | |`element_data` |Text data to be internalized | |`claimed` |Should be incremented when data can be successfully internalized. | |=== Produce an internal label structure based on externalized label data in text format. Currently, all policies' `internalize` entry points are called when internalization is requested, so the implementation should compare the contents of `element_name` to its own name in order to be sure it should be internalizing the data in `element_data`. Just as in the `externalize` entry points, the entry point should return 0 if `element_name` does not match its own name, or when data can successfully be internalized, in which case `*claimed` should be incremented. [[mac-mpo-internalize-pipe-label]] ==== `mpo_internalize_pipe_label` [source,c] ---- int mpo_internalize_pipe_label(struct label *label, char *element_name, char *element_data, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be filled in | |`element_name` |Name of the policy whose label should be internalized | |`element_data` |Text data to be internalized | |`claimed` |Should be incremented when data can be successfully internalized. | |=== Produce an internal label structure based on externalized label data in text format. Currently, all policies' `internalize` entry points are called when internalization is requested, so the implementation should compare the contents of `element_name` to its own name in order to be sure it should be internalizing the data in `element_data`. Just as in the `externalize` entry points, the entry point should return 0 if `element_name` does not match its own name, or when data can successfully be internalized, in which case `*claimed` should be incremented. [[mac-mpo-internalize-socket-label]] ==== `mpo_internalize_socket_label` [source,c] ---- int mpo_internalize_socket_label(struct label *label, char *element_name, char *element_data, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be filled in | |`element_name` |Name of the policy whose label should be internalized | |`element_data` |Text data to be internalized | |`claimed` |Should be incremented when data can be successfully internalized. | |=== Produce an internal label structure based on externalized label data in text format. Currently, all policies' `internalize` entry points are called when internalization is requested, so the implementation should compare the contents of `element_name` to its own name in order to be sure it should be internalizing the data in `element_data`. Just as in the `externalize` entry points, the entry point should return 0 if `element_name` does not match its own name, or when data can successfully be internalized, in which case `*claimed` should be incremented. [[mac-mpo-internalize-vnode-label]] ==== `mpo_internalize_vnode_label` [source,c] ---- int mpo_internalize_vnode_label(struct label *label, char *element_name, char *element_data, int *claimed); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`label` |Label to be filled in | |`element_name` |Name of the policy whose label should be internalized | |`element_data` |Text data to be internalized | |`claimed` |Should be incremented when data can be successfully internalized. | |=== Produce an internal label structure based on externalized label data in text format. Currently, all policies' `internalize` entry points are called when internalization is requested, so the implementation should compare the contents of `element_name` to its own name in order to be sure it should be internalizing the data in `element_data`. Just as in the `externalize` entry points, the entry point should return 0 if `element_name` does not match its own name, or when data can successfully be internalized, in which case `*claimed` should be incremented. [[mac-label-events]] === Label Events This class of entry points is used by the MAC framework to permit policies to maintain label information on kernel objects. For each labeled kernel object of interest to a MAC policy, entry points may be registered for relevant life cycle events. All objects implement initialization, creation, and destruction hooks. Some objects will also implement relabeling, allowing user processes to change the labels on objects. Some objects will also implement object-specific events, such as label events associated with IP reassembly. A typical labeled object will have the following life cycle of entry points: [.programlisting] .... Label initialization o (object-specific wait) \ Label creation o \ Relabel events, o--<--. Various object-specific, | | Access control events ~-->--o \ Label destruction o .... Label initialization permits policies to allocate memory and set initial values for labels without context for the use of the object. The label slot allocated to a policy will be zeroed by default, so some policies may not need to perform initialization. Label creation occurs when the kernel structure is associated with an actual kernel object. For example, Mbufs may be allocated and remain unused in a pool until they are required. mbuf allocation causes label initialization on the mbuf to take place, but mbuf creation occurs when the mbuf is associated with a datagram. Typically, context will be provided for a creation event, including the circumstances of the creation, and labels of other relevant objects in the creation process. For example, when an mbuf is created from a socket, the socket and its label will be presented to registered policies in addition to the new mbuf and its label. Memory allocation in creation events is discouraged, as it may occur in performance sensitive ports of the kernel; in addition, creation calls are not permitted to fail so a failure to allocate memory cannot be reported. Object specific events do not generally fall into the other broad classes of label events, but will generally provide an opportunity to modify or update the label on an object based on additional context. For example, the label on an IP fragment reassembly queue may be updated during the MAC_UPDATE_IPQ entry point as a result of the acceptance of an additional mbuf to that queue. Access control events are discussed in detail in the following section. Label destruction permits policies to release storage or state associated with a label during its association with an object so that the kernel data structures supporting the object may be reused or released. In addition to labels associated with specific kernel objects, an additional class of labels exists: temporary labels. These labels are used to store update information submitted by user processes. These labels are initialized and destroyed as with other label types, but the creation event is MAC_INTERNALIZE, which accepts a user label to be converted to an in-kernel representation. [[mac-fs-label-event-ops]] ==== File System Object Labeling Event Operations [[mac-mpo-associate-vnode-devfs]] ===== `mpo_associate_vnode_devfs` [source,c] ---- void mpo_associate_vnode_devfs(struct mount *mp, struct label *fslabel, struct devfs_dirent *de, struct label *delabel, struct vnode *vp, struct label *vlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`mp` |Devfs mount point | |`fslabel` |Devfs file system label (`mp->mnt_fslabel`) | |`de` |Devfs directory entry | |`delabel` |Policy label associated with `de` | |`vp` |vnode associated with `de` | |`vlabel` |Policy label associated with `vp` | |=== Fill in the label (`vlabel`) for a newly created devfs vnode based on the devfs directory entry passed in `de` and its label. [[mac-mpo-associate-vnode-extattr]] ===== `mpo_associate_vnode_extattr` [source,c] ---- int mpo_associate_vnode_extattr(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`mp` |File system mount point | |`fslabel` |File system label | |`vp` |Vnode to label | |`vlabel` |Policy label associated with `vp` | |=== Attempt to retrieve the label for `vp` from the file system extended attributes. Upon success, the value `0` is returned. Should extended attribute retrieval not be supported, an accepted fallback is to copy `fslabel` into `vlabel`. In the event of an error, an appropriate value for `errno` should be returned. [[mac-mpo-associate-vnode-singlelabel]] ===== `mpo_associate_vnode_singlelabel` [source,c] ---- void mpo_associate_vnode_singlelabel(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`mp` |File system mount point | |`fslabel` |File system label | |`vp` |Vnode to label | |`vlabel` |Policy label associated with `vp` | |=== On non-multilabel file systems, this entry point is called to set the policy label for `vp` based on the file system label, `fslabel`. [[mac-mpo-create-devfs-device]] ===== `mpo_create_devfs_device` [source,c] ---- void mpo_create_devfs_device(dev_t dev, struct devfs_dirent *devfs_dirent, struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`dev` |Device corresponding with `devfs_dirent` | |`devfs_dirent` |Devfs directory entry to be labeled. | |`label` |Label for `devfs_dirent` to be filled in. | |=== Fill out the label on a devfs_dirent being created for the passed device. This call will be made when the device file system is mounted, regenerated, or a new device is made available. [[mac-mpo-create-devfs-directory]] ===== `mpo_create_devfs_directory` [source,c] ---- void mpo_create_devfs_directory(char *dirname, int dirnamelen, struct devfs_dirent *devfs_dirent, struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`dirname` |Name of directory being created | |`namelen` |Length of string `dirname` | |`devfs_dirent` |Devfs directory entry for directory being created. | |=== Fill out the label on a devfs_dirent being created for the passed directory. This call will be made when the device file system is mounted, regenerated, or a new device requiring a specific directory hierarchy is made available. [[mac-mpo-create-devfs-symlink]] ===== `mpo_create_devfs_symlink` [source,c] ---- void mpo_create_devfs_symlink(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de, struct label *delabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`mp` |Devfs mount point | |`dd` |Link destination | |`ddlabel` |Label associated with `dd` | |`de` |Symlink entry | |`delabel` |Label associated with `de` | |=== Fill in the label (`delabel`) for a newly created man:devfs[5] symbolic link entry. [[mac-mpo-create-vnode-extattr]] ===== `mpo_create_vnode_extattr` [source,c] ---- int mpo_create_vnode_extattr(struct ucred *cred, struct mount *mp, struct label *fslabel, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *vlabel, struct componentname *cnp); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`mount` |File system mount point | |`label` |File system label | |`dvp` |Parent directory vnode | |`dlabel` |Label associated with `dvp` | |`vp` |Newly created vnode | |`vlabel` |Policy label associated with `vp` | |`cnp` |Component name for `vp` | |=== Write out the label for `vp` to the appropriate extended attribute. If the write succeeds, fill in `vlabel` with the label, and return 0. Otherwise, return an appropriate error. [[mac-mpo-create-mount]] ===== `mpo_create_mount` [source,c] ---- void mpo_create_mount(struct ucred *cred, struct mount *mp, struct label *mnt, struct label *fslabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`mp` |Object; file system being mounted | |`mntlabel` |Policy label to be filled in for `mp` | |`fslabel` |Policy label for the file system `mp` mounts. | |=== Fill out the labels on the mount point being created by the passed subject credential. This call will be made when a new file system is mounted. [[mac-mpo-create-root-mount]] ===== `mpo_create_root_mount` [source,c] ---- void mpo_create_root_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking -3+|See crossref:mac[mac-mpo-create-mount]. +3+|See crossref:mac[mac-mpo-create-mount, `mpo_create_mount`]. |=== Fill out the labels on the mount point being created by the passed subject credential. This call will be made when the root file system is mounted, after `mpo_create_mount;`. [[mac-mpo-relabel-vnode]] ===== `mpo_relabel_vnode` [source,c] ---- void mpo_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |vnode to relabel | |`vnodelabel` |Existing policy label for `vp` | |`newlabel` |New, possibly partial label to replace `vnodelabel` | |=== Update the label on the passed vnode given the passed update vnode label and the passed subject credential. [[mac-mpo-setlabel-vnode-extattr]] ===== `mpo_setlabel_vnode_extattr` [source,c] ---- int mpo_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp, struct label *vlabel, struct label *intlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Vnode for which the label is being written | |`vlabel` |Policy label associated with `vp` | |`intlabel` |Label to write out | |=== Write out the policy from `intlabel` to an extended attribute. This is called from `vop_stdcreatevnode_ea`. [[mac-mpo-update-devfsdirent]] ===== `mpo_update_devfsdirent` [source,c] ---- void mpo_update_devfsdirent(struct devfs_dirent *devfs_dirent, struct label *direntlabel, struct vnode *vp, struct label *vnodelabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`devfs_dirent` |Object; devfs directory entry | |`direntlabel` |Policy label for `devfs_dirent` to be updated. | |`vp` |Parent vnode |Locked |`vnodelabel` |Policy label for `vp` | |=== Update the `devfs_dirent` label from the passed devfs vnode label. This call will be made when a devfs vnode has been successfully relabeled to commit the label change such that it lasts even if the vnode is recycled. It will also be made when a symlink is created in devfs, following a call to `mac_vnode_create_from_vnode` to initialize the vnode label. [[mac-ipc-label-ops]] ==== IPC Object Labeling Event Operations [[mac-mpo-create-mbuf-from-socket]] ===== `mpo_create_mbuf_from_socket` [source,c] ---- void mpo_create_mbuf_from_socket(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`socket` |Socket |Socket locking WIP |`socketlabel` |Policy label for `socket` | |`m` |Object; mbuf | |`mbuflabel` |Policy label to fill in for `m` | |=== Set the label on a newly created mbuf header from the passed socket label. This call is made when a new datagram or message is generated by the socket and stored in the passed mbuf. [[mac-mpo-create-pipe]] ===== `mpo_create_pipe` [source,c] ---- void mpo_create_pipe(struct ucred *cred, struct pipe *pipe, struct label *pipelabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`pipe` |Pipe | |`pipelabel` |Policy label associated with `pipe` | |=== Set the label on a newly created pipe from the passed subject credential. This call is made when a new pipe is created. [[mac-mpo-create-socket]] ===== `mpo_create_socket` [source,c] ---- void mpo_create_socket(struct ucred *cred, struct socket *so, struct label *socketlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential |Immutable |`so` |Object; socket to label | |`socketlabel` |Label to fill in for `so` | |=== Set the label on a newly created socket from the passed subject credential. This call is made when a socket is created. [[mac-mpo-create-socket-from-socket]] ===== `mpo_create_socket_from_socket` [source,c] ---- void mpo_create_socket_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`oldsocket` |Listening socket | |`oldsocketlabel` |Policy label associated with `oldsocket` | |`newsocket` |New socket | |`newsocketlabel` |Policy label associated with `newsocketlabel` | |=== Label a socket, `newsocket`, newly man:accept[2]ed, based on the man:listen[2] socket, `oldsocket`. [[mac-mpo-relabel-pipe]] ===== `mpo_relabel_pipe` [source,c] ---- void mpo_relabel_pipe(struct ucred *cred, struct pipe *pipe, struct label *oldlabel, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`pipe` |Pipe | |`oldlabel` |Current policy label associated with `pipe` | |`newlabel` |Policy label update to apply to `pipe` | |=== Apply a new label, `newlabel`, to `pipe`. [[mac-mpo-relabel-socket]] ===== `mpo_relabel_socket` [source,c] ---- void mpo_relabel_socket(struct ucred *cred, struct socket *so, struct label *oldlabel, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential |Immutable |`so` |Object; socket | |`oldlabel` |Current label for `so` | |`newlabel` |Label update for `so` | |=== Update the label on a socket from the passed socket label update. [[mpo-set-socket-peer-from-mbuf]] ===== `mpo_set_socket_peer_from_mbuf` [source,c] ---- void mpo_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct label *mbuflabel, struct label *oldlabel, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`mbuf` |First datagram received over socket | |`mbuflabel` |Label for `mbuf` | |`oldlabel` |Current label for the socket | |`newlabel` |Policy label to be filled out for the socket | |=== Set the peer label on a stream socket from the passed mbuf label. This call will be made when the first datagram is received by the stream socket, with the exception of Unix domain sockets. [[mac-mpo-set-socket-peer-from-socket]] ===== `mpo_set_socket_peer_from_socket` [source,c] ---- void mpo_set_socket_peer_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketpeerlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`oldsocket` |Local socket | |`oldsocketlabel` |Policy label for `oldsocket` | |`newsocket` |Peer socket | |`newsocketpeerlabel` |Policy label to fill in for `newsocket` | |=== Set the peer label on a stream UNIX domain socket from the passed remote socket endpoint. This call will be made when the socket pair is connected, and will be made for both endpoints. [[mac-net-labeling-event-ops]] ==== Network Object Labeling Event Operations [[mac-mpo-create-bpfdesc]] ===== `mpo_create_bpfdesc` [source,c] ---- void mpo_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d, struct label *bpflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential |Immutable |`bpf_d` |Object; bpf descriptor | |`bpf` |Policy label to be filled in for `bpf_d` | |=== Set the label on a newly created BPF descriptor from the passed subject credential. This call will be made when a BPF device node is opened by a process with the passed subject credential. [[mac-mpo-create-ifnet]] ===== `mpo_create_ifnet` [source,c] ---- void mpo_create_ifnet(struct ifnet *ifnet, struct label *ifnetlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`ifnet` |Network interface | |`ifnetlabel` |Policy label to fill in for `ifnet` | |=== Set the label on a newly created interface. This call may be made when a new physical interface becomes available to the system, or when a pseudo-interface is instantiated during the boot or as a result of a user action. [[mac-mpo-create-ipq]] ===== `mpo_create_ipq` [source,c] ---- void mpo_create_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`fragment` |First received IP fragment | |`fragmentlabel` |Policy label for `fragment` | |`ipq` |IP reassembly queue to be labeled | |`ipqlabel` |Policy label to be filled in for `ipq` | |=== Set the label on a newly created IP fragment reassembly queue from the mbuf header of the first received fragment. [[mac-mpo-create-datagram-from-ipq]] ===== `mpo_create_datagram_from_ipq` [source,c] ---- void mpo_create_create_datagram_from_ipq(struct ipq *ipq, struct label *ipqlabel, struct mbuf *datagram, struct label *datagramlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`ipq` |IP reassembly queue | |`ipqlabel` |Policy label for `ipq` | |`datagram` |Datagram to be labeled | |`datagramlabel` |Policy label to be filled in for `datagramlabel` | |=== Set the label on a newly reassembled IP datagram from the IP fragment reassembly queue from which it was generated. [[mac-mpo-create-fragment]] ===== `mpo_create_fragment` [source,c] ---- void mpo_create_fragment(struct mbuf *datagram, struct label *datagramlabel, struct mbuf *fragment, struct label *fragmentlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`datagram` |Datagram | |`datagramlabel` |Policy label for `datagram` | |`fragment` |Fragment to be labeled | |`fragmentlabel` |Policy label to be filled in for `datagram` | |=== Set the label on the mbuf header of a newly created IP fragment from the label on the mbuf header of the datagram it was generate from. [[mac-mpo-create-mbuf-from-mbuf]] ===== `mpo_create_mbuf_from_mbuf` [source,c] ---- void mpo_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`oldmbuf` |Existing (source) mbuf | |`oldmbuflabel` |Policy label for `oldmbuf` | |`newmbuf` |New mbuf to be labeled | |`newmbuflabel` |Policy label to be filled in for `newmbuf` | |=== Set the label on the mbuf header of a newly created datagram from the mbuf header of an existing datagram. This call may be made in a number of situations, including when an mbuf is re-allocated for alignment purposes. [[mac-mpo-create-mbuf-linklayer]] ===== `mpo_create_mbuf_linklayer` [source,c] ---- void mpo_create_mbuf_linklayer(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`ifnet` |Network interface | |`ifnetlabel` |Policy label for `ifnet` | |`mbuf` |mbuf header for new datagram | |`mbuflabel` |Policy label to be filled in for `mbuf` | |=== Set the label on the mbuf header of a newly created datagram generated for the purposes of a link layer response for the passed interface. This call may be made in a number of situations, including for ARP or ND6 responses in the IPv4 and IPv6 stacks. [[mac-mpo-create-mbuf-from-bpfdesc]] ===== `mpo_create_mbuf_from_bpfdesc` [source,c] ---- void mpo_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct label *bpflabel, struct mbuf *mbuf, struct label *mbuflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`bpf_d` |BPF descriptor | |`bpflabel` |Policy label for `bpflabel` | |`mbuf` |New mbuf to be labeled | |`mbuflabel` |Policy label to fill in for `mbuf` | |=== Set the label on the mbuf header of a newly created datagram generated using the passed BPF descriptor. This call is made when a write is performed to the BPF device associated with the passed BPF descriptor. [[mac-mpo-create-mbuf-from-ifnet]] ===== `mpo_create_mbuf_from_ifnet` [source,c] ---- void mpo_create_mbuf_from_ifnet(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`ifnet` |Network interface | |`ifnetlabel` |Policy label for `ifnetlabel` | |`mbuf` |mbuf header for new datagram | |`mbuflabel` |Policy label to be filled in for `mbuf` | |=== Set the label on the mbuf header of a newly created datagram generated from the passed network interface. [[mac-mpo-create-mbuf-multicast-encap]] ===== `mpo_create_mbuf_multicast_encap` [source,c] ---- void mpo_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *newmbuf, struct label *newmbuflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`oldmbuf` |mbuf header for existing datagram | |`oldmbuflabel` |Policy label for `oldmbuf` | |`ifnet` |Network interface | |`ifnetlabel` |Policy label for `ifnet` | |`newmbuf` |mbuf header to be labeled for new datagram | |`newmbuflabel` |Policy label to be filled in for `newmbuf` | |=== Set the label on the mbuf header of a newly created datagram generated from the existing passed datagram when it is processed by the passed multicast encapsulation interface. This call is made when an mbuf is to be delivered using the virtual interface. [[mac-mpo-create-mbuf-netlayer]] ===== `mpo_create_mbuf_netlayer` [source,c] ---- void mpo_create_mbuf_netlayer(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`oldmbuf` |Received datagram | |`oldmbuflabel` |Policy label for `oldmbuf` | |`newmbuf` |Newly created datagram | |`newmbuflabel` |Policy label for `newmbuf` | |=== Set the label on the mbuf header of a newly created datagram generated by the IP stack in response to an existing received datagram (`oldmbuf`). This call may be made in a number of situations, including when responding to ICMP request datagrams. [[mac-mpo-fragment-match]] ===== `mpo_fragment_match` [source,c] ---- int mpo_fragment_match(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`fragment` |IP datagram fragment | |`fragmentlabel` |Policy label for `fragment` | |`ipq` |IP fragment reassembly queue | |`ipqlabel` |Policy label for `ipq` | |=== Determine whether an mbuf header containing an IP datagram (`fragment`) fragment matches the label of the passed IP fragment reassembly queue (`ipq`). Return (1) for a successful match, or (0) for no match. This call is made when the IP stack attempts to find an existing fragment reassembly queue for a newly received fragment; if this fails, a new fragment reassembly queue may be instantiated for the fragment. Policies may use this entry point to prevent the reassembly of otherwise matching IP fragments if policy does not permit them to be reassembled based on the label or other information. [[mac-mpo-ifnet-relabel]] ===== `mpo_relabel_ifnet` [source,c] ---- void mpo_relabel_ifnet(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`ifnet` |Object; Network interface | |`ifnetlabel` |Policy label for `ifnet` | |`newlabel` |Label update to apply to `ifnet` | |=== Update the label of network interface, `ifnet`, based on the passed update label, `newlabel`, and the passed subject credential, `cred`. [[mac-mpo-update-ipq]] ===== `mpo_update_ipq` [source,c] ---- void mpo_update_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`mbuf` |IP fragment | |`mbuflabel` |Policy label for `mbuf` | |`ipq` |IP fragment reassembly queue | |`ipqlabel` |Policy label to be updated for `ipq` | |=== Update the label on an IP fragment reassembly queue (`ipq`) based on the acceptance of the passed IP fragment mbuf header (`mbuf`). [[mac-proc-labeling-event-ops]] ==== Process Labeling Event Operations [[mac-mpo-create-cred]] ===== `mpo_create_cred` [source,c] ---- void mpo_create_cred(struct ucred *parent_cred, struct ucred *child_cred); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`parent_cred` |Parent subject credential | |`child_cred` |Child subject credential | |=== Set the label of a newly created subject credential from the passed subject credential. This call will be made when man:crcopy[9] is invoked on a newly created `struct ucred`. This call should not be confused with a process forking or creation event. [[mac-mpo-execve-transition]] ===== `mpo_execve_transition` [source,c] ---- void mpo_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp, struct label *vnodelabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`old` |Existing subject credential |Immutable |`new` |New subject credential to be labeled | |`vp` |File to execute |Locked |`vnodelabel` |Policy label for `vp` | |=== Update the label of a newly created subject credential (`new`) from the passed existing subject credential (`old`) based on a label transition caused by executing the passed vnode (`vp`). This call occurs when a process executes the passed vnode and one of the policies returns a success from the `mpo_execve_will_transition` entry point. Policies may choose to implement this call simply by invoking `mpo_create_cred` and passing the two subject credentials so as not to implement a transitioning event. Policies should not leave this entry point unimplemented if they implement `mpo_create_cred`, even if they do not implement `mpo_execve_will_transition`. [[mac-mpo-execve-will-transition]] ===== `mpo_execve_will_transition` [source,c] ---- int mpo_execve_will_transition(struct ucred *old, struct vnode *vp, struct label *vnodelabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`old` |Subject credential prior to man:execve[2] |Immutable |`vp` |File to execute | |`vnodelabel` |Policy label for `vp` | |=== Determine whether the policy will want to perform a transition event as a result of the execution of the passed vnode by the passed subject credential. Return 1 if a transition is required, 0 if not. Even if a policy returns 0, it should behave correctly in the presence of an unexpected invocation of `mpo_execve_transition`, as that call may happen as a result of another policy requesting a transition. [[mac-mpo-create-proc0]] ===== `mpo_create_proc0` [source,c] ---- void mpo_create_proc0(struct ucred *cred); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential to be filled in | |=== Create the subject credential of process 0, the parent of all kernel processes. [[mac-mpo-create-proc1]] ===== `mpo_create_proc1` [source,c] ---- void mpo_create_proc1(struct ucred *cred); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential to be filled in | |=== Create the subject credential of process 1, the parent of all user processes. [[mac-mpo-relabel-cred]] ===== `mpo_relabel_cred` [source,c] ---- void mpo_relabel_cred(struct ucred *cred, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`newlabel` |Label update to apply to `cred` | |=== Update the label on a subject credential from the passed update label. [[mac-access-control-checks]] === Access Control Checks Access control entry points permit policy modules to influence access control decisions made by the kernel. Generally, although not always, arguments to an access control entry point will include one or more authorizing credentials, information (possibly including a label) for any other objects involved in the operation. An access control entry point may return 0 to permit the operation, or an man:errno[2] error value. The results of invoking the entry point across various registered policy modules will be composed as follows: if all modules permit the operation to succeed, success will be returned. If one or modules returns a failure, a failure will be returned. If more than one module returns a failure, the errno value to return to the user will be selected using the following precedence, implemented by the `error_select()` function in [.filename]#kern_mac.c#: [.informaltable] [cols="1,1", frame="none"] |=== |Most precedence |EDEADLK | |EINVAL | |ESRCH | |EACCES |Least precedence |EPERM |=== If none of the error values returned by all modules are listed in the precedence chart then an arbitrarily selected value from the set will be returned. In general, the rules provide precedence to errors in the following order: kernel failures, invalid arguments, object not present, access not permitted, other. [[mac-mpo-bpfdesc-check-receive-from-ifnet]] ==== `mpo_check_bpfdesc_receive` [source,c] ---- int mpo_check_bpfdesc_receive(struct bpf_d *bpf_d, struct label *bpflabel, struct ifnet *ifnet, struct label *ifnetlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`bpf_d` |Subject; BPF descriptor | |`bpflabel` |Policy label for `bpf_d` | |`ifnet` |Object; network interface | |`ifnetlabel` |Policy label for `ifnet` | |=== Determine whether the MAC framework should permit datagrams from the passed interface to be delivered to the buffers of the passed BPF descriptor. Return (0) for success, or an `errno` value for failure Suggested failure: EACCES for label mismatches, EPERM for lack of privilege. [[mac-mpo-check-kenv-dump]] ==== `mpo_check_kenv_dump` [source,c] ---- int mpo_check_kenv_dump(struct ucred *cred); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |=== Determine whether the subject should be allowed to retrieve the kernel environment (see man:kenv[2]). [[mac-mpo-check-kenv-get]] ==== `mpo_check_kenv_get` [source,c] ---- int mpo_check_kenv_get(struct ucred *cred, char *name); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`name` |Kernel environment variable name | |=== Determine whether the subject should be allowed to retrieve the value of the specified kernel environment variable. [[mac-mpo-check-kenv-set]] ==== `mpo_check_kenv_set` [source,c] ---- int mpo_check_kenv_set(struct ucred *cred, char *name); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`name` |Kernel environment variable name | |=== Determine whether the subject should be allowed to set the specified kernel environment variable. [[mac-mpo-check-kenv-unset]] ==== `mpo_check_kenv_unset` [source,c] ---- int mpo_check_kenv_unset(struct ucred *cred, char *name); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`name` |Kernel environment variable name | |=== Determine whether the subject should be allowed to unset the specified kernel environment variable. [[mac-mpo-check-kld-load]] ==== `mpo_check_kld_load` [source,c] ---- int mpo_check_kld_load(struct ucred *cred, struct vnode *vp, struct label *vlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Kernel module vnode | |`vlabel` |Label associated with `vp` | |=== Determine whether the subject should be allowed to load the specified module file. [[mac-mpo-check-kld-stat]] ==== `mpo_check_kld_stat` [source,c] ---- int mpo_check_kld_stat(struct ucred *cred); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |=== Determine whether the subject should be allowed to retrieve a list of loaded kernel module files and associated statistics. [[mac-mpo-check-kld-unload]] ==== `mpo_check_kld_unload` [source,c] ---- int mpo_check_kld_unload(struct ucred *cred); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |=== Determine whether the subject should be allowed to unload a kernel module. [[mac-mpo-check-pipe-ioctl]] ==== `mpo_check_pipe_ioctl` [source,c] ---- int mpo_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, struct label *pipelabel, unsigned long cmd, void *data); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`pipe` |Pipe | |`pipelabel` |Policy label associated with `pipe` | |`cmd` |man:ioctl[2] command | |`data` |man:ioctl[2] data | |=== Determine whether the subject should be allowed to make the specified man:ioctl[2] call. [[mac-mpo-check-pipe-poll]] ==== `mpo_check_pipe_poll` [source,c] ---- int mpo_check_pipe_poll(struct ucred *cred, struct pipe *pipe, struct label *pipelabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`pipe` |Pipe | |`pipelabel` |Policy label associated with `pipe` | |=== Determine whether the subject should be allowed to poll `pipe`. [[mac-mpo-check-pipe-read]] ==== `mpo_check_pipe_read` [source,c] ---- int mpo_check_pipe_read(struct ucred *cred, struct pipe *pipe, struct label *pipelabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`pipe` |Pipe | |`pipelabel` |Policy label associated with `pipe` | |=== Determine whether the subject should be allowed read access to `pipe`. [[mac-mpo-check-pipe-relabel]] ==== `mpo_check_pipe_relabel` [source,c] ---- int mpo_check_pipe_relabel(struct ucred *cred, struct pipe *pipe, struct label *pipelabel, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`pipe` |Pipe | |`pipelabel` |Current policy label associated with `pipe` | |`newlabel` |Label update to `pipelabel` | |=== Determine whether the subject should be allowed to relabel `pipe`. [[mac-mpo-check-pipe-stat]] ==== `mpo_check_pipe_stat` [source,c] ---- int mpo_check_pipe_stat(struct ucred *cred, struct pipe *pipe, struct label *pipelabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`pipe` |Pipe | |`pipelabel` |Policy label associated with `pipe` | |=== Determine whether the subject should be allowed to retrieve statistics related to `pipe`. [[mac-mpo-check-pipe-write]] ==== `mpo_check_pipe_write` [source,c] ---- int mpo_check_pipe_write(struct ucred *cred, struct pipe *pipe, struct label *pipelabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`pipe` |Pipe | |`pipelabel` |Policy label associated with `pipe` | |=== Determine whether the subject should be allowed to write to `pipe`. [[mac-mpo-cred-check-socket-bind]] ==== `mpo_check_socket_bind` [source,c] ---- int mpo_check_socket_bind(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct sockaddr *sockaddr); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`socket` |Socket to be bound | |`socketlabel` |Policy label for `socket` | |`sockaddr` |Address of `socket` | |=== [[mac-mpo-cred-check-socket-connect]] ==== `mpo_check_socket_connect` [source,c] ---- int mpo_check_socket_connect(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct sockaddr *sockaddr); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`socket` |Socket to be connected | |`socketlabel` |Policy label for `socket` | |`sockaddr` |Address of `socket` | |=== Determine whether the subject credential (`cred`) can connect the passed socket (`socket`) to the passed socket address (`sockaddr`). Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatches, EPERM for lack of privilege. [[mac-mpo-check-socket-receive]] ==== `mpo_check_socket_receive` [source,c] ---- int mpo_check_socket_receive(struct ucred *cred, struct socket *so, struct label *socketlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`so` |Socket | |`socketlabel` |Policy label associated with `so` | |=== Determine whether the subject should be allowed to receive information from the socket `so`. [[mac-mpo-check-socket-send]] ==== `mpo_check_socket_send` [source,c] ---- int mpo_check_socket_send(struct ucred *cred, struct socket *so, struct label *socketlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`so` |Socket | |`socketlabel` |Policy label associated with `so` | |=== Determine whether the subject should be allowed to send information across the socket `so`. [[mac-mpo-check-cred-visible]] ==== `mpo_check_cred_visible` [source,c] ---- int mpo_check_cred_visible(struct ucred *u1, struct ucred *u2); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`u1` |Subject credential | |`u2` |Object credential | |=== Determine whether the subject credential `u1` can "see" other subjects with the passed subject credential `u2`. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatches, EPERM for lack of privilege, or ESRCH to hide visibility. This call may be made in a number of situations, including inter-process status sysctl's used by `ps`, and in procfs lookups. [[mac-mpo-cred-check-socket-visible]] ==== `mpo_check_socket_visible` [source,c] ---- int mpo_check_socket_visible(struct ucred *cred, struct socket *socket, struct label *socketlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`socket` |Object; socket | |`socketlabel` |Policy label for `socket` | |=== [[mac-mpo-cred-check-ifnet-relabel]] ==== `mpo_check_ifnet_relabel` [source,c] ---- int mpo_check_ifnet_relabel(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`ifnet` |Object; network interface | |`ifnetlabel` |Existing policy label for `ifnet` | |`newlabel` |Policy label update to later be applied to `ifnet` | |=== Determine whether the subject credential can relabel the passed network interface to the passed label update. [[mac-mpo-cred-check-socket-relabel]] ==== `mpo_check_socket_relabel` [source,c] ---- int mpo_check_socket_relabel(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`socket` |Object; socket | |`socketlabel` |Existing policy label for `socket` | |`newlabel` |Label update to later be applied to `socketlabel` | |=== Determine whether the subject credential can relabel the passed socket to the passed label update. [[mac-mpo-cred-check-cred-relabel]] ==== `mpo_check_cred_relabel` [source,c] ---- int mpo_check_cred_relabel(struct ucred *cred, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`newlabel` |Label update to later be applied to `cred` | |=== Determine whether the subject credential can relabel itself to the passed label update. [[mac-mpo-cred-check-vnode-relabel]] ==== `mpo_check_vnode_relabel` [source,c] ---- int mpo_check_vnode_relabel(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *newlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential |Immutable |`vp` |Object; vnode |Locked |`vnodelabel` |Existing policy label for `vp` | |`newlabel` |Policy label update to later be applied to `vp` | |=== Determine whether the subject credential can relabel the passed vnode to the passed label update. [[mpo-cred-check-mount-stat]] ==== `mpo_check_mount_stat` [source,c] ---- int mpo_check_mount_stat(struct ucred *cred, struct mount *mp, struct label *mountlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`mp` |Object; file system mount | |`mountlabel` |Policy label for `mp` | |=== Determine whether the subject credential can see the results of a statfs performed on the file system. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatches or EPERM for lack of privilege. This call may be made in a number of situations, including during invocations of man:statfs[2] and related calls, as well as to determine what file systems to exclude from listings of file systems, such as when man:getfsstat[2] is invoked. [[mac-mpo-cred-check-proc-debug]] ==== `mpo_check_proc_debug` [source,c] ---- int mpo_check_proc_debug(struct ucred *cred, struct proc *proc); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential |Immutable |`proc` |Object; process | |=== Determine whether the subject credential can debug the passed process. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, EPERM for lack of privilege, or ESRCH to hide visibility of the target. This call may be made in a number of situations, including use of the man:ptrace[2] and man:ktrace[2] APIs, as well as for some types of procfs operations. [[mac-mpo-cred-check-vnode-access]] ==== `mpo_check_vnode_access` [source,c] ---- int mpo_check_vnode_access(struct ucred *cred, struct vnode *vp, struct label *label, int flags); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |`flags` |man:access[2] flags | |=== Determine how invocations of man:access[2] and related calls by the subject credential should return when performed on the passed vnode using the passed access flags. This should generally be implemented using the same semantics used in `mpo_check_vnode_open`. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatches or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-chdir]] ==== `mpo_check_vnode_chdir` [source,c] ---- int mpo_check_vnode_chdir(struct ucred *cred, struct vnode *dvp, struct label *dlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`dvp` |Object; vnode to man:chdir[2] into | |`dlabel` |Policy label for `dvp` | |=== Determine whether the subject credential can change the process working directory to the passed vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-check-vnode-chroot]] ==== `mpo_check_vnode_chroot` [source,c] ---- int mpo_check_vnode_chroot(struct ucred *cred, struct vnode *dvp, struct label *dlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`dvp` |Directory vnode | |`dlabel` |Policy label associated with `dvp` | |=== Determine whether the subject should be allowed to man:chroot[2] into the specified directory (`dvp`). [[mac-mpo-cred-check-vnode-create]] ==== `mpo_check_vnode_create` [source,c] ---- int mpo_check_vnode_create(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp, struct vattr *vap); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`dvp` |Object; vnode | |`dlabel` |Policy label for `dvp` | |`cnp` |Component name for `dvp` | |`vap` |vnode attributes for `vap` | |=== Determine whether the subject credential can create a vnode with the passed parent directory, passed name information, and passed attribute information. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. This call may be made in a number of situations, including as a result of calls to man:open[2] with O_CREAT, man:mkfifo[2], and others. [[mac-mpo-cred-check-vnode-delete]] ==== `mpo_check_vnode_delete` [source,c] ---- int mpo_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, void *label, struct componentname *cnp); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`dvp` |Parent directory vnode | |`dlabel` |Policy label for `dvp` | |`vp` |Object; vnode to delete | |`label` |Policy label for `vp` | |`cnp` |Component name for `vp` | |=== Determine whether the subject credential can delete a vnode from the passed parent directory and passed name information. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. This call may be made in a number of situations, including as a result of calls to man:unlink[2] and man:rmdir[2]. Policies implementing this entry point should also implement `mpo_check_rename_to` to authorize deletion of objects as a result of being the target of a rename. [[mac-mpo-cred-check-vnode-deleteacl]] ==== `mpo_check_vnode_deleteacl` [source,c] ---- int mpo_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential |Immutable |`vp` |Object; vnode |Locked |`label` |Policy label for `vp` | |`type` |ACL type | |=== Determine whether the subject credential can delete the ACL of passed type from the passed vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-exec]] ==== `mpo_check_vnode_exec` [source,c] ---- int mpo_check_vnode_exec(struct ucred *cred, struct vnode *vp, struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode to execute | |`label` |Policy label for `vp` | |=== Determine whether the subject credential can execute the passed vnode. Determination of execute privilege is made separately from decisions about any transitioning event. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mpo-cred-check-vnode-getacl]] ==== `mpo_check_vnode_getacl` [source,c] ---- int mpo_check_vnode_getacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |`type` |ACL type | |=== Determine whether the subject credential can retrieve the ACL of passed type from the passed vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-getextattr]] ==== `mpo_check_vnode_getextattr` [source,c] ---- int mpo_check_vnode_getextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |`attrnamespace` |Extended attribute namespace | |`name` |Extended attribute name | |`uio` |I/O structure pointer; see man:uio[9] | |=== Determine whether the subject credential can retrieve the extended attribute with the passed namespace and name from the passed vnode. Policies implementing labeling using extended attributes may be interested in special handling of operations on those extended attributes. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-check-vnode-link]] ==== `mpo_check_vnode_link` [source,c] ---- int mpo_check_vnode_link(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`dvp` |Directory vnode | |`dlabel` |Policy label associated with `dvp` | |`vp` |Link destination vnode | |`label` |Policy label associated with `vp` | |`cnp` |Component name for the link being created | |=== Determine whether the subject should be allowed to create a link to the vnode `vp` with the name specified by `cnp`. [[mac-mpo-check-vnode-mmap]] ==== `mpo_check_vnode_mmap` [source,c] ---- int mpo_check_vnode_mmap(struct ucred *cred, struct vnode *vp, struct label *label, int prot); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Vnode to map | |`label` |Policy label associated with `vp` | |`prot` |Mmap protections (see man:mmap[2]) | |=== Determine whether the subject should be allowed to map the vnode `vp` with the protections specified in `prot`. [[mac-mpo-check-vnode-mmap-downgrade]] ==== `mpo_check_vnode_mmap_downgrade` [source,c] ---- void mpo_check_vnode_mmap_downgrade(struct ucred *cred, struct vnode *vp, struct label *label, int *prot); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` -|See crossref:mac[mac-mpo-check-vnode-mmap]. +|See crossref:mac[mac-mpo-check-vnode-mmap, `mpo_check_vnode_mmap`]. | |`vp` | | |`label` | | |`prot` |Mmap protections to be downgraded | |=== Downgrade the mmap protections based on the subject and object labels. [[mac-mpo-check-vnode-mprotect]] ==== `mpo_check_vnode_mprotect` [source,c] ---- int mpo_check_vnode_mprotect(struct ucred *cred, struct vnode *vp, struct label *label, int prot); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Mapped vnode | |`prot` |Memory protections | |=== Determine whether the subject should be allowed to set the specified memory protections on memory mapped from the vnode `vp`. [[mac-mpo-check-vnode-poll]] ==== `mpo_check_vnode_poll` [source,c] ---- int mpo_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`active_cred` |Subject credential | |`file_cred` |Credential associated with the struct file | |`vp` |Polled vnode | |`label` |Policy label associated with `vp` | |=== Determine whether the subject should be allowed to poll the vnode `vp`. [[mac-mpo-check-vnode-rename-from]] ==== `mpo_check_vnode_rename_from` [source,c] ---- int mpo_vnode_rename_from(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`dvp` |Directory vnode | |`dlabel` |Policy label associated with `dvp` | |`vp` |Vnode to be renamed | |`label` |Policy label associated with `vp` | |`cnp` |Component name for `vp` | |=== Determine whether the subject should be allowed to rename the vnode `vp` to something else. [[mac-mpo-check-vnode-rename-to]] ==== `mpo_check_vnode_rename_to` [source,c] ---- int mpo_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, int samedir, struct componentname *cnp); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`dvp` |Directory vnode | |`dlabel` |Policy label associated with `dvp` | |`vp` |Overwritten vnode | |`label` |Policy label associated with `vp` | |`samedir` |Boolean; `1` if the source and destination directories are the same | |`cnp` |Destination component name | |=== Determine whether the subject should be allowed to rename to the vnode `vp`, into the directory `dvp`, or to the name represented by `cnp`. If there is no existing file to overwrite, `vp` and `label` will be NULL. [[mac-mpo-cred-check-socket-listen]] ==== `mpo_check_socket_listen` [source,c] ---- int mpo_check_socket_listen(struct ucred *cred, struct socket *socket, struct label *socketlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`socket` |Object; socket | |`socketlabel` |Policy label for `socket` | |=== Determine whether the subject credential can listen on the passed socket. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-lookup]] ==== `mpo_check_vnode_lookup` [source,c] ---- int mpo_check_vnode_lookup(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`dvp` |Object; vnode | |`dlabel` |Policy label for `dvp` | |`cnp` |Component name being looked up | |=== Determine whether the subject credential can perform a lookup in the passed directory vnode for the passed name. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-open]] ==== `mpo_check_vnode_open` [source,c] ---- int mpo_check_vnode_open(struct ucred *cred, struct vnode *vp, struct label *label, int acc_mode); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |`acc_mode` |man:open[2] access mode | |=== Determine whether the subject credential can perform an open operation on the passed vnode with the passed access mode. Return 0 for success, or an errno value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-readdir]] ==== `mpo_check_vnode_readdir` [source,c] ---- int mpo_check_vnode_readdir(struct ucred *cred, struct vnode *dvp, struct label *dlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`dvp` |Object; directory vnode | |`dlabel` |Policy label for `dvp` | |=== Determine whether the subject credential can perform a `readdir` operation on the passed directory vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-readlink]] ==== `mpo_check_vnode_readlink` [source,c] ---- int mpo_check_vnode_readlink(struct ucred *cred, struct vnode *vp, struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |=== Determine whether the subject credential can perform a `readlink` operation on the passed symlink vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. This call may be made in a number of situations, including an explicit `readlink` call by the user process, or as a result of an implicit `readlink` during a name lookup by the process. [[mac-mpo-cred-check-vnode-revoke]] ==== `mpo_check_vnode_revoke` [source,c] ---- int mpo_check_vnode_revoke(struct ucred *cred, struct vnode *vp, struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |=== Determine whether the subject credential can revoke access to the passed vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-setacl]] ==== `mpo_check_vnode_setacl` [source,c] ---- int mpo_check_vnode_setacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type, struct acl *acl); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |`type` |ACL type | |`acl` |ACL | |=== Determine whether the subject credential can set the passed ACL of passed type on the passed vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-setextattr]] ==== `mpo_check_vnode_setextattr` [source,c] ---- int mpo_check_vnode_setextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |`attrnamespace` |Extended attribute namespace | |`name` |Extended attribute name | |`uio` |I/O structure pointer; see man:uio[9] | |=== Determine whether the subject credential can set the extended attribute of passed name and passed namespace on the passed vnode. Policies implementing security labels backed into extended attributes may want to provide additional protections for those attributes. Additionally, policies should avoid making decisions based on the data referenced from `uio`, as there is a potential race condition between this check and the actual operation. The `uio` may also be `NULL` if a delete operation is being performed. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-setflags]] ==== `mpo_check_vnode_setflags` [source,c] ---- int mpo_check_vnode_setflags(struct ucred *cred, struct vnode *vp, struct label *label, u_long flags); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |`flags` |File flags; see man:chflags[2] | |=== Determine whether the subject credential can set the passed flags on the passed vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-setmode]] ==== `mpo_check_vnode_setmode` [source,c] ---- int mpo_check_vnode_setmode(struct ucred *cred, struct vnode *vp, struct label *label, mode_t mode); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |`mode` |File mode; see man:chmod[2] | |=== Determine whether the subject credential can set the passed mode on the passed vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-setowner]] ==== `mpo_check_vnode_setowner` [source,c] ---- int mpo_check_vnode_setowner(struct ucred *cred, struct vnode *vp, struct label *label, uid_t uid, gid_t gid); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |`uid` |User ID | |`gid` |Group ID | |=== Determine whether the subject credential can set the passed uid and passed gid as file uid and file gid on the passed vnode. The IDs may be set to (`-1`) to request no update. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-vnode-setutimes]] ==== `mpo_check_vnode_setutimes` [source,c] ---- int mpo_check_vnode_setutimes(struct ucred *cred, struct vnode *vp, struct label *label, struct timespec atime, struct timespec mtime); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vp | |`label` |Policy label for `vp` | |`atime` |Access time; see man:utimes[2] | |`mtime` |Modification time; see man:utimes[2] | |=== Determine whether the subject credential can set the passed access timestamps on the passed vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-proc-sched]] ==== `mpo_check_proc_sched` [source,c] ---- int mpo_check_proc_sched(struct ucred *ucred, struct proc *proc); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`proc` |Object; process | |=== Determine whether the subject credential can change the scheduling parameters of the passed process. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, EPERM for lack of privilege, or ESRCH to limit visibility. See man:setpriority[2] for more information. [[mac-mpo-cred-check-proc-signal]] ==== `mpo_check_proc_signal` [source,c] ---- int mpo_check_proc_signal(struct ucred *cred, struct proc *proc, int signal); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`proc` |Object; process | |`signal` |Signal; see man:kill[2] | |=== Determine whether the subject credential can deliver the passed signal to the passed process. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, EPERM for lack of privilege, or ESRCH to limit visibility. [[mac-mpo-cred-check-vnode-stat]] ==== `mpo_check_vnode_stat` [source,c] ---- int mpo_check_vnode_stat(struct ucred *cred, struct vnode *vp, struct label *label); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Object; vnode | |`label` |Policy label for `vp` | |=== Determine whether the subject credential can `stat` the passed vnode. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. See man:stat[2] for more information. [[mac-mpo-cred-check-ifnet-transmit]] ==== `mpo_check_ifnet_transmit` [source,c] ---- int mpo_check_ifnet_transmit(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`ifnet` |Network interface | |`ifnetlabel` |Policy label for `ifnet` | |`mbuf` |Object; mbuf to be sent | |`mbuflabel` |Policy label for `mbuf` | |=== Determine whether the network interface can transmit the passed mbuf. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-cred-check-socket-deliver]] ==== `mpo_check_socket_deliver` [source,c] ---- int mpo_check_socket_deliver(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`ifnet` |Network interface | |`ifnetlabel` |Policy label for `ifnet` | |`mbuf` |Object; mbuf to be delivered | |`mbuflabel` |Policy label for `mbuf` | |=== Determine whether the socket may receive the datagram stored in the passed mbuf header. Return 0 for success, or an `errno` value for failure. Suggested failures: EACCES for label mismatch, or EPERM for lack of privilege. [[mac-mpo-check-socket-visible]] ==== `mpo_check_socket_visible` [source,c] ---- int mpo_check_socket_visible(struct ucred *cred, struct socket *so, struct label *socketlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential |Immutable |`so` |Object; socket | |`socketlabel` |Policy label for `so` | |=== Determine whether the subject credential cred can "see" the passed socket (`socket`) using system monitoring functions, such as those employed by man:netstat[8] and man:sockstat[1]. Return 0 for success, or an `errno` value for failure. Suggested failure: EACCES for label mismatches, EPERM for lack of privilege, or ESRCH to hide visibility. [[mac-mpo-check-system-acct]] ==== `mpo_check_system_acct` [source,c] ---- int mpo_check_system_acct(struct ucred *ucred, struct vnode *vp, struct label *vlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`ucred` |Subject credential | |`vp` |Accounting file; man:acct[5] | |`vlabel` |Label associated with `vp` | |=== Determine whether the subject should be allowed to enable accounting, based on its label and the label of the accounting log file. [[mac-mpo-check-system-nfsd]] ==== `mpo_check_system_nfsd` [source,c] ---- int mpo_check_system_nfsd(struct ucred *cred); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |=== Determine whether the subject should be allowed to call man:nfssvc[2]. [[mac-mpo-check-system-reboot]] ==== `mpo_check_system_reboot` [source,c] ---- int mpo_check_system_reboot(struct ucred *cred, int howto); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`howto` |`howto` parameter from man:reboot[2] | |=== Determine whether the subject should be allowed to reboot the system in the specified manner. [[mac-mpo-check-system-settime]] ==== `mpo_check_system_settime` [source,c] ---- int mpo_check_system_settime(struct ucred *cred); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |=== Determine whether the user should be allowed to set the system clock. [[mac-mpo-check-system-swapon]] ==== `mpo_check_system_swapon` [source,c] ---- int mpo_check_system_swapon(struct ucred *cred, struct vnode *vp, struct label *vlabel); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`vp` |Swap device | |`vlabel` |Label associated with `vp` | |=== Determine whether the subject should be allowed to add `vp` as a swap device. [[mac-mpo-check-system-sysctl]] ==== `mpo_check_system_sysctl` [source,c] ---- int mpo_check_system_sysctl(struct ucred *cred, int *name, u_int *namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen); ---- [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Parameter | Description | Locking |`cred` |Subject credential | |`name` |See man:sysctl[3] | |`namelen` | | |`old` | | |`oldlenp` | | |`inkernel` |Boolean; `1` if called from kernel | |`new` |See man:sysctl[3] | |`newlen` | | |=== Determine whether the subject should be allowed to make the specified man:sysctl[3] transaction. [[mac-label-management]] === Label Management Calls Relabel events occur when a user process has requested that the label on an object be modified. A two-phase update occurs: first, an access control check will be performed to determine if the update is both valid and permitted, and then the update itself is performed via a separate entry point. Relabel entry points typically accept the object, object label reference, and an update label submitted by the process. Memory allocation during relabel is discouraged, as relabel calls are not permitted to fail (failure should be reported earlier in the relabel check). [[mac-userland-arch]] == Userland Architecture The TrustedBSD MAC Framework includes a number of policy-agnostic elements, including MAC library interfaces for abstractly managing labels, modifications to the system credential management and login libraries to support the assignment of MAC labels to users, and a set of tools to monitor and modify labels on processes, files, and network interfaces. More details on the user architecture will be added to this section in the near future. [[mac-userland-labels]] === APIs for Policy-Agnostic Label Management The TrustedBSD MAC Framework provides a number of library and system calls permitting applications to manage MAC labels on objects using a policy-agnostic interface. This permits applications to manipulate labels for a variety of policies without being written to support specific policies. These interfaces are used by general-purpose tools such as man:ifconfig[8], man:ls[1] and man:ps[1] to view labels on network interfaces, files, and processes. The APIs also support MAC management tools including man:getfmac[8], man:getpmac[8], man:setfmac[8], man:setfsmac[8], and man:setpmac[8]. The MAC APIs are documented in man:mac[3]. Applications handle MAC labels in two forms: an internalized form used to return and set labels on processes and objects (`mac_t`), and externalized form based on C strings appropriate for storage in configuration files, display to the user, or input from the user. Each MAC label contains a number of elements, each consisting of a name and value pair. Policy modules in the kernel bind to specific names and interpret the values in policy-specific ways. In the externalized string form, labels are represented by a comma-delimited list of name and value pairs separated by the `/` character. Labels may be directly converted to and from text using provided APIs; when retrieving labels from the kernel, internalized label storage must first be prepared for the desired label element set. Typically, this is done in one of two ways: using man:mac_prepare[3] and an arbitrary list of desired label elements, or one of the variants of the call that loads a default element set from the man:mac.conf[5] configuration file. Per-object defaults permit application writers to usefully display labels associated with objects without being aware of the policies present in the system. [NOTE] ==== Currently, direct manipulation of label elements other than by conversion to a text string, string editing, and conversion back to an internalized label is not supported by the MAC library. Such interfaces may be added in the future if they prove necessary for application writers. ==== [[mac-userland-credentials]] === Binding of Labels to Users The standard user context management interface, man:setusercontext[3], has been modified to retrieve MAC labels associated with a user's class from man:login.conf[5]. These labels are then set along with other user context when either `LOGIN_SETALL` is specified, or when `LOGIN_SETMAC` is explicitly specified. [NOTE] ==== It is expected that, in a future version of FreeBSD, the MAC label database will be separated from the [.filename]#login.conf# user class abstraction, and be maintained in a separate database. However, the man:setusercontext[3] API should remain the same following such a change. ==== [[mac-conclusion]] == Conclusion The TrustedBSD MAC framework permits kernel modules to augment the system security policy in a highly integrated manner. They may do this based on existing object properties, or based on label data that is maintained with the assistance of the MAC framework. The framework is sufficiently flexible to implement a variety of policy types, including information flow security policies such as MLS and Biba, as well as policies based on existing BSD credentials or file protections. Policy authors may wish to consult this documentation as well as existing security modules when implementing a new security service. diff --git a/documentation/content/en/books/arch-handbook/smp/_index.adoc b/documentation/content/en/books/arch-handbook/smp/_index.adoc index 7d773ca258..9922f89eb1 100644 --- a/documentation/content/en/books/arch-handbook/smp/_index.adoc +++ b/documentation/content/en/books/arch-handbook/smp/_index.adoc @@ -1,363 +1,363 @@ --- title: Chapter 8. SMPng Design Document prev: books/arch-handbook/vm next: books/arch-handbook/partii description: SMPng Design Document tags: ["SMPng", "introduction", "locks"] showBookMenu: true weight: 9 path: "/books/arch-handbook/smp/" --- [[smp]] = SMPng Design Document :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 8 :partnums: :source-highlighter: rouge :experimental: :images-path: books/arch-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[smp-intro]] == Introduction This document presents the current design and implementation of the SMPng Architecture. First, the basic primitives and tools are introduced. Next, a general architecture for the FreeBSD kernel's synchronization and execution model is laid out. Then, locking strategies for specific subsystems are discussed, documenting the approaches taken to introduce fine-grained synchronization and parallelism for each subsystem. Finally, detailed implementation notes are provided to motivate design choices, and make the reader aware of important implications involving the use of specific primitives. This document is a work-in-progress, and will be updated to reflect on-going design and implementation activities associated with the SMPng Project. Many sections currently exist only in outline form, but will be fleshed out as work proceeds. Updates or suggestions regarding the document may be directed to the document editors. The goal of SMPng is to allow concurrency in the kernel. The kernel is basically one rather large and complex program. To make the kernel multi-threaded we use some of the same tools used to make other programs multi-threaded. These include mutexes, shared/exclusive locks, semaphores, and condition variables. For the -definitions of these and other SMP-related terms, please see the crossref:smp[smp-glossary] section of this article. +definitions of these and other SMP-related terms, please see the crossref:smp[smp-glossary, Glossary] section of this article. [[smp-lock-fundamentals]] == Basic Tools and Locking Fundamentals === Atomic Instructions and Memory Barriers There are several existing treatments of memory barriers and atomic instructions, so this section will not include a lot of detail. To put it simply, one can not go around reading variables without a lock if a lock is used to protect writes to that variable. This becomes obvious when you consider that memory barriers simply determine relative order of memory operations; they do not make any guarantee about timing of memory operations. That is, a memory barrier does not force the contents of a CPU's local cache or store buffer to flush. Instead, the memory barrier at lock release simply ensures that all writes to the protected data will be visible to other CPU's or devices if the write to release the lock is visible. The CPU is free to keep that data in its cache or store buffer as long as it wants. However, if another CPU performs an atomic instruction on the same datum, the first CPU must guarantee that the updated value is made visible to the second CPU along with any other operations that memory barriers may require. For example, assuming a simple model where data is considered visible when it is in main memory (or a global cache), when an atomic instruction is triggered on one CPU, other CPU's store buffers and caches must flush any writes to that same cache line along with any pending operations behind a memory barrier. This requires one to take special care when using an item protected by atomic instructions. For example, in the sleep mutex implementation, we have to use an `atomic_cmpset` rather than an `atomic_set` to turn on the `MTX_CONTESTED` bit. The reason is that we read the value of `mtx_lock` into a variable and then make a decision based on that read. However, the value we read may be stale, or it may change while we are making our decision. Thus, when the `atomic_set` executed, it may end up setting the bit on another value than the one we made the decision on. Thus, we have to use an `atomic_cmpset` to set the value only if the value we made the decision on is up-to-date and valid. Finally, atomic instructions only allow one item to be updated or read. If one needs to atomically update several items, then a lock must be used instead. For example, if two counters must be read and have values that are consistent relative to each other, then those counters must be protected by a lock rather than by separate atomic instructions. === Read Locks Versus Write Locks Read locks do not need to be as strong as write locks. Both types of locks need to ensure that the data they are accessing is not stale. However, only write access requires exclusive access. Multiple threads can safely read a value. Using different types of locks for reads and writes can be implemented in a number of ways. First, sx locks can be used in this manner by using an exclusive lock when writing and a shared lock when reading. This method is quite straightforward. A second method is a bit more obscure. You can protect a datum with multiple locks. Then for reading that data you simply need to have a read lock of one of the locks. However, to write to the data, you need to have a write lock of all of the locks. This can make writing rather expensive but can be useful when data is accessed in various ways. For example, the parent process pointer is protected by both the `proctree_lock` sx lock and the per-process mutex. Sometimes the proc lock is easier as we are just checking to see who a parent of a process is that we already have locked. However, other places such as `inferior` need to walk the tree of processes via parent pointers and locking each process would be prohibitive as well as a pain to guarantee that the condition you are checking remains valid for both the check and the actions taken as a result of the check. === Locking Conditions and Results If you need a lock to check the state of a variable so that you can take an action based on the state you read, you can not just hold the lock while reading the variable and then drop the lock before you act on the value you read. Once you drop the lock, the variable can change rendering your decision invalid. Thus, you must hold the lock both while reading the variable and while performing the action as a result of the test. [[smp-design]] == General Architecture and Design === Interrupt Handling Following the pattern of several other multi-threaded UNIX(R) kernels, FreeBSD deals with interrupt handlers by giving them their own thread context. Providing a context for interrupt handlers allows them to block on locks. To help avoid latency, however, interrupt threads run at real-time kernel priority. Thus, interrupt handlers should not execute for very long to avoid starving other kernel threads. In addition, since multiple handlers may share an interrupt thread, interrupt handlers should not sleep or use a sleepable lock to avoid starving another interrupt handler. The interrupt threads currently in FreeBSD are referred to as heavyweight interrupt threads. They are called this because switching to an interrupt thread involves a full context switch. In the initial implementation, the kernel was not preemptive and thus interrupts that interrupted a kernel thread would have to wait until the kernel thread blocked or returned to userland before they would have an opportunity to run. To deal with the latency problems, the kernel in FreeBSD has been made preemptive. Currently, we only preempt a kernel thread when we release a sleep mutex or when an interrupt comes in. However, the plan is to make the FreeBSD kernel fully preemptive as described below. Not all interrupt handlers execute in a thread context. Instead, some handlers execute directly in primary interrupt context. These interrupt handlers are currently misnamed "fast" interrupt handlers since the `INTR_FAST` flag used in earlier versions of the kernel is used to mark these handlers. The only interrupts which currently use these types of interrupt handlers are clock interrupts and serial I/O device interrupts. Since these handlers do not have their own context, they may not acquire blocking locks and thus may only use spin mutexes. Finally, there is one optional optimization that can be added in MD code called lightweight context switches. Since an interrupt thread executes in a kernel context, it can borrow the vmspace of any process. Thus, in a lightweight context switch, the switch to the interrupt thread does not switch vmspaces but borrows the vmspace of the interrupted thread. In order to ensure that the vmspace of the interrupted thread does not disappear out from under us, the interrupted thread is not allowed to execute until the interrupt thread is no longer borrowing its vmspace. This can happen when the interrupt thread either blocks or finishes. If an interrupt thread blocks, then it will use its own context when it is made runnable again. Thus, it can release the interrupted thread. The cons of this optimization are that they are very machine specific and complex and thus only worth the effort if their is a large performance improvement. At this point it is probably too early to tell, and in fact, will probably hurt performance as almost all interrupt handlers will immediately block on Giant and require a thread fix-up when they block. Also, an alternative method of interrupt handling has been proposed by Mike Smith that works like so: . Each interrupt handler has two parts: a predicate which runs in primary interrupt context and a handler which runs in its own thread context. . If an interrupt handler has a predicate, then when an interrupt is triggered, the predicate is run. If the predicate returns true then the interrupt is assumed to be fully handled and the kernel returns from the interrupt. If the predicate returns false or there is no predicate, then the threaded handler is scheduled to run. Fitting light weight context switches into this scheme might prove rather complicated. Since we may want to change to this scheme at some point in the future, it is probably best to defer work on light weight context switches until we have settled on the final interrupt handling architecture and determined how light weight context switches might or might not fit into it. === Kernel Preemption and Critical Sections ==== Kernel Preemption in a Nutshell Kernel preemption is fairly simple. The basic idea is that a CPU should always be doing the highest priority work available. Well, that is the ideal at least. There are a couple of cases where the expense of achieving the ideal is not worth being perfect. Implementing full kernel preemption is very straightforward: when you schedule a thread to be executed by putting it on a run queue, you check to see if its priority is higher than the currently executing thread. If so, you initiate a context switch to that thread. While locks can protect most data in the case of a preemption, not all of the kernel is preemption safe. For example, if a thread holding a spin mutex preempted and the new thread attempts to grab the same spin mutex, the new thread may spin forever as the interrupted thread may never get a chance to execute. Also, some code such as the code to assign an address space number for a process during `exec` on the Alpha needs to not be preempted as it supports the actual context switch code. Preemption is disabled for these code sections by using a critical section. ==== Critical Sections The responsibility of the critical section API is to prevent context switches inside of a critical section. With a fully preemptive kernel, every `setrunqueue` of a thread other than the current thread is a preemption point. One implementation is for `critical_enter` to set a per-thread flag that is cleared by its counterpart. If `setrunqueue` is called with this flag set, it does not preempt regardless of the priority of the new thread relative to the current thread. However, since critical sections are used in spin mutexes to prevent context switches and multiple spin mutexes can be acquired, the critical section API must support nesting. For this reason the current implementation uses a nesting count instead of a single per-thread flag. In order to minimize latency, preemptions inside of a critical section are deferred rather than dropped. If a thread that would normally be preempted to is made runnable while the current thread is in a critical section, then a per-thread flag is set to indicate that there is a pending preemption. When the outermost critical section is exited, the flag is checked. If the flag is set, then the current thread is preempted to allow the higher priority thread to run. Interrupts pose a problem with regards to spin mutexes. If a low-level interrupt handler needs a lock, it needs to not interrupt any code needing that lock to avoid possible data structure corruption. Currently, providing this mechanism is piggybacked onto critical section API by means of the `cpu_critical_enter` and `cpu_critical_exit` functions. Currently this API disables and re-enables interrupts on all of FreeBSD's current platforms. This approach may not be purely optimal, but it is simple to understand and simple to get right. Theoretically, this second API need only be used for spin mutexes that are used in primary interrupt context. However, to make the code simpler, it is used for all spin mutexes and even all critical sections. It may be desirable to split out the MD API from the MI API and only use it in conjunction with the MI API in the spin mutex implementation. If this approach is taken, then the MD API likely would need a rename to show that it is a separate API. ==== Design Tradeoffs As mentioned earlier, a couple of trade-offs have been made to sacrifice cases where perfect preemption may not always provide the best performance. The first trade-off is that the preemption code does not take other CPUs into account. Suppose we have a two CPU's A and B with the priority of A's thread as 4 and the priority of B's thread as 2. If CPU B makes a thread with priority 1 runnable, then in theory, we want CPU A to switch to the new thread so that we will be running the two highest priority runnable threads. However, the cost of determining which CPU to enforce a preemption on as well as actually signaling that CPU via an IPI along with the synchronization that would be required would be enormous. Thus, the current code would instead force CPU B to switch to the higher priority thread. Note that this still puts the system in a better position as CPU B is executing a thread of priority 1 rather than a thread of priority 2. The second trade-off limits immediate kernel preemption to real-time priority kernel threads. In the simple case of preemption defined above, a thread is always preempted immediately (or as soon as a critical section is exited) if a higher priority thread is made runnable. However, many threads executing in the kernel only execute in a kernel context for a short time before either blocking or returning to userland. Thus, if the kernel preempts these threads to run another non-realtime kernel thread, the kernel may switch out the executing thread just before it is about to sleep or execute. The cache on the CPU must then adjust to the new thread. When the kernel returns to the preempted thread, it must refill all the cache information that was lost. In addition, two extra context switches are performed that could be avoided if the kernel deferred the preemption until the first thread blocked or returned to userland. Thus, by default, the preemption code will only preempt immediately if the higher priority thread is a real-time priority thread. Turning on full kernel preemption for all kernel threads has value as a debugging aid since it exposes more race conditions. It is especially useful on UP systems were many races are hard to simulate otherwise. Thus, there is a kernel option `FULL_PREEMPTION` to enable preemption for all kernel threads that can be used for debugging purposes. === Thread Migration Simply put, a thread migrates when it moves from one CPU to another. In a non-preemptive kernel this can only happen at well-defined points such as when calling `msleep` or returning to userland. However, in the preemptive kernel, an interrupt can force a preemption and possible migration at any time. This can have negative affects on per-CPU data since with the exception of `curthread` and `curpcb` the data can change whenever you migrate. Since you can potentially migrate at any time this renders unprotected per-CPU data access rather useless. Thus it is desirable to be able to disable migration for sections of code that need per-CPU data to be stable. Critical sections currently prevent migration since they do not allow context switches. However, this may be too strong of a requirement to enforce in some cases since a critical section also effectively blocks interrupt threads on the current processor. As a result, another API has been provided to allow the current thread to indicate that if it preempted it should not migrate to another CPU. This API is known as thread pinning and is provided by the scheduler. The API consists of two functions: `sched_pin` and `sched_unpin`. These functions manage a per-thread nesting count `td_pinned`. A thread is pinned when its nesting count is greater than zero and a thread starts off unpinned with a nesting count of zero. Each scheduler implementation is required to ensure that pinned threads are only executed on the CPU that they were executing on when the `sched_pin` was first called. Since the nesting count is only written to by the thread itself and is only read by other threads when the pinned thread is not executing but while `sched_lock` is held, then `td_pinned` does not need any locking. The `sched_pin` function increments the nesting count and `sched_unpin` decrements the nesting count. Note that these functions only operate on the current thread and bind the current thread to the CPU it is executing on at the time. To bind an arbitrary thread to a specific CPU, the `sched_bind` and `sched_unbind` functions should be used instead. === Callouts The `timeout` kernel facility permits kernel services to register functions for execution as part of the `softclock` software interrupt. Events are scheduled based on a desired number of clock ticks, and callbacks to the consumer-provided function will occur at approximately the right time. The global list of pending timeout events is protected by a global spin mutex, `callout_lock`; all access to the timeout list must be performed with this mutex held. When `softclock` is woken up, it scans the list of pending timeouts for those that should fire. In order to avoid lock order reversal, the `softclock` thread will release the `callout_lock` mutex when invoking the provided `timeout` callback function. If the `CALLOUT_MPSAFE` flag was not set during registration, then Giant will be grabbed before invoking the callout, and then released afterwards. The `callout_lock` mutex will be re-grabbed before proceeding. The `softclock` code is careful to leave the list in a consistent state while releasing the mutex. If `DIAGNOSTIC` is enabled, then the time taken to execute each function is measured, and a warning is generated if it exceeds a threshold. [[smp-lock-strategies]] == Specific Locking Strategies === Credentials `struct ucred` is the kernel's internal credential structure, and is generally used as the basis for process-driven access control within the kernel. BSD-derived systems use a "copy-on-write" model for credential data: multiple references may exist for a credential structure, and when a change needs to be made, the structure is duplicated, modified, and then the reference replaced. Due to wide-spread caching of the credential to implement access control on open, this results in substantial memory savings. With a move to fine-grained SMP, this model also saves substantially on locking operations by requiring that modification only occur on an unshared credential, avoiding the need for explicit synchronization when consuming a known-shared credential. Credential structures with a single reference are considered mutable; shared credential structures must not be modified or a race condition is risked. A mutex, `cr_mtxp` protects the reference count of `struct ucred` so as to maintain consistency. Any use of the structure requires a valid reference for the duration of the use, or the structure may be released out from under the illegitimate consumer. The `struct ucred` mutex is a leaf mutex and is implemented via a mutex pool for performance reasons. Usually, credentials are used in a read-only manner for access control decisions, and in this case `td_ucred` is generally preferred because it requires no locking. When a process' credential is updated the `proc` lock must be held across the check and update operations thus avoid races. The process credential `p_ucred` must be used for check and update operations to prevent time-of-check, time-of-use races. If system call invocations will perform access control after an update to the process credential, the value of `td_ucred` must also be refreshed to the current process value. This will prevent use of a stale credential following a change. The kernel automatically refreshes the `td_ucred` pointer in the thread structure from the process `p_ucred` whenever a process enters the kernel, permitting use of a fresh credential for kernel access control. === File Descriptors and File Descriptor Tables Details to follow. === Jail Structures `struct prison` stores administrative details pertinent to the maintenance of jails created using the man:jail[2] API. This includes the per-jail hostname, IP address, and related settings. This structure is reference-counted since pointers to instances of the structure are shared by many credential structures. A single mutex, `pr_mtx` protects read and write access to the reference count and all mutable variables inside the struct jail. Some variables are set only when the jail is created, and a valid reference to the `struct prison` is sufficient to read these values. The precise locking of each entry is documented via comments in [.filename]#sys/jail.h#. === MAC Framework The TrustedBSD MAC Framework maintains data in a variety of kernel objects, in the form of `struct label`. In general, labels in kernel objects are protected by the same lock as the remainder of the kernel object. For example, the `v_label` label in `struct vnode` is protected by the vnode lock on the vnode. In addition to labels maintained in standard kernel objects, the MAC Framework also maintains a list of registered and active policies. The policy list is protected by a global mutex (`mac_policy_list_lock`) and a busy count (also protected by the mutex). Since many access control checks may occur in parallel, entry to the framework for a read-only access to the policy list requires holding the mutex while incrementing (and later decrementing) the busy count. The mutex need not be held for the duration of the MAC entry operation--some operations, such as label operations on file system objects--are long-lived. To modify the policy list, such as during policy registration and de-registration, the mutex must be held and the reference count must be zero, to prevent modification of the list while it is in use. A condition variable, `mac_policy_list_not_busy`, is available to threads that need to wait for the list to become unbusy, but this condition variable must only be waited on if the caller is holding no other locks, or a lock order violation may be possible. The busy count, in effect, acts as a form of shared/exclusive lock over access to the framework: the difference is that, unlike with an sx lock, consumers waiting for the list to become unbusy may be starved, rather than permitting lock order problems with regards to the busy count and other locks that may be held on entry to (or inside) the MAC Framework. === Modules For the module subsystem there exists a single lock that is used to protect the shared data. This lock is a shared/exclusive (SX) lock and has a good chance of needing to be acquired (shared or exclusively), therefore there are a few macros that have been added to make access to the lock more easy. These macros can be located in [.filename]#sys/module.h# and are quite basic in terms of usage. The main structures protected under this lock are the `module_t` structures (when shared) and the global `modulelist_t` structure, modules. One should review the related source code in [.filename]#kern/kern_module.c# to further understand the locking strategy. === Newbus Device Tree The newbus system will have one sx lock. Readers will hold a shared (read) lock (man:sx_slock[9]) and writers will hold an exclusive (write) lock (man:sx_xlock[9]). Internal functions will not do locking at all. Externally visible ones will lock as needed. Those items that do not matter if the race is won or lost will not be locked, since they tend to be read all over the place (e.g., man:device_get_softc[9]). There will be relatively few changes to the newbus data structures, so a single lock should be sufficient and not impose a performance penalty. === Pipes ... === Processes and Threads - process hierarchy - proc locks, references - thread-specific copies of proc entries to freeze during system calls, including td_ucred - inter-process operations - process groups and sessions === Scheduler Lots of references to `sched_lock` and notes pointing at specific primitives and related magic elsewhere in the document. === Select and Poll The `select` and `poll` functions permit threads to block waiting on events on file descriptors--most frequently, whether or not the file descriptors are readable or writable. ... === SIGIO The SIGIO service permits processes to request the delivery of a SIGIO signal to its process group when the read/write status of specified file descriptors changes. At most one process or process group is permitted to register for SIGIO from any given kernel object, and that process or group is referred to as the owner. Each object supporting SIGIO registration contains pointer field that is `NULL` if the object is not registered, or points to a `struct sigio` describing the registration. This field is protected by a global mutex, `sigio_lock`. Callers to SIGIO maintenance functions must pass in this field "by reference" so that local register copies of the field are not made when unprotected by the lock. One `struct sigio` is allocated for each registered object associated with any process or process group, and contains back-pointers to the object, owner, signal information, a credential, and the general disposition of the registration. Each process or progress group contains a list of registered `struct sigio` structures, `p_sigiolst` for processes, and `pg_sigiolst` for process groups. These lists are protected by the process or process group locks respectively. Most fields in each `struct sigio` are constant for the duration of the registration, with the exception of the `sio_pgsigio` field which links the `struct sigio` into the process or process group list. Developers implementing new kernel objects supporting SIGIO will, in general, want to avoid holding structure locks while invoking SIGIO supporting functions, such as `fsetown` or `funsetown` to avoid defining a lock order between structure locks and the global SIGIO lock. This is generally possible through use of an elevated reference count on the structure, such as reliance on a file descriptor reference to a pipe during a pipe operation. === Sysctl The `sysctl` MIB service is invoked from both within the kernel and from userland applications using a system call. At least two issues are raised in locking: first, the protection of the structures maintaining the namespace, and second, interactions with kernel variables and functions that are accessed by the sysctl interface. Since sysctl permits the direct export (and modification) of kernel statistics and configuration parameters, the sysctl mechanism must become aware of appropriate locking semantics for those variables. Currently, sysctl makes use of a single global sx lock to serialize use of `sysctl`; however, it is assumed to operate under Giant and other protections are not provided. The remainder of this section speculates on locking and semantic changes to sysctl. - Need to change the order of operations for sysctl's that update values from read old, copyin and copyout, write new to copyin, lock, read old and write new, unlock, copyout. Normal sysctl's that just copyout the old value and set a new value that they copyin may still be able to follow the old model. However, it may be cleaner to use the second model for all of the sysctl handlers to avoid lock operations. - To allow for the common case, a sysctl could embed a pointer to a mutex in the SYSCTL_FOO macros and in the struct. This would work for most sysctl's. For values protected by sx locks, spin mutexes, or other locking strategies besides a single sleep mutex, SYSCTL_PROC nodes could be used to get the locking right. === Taskqueue The taskqueue's interface has two basic locks associated with it in order to protect the related shared data. The `taskqueue_queues_mutex` is meant to serve as a lock to protect the `taskqueue_queues` TAILQ. The other mutex lock associated with this system is the one in the `struct taskqueue` data structure. The use of the synchronization primitive here is to protect the integrity of the data in the `struct taskqueue`. It should be noted that there are no separate macros to assist the user in locking down his/her own work since these locks are most likely not going to be used outside of [.filename]#kern/subr_taskqueue.c#. [[smp-implementation-notes]] == Implementation Notes === Sleep Queues A sleep queue is a structure that holds the list of threads asleep on a wait channel. Each thread that is not asleep on a wait channel carries a sleep queue structure around with it. When a thread blocks on a wait channel, it donates its sleep queue structure to that wait channel. Sleep queues associated with a wait channel are stored in a hash table. The sleep queue hash table holds sleep queues for wait channels that have at least one blocked thread. Each entry in the hash table is called a sleepqueue chain. The chain contains a linked list of sleep queues and a spin mutex. The spin mutex protects the list of sleep queues as well as the contents of the sleep queue structures on the list. Only one sleep queue is associated with a given wait channel. If multiple threads block on a wait channel than the sleep queues associated with all but the first thread are stored on a list of free sleep queues in the master sleep queue. When a thread is removed from the sleep queue it is given one of the sleep queue structures from the master queue's free list if it is not the only thread asleep on the queue. The last thread is given the master sleep queue when it is resumed. Since threads may be removed from the sleep queue in a different order than they are added, a thread may depart from a sleep queue with a different sleep queue structure than the one it arrived with. The `sleepq_lock` function locks the spin mutex of the sleep queue chain that maps to a specific wait channel. The `sleepq_lookup` function looks in the hash table for the master sleep queue associated with a given wait channel. If no master sleep queue is found, it returns `NULL`. The `sleepq_release` function unlocks the spin mutex associated with a given wait channel. A thread is added to a sleep queue via the `sleepq_add`. This function accepts the wait channel, a pointer to the mutex that protects the wait channel, a wait message description string, and a mask of flags. The sleep queue chain should be locked via `sleepq_lock` before this function is called. If no mutex protects the wait channel (or it is protected by Giant), then the mutex pointer argument should be `NULL`. The flags argument contains a type field that indicates the kind of sleep queue that the thread is being added to and a flag to indicate if the sleep is interruptible (`SLEEPQ_INTERRUPTIBLE`). Currently there are only two types of sleep queues: traditional sleep queues managed via the `msleep` and `wakeup` functions (`SLEEPQ_MSLEEP`) and condition variable sleep queues (`SLEEPQ_CONDVAR`). The sleep queue type and lock pointer argument are used solely for internal assertion checking. Code that calls `sleepq_add` should explicitly unlock any interlock protecting the wait channel after the associated sleepqueue chain has been locked via `sleepq_lock` and before blocking on the sleep queue via one of the waiting functions. A timeout for a sleep is set by invoking `sleepq_set_timeout`. The function accepts the wait channel and the timeout time as a relative tick count as its arguments. If a sleep should be interrupted by arriving signals, the `sleepq_catch_signals` function should be called as well. This function accepts the wait channel as its only parameter. If there is already a signal pending for this thread, then `sleepq_catch_signals` will return a signal number; otherwise, it will return 0. Once a thread has been added to a sleep queue, it blocks using one of the `sleepq_wait` functions. There are four wait functions depending on whether or not the caller wishes to use a timeout or have the sleep aborted by caught signals or an interrupt from the userland thread scheduler. The `sleepq_wait` function simply waits until the current thread is explicitly resumed by one of the wakeup functions. The `sleepq_timedwait` function waits until either the thread is explicitly resumed or the timeout set by an earlier call to `sleepq_set_timeout` expires. The `sleepq_wait_sig` function waits until either the thread is explicitly resumed or its sleep is aborted. The `sleepq_timedwait_sig` function waits until either the thread is explicitly resumed, the timeout set by an earlier call to `sleepq_set_timeout` expires, or the thread's sleep is aborted. All of the wait functions accept the wait channel as their first parameter. In addition, the `sleepq_timedwait_sig` function accepts a second boolean parameter to indicate if the earlier call to `sleepq_catch_signals` found a pending signal. If the thread is explicitly resumed or is aborted by a signal, then a value of zero is returned by the wait function to indicate a successful sleep. If the thread is resumed by either a timeout or an interrupt from the userland thread scheduler then an appropriate errno value is returned instead. Note that since `sleepq_wait` can only return 0 it does not return anything and the caller should assume a successful sleep. Also, if a thread's sleep times out and is aborted simultaneously then `sleepq_timedwait_sig` will return an error indicating that a timeout occurred. If an error value of 0 is returned and either `sleepq_wait_sig` or `sleepq_timedwait_sig` was used to block, then the function `sleepq_calc_signal_retval` should be called to check for any pending signals and calculate an appropriate return value if any are found. The signal number returned by the earlier call to `sleepq_catch_signals` should be passed as the sole argument to `sleepq_calc_signal_retval`. Threads asleep on a wait channel are explicitly resumed by the `sleepq_broadcast` and `sleepq_signal` functions. Both functions accept the wait channel from which to resume threads, a priority to raise resumed threads to, and a flags argument to indicate which type of sleep queue is being resumed. The priority argument is treated as a minimum priority. If a thread being resumed already has a higher priority (numerically lower) than the priority argument then its priority is not adjusted. The flags argument is used for internal assertions to ensure that sleep queues are not being treated as the wrong type. For example, the condition variable functions should not resume threads on a traditional sleep queue. The `sleepq_broadcast` function resumes all threads that are blocked on the specified wait channel while `sleepq_signal` only resumes the highest priority thread blocked on the wait channel. The sleep queue chain should first be locked via the `sleepq_lock` function before calling these functions. A sleeping thread may have its sleep interrupted by calling the `sleepq_abort` function. This function must be called with `sched_lock` held and the thread must be queued on a sleep queue. A thread may also be removed from a specific sleep queue via the `sleepq_remove` function. This function accepts both a thread and a wait channel as an argument and only awakens the thread if it is on the sleep queue for the specified wait channel. If the thread is not on a sleep queue or it is on a sleep queue for a different wait channel, then this function does nothing. === Turnstiles - Compare/contrast with sleep queues. - Lookup/wait/release. - Describe TDF_TSNOBLOCK race. - Priority propagation. === Details of the Mutex Implementation - Should we require mutexes to be owned for mtx_destroy() since we can not safely assert that they are unowned by anyone else otherwise? ==== Spin Mutexes - Use a critical section... ==== Sleep Mutexes - Describe the races with contested mutexes - Why it is safe to read mtx_lock of a contested mutex when holding the turnstile chain lock. === Witness - What does it do - How does it work [[smp-misc]] == Miscellaneous Topics === Interrupt Source and ICU Abstractions - struct isrc - pic drivers === Other Random Questions/Topics - Should we pass an interlock into `sema_wait`? - Should we have non-sleepable sx locks? - Add some info about proper use of reference counts. :sectnums!: [glossary] [[smp-glossary]] == Glossary [.glosslist] atomic:: An operation is atomic if all of its effects are visible to other CPUs together when the proper access protocol is followed. In the degenerate case are atomic instructions provided directly by machine architectures. At a higher level, if several members of a structure are protected by a lock, then a set of operations are atomic if they are all performed while holding the lock without releasing the lock in between any of the operations. + See Also operation. block:: A thread is blocked when it is waiting on a lock, resource, or condition. Unfortunately this term is a bit overloaded as a result. + See Also sleep. critical section:: A section of code that is not allowed to be preempted. A critical section is entered and exited using the man:critical_enter[9] API. MD:: Machine dependent. + See Also MI. memory operation:: A memory operation reads and/or writes to a memory location. MI:: Machine independent. + See Also MD. operation:: See memory operation. primary interrupt context:: Primary interrupt context refers to the code that runs when an interrupt occurs. This code can either run an interrupt handler directly or schedule an asynchronous interrupt thread to execute the interrupt handlers for a given interrupt source. realtime kernel thread:: A high priority kernel thread. Currently, the only realtime priority kernel threads are interrupt threads. + See Also thread. sleep:: A thread is asleep when it is blocked on a condition variable or a sleep queue via msleep or tsleep. + See Also block. sleepable lock:: A sleepable lock is a lock that can be held by a thread which is asleep. Lockmgr locks and sx locks are currently the only sleepable locks in FreeBSD. Eventually, some sx locks such as the allproc and proctree locks may become non-sleepable locks. + See Also sleep. thread:: A kernel thread represented by a struct thread. Threads own locks and hold a single execution context. wait channel:: A kernel virtual address that threads may sleep on. :sectnums: diff --git a/documentation/content/en/books/design-44bsd/_index.adoc b/documentation/content/en/books/design-44bsd/_index.adoc index af20245ea0..b3b86c58b7 100644 --- a/documentation/content/en/books/design-44bsd/_index.adoc +++ b/documentation/content/en/books/design-44bsd/_index.adoc @@ -1,867 +1,867 @@ --- title: The Design and Implementation of the 4.4BSD Operating System authors: - author: Marshall Kirk McKusick - author: Keith Bostic - author: Michael J. Karels - author: John S. Quarterman copyright: 1996 Addison-Wesley Longman, Inc description: Donated by Addison-Wesley, provides a design overview of 4.4BSD, from which FreeBSD was originally derived trademarks: ["design-44bsd"] bookOrder: 60 tags: ["4.4BSD", "design", "operating system", "BSD", "UNIX"] layout: single --- = The Design and Implementation of the 4.4BSD Operating System :doctype: book :toc: macro :toclevels: 2 :icons: font :sectnums: :sectnumlevels: 6 :partnums: :sectnumoffset: 2 :source-highlighter: rouge :experimental: :images-path: books/design-44bsd/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../images/{images-path} include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] ''' toc::[] [[overview]] == Design Overview of 4.4BSD [[overview-facilities]] === 4.4BSD Facilities and the Kernel The 4.4BSD kernel provides four basic facilities: processes, a filesystem, communications, and system startup. This section outlines where each of these four basic services is described in this book. . Processes constitute a thread of control in an address space. Mechanisms for creating, terminating, and otherwise controlling processes are described in Chapter 4. The system multiplexes separate virtual-address spaces for each process; this memory management is discussed in Chapter 5. . The user interface to the filesystem and devices is similar; common aspects are discussed in Chapter 6. The filesystem is a set of named files, organized in a tree-structured hierarchy of directories, and of operations to manipulate them, as presented in Chapter 7. Files reside on physical media such as disks. 4.4BSD supports several organizations of data on the disk, as set forth in Chapter 8. Access to files on remote machines is the subject of Chapter 9. Terminals are used to access the system; their operation is the subject of Chapter 10. . Communication mechanisms provided by traditional UNIX systems include simplex reliable byte streams between related processes (see pipes, Section 11.1), and notification of exceptional events (see signals, Section 4.7). 4.4BSD also has a general interprocess-communication facility. This facility, described in Chapter 11, uses access mechanisms distinct from those of the filesystem, but, once a connection is set up, a process can access it as though it were a pipe. There is a general networking framework, discussed in Chapter 12, that is normally used as a layer underlying the IPC facility. Chapter 13 describes a particular networking implementation in detail. . Any real operating system has operational issues, such as how to start it running. Startup and operational issues are described in Chapter 14. Sections 2.3 through 2.14 present introductory material related to Chapters 3 through 14. We shall define terms, mention basic system calls, and explore historical developments. Finally, we shall give the reasons for many major design decisions. ==== The Kernel The _kernel_ is the part of the system that runs in protected mode and mediates access by all user programs to the underlying hardware (e.g., CPU, disks, terminals, network links) and software constructs (e.g., filesystem, network protocols). The kernel provides the basic system facilities; it creates and manages processes, and provides functions to access the filesystem and communication facilities. These functions, called _system calls_ appear to user processes as library subroutines. These system calls are the only interface that processes have to these facilities. Details of the system-call mechanism are given in Chapter 3, as are descriptions of several kernel mechanisms that do not execute as the direct result of a process doing a system call. A _kernel_ in traditional operating-system terminology, is a small nucleus of software that provides only the minimal facilities necessary for implementing additional operating-system services. In contemporary research operating systems -- such as Chorus crossref:design-44bsd[biblio-rozier, [Rozier et al, 1988]], Mach crossref:design-44bsd[biblio-accetta, [Accetta et al, 1986]], Tunis crossref:design-44bsd[biblio-ewens, [Ewens et al, 1985]], and the V Kernel crossref:design-44bsd[biblio-cheriton, [Cheriton, 1988]] -- this division of functionality is more than just a logical one. Services such as filesystems and networking protocols are implemented as client application processes of the nucleus or kernel. The 4.4BSD kernel is not partitioned into multiple processes. This basic design decision was made in the earliest versions of UNIX. The first two implementations by Ken Thompson had no memory mapping, and thus made no hardware-enforced distinction between user and kernel space crossref:design-44bsd[biblio-ritchie, [Ritchie, 1988]]. A message-passing system could have been implemented as readily as the actually implemented model of kernel and user processes. The monolithic kernel was chosen for simplicity and performance. And the early kernels were small; the inclusion of facilities such as networking into the kernel has increased its size. The current trend in operating-systems research is to reduce the kernel size by placing such services in user space. Users ordinarily interact with the system through a command-language interpreter, called a _shell_, and perhaps through additional user application programs. Such programs and the shell are implemented with processes. Details of such programs are beyond the scope of this book, which instead concentrates almost exclusively on the kernel. Sections 2.3 and 2.4 describe the services provided by the 4.4BSD kernel, and give an overview of the latter's design. Later chapters describe the detailed design and implementation of these services as they appear in 4.4BSD. [[overview-kernel-organization]] === Kernel Organization In this section, we view the organization of the 4.4BSD kernel in two ways: [arabic] . As a static body of software, categorized by the functionality offered by the modules that make up the kernel . By its dynamic operation, categorized according to the services provided to users The largest part of the kernel implements the system services that applications access through system calls. In 4.4BSD, this software has been organized according to the following: * Basic kernel facilities: timer and system-clock handling, descriptor management, and process management * Memory-management support: paging and swapping * Generic system interfaces: the I/O, control, and multiplexing operations performed on descriptors * The filesystem: files, directories, pathname translation, file locking, and I/O buffer management * Terminal-handling support: the terminal-interface driver and terminal line disciplines * Interprocess-communication facilities: sockets * Support for network communication: communication protocols and generic network facilities, such as routing .Machine-independent software in the 4.4BSD kernel [[table-mach-indep]] [cols=",,",options="header",] |=== |Category |Lines of code |Percentage of kernel |headers |9,393 |4.6 |initialization |1,107 |0.6 |kernel facilities |8,793 |4.4 |generic interfaces |4,782 |2.4 |interprocess communication |4,540 |2.2 |terminal handling |3,911 |1.9 |virtual memory |11,813 |5.8 |vnode management |7,954 |3.9 |filesystem naming |6,550 |3.2 |fast filestore |4,365 |2.2 |log-structure filestore |4,337 |2.1 |memory-based filestore |645 |0.3 |cd9660 filesystem |4,177 |2.1 |miscellaneous filesystems (10) |12,695 |6.3 |network filesystem |17,199 |8.5 |network communication |8,630 |4.3 |internet protocols |11,984 |5.9 |ISO protocols |23,924 |11.8 |X.25 protocols |10,626 |5.3 |XNS protocols |5,192 |2.6 |=== Most of the software in these categories is machine independent and is portable across different hardware architectures. The machine-dependent aspects of the kernel are isolated from the mainstream code. In particular, none of the machine-independent code contains conditional code for specific architecture. When an architecture-dependent action is needed, the machine-independent code calls an architecture-dependent function that is located in the machine-dependent code. The software that is machine dependent includes * Low-level system-startup actions * Trap and fault handling * Low-level manipulation of the run-time context of a process * Configuration and initialization of hardware devices * Run-time support for I/O devices .Machine-dependent software for the HP300 in the 4.4BSD kernel [[table-mach-dep]] [cols=",,",options="header",] |=== |Category |Lines of code |Percentage of kernel |machine dependent headers |1,562 |0.8 |device driver headers |3,495 |1.7 |device driver source |17,506 |8.7 |virtual memory |3,087 |1.5 |other machine dependent |6,287 |3.1 |routines in assembly language |3,014 |1.5 |HP/UX compatibility |4,683 |2.3 |=== crossref:design-44bsd[table-mach-indep] summarizes the machine-independent software that constitutes the 4.4BSD kernel for the HP300. The numbers in column 2 are for lines of C source code, header files, and assembly language. Virtually all the software in the kernel is written in the C programming language; less than 2 percent is written in assembly language. As the statistics in crossref:design-44bsd[table-mach-dep] show, the machine-dependent software, excluding HP/UX and device support, accounts for a minuscule 6.9 percent of the kernel. Only a small part of the kernel is devoted to initializing the system. This code is used when the system is _bootstrapped_ into operation and is responsible for setting up the kernel hardware and software environment (see Chapter 14). Some operating systems (especially those with limited physical memory) discard or _overlay_ the software that performs these functions after that software has been executed. The 4.4BSD kernel does not reclaim the memory used by the startup code because that memory space is barely 0.5 percent of the kernel resources used on a typical machine. Also, the startup code does not appear in one place in the kernel -- it is scattered throughout, and it usually appears in places logically associated with what is being initialized. [[overview-kernel-service]] === Kernel Services The boundary between the kernel- and user-level code is enforced by hardware-protection facilities provided by the underlying hardware. The kernel operates in a separate address space that is inaccessible to user processes. Privileged operations -- such as starting I/O and halting the central processing unit (CPU) -- are available to only the kernel. Applications request services from the kernel with _system calls_. System calls are used to cause the kernel to execute complicated operations, such as writing data to secondary storage, and simple operations, such as returning the current time of day. All system calls appear _synchronous_ to applications: The application does not run while the kernel does the actions associated with a system call. The kernel may finish some operations associated with a system call after it has returned. For example, a _write_ system call will copy the data to be written from the user process to a kernel buffer while the process waits, but will usually return from the system call before the kernel buffer is written to the disk. A system call usually is implemented as a hardware trap that changes the CPU's execution mode and the current address-space mapping. Parameters supplied by users in system calls are validated by the kernel before being used. Such checking ensures the integrity of the system. All parameters passed into the kernel are copied into the kernel's address space, to ensure that validated parameters are not changed as a side effect of the system call. System-call results are returned by the kernel, either in hardware registers or by their values being copied to user-specified memory addresses. Like parameters passed into the kernel, addresses used for the return of results must be validated to ensure that they are part of an application's address space. If the kernel encounters an error while processing a system call, it returns an error code to the user. For the C programming language, this error code is stored in the global variable _errno_, and the function that executed the system call returns the value -1. User applications and the kernel operate independently of each other. 4.4BSD does not store I/O control blocks or other operating-system-related data structures in the application's address space. Each user-level application is provided an independent address space in which it executes. The kernel makes most state changes, such as suspending a process while another is running, invisible to the processes involved. [[overview-process-management]] === Process Management 4.4BSD supports a multitasking environment. Each task or thread of execution is termed a _process_. The _context_ of a 4.4BSD process consists of user-level state, including the contents of its address space and the run-time environment, and kernel-level state, which includes scheduling parameters, resource controls, and identification information. The context includes everything used by the kernel in providing services for the process. Users can create processes, control the processes' execution, and receive notification when the processes' execution status changes. Every process is assigned a unique value, termed a _process identifier_ (PID). This value is used by the kernel to identify a process when reporting status changes to a user, and by a user when referencing a process in a system call. The kernel creates a process by duplicating the context of another process. The new process is termed a _child process_ of the original _parent process_ The context duplicated in process creation includes both the user-level execution state of the process and the process's system state managed by the kernel. Important components of the kernel state are described in Chapter 4. [[fig-process-lifecycle]] .Process lifecycle image:fig1.png[Process lifecycle] The process lifecycle is depicted in -crossref:design-44bsd[fig-process-lifecycle]. +crossref:design-44bsd[fig-process-lifecycle,.Process lifecycle]. A process may create a new process that is a copy of the original by using the _fork_ system call. The _fork_ call returns twice: once in the parent process, where the return value is the process identifier of the child, and once in the child process, where the return value is 0. The parent-child relationship induces a hierarchical structure on the set of processes in the system. The new process shares all its parent's resources, such as file descriptors, signal-handling status, and memory layout. Although there are occasions when the new process is intended to be a copy of the parent, the loading and execution of a different program is a more useful and typical action. A process can overlay itself with the memory image of another program, passing to the newly created image a set of parameters, using the system call _execve_. One parameter is the name of a file whose contents are in a format recognized by the system -- either a binary-executable file or a file that causes the execution of a specified interpreter program to process its contents. A process may terminate by executing an _exit_ system call, sending 8 bits of exit status to its parent. If a process wants to communicate more than a single byte of information with its parent, it must either set up an interprocess-communication channel using pipes or sockets, or use an intermediate file. Interprocess communication is discussed extensively in Chapter 11. A process can suspend execution until any of its child processes terminate using the _wait_ system call, which returns the PID and exit status of the terminated child process. A parent process can arrange to be notified by a signal when a child process exits or terminates abnormally. Using the _wait4_ system call, the parent can retrieve information about the event that caused termination of the child process and about resources consumed by the process during its lifetime. If a process is orphaned because its parent exits before it is finished, then the kernel arranges for the child's exit status to be passed back to a special system process _init_: see Sections 3.1 and 14.6). The details of how the kernel creates and destroys processes are given in Chapter 5. Processes are scheduled for execution according to a _process-priority_ parameter. This priority is managed by a kernel-based scheduling algorithm. Users can influence the scheduling of a process by specifying a parameter (_nice_) that weights the overall scheduling priority, but are still obligated to share the underlying CPU resources according to the kernel's scheduling policy. ==== Signals The system defines a set of _signals_ that may be delivered to a process. Signals in 4.4BSD are modeled after hardware interrupts. A process may specify a user-level subroutine to be a _handler_ to which a signal should be delivered. When a signal is generated, it is blocked from further occurrence while it is being _caught_ by the handler. Catching a signal involves saving the current process context and building a new one in which to run the handler. The signal is then delivered to the handler, which can either abort the process or return to the executing process (perhaps after setting a global variable). If the handler returns, the signal is unblocked and can be generated (and caught) again. Alternatively, a process may specify that a signal is to be _ignored_, or that a default action, as determined by the kernel, is to be taken. The default action of certain signals is to terminate the process. This termination may be accompanied by creation of a _core file_ that contains the current memory image of the process for use in postmortem debugging. Some signals cannot be caught or ignored. These signals include _SIGKILL_, which kills runaway processes, and the job-control signal _SIGSTOP_. A process may choose to have signals delivered on a special stack so that sophisticated software stack manipulations are possible. For example, a language supporting coroutines needs to provide a stack for each coroutine. The language run-time system can allocate these stacks by dividing up the single stack provided by 4.4BSD. If the kernel does not support a separate signal stack, the space allocated for each coroutine must be expanded by the amount of space required to catch a signal. All signals have the same _priority_. If multiple signals are pending simultaneously, the order in which signals are delivered to a process is implementation specific. Signal handlers execute with the signal that caused their invocation to be blocked, but other signals may yet occur. Mechanisms are provided so that processes can protect critical sections of code against the occurrence of specified signals. The detailed design and implementation of signals is described in Section 4.7. ==== Process Groups and Sessions Processes are organized into _process groups_. Process groups are used to control access to terminals and to provide a means of distributing signals to collections of related processes. A process inherits its process group from its parent process. Mechanisms are provided by the kernel to allow a process to alter its process group or the process group of its descendants. Creating a new process group is easy; the value of a new process group is ordinarily the process identifier of the creating process. The group of processes in a process group is sometimes referred to as a _job_ and is manipulated by high-level system software, such as the shell. A common kind of job created by a shell is a _pipeline_ of several processes connected by pipes, such that the output of the first process is the input of the second, the output of the second is the input of the third, and so forth. The shell creates such a job by forking a process for each stage of the pipeline, then putting all those processes into a separate process group. A user process can send a signal to each process in a process group, as well as to a single process. A process in a specific process group may receive software interrupts affecting the group, causing the group to suspend or resume execution, or to be interrupted or terminated. A terminal has a process-group identifier assigned to it. This identifier is normally set to the identifier of a process group associated with the terminal. A job-control shell may create a number of process groups associated with the same terminal; the terminal is the _controlling terminal_ for each process in these groups. A process may read from a descriptor for its controlling terminal only if the terminal's process-group identifier matches that of the process. If the identifiers do not match, the process will be blocked if it attempts to read from the terminal. By changing the process-group identifier of the terminal, a shell can arbitrate a terminal among several different jobs. This arbitration is called _job control_ and is described, with process groups, in Section 4.8. Just as a set of related processes can be collected into a process group, a set of process groups can be collected into a _session_. The main uses for sessions are to create an isolated environment for a daemon process and its children, and to collect together a user's login shell and the jobs that shell spawns. [[overview-memory-management]] === Memory Management Each process has its own private address space. The address space is initially divided into three logical segments: _text_, _data_, and _stack_. The text segment is read-only and contains the machine instructions of a program. The data and stack segments are both readable and writable. The data segment contains the initialized and uninitialized data portions of a program, whereas the stack segment holds the application's run-time stack. On most machines, the stack segment is extended automatically by the kernel as the process executes. A process can expand or contract its data segment by making a system call, whereas a process can change the size of its text segment only when the segment's contents are overlaid with data from the filesystem, or when debugging takes place. The initial contents of the segments of a child process are duplicates of the segments of a parent process. The entire contents of a process address space do not need to be resident for a process to execute. If a process references a part of its address space that is not resident in main memory, the system _pages_ the necessary information into memory. When system resources are scarce, the system uses a two-level approach to maintain available resources. If a modest amount of memory is available, the system will take memory resources away from processes if these resources have not been used recently. Should there be a severe resource shortage, the system will resort to _swapping_ the entire context of a process to secondary storage. The _demand paging_ and _swapping_ done by the system are effectively transparent to processes. A process may, however, advise the system about expected future memory utilization as a performance aid. ==== BSD Memory-Management Design Decisions The support of large sparse address spaces, mapped files, and shared memory was a requirement for 4.2BSD. An interface was specified, called _mmap_, that allowed unrelated processes to request a shared mapping of a file into their address spaces. If multiple processes mapped the same file into their address spaces, changes to the file's portion of an address space by one process would be reflected in the area mapped by the other processes, as well as in the file itself. Ultimately, 4.2BSD was shipped without the _mmap_ interface, because of pressure to make other features, such as networking, available. Further development of the _mmap_ interface continued during the work on 4.3BSD. Over 40 companies and research groups participated in the discussions leading to the revised architecture that was described in the Berkeley Software Architecture Manual crossref:design-44bsd[biblio-mckusick-1, [McKusick et al, 1994]]. Several of the companies have implemented the revised interface crossref:design-44bsd[biblio-gingell, [Gingell et al, 1987]]. Once again, time pressure prevented 4.3BSD from providing an implementation of the interface. Although the latter could have been built into the existing 4.3BSD virtual-memory system, the developers decided not to put it in because that implementation was nearly 10 years old. Furthermore, the original virtual-memory design was based on the assumption that computer memories were small and expensive, whereas disks were locally connected, fast, large, and inexpensive. Thus, the virtual-memory system was designed to be frugal with its use of memory at the expense of generating extra disk traffic. In addition, the 4.3BSD implementation was riddled with VAX memory-management hardware dependencies that impeded its portability to other computer architectures. Finally, the virtual-memory system was not designed to support the tightly coupled multiprocessors that are becoming increasingly common and important today. Attempts to improve the old implementation incrementally seemed doomed to failure. A completely new design, on the other hand, could take advantage of large memories, conserve disk transfers, and have the potential to run on multiprocessors. Consequently, the virtual-memory system was completely replaced in 4.4BSD. The 4.4BSD virtual-memory system is based on the Mach 2.0 VM system crossref:design-44bsd[biblio-tevanian, [Tevanian, 1987]]. with updates from Mach 2.5 and Mach 3.0. It features efficient support for sharing, a clean separation of machine-independent and machine-dependent features, as well as (currently unused) multiprocessor support. Processes can map files anywhere in their address space. They can share parts of their address space by doing a shared mapping of the same file. Changes made by one process are visible in the address space of the other process, and also are written back to the file itself. Processes can also request private mappings of a file, which prevents any changes that they make from being visible to other processes mapping the file or being written back to the file itself. Another issue with the virtual-memory system is the way that information is passed into the kernel when a system call is made. 4.4BSD always copies data from the process address space into a buffer in the kernel. For read or write operations that are transferring large quantities of data, doing the copy can be time consuming. An alternative to doing the copying is to remap the process memory into the kernel. The 4.4BSD kernel always copies the data for several reasons: * Often, the user data are not page aligned and are not a multiple of the hardware page length. * If the page is taken away from the process, it will no longer be able to reference that page. Some programs depend on the data remaining in the buffer even after those data have been written. * If the process is allowed to keep a copy of the page (as it is in current 4.4BSD semantics), the page must be made _copy-on-write_. A copy-on-write page is one that is protected against being written by being made read-only. If the process attempts to modify the page, the kernel gets a write fault. The kernel then makes a copy of the page that the process can modify. Unfortunately, the typical process will immediately try to write new data to its output buffer, forcing the data to be copied anyway. * When pages are remapped to new virtual-memory addresses, most memory-management hardware requires that the hardware address-translation cache be purged selectively. The cache purges are often slow. The net effect is that remapping is slower than copying for blocks of data less than 4 to 8 Kbyte. The biggest incentives for memory mapping are the needs for accessing big files and for passing large quantities of data between processes. The _mmap_ interface provides a way for both of these tasks to be done without copying. ==== Memory Management Inside the Kernel The kernel often does allocations of memory that are needed for only the duration of a single system call. In a user process, such short-term memory would be allocated on the run-time stack. Because the kernel has a limited run-time stack, it is not feasible to allocate even moderate-sized blocks of memory on it. Consequently, such memory must be allocated through a more dynamic mechanism. For example, when the system must translate a pathname, it must allocate a 1-Kbyte buffer to hold the name. Other blocks of memory must be more persistent than a single system call, and thus could not be allocated on the stack even if there was space. An example is protocol-control blocks that remain throughout the duration of a network connection. Demands for dynamic memory allocation in the kernel have increased as more services have been added. A generalized memory allocator reduces the complexity of writing code inside the kernel. Thus, the 4.4BSD kernel has a single memory allocator that can be used by any part of the system. It has an interface similar to the C library routines _malloc_ and _free_ that provide memory allocation to application programs crossref:design-44bsd[biblio-mckusick-2, [McKusick & Karels, 1988]]. Like the C library interface, the allocation routine takes a parameter specifying the size of memory that is needed. The range of sizes for memory requests is not constrained; however, physical memory is allocated and is not paged. The free routine takes a pointer to the storage being freed, but does not require the size of the piece of memory being freed. [[overview-io-system]] === I/O System The basic model of the UNIX I/O system is a sequence of bytes that can be accessed either randomly or sequentially. There are no _access methods_ and no _control blocks_ in a typical UNIX user process. Different programs expect various levels of structure, but the kernel does not impose structure on I/O. For instance, the convention for text files is lines of ASCII characters separated by a single newline character (the ASCII line-feed character), but the kernel knows nothing about this convention. For the purposes of most programs, the model is further simplified to being a stream of data bytes, or an _I/O stream_. It is this single common data form that makes the characteristic UNIX tool-based approach work crossref:design-44bsd[biblio-kernighan, [Kernighan & Pike, 1984]]. An I/O stream from one program can be fed as input to almost any other program. (This kind of traditional UNIX I/O stream should not be confused with the Eighth Edition stream I/O system or with the System V, Release 3 STREAMS, both of which can be accessed as traditional I/O streams.) ==== Descriptors and I/O UNIX processes use _descriptors_ to reference I/O streams. Descriptors are small unsigned integers obtained from the _open_ and _socket_ system calls. The _open_ system call takes as arguments the name of a file and a permission mode to specify whether the file should be open for reading or for writing, or for both. This system call also can be used to create a new, empty file. A _read_ or _write_ system call can be applied to a descriptor to transfer data. The _close_ system call can be used to deallocate any descriptor. Descriptors represent underlying objects supported by the kernel, and are created by system calls specific to the type of object. In 4.4BSD, three kinds of objects can be represented by descriptors: files, pipes, and sockets. * A _file_ is a linear array of bytes with at least one name. A file exists until all its names are deleted explicitly and no process holds a descriptor for it. A process acquires a descriptor for a file by opening that file's name with the _open_ system call. I/O devices are accessed as files. * A _pipe_ is a linear array of bytes, as is a file, but it is used solely as an I/O stream, and it is unidirectional. It also has no name, and thus cannot be opened with _open_. Instead, it is created by the _pipe_ system call, which returns two descriptors, one of which accepts input that is sent to the other descriptor reliably, without duplication, and in order. The system also supports a named pipe or FIFO. A FIFO has properties identical to a pipe, except that it appears in the filesystem; thus, it can be opened using the _open_ system call. Two processes that wish to communicate each open the FIFO: One opens it for reading, the other for writing. * A _socket_ is a transient object that is used for interprocess communication; it exists only as long as some process holds a descriptor referring to it. A socket is created by the _socket_ system call, which returns a descriptor for it. There are different kinds of sockets that support various communication semantics, such as reliable delivery of data, preservation of message ordering, and preservation of message boundaries. In systems before 4.2BSD, pipes were implemented using the filesystem; when sockets were introduced in 4.2BSD, pipes were reimplemented as sockets. The kernel keeps for each process a _descriptor table_, which is a table that the kernel uses to translate the external representation of a descriptor into an internal representation. (The descriptor is merely an index into this table.) The descriptor table of a process is inherited from that process's parent, and thus access to the objects to which the descriptors refer also is inherited. The main ways that a process can obtain a descriptor are by opening or creation of an object, and by inheritance from the parent process. In addition, socket IPC allows passing of descriptors in messages between unrelated processes on the same machine. Every valid descriptor has an associated _file offset_ in bytes from the beginning of the object. Read and write operations start at this offset, which is updated after each data transfer. For objects that permit random access, the file offset also may be set with the _lseek_ system call. Ordinary files permit random access, and some devices do, as well. Pipes and sockets do not. When a process terminates, the kernel reclaims all the descriptors that were in use by that process. If the process was holding the final reference to an object, the object's manager is notified so that it can do any necessary cleanup actions, such as final deletion of a file or deallocation of a socket. ==== Descriptor Management Most processes expect three descriptors to be open already when they start running. These descriptors are 0, 1, 2, more commonly known as _standard input_, _standard output_, and _standard error_, respectively. Usually, all three are associated with the user's terminal by the login process (see Section 14.6) and are inherited through _fork_ and _exec_ by processes run by the user. Thus, a program can read what the user types by reading standard input, and the program can send output to the user's screen by writing to standard output. The standard error descriptor also is open for writing and is used for error output, whereas standard output is used for ordinary output. These (and other) descriptors can be mapped to objects other than the terminal; such mapping is called _I/O redirection_, and all the standard shells permit users to do it. The shell can direct the output of a program to a file by closing descriptor 1 (standard output) and opening the desired output file to produce a new descriptor 1. It can similarly redirect standard input to come from a file by closing descriptor 0 and opening the file. Pipes allow the output of one program to be input to another program without rewriting or even relinking of either program. Instead of descriptor 1 (standard output) of the source program being set up to write to the terminal, it is set up to be the input descriptor of a pipe. Similarly, descriptor 0 (standard input) of the sink program is set up to reference the output of the pipe, instead of the terminal keyboard. The resulting set of two processes and the connecting pipe is known as a _pipeline_. Pipelines can be arbitrarily long series of processes connected by pipes. The _open_, _pipe_, and _socket_ system calls produce new descriptors with the lowest unused number usable for a descriptor. For pipelines to work, some mechanism must be provided to map such descriptors into 0 and 1. The _dup_ system call creates a copy of a descriptor that points to the same file-table entry. The new descriptor is also the lowest unused one, but if the desired descriptor is closed first, _dup_ can be used to do the desired mapping. Care is required, however: If descriptor 1 is desired, and descriptor 0 happens also to have been closed, descriptor 0 will be the result. To avoid this problem, the system provides the _dup2_ system call; it is like _dup_, but it takes an additional argument specifying the number of the desired descriptor (if the desired descriptor was already open, _dup2_ closes it before reusing it). ==== Devices Hardware devices have filenames, and may be accessed by the user via the same system calls used for regular files. The kernel can distinguish a _device special file_ or _special file_, and can determine to what device it refers, but most processes do not need to make this determination. Terminals, printers, and tape drives are all accessed as though they were streams of bytes, like 4.4BSD disk files. Thus, device dependencies and peculiarities are kept in the kernel as much as possible, and even in the kernel most of them are segregated in the device drivers. Hardware devices can be categorized as either _structured_ or _unstructured_; they are known as _block_ or _character_ devices, respectively. Processes typically access devices through _special files_ in the filesystem. I/O operations to these files are handled by kernel-resident software modules termed _device drivers_. Most network-communication hardware devices are accessible through only the interprocess-communication facilities, and do not have special files in the filesystem name space, because the _raw-socket_ interface provides a more natural interface than does a special file. Structured or block devices are typified by disks and magnetic tapes, and include most random-access devices. The kernel supports read-modify-write-type buffering actions on block-oriented structured devices to allow the latter to be read and written in a totally random byte-addressed fashion, like regular files. Filesystems are created on block devices. Unstructured devices are those devices that do not support a block structure. Familiar unstructured devices are communication lines, raster plotters, and unbuffered magnetic tapes and disks. Unstructured devices typically support large block I/O transfers. Unstructured files are called _character devices_ because the first of these to be implemented were terminal device drivers. The kernel interface to the driver for these devices proved convenient for other devices that were not block structured. Device special files are created by the _mknod_ system call. There is an additional system call, _ioctl_, for manipulating the underlying device parameters of special files. The operations that can be done differ for each device. This system call allows the special characteristics of devices to be accessed, rather than overloading the semantics of other system calls. For example, there is an _ioctl_ on a tape drive to write an end-of-tape mark, instead of there being a special or modified version of _write_. ==== Socket IPC The 4.2BSD kernel introduced an IPC mechanism more flexible than pipes, based on _sockets_. A socket is an endpoint of communication referred to by a descriptor, just like a file or a pipe. Two processes can each create a socket, and then connect those two endpoints to produce a reliable byte stream. Once connected, the descriptors for the sockets can be read or written by processes, just as the latter would do with a pipe. The transparency of sockets allows the kernel to redirect the output of one process to the input of another process residing on another machine. A major difference between pipes and sockets is that pipes require a common parent process to set up the communications channel. A connection between sockets can be set up by two unrelated processes, possibly residing on different machines. System V provides local interprocess communication through FIFOs (also known as _named pipes_). FIFOs appear as an object in the filesystem that unrelated processes can open and send data through in the same way as they would communicate through a pipe. Thus, FIFOs do not require a common parent to set them up; they can be connected after a pair of processes are up and running. Unlike sockets, FIFOs can be used on only a local machine; they cannot be used to communicate between processes on different machines. FIFOs are implemented in 4.4BSD only because they are required by the POSIX.1 standard. Their functionality is a subset of the socket interface. The socket mechanism requires extensions to the traditional UNIX I/O system calls to provide the associated naming and connection semantics. Rather than overloading the existing interface, the developers used the existing interfaces to the extent that the latter worked without being changed, and designed new interfaces to handle the added semantics. The _read_ and _write_ system calls were used for byte-stream type connections, but six new system calls were added to allow sending and receiving addressed messages such as network datagrams. The system calls for writing messages include _send_, _sendto_, and _sendmsg_. The system calls for reading messages include _recv_, _recvfrom_, and _recvmsg_. In retrospect, the first two in each class are special cases of the others; _recvfrom_ and _sendto_ probably should have been added as library interfaces to _recvmsg_ and _sendmsg_, respectively. ==== Scatter/Gather I/O In addition to the traditional _read_ and _write_ system calls, 4.2BSD introduced the ability to do scatter/gather I/O. Scatter input uses the _readv_ system call to allow a single read to be placed in several different buffers. Conversely, the _writev_ system call allows several different buffers to be written in a single atomic write. Instead of passing a single buffer and length parameter, as is done with _read_ and _write_, the process passes in a pointer to an array of buffers and lengths, along with a count describing the size of the array. This facility allows buffers in different parts of a process address space to be written atomically, without the need to copy them to a single contiguous buffer. Atomic writes are necessary in the case where the underlying abstraction is record based, such as tape drives that output a tape block on each write request. It is also convenient to be able to read a single request into several different buffers (such as a record header into one place and the data into another). Although an application can simulate the ability to scatter data by reading the data into a large buffer and then copying the pieces to their intended destinations, the cost of memory-to-memory copying in such cases often would more than double the running time of the affected application. Just as _send_ and _recv_ could have been implemented as library interfaces to _sendto_ and _recvfrom_, it also would have been possible to simulate _read_ with _readv_ and _write_ with _writev_. However, _read_ and _write_ are used so much more frequently that the added cost of simulating them would not have been worthwhile. ==== Multiple Filesystem Support With the expansion of network computing, it became desirable to support both local and remote filesystems. To simplify the support of multiple filesystems, the developers added a new virtual node or _vnode_ interface to the kernel. The set of operations exported from the vnode interface appear much like the filesystem operations previously supported by the local filesystem. However, they may be supported by a wide range of filesystem types: * Local disk-based filesystems * Files imported using a variety of remote filesystem protocols * Read-only CD-ROM filesystems * Filesystems providing special-purpose interfaces -- for example, the `/proc` filesystem A few variants of 4.4BSD, such as FreeBSD, allow filesystems to be loaded dynamically when the filesystems are first referenced by the _mount_ system call. The vnode interface is described in Section 6.5; its ancillary support routines are described in Section 6.6; several of the special-purpose filesystems are described in Section 6.7. [[overview-filesystem]] === Filesystems A regular file is a linear array of bytes, and can be read and written starting at any byte in the file. The kernel distinguishes no record boundaries in regular files, although many programs recognize line-feed characters as distinguishing the ends of lines, and other programs may impose other structure. No system-related information about a file is kept in the file itself, but the filesystem stores a small amount of ownership, protection, and usage information with each file. A _filename_ component is a string of up to 255 characters. These filenames are stored in a type of file called a _directory_. The information in a directory about a file is called a _directory entry_ and includes, in addition to the filename, a pointer to the file itself. Directory entries may refer to other directories, as well as to plain files. A hierarchy of directories and files is thus formed, and is called a _filesystem_; .A small filesystem [[fig-small-fs]] image:fig2.png[A small filesystem] a small one is shown in crossref:design-44bsd[fig-small-fs]. Directories may contain subdirectories, and there is no inherent limitation to the depth with which directory nesting may occur. To protect the consistency of the filesystem, the kernel does not permit processes to write directly into directories. A filesystem may include not only plain files and directories, but also references to other objects, such as devices and sockets. The filesystem forms a tree, the beginning of which is the _root directory_, sometimes referred to by the name _slash_, spelled with a single solidus character (/). The root directory contains files; in our example in Fig 2.2, it contains `vmunix`, a copy of the kernel-executable object file. It also contains directories; in this example, it contains the `usr` directory. Within the `usr` directory is the `bin` directory, which mostly contains executable object code of programs, such as the files `ls` and `vi`. A process identifies a file by specifying that file's _pathname_, which is a string composed of zero or more filenames separated by slash (/) characters. The kernel associates two directories with each process for use in interpreting pathnames. A process's _root directory_ is the topmost point in the filesystem that the process can access; it is ordinarily set to the root directory of the entire filesystem. A pathname beginning with a slash is called an _absolute pathname_, and is interpreted by the kernel starting with the process's root directory. A pathname that does not begin with a slash is called a _relative pathname_, and is interpreted relative to the _current working directory_ of the process. (This directory also is known by the shorter names _current directory_ or _working directory_.) The current directory itself may be referred to directly by the name _dot_, spelled with a single period (`.`) The filename _dot-dot_ (`..`) refers to a directory's parent directory. The root directory is its own parent. A process may set its root directory with the _chroot_ system call, and its current directory with the _chdir_ system call. Any process may do _chdir_ at any time, but _chroot_ is permitted only a process with superuser privileges. _Chroot_ is normally used to set up restricted access to the system. Using the filesystem shown in Fig. 2.2, if a process has the root of the filesystem as its root directory, and has `/usr` as its current directory, it can refer to the file `vi` either from the root with the absolute pathname `/usr/bin/vi`, or from its current directory with the relative pathname `bin/vi`. System utilities and databases are kept in certain well-known directories. Part of the well-defined hierarchy includes a directory that contains the _home directory_ for each user -- for example, `/usr/staff/mckusick` and `/usr/staff/karels` in Fig. 2.2. When users log in, the current working directory of their shell is set to the home directory. Within their home directories, users can create directories as easily as they can regular files. Thus, a user can build arbitrarily complex subhierarchies. The user usually knows of only one filesystem, but the system may know that this one virtual filesystem is really composed of several physical filesystems, each on a different device. A physical filesystem may not span multiple hardware devices. Since most physical disk devices are divided into several logical devices, there may be more than one filesystem per physical device, but there will be no more than one per logical device. One filesystem -- the filesystem that anchors all absolute pathnames -- is called the _root filesystem_, and is always available. Others may be mounted; that is, they may be integrated into the directory hierarchy of the root filesystem. References to a directory that has a filesystem mounted on it are converted transparently by the kernel into references to the root directory of the mounted filesystem. The _link_ system call takes the name of an existing file and another name to create for that file. After a successful _link_, the file can be accessed by either filename. A filename can be removed with the _unlink_ system call. When the final name for a file is removed (and the final process that has the file open closes it), the file is deleted. Files are organized hierarchically in _directories_. A directory is a type of file, but, in contrast to regular files, a directory has a structure imposed on it by the system. A process can read a directory as it would an ordinary file, but only the kernel is permitted to modify a directory. Directories are created by the _mkdir_ system call and are removed by the _rmdir_ system call. Before 4.2BSD, the _mkdir_ and _rmdir_ system calls were implemented by a series of _link_ and _unlink_ system calls being done. There were three reasons for adding systems calls explicitly to create and delete directories: [arabic] . The operation could be made atomic. If the system crashed, the directory would not be left half-constructed, as could happen when a series of link operations were used. . When a networked filesystem is being run, the creation and deletion of files and directories need to be specified atomically so that they can be serialized. . When supporting non-UNIX filesystems, such as an MS-DOS filesystem, on another partition of the disk, the other filesystem may not support link operations. Although other filesystems might support the concept of directories, they probably would not create and delete the directories with links, as the UNIX filesystem does. Consequently, they could create and delete directories only if explicit directory create and delete requests were presented. The _chown_ system call sets the owner and group of a file, and _chmod_ changes protection attributes. _Stat_ applied to a filename can be used to read back such properties of a file. The _fchown_, _fchmod_, and _fstat_ system calls are applied to a descriptor, instead of to a filename, to do the same set of operations. The _rename_ system call can be used to give a file a new name in the filesystem, replacing one of the file's old names. Like the directory-creation and directory-deletion operations, the _rename_ system call was added to 4.2BSD to provide atomicity to name changes in the local filesystem. Later, it proved useful explicitly to export renaming operations to foreign filesystems and over the network. The _truncate_ system call was added to 4.2BSD to allow files to be shortened to an arbitrary offset. The call was added primarily in support of the Fortran run-time library, which has the semantics such that the end of a random-access file is set to be wherever the program most recently accessed that file. Without the _truncate_ system call, the only way to shorten a file was to copy the part that was desired to a new file, to delete the old file, then to rename the copy to the original name. As well as this algorithm being slow, the library could potentially fail on a full filesystem. Once the filesystem had the ability to shorten files, the kernel took advantage of that ability to shorten large empty directories. The advantage of shortening empty directories is that it reduces the time spent in the kernel searching them when names are being created or deleted. Newly created files are assigned the user identifier of the process that created them and the group identifier of the directory in which they were created. A three-level access-control mechanism is provided for the protection of files. These three levels specify the accessibility of a file to [arabic] . The user who owns the file . The group that owns the file . Everyone else Each level of access has separate indicators for read permission, write permission, and execute permission. Files are created with zero length, and may grow when they are written. While a file is open, the system maintains a pointer into the file indicating the current location in the file associated with the descriptor. This pointer can be moved about in the file in a random-access fashion. Processes sharing a file descriptor through a _fork_ or _dup_ system call share the current location pointer. Descriptors created by separate _open_ system calls have separate current location pointers. Files may have _holes_ in them. Holes are void areas in the linear extent of the file where data have never been written. A process can create these holes by positioning the pointer past the current end-of-file and writing. When read, holes are treated by the system as zero-valued bytes. Earlier UNIX systems had a limit of 14 characters per filename component. This limitation was often a problem. For example, in addition to the natural desire of users to give files long descriptive names, a common way of forming filenames is as `basename.extension`, where the extension (indicating the kind of file, such as `.c` for C source or `.o` for intermediate binary object) is one to three characters, leaving 10 to 12 characters for the basename. Source-code-control systems and editors usually take up another two characters, either as a prefix or a suffix, for their purposes, leaving eight to 10 characters. It is easy to use 10 or 12 characters in a single English word as a basename (e.g., `multiplexer`). It is possible to keep within these limits, but it is inconvenient or even dangerous, because other UNIX systems accept strings longer than the limit when creating files, but then _truncate_ to the limit. A C language source file named `multiplexer.c` (already 13 characters) might have a source-code-control file with `s.` prepended, producing a filename `s.multiplexer` that is indistinguishable from the source-code-control file for `multiplexer.ms`, a file containing `troff` source for documentation for the C program. The contents of the two original files could easily get confused with no warning from the source-code-control system. Careful coding can detect this problem, but the long filenames first introduced in 4.2BSD practically eliminate it. [[overview-filestore]] === Filestores The operations defined for local filesystems are divided into two parts. Common to all local filesystems are hierarchical naming, locking, quotas, attribute management, and protection. These features are independent of how the data will be stored. 4.4BSD has a single implementation to provide these semantics. The other part of the local filesystem is the organization and management of the data on the storage media. Laying out the contents of files on the storage media is the responsibility of the filestore. 4.4BSD supports three different filestore layouts: * The traditional Berkeley Fast Filesystem * The log-structured filesystem, based on the Sprite operating-system design crossref:design-44bsd[biblio-rosenblum, [Rosenblum & Ousterhout, 1992]] * A memory-based filesystem Although the organizations of these filestores are completely different, these differences are indistinguishable to the processes using the filestores. The Fast Filesystem organizes data into cylinder groups. Files that are likely to be accessed together, based on their locations in the filesystem hierarchy, are stored in the same cylinder group. Files that are not expected to accessed together are moved into different cylinder groups. Thus, files written at the same time may be placed far apart on the disk. The log-structured filesystem organizes data as a log. All data being written at any point in time are gathered together, and are written at the same disk location. Data are never overwritten; instead, a new copy of the file is written that replaces the old one. The old files are reclaimed by a garbage-collection process that runs when the filesystem becomes full and additional free space is needed. The memory-based filesystem is designed to store data in virtual memory. It is used for filesystems that need to support fast but temporary data, such as `/tmp`. The goal of the memory-based filesystem is to keep the storage packed as compactly as possible to minimize the usage of virtual-memory resources. [[overview-nfs]] === Network Filesystem Initially, networking was used to transfer data from one machine to another. Later, it evolved to allowing users to log in remotely to another machine. The next logical step was to bring the data to the user, instead of having the user go to the data -- and network filesystems were born. Users working locally do not experience the network delays on each keystroke, so they have a more responsive environment. Bringing the filesystem to a local machine was among the first of the major client-server applications. The _server_ is the remote machine that exports one or more of its filesystems. The _client_ is the local machine that imports those filesystems. From the local client's point of view, a remotely mounted filesystem appears in the file-tree name space just like any other locally mounted filesystem. Local clients can change into directories on the remote filesystem, and can read, write, and execute binaries within that remote filesystem identically to the way that they can do these operations on a local filesystem. When the local client does an operation on a remote filesystem, the request is packaged and is sent to the server. The server does the requested operation and returns either the requested information or an error indicating why the request was denied. To get reasonable performance, the client must cache frequently accessed data. The complexity of remote filesystems lies in maintaining cache consistency between the server and its many clients. Although many remote-filesystem protocols have been developed over the years, the most pervasive one in use among UNIX systems is the Network Filesystem (NFS), whose protocol and most widely used implementation were done by Sun Microsystems. The 4.4BSD kernel supports the NFS protocol, although the implementation was done independently from the protocol specification crossref:design-44bsd[biblio-macklem, [Macklem, 1994]]. The NFS protocol is described in Chapter 9. [[overview-terminal]] === Terminals Terminals support the standard system I/O operations, as well as a collection of terminal-specific operations to control input-character editing and output delays. At the lowest level are the terminal device drivers that control the hardware terminal ports. Terminal input is handled according to the underlying communication characteristics, such as baud rate, and according to a set of software-controllable parameters, such as parity checking. Layered above the terminal device drivers are line disciplines that provide various degrees of character processing. The default line discipline is selected when a port is being used for an interactive login. The line discipline is run in _canonical mode_; input is processed to provide standard line-oriented editing functions, and input is presented to a process on a line-by-line basis. Screen editors and programs that communicate with other computers generally run in _noncanonical mode_ (also commonly referred to as _raw mode_ or _character-at-a-time mode_). In this mode, input is passed through to the reading process immediately and without interpretation. All special-character input processing is disabled, no erase or other line editing processing is done, and all characters are passed to the program that is reading from the terminal. It is possible to configure the terminal in thousands of combinations between these two extremes. For example, a screen editor that wanted to receive user interrupts asynchronously might enable the special characters that generate signals and enable output flow control, but otherwise run in noncanonical mode; all other characters would be passed through to the process uninterpreted. On output, the terminal handler provides simple formatting services, including * Converting the line-feed character to the two-character carriage-return-line-feed sequence * Inserting delays after certain standard control characters * Expanding tabs * Displaying echoed nongraphic ASCII characters as a two-character sequence of the form `^C` (i.e., the ASCII caret character followed by the ASCII character that is the character's value offset from the ASCII `@` character). Each of these formatting services can be disabled individually by a process through control requests. [[overview-ipc]] === Interprocess Communication Interprocess communication in 4.4BSD is organized in _communication domains_. Domains currently supported include the _local domain_, for communication between processes executing on the same machine; the _internet domain_, for communication between processes using the TCP/IP protocol suite (perhaps within the Internet); the ISO/OSI protocol family for communication between sites required to run them; and the _XNS domain_, for communication between processes using the XEROX Network Systems (XNS) protocols. Within a domain, communication takes place between communication endpoints known as _sockets_. As mentioned in Section 2.6, the _socket_ system call creates a socket and returns a descriptor; other IPC system calls are described in Chapter 11. Each socket has a type that defines its communications semantics; these semantics include properties such as reliability, ordering, and prevention of duplication of messages. Each socket has associated with it a _communication protocol_. This protocol provides the semantics required by the socket according to the latter's type. Applications may request a specific protocol when creating a socket, or may allow the system to select a protocol that is appropriate for the type of socket being created. Sockets may have addresses bound to them. The form and meaning of socket addresses are dependent on the communication domain in which the socket is created. Binding a name to a socket in the local domain causes a file to be created in the filesystem. Normal data transmitted and received through sockets are untyped. Data-representation issues are the responsibility of libraries built on top of the interprocess-communication facilities. In addition to transporting normal data, communication domains may support the transmission and reception of specially typed data, termed _access rights_. The local domain, for example, uses this facility to pass descriptors between processes. Networking implementations on UNIX before 4.2BSD usually worked by overloading the character-device interfaces. One goal of the socket interface was for naive programs to be able to work without change on stream-style connections. Such programs can work only if the _read_ and _write_ systems calls are unchanged. Consequently, the original interfaces were left intact, and were made to work on stream-type sockets. A new interface was added for more complicated sockets, such as those used to send datagrams, with which a destination address must be presented with each _send_ call. Another benefit is that the new interface is highly portable. Shortly after a test release was available from Berkeley, the socket interface had been ported to System III by a UNIX vendor (although AT&T did not support the socket interface until the release of System V Release 4, deciding instead to use the Eighth Edition stream mechanism). The socket interface was also ported to run in many Ethernet boards by vendors, such as Excelan and Interlan, that were selling into the PC market, where the machines were too small to run networking in the main processor. More recently, the socket interface was used as the basis for Microsoft's Winsock networking interface for Windows. [[overview-network-communication]] === Network Communication Some of the communication domains supported by the _socket_ IPC mechanism provide access to network protocols. These protocols are implemented as a separate software layer logically below the socket software in the kernel. The kernel provides many ancillary services, such as buffer management, message routing, standardized interfaces to the protocols, and interfaces to the network interface drivers for the use of the various network protocols. At the time that 4.2BSD was being implemented, there were many networking protocols in use or under development, each with its own strengths and weaknesses. There was no clearly superior protocol or protocol suite. By supporting multiple protocols, 4.2BSD could provide interoperability and resource sharing among the diverse set of machines that was available in the Berkeley environment. Multiple-protocol support also provides for future changes. Today's protocols designed for 10- to 100-Mbit-per-second Ethernets are likely to be inadequate for tomorrow's 1- to 10-Gbit-per-second fiber-optic networks. Consequently, the network-communication layer is designed to support multiple protocols. New protocols are added to the kernel without the support for older protocols being affected. Older applications can continue to operate using the old protocol over the same physical network as is used by newer applications running with a newer network protocol. [[overview-network-implementation]] === Network Implementation The first protocol suite implemented in 4.2BSD was DARPA's Transmission Control Protocol/Internet Protocol (TCP/IP). The CSRG chose TCP/IP as the first network to incorporate into the socket IPC framework, because a 4.1BSD-based implementation was publicly available from a DARPA-sponsored project at Bolt, Beranek, and Newman (BBN). That was an influential choice: The 4.2BSD implementation is the main reason for the extremely widespread use of this protocol suite. Later performance and capability improvements to the TCP/IP implementation have also been widely adopted. The TCP/IP implementation is described in detail in Chapter 13. The release of 4.3BSD added the Xerox Network Systems (XNS) protocol suite, partly building on work done at the University of Maryland and at Cornell University. This suite was needed to connect isolated machines that could not communicate using TCP/IP. The release of 4.4BSD added the ISO protocol suite because of the latter's increasing visibility both within and outside the United States. Because of the somewhat different semantics defined for the ISO protocols, some minor changes were required in the socket interface to accommodate these semantics. The changes were made such that they were invisible to clients of other existing protocols. The ISO protocols also required extensive addition to the two-level routing tables provided by the kernel in 4.3BSD. The greatly expanded routing capabilities of 4.4BSD include arbitrary levels of routing with variable-length addresses and network masks. [[overview-operation]] === System Operation Bootstrapping mechanisms are used to start the system running. First, the 4.4BSD kernel must be loaded into the main memory of the processor. Once loaded, it must go through an initialization phase to set the hardware into a known state. Next, the kernel must do autoconfiguration, a process that finds and configures the peripherals that are attached to the processor. The system begins running in single-user mode while a start-up script does disk checks and starts the accounting and quota checking. Finally, the start-up script starts the general system services and brings up the system to full multiuser operation. During multiuser operation, processes wait for login requests on the terminal lines and network ports that have been configured for user access. When a login request is detected, a login process is spawned and user validation is done. When the login validation is successful, a login shell is created from which the user can run additional processes. :sectnums!: [bibliography] [[references]] == References [[biblio-accetta]] Accetta et al, 1986 Mach: A New Kernel Foundation for UNIX Development" M.Accetta R.Baron W.Bolosky D.Golub R.Rashid A.Tevanian M.Young 93-113 USENIX Association Conference Proceedings USENIX Association June 1986 [[biblio-cheriton]] Cheriton, 1988 The V Distributed System D. R.Cheriton 314-333 Comm ACM, 31, 3 March 1988 [[biblio-ewens]] Ewens et al, 1985 Tunis: A Distributed Multiprocessor Operating System P.Ewens D. R.Blythe M.Funkenhauser R. C.Holt 247-254 USENIX Assocation Conference Proceedings USENIX Association June 1985 [[biblio-gingell]] Gingell et al, 1987 Virtual Memory Architecture in SunOS R.Gingell J.Moran W.Shannon 81-94 USENIX Association Conference Proceedings USENIX Association June 1987 [[biblio-kernighan]] Kernighan & Pike, 1984 The UNIX Programming Environment B. W.Kernighan R.Pike Prentice-Hall Englewood Cliffs NJ 1984 [[biblio-macklem]] Macklem, 1994 The 4.4BSD NFS Implementation R.Macklem 6:1-14 4.4BSD System Manager's Manual O'Reilly & Associates, Inc. Sebastopol CA 1994 [[biblio-mckusick-2]] McKusick & Karels, 1988 Design of a General Purpose Memory Allocator for the 4.3BSD UNIX Kernel M. K.McKusick M. J.Karels 295-304 USENIX Assocation Conference Proceedings USENIX Assocation June 1998 [[biblio-mckusick-1]] McKusick et al, 1994 Berkeley Software Architecture Manual, 4.4BSD Edition M. K.McKusick M. J.Karels S. J.Leffler W. N.Joy R. S.Faber 5:1-42 4.4BSD Programmer's Supplementary Documents O'Reilly & Associates, Inc. Sebastopol CA 1994 [[biblio-ritchie]] Ritchie, 1988 Early Kernel Design private communication D. M.Ritchie March 1988 [[biblio-rosenblum]] Rosenblum & Ousterhout, 1992 The Design and Implementation of a Log-Structured File System M.Rosenblum K.Ousterhout 26-52 ACM Transactions on Computer Systems, 10, 1 Association for Computing Machinery February 1992 [[biblio-rozier]] Rozier et al, 1988 Chorus Distributed Operating Systems M.Rozier V.Abrossimov F.Armand I.Boule M.Gien M.Guillemont F.Herrmann C.Kaiser S.Langlois P.Leonard W.Neuhauser 305-370 USENIX Computing Systems, 1, 4 Fall 1988 [[biblio-tevanian]] Tevanian, 1987 Architecture-Independent Virtual Memory Management for Parallel and Distributed Environments: The Mach Approach Technical Report CMU-CS-88-106, A.Tevanian Department of Computer Science, Carnegie-Mellon University Pittsburgh PA December 1987 diff --git a/documentation/content/en/books/dev-model/_index.adoc b/documentation/content/en/books/dev-model/_index.adoc index d30dbd7253..6d621f6a29 100644 --- a/documentation/content/en/books/dev-model/_index.adoc +++ b/documentation/content/en/books/dev-model/_index.adoc @@ -1,1208 +1,1208 @@ --- title: A project model for the FreeBSD Project authors: - author: Niklas Saers copyright: 2002-2005 Niklas Saers description: A formal study of the organization of the FreeBSD project trademarks: ["freebsd", "ibm", "ieee", "adobe", "intel", "linux", "microsoft", "opengroup", "sun", "netbsd", "general"] bookOrder: 45 tags: ["model", "project model", "FreeBSD"] layout: single --- //// Copyright (c) 2002-2005 Niklas Saers All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must 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. //// = A project model for the FreeBSD Project :doctype: book :toc: macro :toclevels: 2 :icons: font :sectnums: :sectnumlevels: 6 :partnums: :source-highlighter: rouge :experimental: :images-path: books/dev-model/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../images/{images-path} include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] include::../../../../../shared/asciidoctor.adoc[] endif::[] ''' toc::[] [[foreword]] [.abstract-title] Foreword Up until now, the FreeBSD project has released a number of described techniques to do different parts of work. However, a project model summarising how the project is structured is needed because of the increasing amount of project members. footnote:[This goes hand-in-hand with Brooks' law that adding another person to a late project will make it later since it will increase the communication needs . A project model is a tool to reduce the communication needs.] This paper will provide such a project model and is donated to the FreeBSD Documentation project where it can evolve together with the project so that it can at any point in time reflect the way the project works. It is based on [crossref:dev-model[thesis, Saers,2003]]. I would like to thank the following people for taking the time to explain things that were unclear to me and for proofreading the document. * Andrey A. Chernov mailto:ache@freebsd.org[ache@freebsd.org] * Bruce A. Mah mailto:bmah@freebsd.org[bmah@freebsd.org] * Dag-Erling Smørgrav mailto:des@freebsd.org[des@freebsd.org] * Giorgos Keramidas mailto:keramida@freebsd.org[keramida@freebsd.org] * Ingvil Hovig mailto:ingvil.hovig@skatteetaten.no[ingvil.hovig@skatteetaten.no] * Jesper Holck mailto:jeh.inf@cbs.dk[jeh.inf@cbs.dk] * John Baldwin mailto:jhb@freebsd.org[jhb@freebsd.org] * John Polstra mailto:jdp@freebsd.org[jdp@freebsd.org] * Kirk McKusick mailto:mckusick@freebsd.org[mckusick@freebsd.org] * Mark Linimon mailto:linimon@freebsd.org[linimon@freebsd.org] * Marleen Devos * Niels Jørgenssen mailto:nielsj@ruc.dk[nielsj@ruc.dk] * Nik Clayton mailto:nik@freebsd.org[nik@freebsd.org] * Poul-Henning Kamp mailto:phk@freebsd.org[phk@freebsd.org] * Simon L. Nielsen mailto:simon@freebsd.org[simon@freebsd.org] [[overview]] == Overview A project model is a means to reduce the communications overhead in a project. As shown by [crossref:dev-model[brooks, Brooks, 1995]], increasing the number of project participants increases the communication in the project exponentionally. FreeBSD has during the past few years increased both its mass of active users and committers, and the communication in the project has risen accordingly. This project model will serve to reduce this overhead by providing an up-to-date description of the project. During the Core elections in 2002, Mark Murray stated "I am opposed to a long rule-book, as that satisfies lawyer-tendencies, and is counter to the technocentricity that the project so badly needs." [crossref:dev-model[bsd-election2002, FreeBSD, 2002B]]. This project model is not meant to be a tool to justify creating impositions for developers, but as a tool to facilitate coordination. It is meant as a description of the project, with an overview of how the different processes are executed. It is an introduction to how the FreeBSD project works. The FreeBSD project model will be described as of July 1st, 2004. It is based on the Niels Jørgensen's paper [crossref:dev-model[jorgensen2001, Jørgensen, 2001]], FreeBSD's official documents, discussions on FreeBSD mailing lists and interviews with developers. After providing definitions of terms used, this document will outline the organisational structure (including role descriptions and communication lines), discuss the methodology model and after presenting the tools used for process control, it will present the defined processes. Finally it will outline major sub-projects of the FreeBSD project. [crossref:dev-model[freebsd-developer-handbook, FreeBSD, 2002A]] Section 1.2 and 1.3 give the vision and the architectural guidelines for the project. The vision is "To produce the best UNIX-like operating system package possible, with due respect to the original software tools ideology as well as usability, performance and stability." The architectural guidelines help determine whether a problem that someone wants to be solved is within the scope of the project [[definitions]] == Definitions [[ref-activity]] === Activity An "activity" is an element of work performed during the course of a project [crossref:dev-model[ref-pmbok, PMI, 2000]]. It has an output and leads towards an outcome. Such an output can either be an input to another activity or a part of the process' delivery. [[def-process]] === Process A "process" is a series of activities that lead towards a particular outcome. A process can consist of one or more sub-processes. An example of a process is software design. [[ref-hat]] === Hat A "hat" is synonymous with role. A hat has certain responsibilities in a process and for the process outcome. The hat executes activities. It is well defined what issues the hat should be contacted about by the project members and people outside the project. [[ref-outcome]] === Outcome An "outcome" is the final output of the process. This is synonymous with deliverable, that is defined as "any measurable, tangible, verifiable outcome, result or item that must be produced to complete a project or part of a project. Often used more narrowly in reference to an external deliverable, which is a deliverable that is subject to approval by the project sponsor or customer" by [crossref:dev-model[ref-pmbok, PMI, 2000]]. Examples of outcomes are a piece of software, a decision made or a report written. [[ref-freebsd]] === FreeBSD When saying "FreeBSD" we will mean the BSD derivative UNIX-like operating system FreeBSD, whereas when saying "the FreeBSD Project" we will mean the project organisation. [[model-orgstruct]] == Organisational structure While no-one takes ownership of FreeBSD, the FreeBSD organisation is divided into core, committers and contributors and is part of the FreeBSD community that lives around it. The FreeBSD Project's structure (in order of descending authority) [.informaltable] [cols="1,1", options="header"] |=== | Group | Number of people |Core members |9 |Committers |318 |Contributors |~3000 |=== Number of committers has been determined by going through CVS logs from January 1st, 2004 to December 31st, 2004 and contributors by going through the list of contributions and problem reports. The main resource in the FreeBSD community is its developers: the committers and contributors. It is with their contributions that the project can move forward. Regular developers are referred to as contributors. As of January 1st, 2003, there are an estimated 5500 contributors on the project. Committers are developers with the privilege of being able to commit changes. These are usually the most active developers who are willing to spend their time not only integrating their own code but integrating code submitted by the developers who do not have this privilege. They are also the developers who elect the core team, and they have access to closed discussions. The project can be grouped into four distinct separate parts, and most developers will focus their involvement in one part of FreeBSD. The four parts are kernel development, userland development, ports and documentation. When referring to the base system, both kernel and userland is meant. This split changes our table to look like this: The FreeBSD Project's structure with committers in categories [.informaltable] [cols="1,1,1", options="header"] |=== | Group | Category | Number of people |Core members | |9 |Committers |Base |164 | |Docs |45 | |Ports |166 | |Total |374 |Contributors | |~3000 |=== Number of committers per area has been determined by going through CVS logs from January 1st, 2004 to December 31st, 2004. Note that many committers work in multiple areas, making the total number higher than the real number of committers. The total number of active unique committers on June 2022 was 317. Committers fall into three groups: committers who are only concerned with one area of the project (for instance file systems), committers who are involved only with one sub-project, and committers who commit to different parts of the code, including sub-projects. Because some committers work on different parts, the total number in the committers section of the table is higher than in the above table. The kernel is the main building block of FreeBSD. While the userland applications are protected against faults in other userland applications, the entire system is vulnerable to errors in the kernel. This, combined with the vast amount of dependencies in the kernel and that it is not easy to see all the consequences of a kernel change, demands developers with a relative full understanding of the kernel. Multiple development efforts in the kernel also require a closer coordination than userland applications do. The core utilities, known as userland, provide the interface that identifies FreeBSD, both user interface, shared libraries and external interfaces to connecting clients. Currently, 162 people are involved in userland development and maintenance, many being maintainers for their own part of the code. -Maintainership will be discussed in the crossref:dev-model[role-maintainer] section. +Maintainership will be discussed in the crossref:dev-model[role-maintainer, Maintainership] section. -Documentation is handled by crossref:dev-model[sub-project-documentation] and includes all documents surrounding the FreeBSD project, including the web pages. +Documentation is handled by crossref:dev-model[sub-project-documentation, The FreeBSD Documentation Project] and includes all documents surrounding the FreeBSD project, including the web pages. There were during 2004 101 people making commits to the FreeBSD Documentation Project. Ports is the collection of meta-data that is needed to make software packages build correctly on FreeBSD. An example of a port is the port for the web-browser Mozilla. It contains information about where to fetch the source, what patches to apply and how, and how the package should be installed on the system. This allows automated tools to fetch, build and install the package. As of this writing, there are more than 12600 ports available. footnote:[Statistics are generated by counting the number of entries in the file fetched by portsdb by April 1st, 2005. portsdb is a part of the port sysutils/portupgrade.] , ranging from web servers to games, programming languages and most of the application types that are in use on modern computers. -Ports will be discussed further in the section crossref:dev-model[sub-project-ports]. +Ports will be discussed further in the section crossref:dev-model[sub-project-ports, The Ports Subproject]. [[methodology-model]] == Methodology model [[development-model]] === Development model There is no defined model for how people write code in FreeBSD. However, Niels Jørgenssen has suggested a model of how written code is integrated into the project. Jørgenssen's model for change integration [.informaltable] [cols="1,1,1", options="header"] |=== | Stage | Next if successful | Next if unsuccessful |code |review | |review |pre-commit test |code |pre-commit test |development release |code |development release |parallel debugging |code |parallel debugging |production release |code |production release | |code |=== The "development release" is the FreeBSD-CURRENT ("-CURRENT") branch and the "production release" is the FreeBSD-STABLE branch ("-STABLE") [crossref:dev-model[jorgensen2001, Jørgensen, 2001]]. This is a model for one change, and shows that after coding, developers seek community review and try integrating it with their own systems. After integrating the change into the development release, called FreeBSD-CURRENT, it is tested by many users and developers in the FreeBSD community. After it has gone through enough testing, it is merged into the production release, called FreeBSD-STABLE. Unless each stage is finished successfully, the developer needs to go back and make modifications in the code and restart the process. To integrate a change with either -CURRENT or -STABLE is called making a commit. Jørgensen found that most FreeBSD developers work individually, meaning that this model is used in parallel by many developers on the different ongoing development efforts. A developer can also be working on multiple changes, so that while they are waiting for review or people to test one or more of their changes, they may be writing another change. As each commit represents an increment, this is a massively incremental model. The commits are in fact so frequent that during one year footnote:[The period from January 1st, 2004 to December 31st, 2004 was examined to find this number.] , 85427 commits were made, making a daily average of 233 commits. Within the "code" bracket in Jørgensen's model, each programmer has their own working style and follows their own development models. The bracket could very well have been called "development" as it includes requirements gathering and analysis, system and detailed design, implementation and verification. However, the only output from these stages is the source code or system documentation. From a stepwise model's perspective (such as the waterfall model), the other brackets can be seen as further verification and system integration. This system integration is also important to see if a change is accepted by the community. Up until the code is committed, the developer is free to choose how much to communicate about it to the rest of the project. In order for -CURRENT to work as a buffer (so that bright ideas that had some undiscovered drawbacks can be backed out) the minimum time a commit should be in -CURRENT before merging it to -STABLE is 3 days. Such a merge is referred to as an MFC (Merge From Current). It is important to notice the word "change". Most commits do not contain radical new features, but are maintenance updates. The only exceptions from this model are security fixes and changes to features that are deprecated in the -CURRENT branch. In these cases, changes can be committed directly to the -STABLE branch. In addition to many people working on the project, there are many related projects to the FreeBSD Project. These are either projects developing brand new features, sub-projects or projects whose outcome is incorporated into FreeBSD footnote:[For instance, the development of the Bluetooth stack started as a sub-project until it was deemed stable enough to be merged into the -CURRENT branch. Now it is a part of the core FreeBSD system.]. These projects fit into the FreeBSD Project just like regular development efforts: they produce code that is integrated with the FreeBSD Project. However, some of them (like Ports and Documentation) have the privilege of being applicable to both branches or commit directly to both -CURRENT and -STABLE. There is no standards to how design should be done, nor is design collected in a centralised repository. The main design is that of 4.4BSD. footnote:[According to Kirk McKusick, after 20 years of developing UNIX operating systems, the interfaces are for the most part figured out. There is therefore no need for much design. However, new applications of the system and new hardware leads to some implementations being more beneficial than those that used to be preferred. One example is the introduction of web browsing that made the normal TCP/IP connection a short burst of data rather than a steady stream over a longer period of time.] As design is a part of the "Code" bracket in Jørgenssen's model, it is up to every developer or sub-project how this should be done. Even if the design should be stored in a central repository, the output from the design stages would be of limited use as the differences of methodologies would make them poorly if at all interoperable. For the overall design of the project, the project relies on the sub-projects to negotiate fit interfaces between each other rather than to dictate interfacing. [[release-branches]] === Release branches The releases of FreeBSD are best illustrated by a tree with many branches where each major branch represents a major version. Minor versions are represented by branches of the major branches. In the following release tree, arrows that follow one-another in a particular direction represent a branch. Boxes with full lines and diamonds represent official releases. Boxes with dotted lines represent the development branch at that time. Security branches are represented by ovals. Diamonds differ from boxes in that they represent a fork, meaning a place where a branch splits into two branches where one of the branches becomes a sub-branch. For example, at 4.0-RELEASE the 4.0-CURRENT branch split into 4-STABLE and 5.0-CURRENT. At 4.5-RELEASE, the branch forked off a security branch called RELENG_4_5. .The FreeBSD release tree image::branches.png[Refer to table below for a screen-reader friendly version.] [.informaltable] [cols="1,1,1", options="header"] |=== | Major release | Forked from | Following minor releases |... | | |3.0 Current (development branch) | |Releng 3 branches: 3.0 Release to 3.5 Release, leading to 3.5.1 Release and the subsequent 3 Stable branch |4.0 Current (development branch) |3.1 Release |Releng 4 branches: 4.1 Release to 4.6 Release (and 4.6.2 Release), then 4.7 Release to 4.11 Release (all starting at 4.3 Release also leading to a Releng_4_n branch), and the subsequent 4 Release branch |5.0 Current (development branch) |4.0 Release |Releng 5 branches: 5.0 Release to 5.4 Release (all except 5.0 and 5.3 also leading to a Releng_5_n branch), and the subsequent 5 Release branch |6.0 Current (development branch) |5.3 Release | |... | | |=== The latest -CURRENT version is always referred to as -CURRENT, while the latest -STABLE release is always referred to as -STABLE. In this figure, -STABLE refers to 4-STABLE while -CURRENT refers to 5.0-CURRENT following 5.0-RELEASE. [crossref:dev-model[freebsd-releng, FreeBSD, 2002E]] A "major release" is always made from the -CURRENT branch. However, the -CURRENT branch does not need to fork at that point in time, but can focus on stabilising. An example of this is that following 3.0-RELEASE, 3.1-RELEASE was also a continuation of the -CURRENT-branch, and -CURRENT did not become a true development branch until this version was released and the 3-STABLE branch was forked. When -CURRENT returns to becoming a development branch, it can only be followed by a major release. 5-STABLE is predicted to be forked off 5.0-CURRENT at around 5.3-RELEASE. It is not until 5-STABLE is forked that the development branch will be branded 6.0-CURRENT. A "minor release" is made from the -CURRENT branch following a major release, or from the -STABLE branch. Following and including, 4.3-RELEASEfootnote:[The first release this actually happened for was 4.5-RELEASE, but security branches were at the same time created for 4.3-RELEASE and 4.4-RELEASE.], when a minor release has been made, it becomes a "security branch". This is meant for organisations that do not want to follow the -STABLE branch and the potential new/changed features it offers, but instead require an absolutely stable environment, only updating to implement security updates. footnote:[There is a terminology overlap with respect to the word "stable", which leads to some confusion. The -STABLE branch is still a development branch, whose goal is to be useful for most people. If it is never acceptable for a system to get changes that are not announced at the time it is deployed, that system should run a security branch.] Each update to a security branch is called a "patchlevel". For every security enhancement that is done, the patchlevel number is increased, making it easy for people tracking the branch to see what security enhancements they have implemented. In cases where there have been especially serious security flaws, an entire new release can be made from a security branch. An example of this is 4.6.2-RELEASE. [[model-summary]] === Model summary To summarise, the development model of FreeBSD can be seen as the following tree: .The overall development model image::freebsd-code-model.png[Refer to paragraphs below for a screen-reader friendly version.] The tree of the FreeBSD development with ongoing development efforts and continuous integration. The tree symbolises the release versions with major versions spawning new main branches and minor versions being versions of the main branch. The top branch is the -CURRENT branch where all new development is integrated, and the -STABLE branch is the branch directly below it. Below the -STABLE branch are old, unsupported versions. Clouds of development efforts hang over the project where developers use the development models they see fit. The product of their work is then integrated into -CURRENT where it undergoes parallel debugging and is finally merged from -CURRENT into -STABLE. Security fixes are merged from -STABLE to the security branches. Many committers have a special area of responsibility. These roles are called hats. These hats can be either project roles, such as public relations officer, or maintainer for a certain area of the code. Because this is a project where people give voluntarily of their spare time, people with assigned hats are not always available. They must therefore appoint a deputy that can perform the hat's role in their absence. The other option is to have the role held by a group. Many of these hats are not formalised. Formalised hats have a charter stating the exact purpose of the hat along with its privileges and responsibilities. The writing of such charters is a new part of the project, and has thus yet to be completed for all hats. These hat descriptions are not such a formalisation, rather a summary of the role with links to the charter where available and contact addresses. [[sect-hats]] == Hats [[general-hats]] === General Hats [[role-contributor]] ==== Contributor A Contributor contributes to the FreeBSD project either as a developer, as an author, by sending problem reports, or in other ways contributing to the progress of the project. A contributor has no special privileges in the FreeBSD project. [crossref:dev-model[freebsd-contributors, FreeBSD, 2002F]] [[role-committer]] ==== Committer A person who has the required privileges to add their code or documentation to the repository. A committer has made a commit within the past 12 months. [crossref:dev-model[freebsd-developer-handbook, FreeBSD, 2000A]] An active committer is a committer who has made an average of one commit per month during that time. It is worth noting that there are no technical barriers to prevent someone, once having gained commit privileges to the main- or a sub-project, to make commits in parts of that project's source the committer did not specifically get permission to modify. However, when wanting to make modifications to parts a committer has not been involved in before, they should read the logs to see what has happened in this area before, and also read the MAINTAINERS file to see if the maintainer of this part has any special requests on how changes in the code should be made. [[role-core]] ==== Core Team The core team is elected by the committers from the pool of committers and serves as the board of directors of the FreeBSD project. It promotes active contributors to committers, assigns people to well-defined hats, and is the final arbiter of decisions involving which way the project should be heading. As of July 1st, 2004, core consisted of 9 members. Elections are held every two years. [[role-maintainer]] ==== Maintainership Maintainership means that the person is responsible for what is allowed to go into that area of the code and has the final say should disagreements over the code occur. This involves proactive work aimed at stimulating contributions and reactive work in reviewing commits. With the FreeBSD source comes the MAINTAINERS file that contains a one-line summary of how each maintainer would like contributions to be made. Having this notice and contact information enables developers to focus on the development effort rather than being stuck in a slow correspondence should the maintainer be unavailable for some time. If the maintainer is unavailable for an unreasonably long period of time, and other people do a significant amount of work, maintainership may be switched without the maintainer's approval. This is based on the stance that maintainership should be demonstrated, not declared. Maintainership of a particular piece of code is a hat that is not held as a group. [[official-hats]] === Official Hats The official hats in the FreeBSD Project are hats that are more or less formalised and mainly administrative roles. They have the authority and responsibility for their area. The following list shows the responsibility lines and gives a description of each hat, including who it is held by. [[role-doc-manager]] ==== Documentation project manager -crossref:dev-model[sub-project-documentation] architect is responsible for defining and following up documentation goals for the committers in the Documentation project, which they supervise. +crossref:dev-model[sub-project-documentation, The FreeBSD Documentation Project] architect is responsible for defining and following up documentation goals for the committers in the Documentation project, which they supervise. Hat held by: The DocEng team mailto:doceng@FreeBSD.org[doceng@FreeBSD.org]. The https://www.freebsd.org/internal/doceng/[ DocEng Charter]. [[role-postmaster]] ==== Postmaster The Postmaster is responsible for mail being correctly delivered to the committers' email address. They are also responsible for ensuring that the mailing lists work and should take measures against possible disruptions of mail such as having troll-, spam- and virus-filters. Hat currently held by: the Postmaster Team mailto:postmaster@FreeBSD.org[postmaster@FreeBSD.org]. [[role-release-coordination]] ==== Release Coordination The responsibilities of the Release Engineering Team are * Setting, publishing and following a release schedule for official releases * Documenting and formalising release engineering procedures * Creation and maintenance of code branches * Coordinating with the Ports and Documentation teams to have an updated set of packages and documentation released with the new releases * Coordinating with the Security team so that pending releases are not affected by recently disclosed vulnerabilities. Further information about the development process is available in the -crossref:dev-model[process-release-engineering] section. +crossref:dev-model[process-release-engineering, Release engineering] section. [[role-releng]] Hat held by: the Release Engineering team mailto:re@FreeBSD.org[re@FreeBSD.org]. The https://www.freebsd.org/releng/charter/[ Release Engineering Charter]. [[role-pr-cr]] ==== Public Relations & Corporate Liaison The Public Relations & Corporate Liaison's responsibilities are: * Making press statements when happenings that are important to the FreeBSD Project happen. * Being the official contact person for corporations that are working close with the FreeBSD Project. * Take steps to promote FreeBSD within both the Open Source community and the corporate world. * Handle the "freebsd-advocacy" mailing list. This hat is currently not occupied. [[role-security-officer]] ==== Security Officer The Security Officer's main responsibility is to coordinate information exchange with others in the security community and in the FreeBSD project. The Security Officer is also responsible for taking action when security problems are reported and promoting proactive development behavior when it comes to security. Because of the fear that information about vulnerabilities may leak out to people with malicious intent before a patch is available, only the Security Officer, consisting of an officer, a deputy and two -crossref:dev-model[role-core] members, receive sensitive information about security issues. +crossref:dev-model[role-core, Core Team] members, receive sensitive information about security issues. However, to create or implement a patch, the Security Officer has the Security Officer Team mailto:security-team@FreeBSD.org[security-team@FreeBSD.org] to help do the work. [[role-repo-manager]] ==== Source Repository Manager The Source Repository Manager is the only one who is allowed to directly modify -the repository without using the crossref:dev-model[tool-git] tool. +the repository without using the crossref:dev-model[tool-git, Git] tool. It is their responsibility to ensure that technical problems that arise in the repository are resolved quickly. The source repository manager has the authority to back out commits if this is necessary to resolve a Git technical problem. Hat held by: the Source Repository Manager mailto:clusteradm@FreeBSD.org[clusteradm@FreeBSD.org]. [[role-election-manager]] ==== Election Manager The Election Manager is responsible for the -crossref:dev-model[process-core-election] process. +crossref:dev-model[process-core-election, Core election] process. The manager is responsible for running and maintaining the election system, and is the final authority should minor unforeseen events happen in the election process. Major unforeseen events have to be discussed with the -crossref:dev-model[role-core] +crossref:dev-model[role-core, Core Team] Hat held only during elections. [[role-webmaster]] ==== Web site Management The Web site Management hat is responsible for coordinating the rollout of updated web pages on mirrors around the world, for the overall structure of the primary web site and the system it is running upon. The management needs to coordinate the content with -crossref:dev-model[sub-project-documentation] and acts as maintainer for the "www" tree. +crossref:dev-model[sub-project-documentation, The FreeBSD Documentation Project] and acts as maintainer for the "www" tree. Hat held by: the FreeBSD Webmasters mailto:www@FreeBSD.org[www@FreeBSD.org]. [[role-ports-manager]] ==== Ports Manager -The Ports Manager acts as a liaison between crossref:dev-model[sub-project-ports] and the core project, and all requests from the project should go to the ports manager. +The Ports Manager acts as a liaison between crossref:dev-model[sub-project-ports, The Ports Subproject] and the core project, and all requests from the project should go to the ports manager. Hat held by: the Ports Management Team mailto:portmgr@FreeBSD.org[portmgr@FreeBSD.org]. The https://www.freebsd.org/portmgr/charter/[Portmgr charter]. [[role-standards]] ==== Standards The Standards hat is responsible for ensuring that FreeBSD complies with the standards it is committed to , keeping up to date on the development of these standards and notifying FreeBSD developers of important changes that allows them to take a proactive role and decrease the time between a standards update and FreeBSD's compliancy. Hat currently held by: Garrett Wollman mailto:wollman@FreeBSD.org[wollman@FreeBSD.org]. [[role-core-secretary]] ==== Core Secretary The Core Secretary's main responsibility is to write drafts to and publish the final Core Reports. The secretary also keeps the core agenda, thus ensuring that no balls are dropped unresolved. Hat currently held by: {rene}. [[role-bugmeister]] ==== Bugmeister The Bugmeister is responsible for ensuring that the maintenance database is in working order, that the entries are correctly categorised and that there are no invalid entries. They supervise bugbusters. Hat currently held by: the Bugmeister Team mailto:bugmeister@FreeBSD.org[bugmeister@FreeBSD.org]. [[role-donations]] ==== Donations Liaison Officer The task of the donations liaison officer is to match the developers with needs with people or organisations willing to make a donation. Hat held by: the Donations Liaison Office mailto:donations@FreeBSD.org[donations@FreeBSD.org]. The https://www.freebsd.org/donations/[ Donations Liaison Charter]. [[role-admin]] ==== Admin (Also called "FreeBSD Cluster Admin") The admin team consists of the people responsible for administrating the computers that the project relies on for its distributed work and communication to be synchronised. It consists mainly of those people who have physical access to the servers. Hat held by: the Admin team mailto:admin@FreeBSD.org[admin@FreeBSD.org]. [[proc-depend-hats]] === Process dependent hats [[role-problem-originator]] ==== Report originator The person originally responsible for filing a Problem Report. [[role-bugbuster]] ==== Bugbuster A person who will either find the right person to solve the problem, or close the PR if it is a duplicate or otherwise not an interesting one. [[role-mentor]] ==== Mentor A mentor is a committer who takes it upon them to introduce a new committer to the project, both in terms of ensuring the new committer's setup is valid, that the new committer knows the available tools required in their work, and that the new committer knows what is expected of them in terms of behavior. [[role-vendor]] ==== Vendor The person(s) or organisation whom external code comes from and whom patches are sent to. [[role-reviewer]] ==== Reviewers People on the mailing list where the request for review is posted. The following section will describe the defined project processes. Issues that are not handled by these processes happen on an ad-hoc basis based on what has been customary to do in similar cases. [[model-processes]] == Processes [[proc-addrem-committer]] === Adding new and removing old committers The Core team has the responsibility of giving and removing commit privileges to contributors. This can only be done through a vote on the core mailing list. The ports and documentation sub-projects can give commit privileges to people working on these projects, but have to date not removed such privileges. Normally a contributor is recommended to core by a committer. For contributors or outsiders to contact core asking to be a committer is not well thought of and is usually rejected. If the area of particular interest for the developer potentially overlaps with other committers' area of maintainership, the opinion of those maintainers is sought. However, it is frequently this committer that recommends the developer. When a contributor is given committer status, they are assigned a mentor. The committer who recommended the new committer will, in the general case, take it upon themselves to be the new committers mentor. When a contributor is given their commit bit, a -crossref:dev-model[tool-pgp]-signed email is sent from either -crossref:dev-model[role-core-secretary], crossref:dev-model[role-ports-manager], or nik@freebsd.org to both admins@freebsd.org, the assigned mentor, the new committer, and core confirming the approval of a new account. -The mentor then gathers a password line, crossref:dev-model[tool-ssh2] public +crossref:dev-model[tool-pgp, Pretty Good Privacy]-signed email is sent from either +crossref:dev-model[role-core-secretary], crossref:dev-model[role-ports-manager, Ports Manager], or nik@freebsd.org to both admins@freebsd.org, the assigned mentor, the new committer, and core confirming the approval of a new account. +The mentor then gathers a password line, crossref:dev-model[tool-ssh2, Secure Shell] public key, and PGP key from the new committer and sends them to -crossref:dev-model[role-admin]. +crossref:dev-model[role-admin, Admin]. When the new account is created, the mentor activates the commit bit and guides the new committer through the rest of the initial process. .Process summary: adding a new committer image::proc-add-committer.png[Refer to paragraph below for a screen-reader friendly version.] When a contributor sends a piece of code, the receiving committer may choose to recommend that the contributor is given commit privileges. If they recommend this to core, core will vote on this recommendation. If the vote is in favour, a mentor is assigned the new committer and the new committer has to email their details to the administrators for an account to be created. After this, the new committer is all set to make their first commit. By tradition, this is by adding their name to the committers list. Recall that a committer is considered to be someone who has committed code during the past 12 months. However, it is not until after 18 months of inactivity have passed that commit privileges are eligible to be revoked. [crossref:dev-model[freebsd-expiration-policy, FreeBSD, 2002H]] There are, however, no automatic procedures for doing this. For reactions concerning commit privileges not triggered by time, see crossref:dev-model[process-reactions,section 1.5.8]. .Process summary: removing a committer image::proc-rm-committer.png[Refer to paragraph below for a screen-reader friendly version.] When Core decides to clean up the committers list, they check who has not made a commit for the past 18 months. Committers who have not done so have their commit bits revoked and their account removed by the administrators. It is also possible for committers to request that their commit bit be retired if for some reason they are no longer going to be actively committing to the project. In this case, it can also be restored at a later time by core, should the committer ask. Roles in this process: -. crossref:dev-model[role-core] -. crossref:dev-model[role-contributor] -. crossref:dev-model[role-committer] -. crossref:dev-model[role-maintainer] -. crossref:dev-model[role-mentor] +. crossref:dev-model[role-core, Core Team] +. crossref:dev-model[role-contributor, Contributor] +. crossref:dev-model[role-committer, Committer] +. crossref:dev-model[role-maintainer, Maintainership] +. crossref:dev-model[role-mentor, Mentor] [crossref:dev-model[freebsd-bylaws, FreeBSD, 2000A]] [crossref:dev-model[freebsd-expiration-policy, FreeBSD, 2002H]] [crossref:dev-model[freebsd-new-account, FreeBSD, 2002I]] [[committing]] === Committing code The committing of new or modified code is one of the most frequent processes in the FreeBSD project and will usually happen many times a day. Committing of code can only be done by a "committer". Committers commit either code written by themselves, code submitted to them, or code submitted through a crossref:dev-model[model-pr,problem report]. When code is written by the developer that is non-trivial, they should seek a code review from the community. This is done by sending mail to the relevant list asking for review. Before submitting the code for review, they should ensure it compiles correctly with the entire tree and that all relevant tests run. This is called "pre-commit test". When contributed code is received, it should be reviewed by the committer and tested the same way. When a change is committed to a part of the source that has been contributed -from an outside crossref:dev-model[role-vendor], the maintainer should ensure that the patch is contributed back to the vendor. +from an outside crossref:dev-model[role-vendor, Vendor], the maintainer should ensure that the patch is contributed back to the vendor. This is in line with the open source philosophy and makes it easier to stay in sync with outside projects as the patches do not have to be reapplied every time a new release is made. After the code has been available for review and no further changes are necessary, the code is committed into the development branch, -CURRENT. If the change applies for the -STABLE branch or the other branches as well, a "Merge From Current" ("MFC") countdown is set by the committer. After the number of days the committer chose when setting the MFC have passed, an email will automatically be sent to the committer reminding them to commit it to the -STABLE branch (and possibly security branches as well). Only security critical changes should be merged to security branches. Delaying the commit to -STABLE and other branches allows for "parallel debugging" where the committed code is tested on a wide range of configurations. This makes changes to -STABLE to contain fewer faults and thus giving the branch its name. .Process summary: A committer commits code image::proc-commit.png[Refer to paragraph below for a screen-reader friendly version.] When a committer has written a piece of code and wants to commit it, they first need to determine if it is trivial enough to go in without prior review or if it should first be reviewed by the developer community. If the code is trivial or has been reviewed and the committer is not the maintainer, they should consult the maintainer before proceeding. If the code is contributed by an outside vendor, the maintainer should create a patch that is sent back to the vendor. The code is then committed and then deployed by the users. Should they find problems with the code, this will be reported and the committer can go back to writing a patch. If a vendor is affected, they can choose to implement or ignore the patch. .Process summary: A contributor commits code image::proc-contrib.png[Refer to paragraphs below and above for a screen-reader friendly version.] The difference when a contributor makes a code contribution is that they submit the code through the Bugzilla interface. This report is picked up by the maintainer who reviews the code and commits it. Hats included in this process are: -. crossref:dev-model[role-committer] -. crossref:dev-model[role-contributor] -. crossref:dev-model[role-vendor] -. crossref:dev-model[role-reviewer] +. crossref:dev-model[role-committer, Committer] +. crossref:dev-model[role-contributor, Contributor] +. crossref:dev-model[role-vendor, Vendor] +. crossref:dev-model[role-reviewer, Reviewers] [crossref:dev-model[freebsd-committer, FreeBSD, 2001]] [crossref:dev-model[jorgensen2001, Jørgensen, 2001]] [[process-core-election]] === Core election Core elections are held at least every two years. footnote:[The first Core election was held September 2000] Nine core members are elected. New elections are held if the number of core members drops below seven. New elections can also be held should at least 1/3 of the active committers demand this. When an election is to take place, core announces this at least 6 weeks in advance, and appoints an election manager to run the elections. Only committers can be elected into core. The candidates need to submit their candidacy at least one week before the election starts, but can refine their statements until the voting starts. They are presented in the http://election.uk.freebsd.org/candidates.html[candidates list]. When writing their election statements, the candidates must answer a few standard questions submitted by the election manager. During elections, the rule that a committer must have committed during the 12 past months is followed strictly. Only these committers are eligible to vote. When voting, the committer may vote once in support of up to nine nominees. The voting is done over a period of four weeks with reminders being posted on "developers" mailing list that is available to all committers. The election results are released one week after the election ends, and the new core team takes office one week after the results have been posted. Should there be a voting tie, this will be resolved by the new, unambiguously elected core members. Votes and candidate statements are archived, but the archives are not publicly available. .Process summary: Core elections image::proc-elections.png[Refer to paragraph below for a screen-reader friendly version.] Core announces the election and selects an election manager who prepares the elections, and when ready, candidates can announce their candidacies through submitting their statements. The committers then vote. After the vote is over, the election results are announced and the new core team takes office. Hats in core elections are: -* crossref:dev-model[role-core] -* crossref:dev-model[role-committer] -* crossref:dev-model[role-election-manager] +* crossref:dev-model[role-core, Core Team] +* crossref:dev-model[role-committer, Committer] +* crossref:dev-model[role-election-manager, Election Manager] [crossref:dev-model[freebsd-bylaws, FreeBSD, 2000A]] [crossref:dev-model[bsd-election2002, FreeBSD, 2002B]] [crossref:dev-model[freebsd-election, FreeBSD, 2002G]] [[new-features]] === Development of new features Within the project there are sub-projects that are working on new features. These projects are generally done by one person [crossref:dev-model[jorgensen2001, Jørgensen, 2001]]. Every project is free to organise development as it sees fit. However, when the project is merged to the -CURRENT branch it must follow the project guidelines. When the code has been well tested in the -CURRENT branch and deemed stable enough and relevant to the -STABLE branch, it is merged to the -STABLE branch. The requirements of the project are given by developer wishes, requests from the community in terms of direct requests by mail, Problem Reports, commercial funding for the development of features, or contributions by the scientific community. The wishes that come within the responsibility of a developer are given to that developer who prioritises their time between the request and their wishes. A common way to do this is maintain a TODO-list maintained by the project. Items that do not come within someone's responsibility are collected on TODO-lists unless someone volunteers to take the responsibility. All requests, their distribution and follow-up are handled by the -crossref:dev-model[tool-bugzilla] tool. +crossref:dev-model[tool-bugzilla, Bugzilla] tool. Requirements analysis happens in two ways. The requests that come in are discussed on mailing lists, both within the main project and in the sub-project that the request belongs to or is spawned by the request. Furthermore, individual developers on the sub-project will evaluate the feasibility of the requests and determine the prioritisation between them. Other than archives of the discussions that have taken place, no outcome is created by this phase that is merged into the main project. As the requests are prioritised by the individual developers on the basis of doing what they find interesting, necessary, or are funded to do, there is no overall strategy or prioritisation of what requests to regard as requirements and following up their correct implementation. However, most developers have some shared vision of what issues are more important, and they can ask for guidelines from the release engineering team. The verification phase of the project is two-fold. Before committing code to the current-branch, developers request their code to be reviewed by their peers. This review is for the most part done by functional testing, but also code review is important. When the code is committed to the branch, a broader functional testing will happen, that may trigger further code review and debugging should the code not behave as expected. This second verification form may be regarded as structural verification. Although the sub-projects themselves may write formal tests such as unit tests, these are usually not collected by the main project and are usually removed before the code is committed to the current branch. footnote:[More and more tests are however performed when building the system (make world). These tests are however a very new addition and no systematic framework for these tests have yet been created.] [[model-maintenance]] === Maintenance It is an advantage to the project to for each area of the source have at least one person that knows this area well. Some parts of the code have designated maintainers. Others have de-facto maintainers, and some parts of the system do not have maintainers. The maintainer is usually a person from the sub-project that wrote and integrated the code, or someone who has ported it from the platform it was written for. footnote:[sendmail and named are examples of code that has been merged from other platforms.] The maintainer's job is to make sure the code is in sync with the project the code comes from if it is contributed code, and apply patches submitted by the community or write fixes to issues that are discovered. The main bulk of work that is put into the FreeBSD project is maintenance. [crossref:dev-model[jorgensen2001, Jørgensen, 2001]] has made a figure showing the life cycle of changes. Jørgenssen's model for change integration [.informaltable] [cols="1,1,1", options="header"] |=== | Stage | Next if successful | Next if unsuccessful |code |review | |review |pre-commit test |code |pre-commit test |development release |code |development release |parallel debugging |code |parallel debugging |production release |code |production release | |code |=== Here "development release" refers to the -CURRENT branch while "production release" refers to the -STABLE branch. The "pre-commit test" is the functional testing by peer developers when asked to do so or trying out the code to determine the status of the sub-project. "Parallel debugging" is the functional testing that can trigger more review, and debugging when the code is included in the -CURRENT branch. As of this writing, there were 269 committers in the project. When they commit a change to a branch, that constitutes a new release. It is very common for users in the community to track a particular branch. The immediate existence of a new release makes the changes widely available right away and allows for rapid feedback from the community. This also gives the community the response time they expect on issues that are of importance to them. This makes the community more engaged, and thus allows for more and better feedback that again spurs more maintenance and ultimately should create a better product. Before making changes to code in parts of the tree that has a history unknown to the committer, the committer is required to read the commit logs to see why certain features are implemented the way they are in order not to make mistakes that have previously either been thought through or resolved. [[model-pr]] === Problem reporting Before FreeBSD 10, FreeBSD included a problem reporting tool called `send-pr`. Problems include bug reports, feature requests, feature enhancements and notices of new versions of external software that are included in the project. Although `send-pr` is available, users and developers are encouraged to submit issues using our https://bugs.freebsd.org/submit/[ problem report form]. Problem reports are sent to an email address where it is inserted into the Problem Reports maintenance database. -A crossref:dev-model[role-bugbuster] classifies the problem and sends it to the correct group or maintainer within the project. +A crossref:dev-model[role-bugbuster, Bugbuster] classifies the problem and sends it to the correct group or maintainer within the project. After someone has taken responsibility for the report, the report is being analysed. This analysis includes verifying the problem and thinking out a solution for the problem. Often feedback is required from the report originator or even from the FreeBSD community. Once a patch for the problem is made, the originator may be asked to try it out. Finally, the working patch is integrated into the project, and documented if applicable. It there goes through the regular maintenance cycle as described in section -crossref:dev-model[model-maintenance]. +crossref:dev-model[model-maintenance, Maintenance]. These are the states a problem report can be in: open, analyzed, feedback, patched, suspended and closed. The suspended state is for when further progress is not possible due to the lack of information or for when the task would require so much work that nobody is working on it at the moment. .Process summary: problem reporting image::proc-pr.png[Refer to paragraph below for a screen-reader friendly version.] A problem is reported by the report originator. It is then classified by a bugbuster and handed to the correct maintainer. They verify the problem and discuss the problem with the originator until they have enough information to create a working patch. This patch is then committed and the problem report is closed. The roles included in this process are: -. crossref:dev-model[role-problem-originator] -. crossref:dev-model[role-maintainer] -. crossref:dev-model[role-bugbuster] +. crossref:dev-model[role-problem-originator, Report originator] +. crossref:dev-model[role-maintainer, Maintainership] +. crossref:dev-model[role-bugbuster, Bugbuster] [crossref:dev-model[freebsd-handle-pr, FreeBSD, 2002C]]. [crossref:dev-model[freebsd-send-pr, FreeBSD, 2002D]] [[process-reactions]] === Reacting to misbehavior [crossref:dev-model[freebsd-committer, FreeBSD, 2001]] has a number of rules that committers should follow. However, it happens that these rules are broken. The following rules exist in order to be able to react to misbehavior. They specify what actions will result in how long a suspension of the committer's commit privileges. * Committing during code freezes without the approval of the Release Engineering team - 2 days * Committing to a security branch without approval - 2 days * Commit wars - 5 days to all participating parties * Impolite or inappropriate behavior - 5 days [crossref:dev-model[ref-freebsd-trenches, Lehey, 2002]] For the suspensions to be efficient, any single core member can implement a suspension before discussing it on the "core" mailing list. Repeat offenders can, with a 2/3 vote by core, receive harsher penalties, including permanent removal of commit privileges. (However, the latter is always viewed as a last resort, due to its inherent tendency to create controversy.) All suspensions are posted to the "developers" mailing list, a list available to committers only. It is important that you cannot be suspended for making technical errors. All penalties come from breaking social etiquette. Hats involved in this process: -* crossref:dev-model[role-core] -* crossref:dev-model[role-committer] +* crossref:dev-model[role-core, Core Team] +* crossref:dev-model[role-committer, Committer] [[process-release-engineering]] === Release engineering The FreeBSD project has a Release Engineering team with a principal release engineer that is responsible for creating releases of FreeBSD that can be brought out to the user community via the net or sold in retail outlets. Since FreeBSD is available on multiple platforms and releases for the different architectures are made available at the same time, the team has one person in charge of each architecture. Also, there are roles in the team responsible for coordinating quality assurance efforts, building a package set and for having an updated set of documents. When referring to the release engineer, a representative for the release engineering team is meant. When a release is coming, the FreeBSD project changes shape somewhat. A release schedule is made containing feature- and code-freezes, release of interim releases and the final release. A feature-freeze means no new features are allowed to be committed to the branch without the release engineers' explicit consent. Code-freeze means no changes to the code (like bugs-fixes) are allowed to be committed without the release engineers' explicit consent. This feature- and code-freeze is known as stabilising. During the release process, the release engineer has the full authority to revert to older versions of code and thus "back out" changes should they find that the changes are not suitable to be included in the release. There are three different kinds of releases: . .0 releases are the first release of a major version. These are branched of the -CURRENT branch and have a significantly longer release engineering cycle due to the unstable nature of the -CURRENT branch . .X releases are releases of the -STABLE branch. They are scheduled to come out every 4 months. . .X.Y releases are security releases that follow the .X branch. These come out only when sufficient security fixes have been merged since the last release on that branch. New features are rarely included, and the security team is far more involved in these than in regular releases. For releases of the -STABLE-branch, the release process starts 45 days before the anticipated release date. During the first phase, the first 15 days, the developers merge what changes they have had in -CURRENT that they want to have in the release to the release branch. When this period is over, the code enters a 15 day code freeze in which only bug fixes, documentation updates, security-related fixes and minor device driver changes are allowed. These changes must be approved by the release engineer in advance. At the beginning of the last 15 day period a release candidate is created for widespread testing. Updates are less likely to be allowed during this period, except for important bug fixes and security updates. In this final period, all releases are considered release candidates. At the end of the release process, a release is created with the new version number, including binary distributions on web sites and the creation of CD-ROM images. However, the release is not considered "really released" until a -crossref:dev-model[tool-pgp]-signed message stating exactly that, is sent to the mailing list freebsd-announce; anything labelled as a "release" before that may well be in-process and subject to change before the PGP-signed message is sent. footnote:[Many commercial vendors use these images to create CD-ROMs that are sold in retail outlets.]. +crossref:dev-model[tool-pgp, Pretty Good Privacy]-signed message stating exactly that, is sent to the mailing list freebsd-announce; anything labelled as a "release" before that may well be in-process and subject to change before the PGP-signed message is sent. footnote:[Many commercial vendors use these images to create CD-ROMs that are sold in retail outlets.]. The releases of the -CURRENT-branch (that is, all releases that end with ".0") are very similar, but with twice as long timeframe. It starts 8 weeks prior to the release with announcement of the release time line. Two weeks into the release process, the feature freeze is initiated and performance tweaks should be kept to a minimum. Four weeks prior to the release, an official beta version is made available. Two weeks prior to release, the code is officially branched into a new version. This version is given release candidate status, and as with the release engineering of -STABLE, the code freeze of the release candidate is hardened. However, development on the main development branch can continue. Other than these differences, the release engineering processes are alike. *.0 releases go into their own branch and are aimed mainly at early adopters. The branch then goes through a period of stabilisation, and it is not until the crossref:dev-model[role-releng, Release Engineering Team] decides the demands to stability have been satisfied that the branch becomes -STABLE and -CURRENT targets the next major version. While this for the majority has been with *.1 versions, this is not a demand. Most releases are made when a given date that has been deemed a long enough time since the previous release comes. A target is set for having major releases every 18 months and minor releases every 4 months. The user community has made it very clear that security and stability cannot be sacrificed by self-imposed deadlines and target release dates. For slips of time not to become too long with regards to security and stability issues, extra discipline is required when committing changes to -STABLE. . Make release schedule . Feature freeze . Code freeze . Make branch . Release candidate . Stabilize release (loop back to previous step as many times as necessary; when release is considered stable, proceed with next step) . Build packages . Warn mirrors . Publish release // Keep the spaces around the external square bracket to avoid a warning in the // PDF converter [ crossref:dev-model[freebsd-releng, FreeBSD, 2002E] ] [[tools]] == Tools The major support tools for supporting the development process are Bugzilla, Mailman, and OpenSSH. These are externally developed tools and are commonly used in the open source world. [[tool-git]] === Git Git is a system to handle multiple versions of text files and tracking who committed what changes and why. A project lives within a "repository" and different versions are considered different "branches". [[tool-bugzilla]] === Bugzilla Bugzilla is a maintenance database consisting of a set of tools to track bugs at a central site. It supports the bug tracking process for sending and handling bugs as well as querying and updating the database and editing bug reports. The project uses its web interface to send "Problem Reports" to the project's central Bugzilla server. The committers also have web and command-line clients. [[model-mailman]] === Mailman Mailman is a program that automates the management of mailing lists. The FreeBSD Project uses it to run 16 general lists, 60 technical lists, 4 limited lists and 5 lists with Git commit logs. It is also used for many mailing lists set up and used by other people and projects in the FreeBSD community. General lists are lists for the general public, technical lists are mainly for the development of specific areas of interest, and closed lists are for internal communication not intended for the general public. The majority of all the communication in the project goes through these 85 lists [crossref:dev-model[ref-bsd-handbook, FreeBSD, 2003A], Appendix C]. [[tool-pgp]] === Pretty Good Privacy Pretty Good Privacy, better known as PGP, is a cryptosystem using a public key architecture to allow people to digitally sign and/or encrypt information in order to ensure secure communication between two parties. A signature is used when sending information out to many recipients, enabling them to verify that the information has not been tampered with before they received it. In the FreeBSD Project this is the primary means of ensuring that information has been written by the person who claims to have written it, and not altered in transit. [[tool-ssh2]] === Secure Shell Secure Shell is a standard for securely logging into a remote system and for executing commands on the remote system. It allows other connections, called tunnels, to be established and protected between the two involved systems. This standard exists in two primary versions, and only version two is used for the FreeBSD Project. The most common implementation of the standard is OpenSSH that is a part of the project's main distribution. Since its source is updated more often than FreeBSD releases, the latest version is also available in the ports tree. [[sub-projects]] == Sub-projects Sub-projects are formed to reduce the amount of communication needed to coordinate the group of developers. When a problem area is sufficiently isolated, most communication would be within the group focusing on the problem, requiring less communication with the groups they communicate with than were the group not isolated. [[sub-project-ports]] === The Ports Subproject A "port" is a set of meta-data and patches that are needed to fetch, compile and install correctly an external piece of software on a FreeBSD system. The amount of ports has grown at a tremendous rate, as shown by the following figure. .Number of ports added between 1995 and 2022 [[fig-ports]] image::portsstatus.svg -crossref:dev-model[fig-ports] shows the number of ports available to FreeBSD in the period 1995 to 2022. +crossref:dev-model[fig-ports,image::portsstatus.svg] shows the number of ports available to FreeBSD in the period 1995 to 2022. It looks like the curve has first grown exponentially, and then from the middle of 2001 to the middle of 2007 grown linearly at a rate of about 2000 ports/year, before its growth rate gets lower. As the external software described by the port often is under continued development, the amount of work required to maintain the ports is already large, and increasing. This has led to the ports part of the FreeBSD project gaining a more empowered structure, and is more and more becoming a sub-project of the FreeBSD project. -Ports has its own core team with the crossref:dev-model[role-ports-manager] as its leader, and this team can appoint committers without FreeBSD Core's approval. +Ports has its own core team with the crossref:dev-model[role-ports-manager, Ports Manager] as its leader, and this team can appoint committers without FreeBSD Core's approval. Unlike in the FreeBSD Project, where a lot of maintenance frequently is rewarded with a commit bit, the ports sub-project contains many active maintainers that are not committers. Unlike the main project, the ports tree is not branched. Every release of FreeBSD follows the current ports collection and has thus available updated information on where to find programs and how to build them. This, however, means that a port that makes dependencies on the system may need to have variations depending on what version of FreeBSD it runs on. With an unbranched ports repository it is not possible to guarantee that any port will run on anything other than -CURRENT and -STABLE, in particular older, minor releases. There is neither the infrastructure nor volunteer time needed to guarantee this. For efficiency of communication, teams depending on Ports, such as the release engineering team, have their own ports liaisons. [[sub-project-documentation]] === The FreeBSD Documentation Project The FreeBSD Documentation project was started January 1995. From the initial group of a project leader, four team leaders and 16 members, they are now a total of 44 committers. The documentation mailing list has just under 300 members, indicating that there is quite a large community around it. The goal of the Documentation project is to provide good and useful documentation of the FreeBSD project, thus making it easier for new users to get familiar with the system and detailing advanced features for the users. The main tasks in the Documentation project are to work on current projects in the "FreeBSD Documentation Set", and translate the documentation to other languages. Like the FreeBSD Project, documentation is split in the same branches. This is done so that there is always an updated version of the documentation for each version. Only documentation errors are corrected in the security branches. Like the ports sub-project, the Documentation project can appoint documentation committers without FreeBSD Core's approval. [crossref:dev-model[freebsd-doceng-charter, FreeBSD, 2003B]]. The Documentation project has extref:{fdp-primer}[a primer]. This is used both to introduce new project members to the standard tools and syntaxes and to act as a reference when working on the project. :sectnums!: [bibliography] [[bibliography]] == References [[brooks]] [Brooks, 1995] Frederick P. Brooks. Copyright © 1975, 1995 Pearson Education Limited. 0201835959. Addison-Wesley Pub Co. The Mythical Man-Month. Essays on Software Engineering, Anniversary Edition (2nd Edition). [[thesis]] [Saers, 2003] Niklas Saers. Copyright © 2003. A project model for the FreeBSD Project. Candidatus Scientiarum thesis. http://niklas.saers.com/thesis. [[jorgensen2001]] [Jørgensen, 2001] Niels Jørgensen. Copyright © 2001. Putting it All in the Trunk. Incremental Software Development in the FreeBSD Open Source Project. http://www.dat.ruc.dk/~nielsj/research/papers/freebsd.pdf. [[ref-pmbok]] [PMI, 2000] Project Management Institute. Copyright © 1996, 2000 Project Management Institute. 1-880410-23-0. Project Management Institute. Newtown Square Pennsylvania USA . PMBOK Guide. A Guide to the Project Management Body of Knowledge, 2000 Edition. [[freebsd-bylaws]] [FreeBSD, 2000A] Copyright © 2002 The FreeBSD Project. Core Bylaws. https://www.freebsd.org/internal/bylaws/. [[freebsd-developer-handbook]] [FreeBSD, 2002A] Copyright © 2002 The FreeBSD Documentation Project. FreeBSD Developer's Handbook. extref:{developers-handbook}[Developers Handbook]. [[bsd-election2002]] [FreeBSD, 2002B] Copyright © 2002 The FreeBSD Project. Core team election 2002. http://election.uk.freebsd.org/candidates.html. [[freebsd-handle-pr]] [FreeBSD, 2002C] Dag-Erling Smørgrav and Hiten Pandya. Copyright © 2002 The FreeBSD Documentation Project. The FreeBSD Documentation Project. Problem Report Handling Guidelines. extref:{pr-guidelines}[Problem Report Handling Guidelines]. [[freebsd-send-pr]] [FreeBSD, 2002D] Dag-Erling Smørgrav. Copyright © 2002 The FreeBSD Documentation Project. The FreeBSD Documentation Project. Writing FreeBSD Problem Reports. extref:{problem-reports}[Writing FreeBSD Problem Reports]. [[freebsd-committer]] [FreeBSD, 2001] Copyright © 2001 The FreeBSD Documentation Project. The FreeBSD Documentation Project. Committers Guide. extref:{committers-guide}[Committer's Guide]. [[freebsd-releng]] [FreeBSD, 2002E] Murray Stokely. Copyright © 2002 The FreeBSD Documentation Project. The FreeBSD Documentation Project. FreeBSD Release Engineering. extref:{releng}[FreeBSD Release Engineering]. [[ref-bsd-handbook]] [FreeBSD, 2003A] The FreeBSD Documentation Project. FreeBSD Handbook. extref:{handbook}[FreeBSD Handbook]. [[freebsd-contributors]] [FreeBSD, 2002F] Copyright © 2002 The FreeBSD Documentation Project. The FreeBSD Documentation Project. Contributors to FreeBSD. extref:{contributors}[Contributors to FreeBSD]. [[freebsd-election]] [FreeBSD, 2002G] Copyright © 2002 The FreeBSD Project. The FreeBSD Project. Core team elections 2002. http://election.uk.freebsd.org. [[freebsd-expiration-policy]] [FreeBSD, 2002H] Copyright © 2002 The FreeBSD Project. The FreeBSD Project. Commit Bit Expiration Policy. 2002/04/06 15:35:30. https://www.freebsd.org/internal/expire-bits/. [[freebsd-new-account]] [FreeBSD, 2002I] Copyright © 2002 The FreeBSD Project. The FreeBSD Project. New Account Creation Procedure. 2002/08/19 17:11:27. https://www.freebsd.org/internal/new-account/. [[freebsd-doceng-charter]] [FreeBSD, 2003B] Copyright © 2002 The FreeBSD Documentation Project. The FreeBSD Documentation Project. FreeBSD DocEng Team Charter. 2003/03/16 12:17. https://www.freebsd.org/internal/doceng/. [[ref-freebsd-trenches]] [Lehey, 2002] Greg Lehey. Copyright © 2002 Greg Lehey. Greg Lehey. Two years in the trenches. The evolution of a software project. http://www.lemis.com/grog/In-the-trenches.pdf. diff --git a/documentation/content/en/books/developers-handbook/tools/_index.adoc b/documentation/content/en/books/developers-handbook/tools/_index.adoc index 15cf026c77..bb31426367 100644 --- a/documentation/content/en/books/developers-handbook/tools/_index.adoc +++ b/documentation/content/en/books/developers-handbook/tools/_index.adoc @@ -1,1637 +1,1637 @@ --- title: Chapter 2. Programming Tools authors: - author: James Raynard - author: Murray Stokely prev: books/developers-handbook/introduction next: books/developers-handbook/secure description: Programming Tools tags: ["tools", "Interpreters", "Compilers", "cc", "make", "Debugging", "lldb", "gdb", "clang", "Emacs"] showBookMenu: true weight: 3 path: "/books/developers-handbook/tools/" --- [[tools]] = Programming Tools :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 2 :partnums: :source-highlighter: rouge :experimental: :c-plus-plus-command: c++ :clang-plus-plus-command: clang++ :images-path: books/developers-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[tools-synopsis]] == Synopsis This chapter is an introduction to using some of the programming tools supplied with FreeBSD, although much of it will be applicable to many other versions of UNIX(R). It does _not_ attempt to describe coding in any detail. Most of the chapter assumes little or no previous programming knowledge, although it is hoped that most programmers will find something of value in it. [[tools-intro]] == Introduction FreeBSD offers an excellent development environment. Compilers for C and C++ and an assembler come with the basic system, not to mention classic UNIX(R) tools such as `sed` and `awk`. If that is not enough, there are many more compilers and interpreters in the Ports collection. The following section, crossref:tools[tools-programming,Introduction to Programming], lists some of the available options. FreeBSD is very compatible with standards such as POSIX(R) and ANSI C, as well with its own BSD heritage, so it is possible to write applications that will compile and run with little or no modification on a wide range of platforms. However, all this power can be rather overwhelming at first if you have never written programs on a UNIX(R) platform before. This document aims to help you get up and running, without getting too deeply into more advanced topics. The intention is that this document should give you enough of the basics to be able to make some sense of the documentation. Most of the document requires little or no knowledge of programming, although it does assume a basic competence with using UNIX(R) and a willingness to learn! [[tools-programming]] == Introduction to Programming A program is a set of instructions that tell the computer to do various things; sometimes the instruction it has to perform depends on what happened when it performed a previous instruction. This section gives an overview of the two main ways in which you can give these instructions, or "commands" as they are usually called. One way uses an _interpreter_, the other a _compiler_. As human languages are too difficult for a computer to understand in an unambiguous way, commands are usually written in one or other languages specially designed for the purpose. === Interpreters With an interpreter, the language comes as an environment, where you type in commands at a prompt and the environment executes them for you. For more complicated programs, you can type the commands into a file and get the interpreter to load the file and execute the commands in it. If anything goes wrong, many interpreters will drop you into a debugger to help you track down the problem. The advantage of this is that you can see the results of your commands immediately, and mistakes can be corrected readily. The biggest disadvantage comes when you want to share your programs with someone. They must have the same interpreter, or you must have some way of giving it to them, and they need to understand how to use it. Also users may not appreciate being thrown into a debugger if they press the wrong key! From a performance point of view, interpreters can use up a lot of memory, and generally do not generate code as efficiently as compilers. In my opinion, interpreted languages are the best way to start if you have not done any programming before. This kind of environment is typically found with languages like Lisp, Smalltalk, Perl and Basic. It could also be argued that the UNIX(R) shell (`sh`, `csh`) is itself an interpreter, and many people do in fact write shell "scripts" to help with various "housekeeping" tasks on their machine. Indeed, part of the original UNIX(R) philosophy was to provide lots of small utility programs that could be linked together in shell scripts to perform useful tasks. === Interpreters Available with FreeBSD Here is a list of interpreters that are available from the FreeBSD Ports Collection, with a brief discussion of some of the more popular interpreted languages. Instructions on how to get and install applications from the Ports Collection can be found in the extref:{handbook}[Ports section, ports-using] of the handbook. BASIC:: Short for Beginner's All-purpose Symbolic Instruction Code. Developed in the 1950s for teaching University students to program and provided with every self-respecting personal computer in the 1980s, BASIC has been the first programming language for many programmers. It is also the foundation for Visual Basic. + The Bywater Basic Interpreter can be found in the Ports Collection as package:lang/bwbasic[] and the Phil Cockroft's Basic Interpreter (formerly Rabbit Basic) is available as package:lang/pbasic[]. Lisp:: A language that was developed in the late 1950s as an alternative to the "number-crunching" languages that were popular at the time. Instead of being based on numbers, Lisp is based on lists; in fact, the name is short for "List Processing". It is very popular in AI (Artificial Intelligence) circles. + Lisp is an extremely powerful and sophisticated language, but can be rather large and unwieldy. + Various implementations of Lisp that can run on UNIX(R) systems are available in the Ports Collection for FreeBSD. CLISP by Bruno Haible and Michael Stoll is available as package:lang/clisp[]. SLisp, a simpler Lisp implementations, is available as package:lang/slisp[]. Perl:: Very popular with system administrators for writing scripts; also often used on World Wide Web servers for writing CGI scripts. + Perl is available in the Ports Collection as package:lang/perl5.36[] for all FreeBSD releases. Scheme:: A dialect of Lisp that is rather more compact and cleaner than Common Lisp. Popular in Universities as it is simple enough to teach to undergraduates as a first language, while it has a high enough level of abstraction to be used in research work. + Scheme is available from the Ports Collection as package:lang/elk[] for the Elk Scheme Interpreter. The MIT Scheme Interpreter can be found in package:lang/mit-scheme[] and the SCM Scheme Interpreter in package:lang/scm[]. Lua:: Lua is a lightweight embeddable scripting language. It is widely portable and relatively simple. Lua is available in the Ports Collection in package:lang/lua54[]. It is also included in the base system as [.filename]#/usr/libexec/flua# for use by base system components. Third party software should not depend on [.filename]#flua#. Python:: Python is an Object-Oriented, interpreted language. Its advocates argue that it is one of the best languages to start programming with, since it is relatively easy to start with, but is not limited in comparison to other popular interpreted languages that are used for the development of large, complex applications (Perl and Tcl are two other languages that are popular for such tasks). + The latest version of Python is available from the Ports Collection in package:lang/python[]. Ruby:: Ruby is an interpreter, pure object-oriented programming language. It has become widely popular because of its easy to understand syntax, flexibility when writing code, and the ability to easily develop and maintain large, complex programs. + Ruby is available from the Ports Collection as package:lang/ruby32[]. Tcl and Tk:: Tcl is an embeddable, interpreted language, that has become widely used and became popular mostly because of its portability to many platforms. It can be used both for quickly writing small, prototype applications, or (when combined with Tk, a GUI toolkit) fully-fledged, featureful programs. + Various versions of Tcl are available as ports for FreeBSD. The latest version, Tcl 8.7, can be found in package:lang/tcl87[]. === Compilers Compilers are rather different. First of all, you write your code in a file (or files) using an editor. You then run the compiler and see if it accepts your program. If it did not compile, grit your teeth and go back to the editor; if it did compile and gave you a program, you can run it either at a shell command prompt or in a debugger to see if it works properly.footnote:[If you run it in the shell, you may get a core dump.] Obviously, this is not quite as direct as using an interpreter. However it allows you to do a lot of things which are very difficult or even impossible with an interpreter, such as writing code which interacts closely with the operating system-or even writing your own operating system! It is also useful if you need to write very efficient code, as the compiler can take its time and optimize the code, which would not be acceptable in an interpreter. Moreover, distributing a program written for a compiler is usually more straightforward than one written for an interpreter-you can just give them a copy of the executable, assuming they have the same operating system as you. As the edit-compile-run-debug cycle is rather tedious when using separate programs, many commercial compiler makers have produced Integrated Development Environments (IDEs for short). FreeBSD does not include an IDE in the base system, but package:devel/kdevelop[] is available in the Ports Collection and many use Emacs for this purpose. -Using Emacs as an IDE is discussed in crossref:tools[emacs]. +Using Emacs as an IDE is discussed in crossref:tools[emacs, Using Emacs as a Development Environment]. [[tools-compiling]] == Compiling with `cc` This section deals with the clang compiler for C and C++, as it's installed with the FreeBSD base system. Clang is installed as `cc`; the GNU compiler package:lang/gcc[gcc] is available in the Ports Collection. The details of producing a program with an interpreter vary considerably between interpreters, and are usually well covered in the documentation and on-line help for the interpreter. Once you have written your masterpiece, the next step is to convert it into something that will (hopefully!) run on FreeBSD. This usually involves several steps, each of which is done by a separate program. [.procedure] . Pre-process your source code to remove comments and do other tricks like expanding macros in C. . Check the syntax of your code to see if you have obeyed the rules of the language. If you have not, it will complain! . Convert the source code into assembly language-this is very close to machine code, but still understandable by humans. Allegedly. . Convert the assembly language into machine code-yep, we are talking bits and bytes, ones and zeros here. . Check that you have used things like functions and global variables in a consistent way. For example, if you have called a non-existent function, it will complain. . If you are trying to produce an executable from several source code files, work out how to fit them all together. . Work out how to produce something that the system's run-time loader will be able to load into memory and run. . Finally, write the executable on the filesystem. The word _compiling_ is often used to refer to just steps 1 to 4-the others are referred to as _linking_. Sometimes step 1 is referred to as _pre-processing_ and steps 3-4 as _assembling_. Fortunately, almost all this detail is hidden from you, as `cc` is a front end that manages calling all these programs with the right arguments for you; simply typing [source,bash] .... % cc foobar.c .... will cause [.filename]#foobar.c# to be compiled by all the steps above. If you have more than one file to compile, just do something like [source,bash] .... % cc foo.c bar.c .... Note that the syntax checking is just that - checking the syntax. It will not check for any logical mistakes you may have made, like putting the program into an infinite loop, or using a bubble sort when you meant to use a binary sort.footnote:[In case you did not know, a binary sort is an efficient way of sorting things into order and a bubble sort is not.] There are lots and lots of options for `cc`, which are all in the manual page. Here are a few of the most important ones, with examples of how to use them. `-o _filename_`:: The output name of the file. If you do not use this option, `cc` will produce an executable called [.filename]#a.out#.footnote:[The reasons for this are buried in the mists of history.] + [source,bash] .... % cc foobar.c executable is a.out % cc -o foobar foobar.c executable is foobar .... `-c`:: Just compile the file, do not link it. Useful for toy programs where you just want to check the syntax, or if you are using a [.filename]#Makefile#. + [source,bash] .... % cc -c foobar.c .... + This will produce an _object file_ (not an executable) called [.filename]#foobar.o#. This can be linked together with other object files into an executable. `-g`:: Create a debug version of the executable. This makes the compiler put information into the executable about which line of which source file corresponds to which function call. A debugger can use this information to show the source code as you step through the program, which is _very_ useful; the disadvantage is that all this extra information makes the program much bigger. Normally, you compile with `-g` while you are developing a program and then compile a "release version" without `-g` when you are satisfied it works properly. + [source,bash] .... % cc -g foobar.c .... + This will produce a debug version of the program. footnote:[Note, we did not use the -o flag to specify the executable name, so we will get an executable called a.out. Producing a debug version called foobar is left as an exercise for the reader!] `-O`:: Create an optimized version of the executable. The compiler performs various clever tricks to try to produce an executable that runs faster than normal. You can add a number after the `-O` to specify a higher level of optimization, but this often exposes bugs in the compiler's optimizer. + [source,bash] .... % cc -O -o foobar foobar.c .... + This will produce an optimized version of [.filename]#foobar#. The following three flags will force `cc` to check that your code complies to the relevant international standard, often referred to as the ANSI standard, though strictly speaking it is an ISO standard. `-Wall`:: Enable all the warnings which the authors of `cc` believe are worthwhile. Despite the name, it will not enable all the warnings `cc` is capable of. `-ansi`:: Turn off most, but not all, of the non-ANSI C features provided by `cc`. Despite the name, it does not guarantee strictly that your code will comply to the standard. `-pedantic`:: Turn off _all_ ``cc``'s non-ANSI C features. Without these flags, `cc` will allow you to use some of its non-standard extensions to the standard. Some of these are very useful, but will not work with other compilers - in fact, one of the main aims of the standard is to allow people to write code that will work with any compiler on any system. This is known as _portable code_. Generally, you should try to make your code as portable as possible, as otherwise you may have to completely rewrite the program later to get it to work somewhere else - and who knows what you may be using in a few years time? [source,bash] .... % cc -Wall -ansi -pedantic -o foobar foobar.c .... This will produce an executable [.filename]#foobar# after checking [.filename]#foobar.c# for standard compliance. `-l__library__`:: Specify a function library to be used at link time. + The most common example of this is when compiling a program that uses some of the mathematical functions in C. Unlike most other platforms, these are in a separate library from the standard C one and you have to tell the compiler to add it. + The rule is that if the library is called [.filename]#libsomething.a#, you give `cc` the argument `-l__something__`. For example, the math library is [.filename]#libm.a#, so you give `cc` the argument `-lm`. A common "gotcha" with the math library is that it has to be the last library on the command line. + [source,bash] .... % cc -o foobar foobar.c -lm .... + This will link the math library functions into [.filename]#foobar#. + If you are compiling C++ code, use {c-plus-plus-command}. {c-plus-plus-command} can also be invoked as {clang-plus-plus-command} on FreeBSD. + [source,bash] .... % c++ -o foobar foobar.cc .... + This will both produce an executable [.filename]#foobar# from the C++ source file [.filename]#foobar.cc#. === Common `cc` Queries and Problems ==== I compiled a file called foobar.c and I cannot find an executable called foobar. Where has it gone? Remember, `cc` will call the executable [.filename]#a.out# unless you tell it differently. Use the `-o _filename_` option: [source,bash] .... % cc -o foobar foobar.c .... ==== OK, I have an executable called foobar, I can see it when I run ls, but when I type in foobar at the command prompt it tells me there is no such file. Why can it not find it? Unlike MS-DOS(R), UNIX(R) does not look in the current directory when it is trying to find out which executable you want it to run, unless you tell it to. Type `./foobar`, which means "run the file called [.filename]#foobar# in the current directory." === I called my executable test, but nothing happens when I run it. What is going on? Most UNIX(R) systems have a program called `test` in [.filename]#/usr/bin# and the shell is picking that one up before it gets to checking the current directory. Either type: [source,bash] .... % ./test .... or choose a better name for your program! ==== I compiled my program and it seemed to run all right at first, then there was an error and it said something about core dumped. What does that mean? The name _core dump_ dates back to the very early days of UNIX(R), when the machines used core memory for storing data. Basically, if the program failed under certain conditions, the system would write the contents of core memory to disk in a file called [.filename]#core#, which the programmer could then pore over to find out what went wrong. ==== Fascinating stuff, but what I am supposed to do now? -Use a debugger to analyze the core (see crossref:tools[debugging]). +Use a debugger to analyze the core (see crossref:tools[debugging, Debugging]). ==== When my program dumped core, it said something about a segmentation fault. What is that? This basically means that your program tried to perform some sort of illegal operation on memory; UNIX(R) is designed to protect the operating system and other programs from rogue programs. Common causes for this are: * Trying to write to a NULL pointer, eg + [.programlisting] .... char *foo = NULL; strcpy(foo, "bang!"); .... * Using a pointer that has not been initialized, eg + [.programlisting] .... char *foo; strcpy(foo, "bang!"); .... + The pointer will have some random value that, with luck, will point into an area of memory that is not available to your program and the kernel will kill your program before it can do any damage. If you are unlucky, it will point somewhere inside your own program and corrupt one of your data structures, causing the program to fail mysteriously. * Trying to access past the end of an array, eg + [.programlisting] .... int bar[20]; bar[27] = 6; .... * Trying to store something in read-only memory, eg + [.programlisting] .... char *foo = "My string"; strcpy(foo, "bang!"); .... + UNIX(R) compilers often put string literals like `"My string"` into read-only areas of memory. * Doing naughty things with `malloc()` and `free()`, eg + [.programlisting] .... char bar[80]; free(bar); .... + or + [.programlisting] .... char *foo = malloc(27); free(foo); free(foo); .... Making one of these mistakes will not always lead to an error, but they are always bad practice. Some systems and compilers are more tolerant than others, which is why programs that run well on one system can crash when you try them on another. ==== Sometimes when I get a core dump it says bus error. It says in my UNIX(R) book that this means a hardware problem, but the computer still seems to be working. Is this true? No, fortunately not (unless of course you really do have a hardware problem...). This is usually another way of saying that you accessed memory in a way you should not have. ==== This dumping core business sounds as though it could be quite useful, if I can make it happen when I want to. Can I do this, or do I have to wait until there is an error? Yes, just go to another console or xterm, do [source,bash] .... % ps .... to find out the process ID of your program, and do [source,bash] .... % kill -ABRT pid .... where `_pid_` is the process ID you looked up. This is useful if your program has got stuck in an infinite loop, for instance. If your program happens to trap SIGABRT, there are several other signals which have a similar effect. Alternatively, you can create a core dump from inside your program, by calling the `abort()` function. See the manual page of man:abort[3] to learn more. If you want to create a core dump from outside your program, but do not want the process to terminate, you can use the `gcore` program. See the manual page of man:gcore[1] for more information. [[tools-make]] == Make === What is `make`? When you are working on a simple program with only one or two source files, typing in [source,bash] .... % cc file1.c file2.c .... is not too bad, but it quickly becomes very tedious when there are several files-and it can take a while to compile, too. One way to get around this is to use object files and only recompile the source file if the source code has changed. So we could have something like: [source,bash] .... % cc file1.o file2.o … file37.c … .... if we had changed [.filename]#file37.c#, but not any of the others, since the last time we compiled. This may speed up the compilation quite a bit, but does not solve the typing problem. Or we could write a shell script to solve the typing problem, but it would have to re-compile everything, making it very inefficient on a large project. What happens if we have hundreds of source files lying about? What if we are working in a team with other people who forget to tell us when they have changed one of their source files that we use? Perhaps we could put the two solutions together and write something like a shell script that would contain some kind of magic rule saying when a source file needs compiling. Now all we need now is a program that can understand these rules, as it is a bit too complicated for the shell. This program is called `make`. It reads in a file, called a _makefile_, that tells it how different files depend on each other, and works out which files need to be re-compiled and which ones do not. For example, a rule could say something like "if [.filename]#fromboz.o# is older than [.filename]#fromboz.c#, that means someone must have changed [.filename]#fromboz.c#, so it needs to be re-compiled." The makefile also has rules telling make _how_ to re-compile the source file, making it a much more powerful tool. Makefiles are typically kept in the same directory as the source they apply to, and can be called [.filename]#makefile#, [.filename]#Makefile# or [.filename]#MAKEFILE#. Most programmers use the name [.filename]#Makefile#, as this puts it near the top of a directory listing, where it can easily be seen.footnote:[They do not use the MAKEFILE form as block capitals are often used for documentation files like README.] === Example of Using `make` Here is a very simple make file: [.programlisting] .... foo: foo.c cc -o foo foo.c .... It consists of two lines, a dependency line and a creation line. The dependency line here consists of the name of the program (known as the _target_), followed by a colon, then whitespace, then the name of the source file. When `make` reads this line, it looks to see if [.filename]#foo# exists; if it exists, it compares the time [.filename]#foo# was last modified to the time [.filename]#foo.c# was last modified. If [.filename]#foo# does not exist, or is older than [.filename]#foo.c#, it then looks at the creation line to find out what to do. In other words, this is the rule for working out when [.filename]#foo.c# needs to be re-compiled. The creation line starts with a tab (press kbd:[tab]) and then the command you would type to create [.filename]#foo# if you were doing it at a command prompt. If [.filename]#foo# is out of date, or does not exist, `make` then executes this command to create it. In other words, this is the rule which tells make how to re-compile [.filename]#foo.c#. So, when you type `make`, it will make sure that [.filename]#foo# is up to date with respect to your latest changes to [.filename]#foo.c#. This principle can be extended to [.filename]#Makefile#'s with hundreds of targets-in fact, on FreeBSD, it is possible to compile the entire operating system just by typing `make world` in the appropriate directory! Another useful property of makefiles is that the targets do not have to be programs. For instance, we could have a make file that looks like this: [.programlisting] .... foo: foo.c cc -o foo foo.c install: cp foo /home/me .... We can tell make which target we want to make by typing: [source,bash] .... % make target .... `make` will then only look at that target and ignore any others. For example, if we type `make foo` with the makefile above, make will ignore the `install` target. If we just type `make` on its own, make will always look at the first target and then stop without looking at any others. So if we typed `make` here, it will just go to the `foo` target, re-compile [.filename]#foo# if necessary, and then stop without going on to the `install` target. Notice that the `install` target does not actually depend on anything! This means that the command on the following line is always executed when we try to make that target by typing `make install`. In this case, it will copy [.filename]#foo# into the user's home directory. This is often used by application makefiles, so that the application can be installed in the correct directory when it has been correctly compiled. This is a slightly confusing subject to try to explain. If you do not quite understand how `make` works, the best thing to do is to write a simple program like "hello world" and a make file like the one above and experiment. Then progress to using more than one source file, or having the source file include a header file. `touch` is very useful here-it changes the date on a file without you having to edit it. === Make and include-files C code often starts with a list of files to include, for example stdio.h. Some of these files are system-include files, some of them are from the project you are now working on: [.programlisting] .... #include #include "foo.h" int main(.... .... To make sure that this file is recompiled the moment [.filename]#foo.h# is changed, you have to add it in your [.filename]#Makefile#: [.programlisting] .... foo: foo.c foo.h .... The moment your project is getting bigger and you have more and more own include-files to maintain, it will be a pain to keep track of all include files and the files which are depending on it. If you change an include-file but forget to recompile all the files which are depending on it, the results will be devastating. `clang` has an option to analyze your files and to produce a list of include-files and their dependencies: `-MM`. If you add this to your Makefile: [.programlisting] .... depend: cc -E -MM *.c > .depend .... and run `make depend`, the file [.filename]#.depend# will appear with a list of object-files, C-files and the include-files: [.programlisting] .... foo.o: foo.c foo.h .... If you change [.filename]#foo.h#, next time you run `make` all files depending on [.filename]#foo.h# will be recompiled. Do not forget to run `make depend` each time you add an include-file to one of your files. === FreeBSD Makefiles Makefiles can be rather complicated to write. Fortunately, BSD-based systems like FreeBSD come with some very powerful ones as part of the system. One very good example of this is the FreeBSD ports system. Here is the essential part of a typical ports [.filename]#Makefile#: [.programlisting] .... MASTER_SITES= ftp://freefall.cdrom.com/pub/FreeBSD/LOCAL_PORTS/ DISTFILES= scheme-microcode+dist-7.3-freebsd.tgz .include .... Now, if we go to the directory for this port and type `make`, the following happens: [.procedure] . A check is made to see if the source code for this port is already on the system. . If it is not, an FTP connection to the URL in MASTER_SITES is set up to download the source. . The checksum for the source is calculated and compared it with one for a known, good, copy of the source. This is to make sure that the source was not corrupted while in transit. . Any changes required to make the source work on FreeBSD are applied-this is known as _patching_. . Any special configuration needed for the source is done. (Many UNIX(R) program distributions try to work out which version of UNIX(R) they are being compiled on and which optional UNIX(R) features are present-this is where they are given the information in the FreeBSD ports scenario). . The source code for the program is compiled. In effect, we change to the directory where the source was unpacked and do `make`-the program's own make file has the necessary information to build the program. . We now have a compiled version of the program. If we wish, we can test it now; when we feel confident about the program, we can type `make install`. This will cause the program and any supporting files it needs to be copied into the correct location; an entry is also made into a `package database`, so that the port can easily be uninstalled later if we change our mind about it. Now I think you will agree that is rather impressive for a four line script! The secret lies in the last line, which tells `make` to look in the system makefile called [.filename]#bsd.port.mk#. It is easy to overlook this line, but this is where all the clever stuff comes from-someone has written a makefile that tells `make` to do all the things above (plus a couple of other things I did not mention, including handling any errors that may occur) and anyone can get access to that just by putting a single line in their own make file! If you want to have a look at these system makefiles, they are in [.filename]#/usr/share/mk#, but it is probably best to wait until you have had a bit of practice with makefiles, as they are very complicated (and if you do look at them, make sure you have a flask of strong coffee handy!) === More Advanced Uses of `make` `Make` is a very powerful tool, and can do much more than the simple example above shows. Unfortunately, there are several different versions of `make`, and they all differ considerably. The best way to learn what they can do is probably to read the documentation-hopefully this introduction will have given you a base from which you can do this. The man:make[1] manual page offers a comprehensive discussion of variables, arguments, and how to use make. Many applications in the ports use GNU make, which has a very good set of "info" pages. If you have installed any of these ports, GNU make will automatically have been installed as `gmake`. It is also available as a port and package in its own right. To view the info pages for GNU make, you will have to edit [.filename]#dir# in the [.filename]#/usr/local/info# directory to add an entry for it. This involves adding a line like [.programlisting] .... * Make: (make). The GNU Make utility. .... to the file. Once you have done this, you can type `info` and then select [.guimenuitem]#make# from the menu (or in Emacs, do `C-h i`). [[debugging]] == Debugging === Introduction to Available Debuggers Using a debugger allows running the program under more controlled circumstances. Typically, it is possible to step through the program a line at a time, inspect the value of variables, change them, tell the debugger to run up to a certain point and then stop, and so on. It is also possible to attach to a program that is already running, or load a core file to investigate why the program crashed. This section is intended to be a quick introduction to using debuggers and does not cover specialized topics such as debugging the kernel. For more information about that, refer to crossref:kerneldebug[kerneldebug,Kernel Debugging]. The standard debugger supplied with FreeBSD is called `lldb` (LLVM debugger). As it is part of the standard installation for that release, there is no need to do anything special to use it. It has good command help, accessible via the `help` command, as well as https://lldb.llvm.org/[a web tutorial and documentation]. [NOTE] ==== The `lldb` command is also available extref:{handbook}ports/[from ports or packages, ports-using] as package:devel/llvm[]. ==== The other debugger available with FreeBSD is called `gdb` (GNU debugger). Unlike lldb, it is not installed by default on FreeBSD; to use it, extref:{handbook}#ports-using/[install] package:devel/gdb[] from ports or packages. It has excellent on-line help, as well as a set of info pages. The two debuggers have a similar feature set, so which one to use is largely a matter of taste. If familiar with one only, use that one. People familiar with neither or both but wanting to use one from inside Emacs will need to use `gdb` as `lldb` is unsupported by Emacs. Otherwise, try both and see which one you prefer. === Using lldb ==== Starting lldb Start up lldb by typing [source,bash] .... % lldb -- progname .... ==== Running a Program with lldb Compile the program with `-g` to get the most out of using `lldb`. It will work without, but will only display the name of the function currently running, instead of the source code. If it displays a line like: [source,bash] .... Breakpoint 1: where = temp`main, address = … .... (without an indication of source code filename and line number) when setting a breakpoint, this means that the program was not compiled with `-g`. [TIP] ==== Most `lldb` commands have shorter forms that can be used instead. The longer forms are used here for clarity. ==== At the `lldb` prompt, type `breakpoint set -n main`. This will tell the debugger not to display the preliminary set-up code in the program being run and to stop execution at the beginning of the program's code. Now type `process launch` to actually start the program- it will start at the beginning of the set-up code and then get stopped by the debugger when it calls `main()`. To step through the program a line at a time, type `thread step-over`. When the program gets to a function call, step into it by typing `thread step-in`. Once in a function call, return from it by typing `thread step-out` or use `up` and `down` to take a quick look at the caller. Here is a simple example of how to spot a mistake in a program with `lldb`. This is our program (with a deliberate mistake): [.programlisting] .... #include int bazz(int anint); main() { int i; printf("This is my program\n"); bazz(i); return 0; } int bazz(int anint) { printf("You gave me %d\n", anint); return anint; } .... This program sets i to be `5` and passes it to a function `bazz()` which prints out the number we gave it. Compiling and running the program displays [source,bash] .... % cc -g -o temp temp.c % ./temp This is my program anint = -5360 .... That is not what was expected! Time to see what is going on! [source,bash] .... % lldb -- temp (lldb) target create "temp" Current executable set to 'temp' (x86_64). (lldb) breakpoint set -n main Skip the set-up code Breakpoint 1: where = temp`main + 15 at temp.c:8:2, address = 0x00000000002012ef lldb puts breakpoint at main() (lldb) process launch Run as far as main() Process 9992 launching Process 9992 launched: '/home/pauamma/tmp/temp' (x86_64) Program starts running Process 9992 stopped * thread #1, name = 'temp', stop reason = breakpoint 1.1 lldb stops at main() frame #0: 0x00000000002012ef temp`main at temp.c:8:2 5 main() { 6 int i; 7 -> 8 printf("This is my program\n"); Indicates the line where it stopped 9 bazz(i); 10 return 0; 11 } (lldb) thread step-over Go to next line This is my program Program prints out Process 9992 stopped * thread #1, name = 'temp', stop reason = step over frame #0: 0x0000000000201300 temp`main at temp.c:9:7 6 int i; 7 8 printf("This is my program\n"); -> 9 bazz(i); 10 return 0; 11 } 12 (lldb) thread step-in step into bazz() Process 9992 stopped * thread #1, name = 'temp', stop reason = step in frame #0: 0x000000000020132b temp`bazz(anint=-5360) at temp.c:14:29 lldb displays stack frame 11 } 12 13 int bazz(int anint) { -> 14 printf("You gave me %d\n", anint); 15 return anint; 16 } (lldb) .... Hang on a minute! How did anint get to be `-5360`? Was it not set to `5` in `main()`? Let us move up to `main()` and have a look. [source,bash] .... (lldb) up Move up call stack frame #1: 0x000000000020130b temp`main at temp.c:9:2 lldb displays stack frame 6 int i; 7 8 printf("This is my program\n"); -> 9 bazz(i); 10 return 0; 11 } 12 (lldb) frame variable i Show us the value of i (int) i = -5360 lldb displays -5360 .... Oh dear! Looking at the code, we forgot to initialize i. We meant to put [.programlisting] .... ... main() { int i; i = 5; printf("This is my program\n"); ... .... but we left the `i=5;` line out. As we did not initialize i, it had whatever number happened to be in that area of memory when the program ran, which in this case happened to be `-5360`. [NOTE] ==== The `lldb` command displays the stack frame every time we go into or out of a function, even if we are using `up` and `down` to move around the call stack. This shows the name of the function and the values of its arguments, which helps us keep track of where we are and what is going on. (The stack is a storage area where the program stores information about the arguments passed to functions and where to go when it returns from a function call.) ==== ==== Examining a Core File with lldb A core file is basically a file which contains the complete state of the process when it crashed. In "the good old days", programmers had to print out hex listings of core files and sweat over machine code manuals, but now life is a bit easier. Incidentally, under FreeBSD and other 4.4BSD systems, a core file is called [.filename]#progname.core# instead of just [.filename]#core#, to make it clearer which program a core file belongs to. To examine a core file, specify the name of the core file in addition to the program itself. Instead of starting up `lldb` in the usual way, type `lldb -c _progname_.core \-- _progname_`. The debugger will display something like this: [source,bash,subs="verbatim,quotes"] .... % lldb -c [.filename]#progname.core# -- [.filename]#progname# (lldb) target create "[.filename]#progname#" --core "[.filename]#progname#.core" Core file '/home/pauamma/tmp/[.filename]#progname.core#' (x86_64) was loaded. (lldb) .... In this case, the program was called [.filename]#progname#, so the core file is called [.filename]#progname.core#. The debugger does not display why the program crashed or where. For this, use `thread backtrace all`. This will also show how the function where the program dumped core was called. [source,bash,subs="verbatim,quotes"] .... (lldb) thread backtrace all * thread #1, name = 'progname', stop reason = signal SIGSEGV * frame #0: 0x0000000000201347 progname`bazz(anint=5) at temp2.c:17:10 frame #1: 0x0000000000201312 progname`main at temp2.c:10:2 frame #2: 0x000000000020110f progname`_start(ap=, cleanup=) at crt1.c:76:7 (lldb) .... `SIGSEGV` indicates that the program tried to access memory (run code or read/write data usually) at a location that does not belong to it, but does not give any specifics. For that, look at the source code at line 10 of file temp2.c, in `bazz()`. The backtrace also says that in this case, `bazz()` was called from `main()`. ==== Attaching to a Running Program with lldb One of the neatest features about `lldb` is that it can attach to a program that is already running. Of course, that requires sufficient permissions to do so. A common problem is stepping through a program that forks and wanting to trace the child, but the debugger will only trace the parent. To do that, start up another `lldb`, use `ps` to find the process ID for the child, and do [source,bash] .... (lldb) process attach -p pid .... in `lldb`, and then debug as usual. For that to work well, the code that calls `fork` to create the child needs to do something like the following (courtesy of the `gdb` info pages): [.programlisting] .... ... if ((pid = fork()) < 0) /* _Always_ check this */ error(); else if (pid == 0) { /* child */ int PauseMode = 1; while (PauseMode) sleep(10); /* Wait until someone attaches to us */ ... } else { /* parent */ ... .... Now all that is needed is to attach to the child, set PauseMode to `0` with `expr PauseMode = 0` and wait for the `sleep()` call to return. === Remote Debugging Using LLDB [NOTE] ==== The described functionality is available starting with LLDB version 12.0.0. Users of FreeBSD releases containing an earlier LLDB version may wish to use the snapshot available in extref:{handbook}[ports or packages, ports-using], as package:devel/llvm-devel[]. ==== Starting with LLDB 12.0.0, remote debugging is supported on FreeBSD. This means that `lldb-server` can be started to debug a program on one host, while the interactive `lldb` client connects to it from another one. To launch a new process to be debugged remotely, run `lldb-server` on the remote server by typing [source,bash] .... % lldb-server g host:port -- progname .... The process will be stopped immediately after launching, and `lldb-server` will wait for the client to connect. Start `lldb` locally and type the following command to connect to the remote server: [source,bash] .... (lldb) gdb-remote host:port .... `lldb-server` can also attach to a running process. To do that, type the following on the remote server: [source,bash] .... % lldb-server g host:port --attach pid-or-name .... === Using gdb ==== Starting gdb Start up gdb by typing [source,bash] .... % gdb progname .... although many people prefer to run it inside Emacs. To do this, type: [source,bash] .... M-x gdb RET progname RET .... Finally, for those finding its text-based command-prompt style off-putting, there is a graphical front-end for it (package:devel/xxgdb[]) in the Ports Collection. ==== Running a Program with gdb Compile the program with `-g` to get the most out of using `gdb`. It will work without, but will only display the name of the function currently running, instead of the source code. A line like: [source,bash] .... ... (no debugging symbols found) ... .... when `gdb` starts up means that the program was not compiled with `-g`. At the `gdb` prompt, type `break main`. This will tell the debugger to skip the preliminary set-up code in the program being run and to stop execution at the beginning of the program's code. Now type `run` to start the program- it will start at the beginning of the set-up code and then get stopped by the debugger when it calls `main()`. To step through the program a line at a time, press `n`. When at a function call, step into it by pressing `s`. Once in a function call, return from it by pressing `f`, or use `up` and `down` to take a quick look at the caller. Here is a simple example of how to spot a mistake in a program with `gdb`. This is our program (with a deliberate mistake): [.programlisting] .... #include int bazz(int anint); main() { int i; printf("This is my program\n"); bazz(i); return 0; } int bazz(int anint) { printf("You gave me %d\n", anint); return anint; } .... This program sets i to be `5` and passes it to a function `bazz()` which prints out the number we gave it. Compiling and running the program displays [source,bash] .... % cc -g -o temp temp.c % ./temp This is my program anint = 4231 .... That was not what we expected! Time to see what is going on! [source,bash] .... % gdb temp GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.13 (i386-unknown-freebsd), Copyright 1994 Free Software Foundation, Inc. (gdb) break main Skip the set-up code Breakpoint 1 at 0x160f: file temp.c, line 9. gdb puts breakpoint at main() (gdb) run Run as far as main() Starting program: /home/james/tmp/temp Program starts running Breakpoint 1, main () at temp.c:9 gdb stops at main() (gdb) n Go to next line This is my program Program prints out (gdb) s step into bazz() bazz (anint=4231) at temp.c:17 gdb displays stack frame (gdb) .... Hang on a minute! How did anint get to be `4231`? Was it not set to `5` in `main()`? Let us move up to `main()` and have a look. [source,bash] .... (gdb) up Move up call stack #1 0x1625 in main () at temp.c:11 gdb displays stack frame (gdb) p i Show us the value of i $1 = 4231 gdb displays 4231 .... Oh dear! Looking at the code, we forgot to initialize i. We meant to put [.programlisting] .... ... main() { int i; i = 5; printf("This is my program\n"); ... .... but we left the `i=5;` line out. As we did not initialize i, it had whatever number happened to be in that area of memory when the program ran, which in this case happened to be `4231`. [NOTE] ==== The `gdb` command displays the stack frame every time we go into or out of a function, even if we are using `up` and `down` to move around the call stack. This shows the name of the function and the values of its arguments, which helps us keep track of where we are and what is going on. (The stack is a storage area where the program stores information about the arguments passed to functions and where to go when it returns from a function call.) ==== ==== Examining a Core File with gdb A core file is basically a file which contains the complete state of the process when it crashed. In "the good old days", programmers had to print out hex listings of core files and sweat over machine code manuals, but now life is a bit easier. Incidentally, under FreeBSD and other 4.4BSD systems, a core file is called [.filename]#progname.core# instead of just [.filename]#core#, to make it clearer which program a core file belongs to. To examine a core file, start up `gdb` in the usual way. Instead of typing `break` or `run`, type [source,bash] .... (gdb) core progname.core .... If the core file is not in the current directory, type `dir /path/to/core/file` first. The debugger should display something like this: [source,bash,subs="verbatim,quotes"] .... % gdb [.filename]#progname# GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.13 (i386-unknown-freebsd), Copyright 1994 Free Software Foundation, Inc. (gdb) core [.filename]#progname.core# Core was generated by `[.filename]#progname#'. Program terminated with signal 11, Segmentation fault. Cannot access memory at address 0x7020796d. #0 0x164a in bazz (anint=0x5) at temp.c:17 (gdb) .... In this case, the program was called [.filename]#progname#, so the core file is called [.filename]#progname.core#. We can see that the program crashed due to trying to access an area in memory that was not available to it in a function called `bazz`. Sometimes it is useful to be able to see how a function was called, as the problem could have occurred a long way up the call stack in a complex program. `bt` causes `gdb` to print out a back-trace of the call stack: [source,bash] .... (gdb) bt #0 0x164a in bazz (anint=0x5) at temp.c:17 #1 0xefbfd888 in end () #2 0x162c in main () at temp.c:11 (gdb) .... The `end()` function is called when a program crashes; in this case, the `bazz()` function was called from `main()`. ==== Attaching to a Running Program with gdb One of the neatest features about `gdb` is that it can attach to a program that is already running. Of course, that requires sufficient permissions to do so. A common problem is stepping through a program that forks and wanting to trace the child, but the debugger will only trace the parent. To do that, start up another `gdb`, use `ps` to find the process ID for the child, and do [source,bash] .... (gdb) attach pid .... in `gdb`, and then debug as usual. For that to work well, the code that calls `fork` to create the child needs to do something like the following (courtesy of the `gdb` info pages): [.programlisting] .... ... if ((pid = fork()) < 0) /* _Always_ check this */ error(); else if (pid == 0) { /* child */ int PauseMode = 1; while (PauseMode) sleep(10); /* Wait until someone attaches to us */ ... } else { /* parent */ ... .... Now all that is needed is to attach to the child, set PauseMode to `0`, and wait for the `sleep()` call to return! [[emacs]] == Using Emacs as a Development Environment === Emacs Emacs is a highly customizable editor-indeed, it has been customized to the point where it is more like an operating system than an editor! Many developers and sysadmins do in fact spend practically all their time working inside Emacs, leaving it only to log out. It is impossible even to summarize everything Emacs can do here, but here are some of the features of interest to developers: * Very powerful editor, allowing search-and-replace on both strings and regular expressions (patterns), jumping to start/end of block expression, etc, etc. * Pull-down menus and online help. * Language-dependent syntax highlighting and indentation. * Completely customizable. * You can compile and debug programs within Emacs. * On a compilation error, you can jump to the offending line of source code. * Friendly-ish front-end to the `info` program used for reading GNU hypertext documentation, including the documentation on Emacs itself. * Friendly front-end to `gdb`, allowing you to look at the source code as you step through your program. And doubtless many more that have been overlooked. Emacs can be installed on FreeBSD using the package:editors/emacs[] port. Once it is installed, start it up and do `C-h t` to read an Emacs tutorial-that means hold down kbd:[control], press kbd:[h], let go of kbd:[control], and then press kbd:[t]. (Alternatively, you can use the mouse to select [.guimenuitem]#Emacs Tutorial# from the menu:Help[] menu.) Although Emacs does have menus, it is well worth learning the key bindings, as it is much quicker when you are editing something to press a couple of keys than to try to find the mouse and then click on the right place. And, when you are talking to seasoned Emacs users, you will find they often casually throw around expressions like "`M-x replace-s RET foo RET bar RET`" so it is useful to know what they mean. And in any case, Emacs has far too many useful functions for them to all fit on the menu bars. Fortunately, it is quite easy to pick up the key-bindings, as they are displayed next to the menu item. My advice is to use the menu item for, say, opening a file until you understand how it works and feel confident with it, then try doing C-x C-f. When you are happy with that, move on to another menu command. If you cannot remember what a particular combination of keys does, select [.guimenuitem]#Describe Key# from the menu:Help[] menu and type it in-Emacs will tell you what it does. You can also use the [.guimenuitem]#Command Apropos# menu item to find out all the commands which contain a particular word in them, with the key binding next to it. By the way, the expression above means hold down the kbd:[Meta] key, press kbd:[x], release the kbd:[Meta] key, type `replace-s` (short for `replace-string`-another feature of Emacs is that you can abbreviate commands), press the kbd:[return] key, type `foo` (the string you want replaced), press the kbd:[return] key, type bar (the string you want to replace `foo` with) and press kbd:[return] again. Emacs will then do the search-and-replace operation you have just requested. If you are wondering what on earth kbd:[Meta] is, it is a special key that many UNIX(R) workstations have. Unfortunately, PC's do not have one, so it is usually kbd:[alt] (or if you are unlucky, the kbd:[escape] key). Oh, and to get out of Emacs, do `C-x C-c` (that means hold down the kbd:[control] key, press kbd:[x], press kbd:[c] and release the kbd:[control] key). If you have any unsaved files open, Emacs will ask you if you want to save them. (Ignore the bit in the documentation where it says `C-z` is the usual way to leave Emacs-that leaves Emacs hanging around in the background, and is only really useful if you are on a system which does not have virtual terminals). === Configuring Emacs Emacs does many wonderful things; some of them are built in, some of them need to be configured. Instead of using a proprietary macro language for configuration, Emacs uses a version of Lisp specially adapted for editors, known as Emacs Lisp. Working with Emacs Lisp can be quite helpful if you want to go on and learn something like Common Lisp. Emacs Lisp has many features of Common Lisp, although it is considerably smaller (and thus easier to master). The best way to learn Emacs Lisp is to read the online link:https://www.gnu.org/software/emacs/manual/elisp.html[Emacs Reference] manual. However, there is no need to actually know any Lisp to get started with configuring Emacs, as I have included a sample [.filename]#.emacs#, which should be enough to get you started. Just copy it into your home directory and restart Emacs if it is already running; it will read the commands from the file and (hopefully) give you a useful basic setup. === A Sample [.filename]#.emacs# Unfortunately, there is far too much here to explain it in detail; however there are one or two points worth mentioning. * Everything beginning with a `;` is a comment and is ignored by Emacs. * In the first line, the `-*- Emacs-Lisp -*-` is so that we can edit [.filename]#.emacs# itself within Emacs and get all the fancy features for editing Emacs Lisp. Emacs usually tries to guess this based on the filename, and may not get it right for [.filename]#.emacs#. * The kbd:[tab] key is bound to an indentation function in some modes, so when you press the tab key, it will indent the current line of code. If you want to put a tab character in whatever you are writing, hold the kbd:[control] key down while you are pressing the kbd:[tab] key. * This file supports syntax highlighting for C, C++, Perl, Lisp and Scheme, by guessing the language from the filename. * Emacs already has a pre-defined function called `next-error`. In a compilation output window, this allows you to move from one compilation error to the next by doing `M-n`; we define a complementary function, `previous-error`, that allows you to go to a previous error by doing `M-p`. The nicest feature of all is that `C-c C-c` will open up the source file in which the error occurred and jump to the appropriate line. * We enable Emacs's ability to act as a server, so that if you are doing something outside Emacs and you want to edit a file, you can just type in + [source,bash] .... % emacsclient filename .... + and then you can edit the file in your Emacs!footnote:[Many Emacs users set their EDITOR environment to emacsclient so this happens every time they need to edit a file.] .A Sample [.filename]#.emacs# ==== [.programlisting] .... ;; -*-Emacs-Lisp-*- ;; This file is designed to be re-evaled; use the variable first-time ;; to avoid any problems with this. (defvar first-time t "Flag signifying this is the first time that .emacs has been evaled") ;; Meta (global-set-key "\M- " 'set-mark-command) (global-set-key "\M-\C-h" 'backward-kill-word) (global-set-key "\M-\C-r" 'query-replace) (global-set-key "\M-r" 'replace-string) (global-set-key "\M-g" 'goto-line) (global-set-key "\M-h" 'help-command) ;; Function keys (global-set-key [f1] 'manual-entry) (global-set-key [f2] 'info) (global-set-key [f3] 'repeat-complex-command) (global-set-key [f4] 'advertised-undo) (global-set-key [f5] 'eval-current-buffer) (global-set-key [f6] 'buffer-menu) (global-set-key [f7] 'other-window) (global-set-key [f8] 'find-file) (global-set-key [f9] 'save-buffer) (global-set-key [f10] 'next-error) (global-set-key [f11] 'compile) (global-set-key [f12] 'grep) (global-set-key [C-f1] 'compile) (global-set-key [C-f2] 'grep) (global-set-key [C-f3] 'next-error) (global-set-key [C-f4] 'previous-error) (global-set-key [C-f5] 'display-faces) (global-set-key [C-f8] 'dired) (global-set-key [C-f10] 'kill-compilation) ;; Keypad bindings (global-set-key [up] "\C-p") (global-set-key [down] "\C-n") (global-set-key [left] "\C-b") (global-set-key [right] "\C-f") (global-set-key [home] "\C-a") (global-set-key [end] "\C-e") (global-set-key [prior] "\M-v") (global-set-key [next] "\C-v") (global-set-key [C-up] "\M-\C-b") (global-set-key [C-down] "\M-\C-f") (global-set-key [C-left] "\M-b") (global-set-key [C-right] "\M-f") (global-set-key [C-home] "\M-<") (global-set-key [C-end] "\M->") (global-set-key [C-prior] "\M-<") (global-set-key [C-next] "\M->") ;; Mouse (global-set-key [mouse-3] 'imenu) ;; Misc (global-set-key [C-tab] "\C-q\t") ; Control tab quotes a tab. (setq backup-by-copying-when-mismatch t) ;; Treat 'y' or as yes, 'n' as no. (fset 'yes-or-no-p 'y-or-n-p) (define-key query-replace-map [return] 'act) (define-key query-replace-map [?\C-m] 'act) ;; Load packages (require 'desktop) (require 'tar-mode) ;; Pretty diff mode (autoload 'ediff-buffers "ediff" "Intelligent Emacs interface to diff" t) (autoload 'ediff-files "ediff" "Intelligent Emacs interface to diff" t) (autoload 'ediff-files-remote "ediff" "Intelligent Emacs interface to diff") (if first-time (setq auto-mode-alist (append '(("\\.cpp$" . c++-mode) ("\\.hpp$" . c++-mode) ("\\.lsp$" . lisp-mode) ("\\.scm$" . scheme-mode) ("\\.pl$" . perl-mode) ) auto-mode-alist))) ;; Auto font lock mode (defvar font-lock-auto-mode-list (list 'c-mode 'c++-mode 'c++-c-mode 'emacs-lisp-mode 'lisp-mode 'perl-mode 'scheme-mode) "List of modes to always start in font-lock-mode") (defvar font-lock-mode-keyword-alist '((c++-c-mode . c-font-lock-keywords) (perl-mode . perl-font-lock-keywords)) "Associations between modes and keywords") (defun font-lock-auto-mode-select () "Automatically select font-lock-mode if the current major mode is in font-lock-auto-mode-list" (if (memq major-mode font-lock-auto-mode-list) (progn (font-lock-mode t)) ) ) (global-set-key [M-f1] 'font-lock-fontify-buffer) ;; New dabbrev stuff ;(require 'new-dabbrev) (setq dabbrev-always-check-other-buffers t) (setq dabbrev-abbrev-char-regexp "\\sw\\|\\s_") (add-hook 'emacs-lisp-mode-hook '(lambda () (set (make-local-variable 'dabbrev-case-fold-search) nil) (set (make-local-variable 'dabbrev-case-replace) nil))) (add-hook 'c-mode-hook '(lambda () (set (make-local-variable 'dabbrev-case-fold-search) nil) (set (make-local-variable 'dabbrev-case-replace) nil))) (add-hook 'text-mode-hook '(lambda () (set (make-local-variable 'dabbrev-case-fold-search) t) (set (make-local-variable 'dabbrev-case-replace) t))) ;; C++ and C mode... (defun my-c++-mode-hook () (setq tab-width 4) (define-key c++-mode-map "\C-m" 'reindent-then-newline-and-indent) (define-key c++-mode-map "\C-ce" 'c-comment-edit) (setq c++-auto-hungry-initial-state 'none) (setq c++-delete-function 'backward-delete-char) (setq c++-tab-always-indent t) (setq c-indent-level 4) (setq c-continued-statement-offset 4) (setq c++-empty-arglist-indent 4)) (defun my-c-mode-hook () (setq tab-width 4) (define-key c-mode-map "\C-m" 'reindent-then-newline-and-indent) (define-key c-mode-map "\C-ce" 'c-comment-edit) (setq c-auto-hungry-initial-state 'none) (setq c-delete-function 'backward-delete-char) (setq c-tab-always-indent t) ;; BSD-ish indentation style (setq c-indent-level 4) (setq c-continued-statement-offset 4) (setq c-brace-offset -4) (setq c-argdecl-indent 0) (setq c-label-offset -4)) ;; Perl mode (defun my-perl-mode-hook () (setq tab-width 4) (define-key c++-mode-map "\C-m" 'reindent-then-newline-and-indent) (setq perl-indent-level 4) (setq perl-continued-statement-offset 4)) ;; Scheme mode... (defun my-scheme-mode-hook () (define-key scheme-mode-map "\C-m" 'reindent-then-newline-and-indent)) ;; Emacs-Lisp mode... (defun my-lisp-mode-hook () (define-key lisp-mode-map "\C-m" 'reindent-then-newline-and-indent) (define-key lisp-mode-map "\C-i" 'lisp-indent-line) (define-key lisp-mode-map "\C-j" 'eval-print-last-sexp)) ;; Add all of the hooks... (add-hook 'c++-mode-hook 'my-c++-mode-hook) (add-hook 'c-mode-hook 'my-c-mode-hook) (add-hook 'scheme-mode-hook 'my-scheme-mode-hook) (add-hook 'emacs-lisp-mode-hook 'my-lisp-mode-hook) (add-hook 'lisp-mode-hook 'my-lisp-mode-hook) (add-hook 'perl-mode-hook 'my-perl-mode-hook) ;; Complement to next-error (defun previous-error (n) "Visit previous compilation error message and corresponding source code." (interactive "p") (next-error (- n))) ;; Misc... (transient-mark-mode 1) (setq mark-even-if-inactive t) (setq visible-bell nil) (setq next-line-add-newlines nil) (setq compile-command "make") (setq suggest-key-bindings nil) (put 'eval-expression 'disabled nil) (put 'narrow-to-region 'disabled nil) (put 'set-goal-column 'disabled nil) (if (>= emacs-major-version 21) (setq show-trailing-whitespace t)) ;; Elisp archive searching (autoload 'format-lisp-code-directory "lispdir" nil t) (autoload 'lisp-dir-apropos "lispdir" nil t) (autoload 'lisp-dir-retrieve "lispdir" nil t) (autoload 'lisp-dir-verify "lispdir" nil t) ;; Font lock mode (defun my-make-face (face color &optional bold) "Create a face from a color and optionally make it bold" (make-face face) (copy-face 'default face) (set-face-foreground face color) (if bold (make-face-bold face)) ) (if (eq window-system 'x) (progn (my-make-face 'blue "blue") (my-make-face 'red "red") (my-make-face 'green "dark green") (setq font-lock-comment-face 'blue) (setq font-lock-string-face 'bold) (setq font-lock-type-face 'bold) (setq font-lock-keyword-face 'bold) (setq font-lock-function-name-face 'red) (setq font-lock-doc-string-face 'green) (add-hook 'find-file-hooks 'font-lock-auto-mode-select) (setq baud-rate 1000000) (global-set-key "\C-cmm" 'menu-bar-mode) (global-set-key "\C-cms" 'scroll-bar-mode) (global-set-key [backspace] 'backward-delete-char) ; (global-set-key [delete] 'delete-char) (standard-display-european t) (load-library "iso-transl"))) ;; X11 or PC using direct screen writes (if window-system (progn ;; (global-set-key [M-f1] 'hilit-repaint-command) ;; (global-set-key [M-f2] [?\C-u M-f1]) (setq hilit-mode-enable-list '(not text-mode c-mode c++-mode emacs-lisp-mode lisp-mode scheme-mode) hilit-auto-highlight nil hilit-auto-rehighlight 'visible hilit-inhibit-hooks nil hilit-inhibit-rebinding t) (require 'hilit19) (require 'paren)) (setq baud-rate 2400) ; For slow serial connections ) ;; TTY type terminal (if (and (not window-system) (not (equal system-type 'ms-dos))) (progn (if first-time (progn (keyboard-translate ?\C-h ?\C-?) (keyboard-translate ?\C-? ?\C-h))))) ;; Under UNIX (if (not (equal system-type 'ms-dos)) (progn (if first-time (server-start)))) ;; Add any face changes here (add-hook 'term-setup-hook 'my-term-setup-hook) (defun my-term-setup-hook () (if (eq window-system 'pc) (progn ;; (set-face-background 'default "red") ))) ;; Restore the "desktop" - do this as late as possible (if first-time (progn (desktop-load-default) (desktop-read))) ;; Indicate that this file has been read at least once (setq first-time nil) ;; No need to debug anything now (setq debug-on-error nil) ;; All done (message "All done, %s%s" (user-login-name) ".") .... ==== === Extending the Range of Languages Emacs Understands Now, this is all very well if you only want to program in the languages already catered for in [.filename]#.emacs# (C, C++, Perl, Lisp and Scheme), but what happens if a new language called "whizbang" comes out, full of exciting features? The first thing to do is find out if whizbang comes with any files that tell Emacs about the language. These usually end in [.filename]#.el#, short for "Emacs Lisp". For example, if whizbang is a FreeBSD port, we can locate these files by doing [source,bash] .... % find /usr/ports/lang/whizbang -name "*.el" -print .... and install them by copying them into the Emacs site Lisp directory. On FreeBSD, this is [.filename]#/usr/local/share/emacs/site-lisp#. So for example, if the output from the find command was [source,bash] .... /usr/ports/lang/whizbang/work/misc/whizbang.el .... we would do [source,bash] .... # cp /usr/ports/lang/whizbang/work/misc/whizbang.el /usr/local/share/emacs/site-lisp .... Next, we need to decide what extension whizbang source files have. Let us say for the sake of argument that they all end in [.filename]#.wiz#. We need to add an entry to our [.filename]#.emacs# to make sure Emacs will be able to use the information in [.filename]#whizbang.el#. Find the auto-mode-alist entry in [.filename]#.emacs# and add a line for whizbang, such as: [.programlisting] .... ... ("\\.lsp$" . lisp-mode) ("\\.wiz$" . whizbang-mode) ("\\.scm$" . scheme-mode) ... .... This means that Emacs will automatically go into `whizbang-mode` when you edit a file ending in [.filename]#.wiz#. Just below this, you will find the font-lock-auto-mode-list entry. Add `whizbang-mode` to it like so: [.programlisting] .... ;; Auto font lock mode (defvar font-lock-auto-mode-list (list 'c-mode 'c++-mode 'c++-c-mode 'emacs-lisp-mode 'whizbang-mode 'lisp-mode 'perl-mode 'scheme-mode) "List of modes to always start in font-lock-mode") .... This means that Emacs will always enable `font-lock-mode` (ie syntax highlighting) when editing a [.filename]#.wiz# file. And that is all that is needed. If there is anything else you want done automatically when you open up [.filename]#.wiz#, you can add a `whizbang-mode hook` (see `my-scheme-mode-hook` for a simple example that adds `auto-indent`). [[tools-reading]] == Further Reading For information about setting up a development environment for contributing fixes to FreeBSD itself, please see man:development[7]. * Brian Harvey and Matthew Wright _Simply Scheme_ MIT 1994. ISBN 0-262-08226-8 * Randall Schwartz _Learning Perl_ O'Reilly 1993 ISBN 1-56592-042-2 * Patrick Henry Winston and Berthold Klaus Paul Horn _Lisp (3rd Edition)_ Addison-Wesley 1989 ISBN 0-201-08319-1 * Brian W. Kernighan and Rob Pike _The Unix Programming Environment_ Prentice-Hall 1984 ISBN 0-13-937681-X * Brian W. Kernighan and Dennis M. Ritchie _The C Programming Language (2nd Edition)_ Prentice-Hall 1988 ISBN 0-13-110362-8 * Bjarne Stroustrup _The C++ Programming Language_ Addison-Wesley 1991 ISBN 0-201-53992-6 * W. Richard Stevens _Advanced Programming in the Unix Environment_ Addison-Wesley 1992 ISBN 0-201-56317-7 * W. Richard Stevens _Unix Network Programming_ Prentice-Hall 1990 ISBN 0-13-949876-1 diff --git a/documentation/content/en/books/fdp-primer/editor-config/_index.adoc b/documentation/content/en/books/fdp-primer/editor-config/_index.adoc index 43411e6d6d..d7cf1b516e 100644 --- a/documentation/content/en/books/fdp-primer/editor-config/_index.adoc +++ b/documentation/content/en/books/fdp-primer/editor-config/_index.adoc @@ -1,329 +1,329 @@ --- title: Chapter 13. Editor Configuration prev: books/fdp-primer/writing-style next: books/fdp-primer/trademarks description: Configuration used in the texts editors in the FreeBSD Documentation Project tags: ["editor", "configuration", "vim", "emacs", "FreeBSD"] showBookMenu: true weight: 13 path: "/books/fdp-primer/editor-config/" --- [[editor-config]] = Editor Configuration :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 13 :partnums: :source-highlighter: rouge :experimental: :images-path: books/fdp-primer/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] Adjusting your text editor configuration can make working on document files quicker and easier, and help documents conform to FDP guidelines. [[editor-config-vim]] == Vim -Install from package:editors/vim[], then follow the configuration instructions in crossref:editor-config[editor-config-vim-config]. +Install from package:editors/vim[], then follow the configuration instructions in crossref:editor-config[editor-config-vim-config, Configuration]. More advanced users can use a proper linter like link:https://github.com/dense-analysis/ale[Ale] which can also act as a Vim link:https://langserver.org/[Language Server Protocol] client. [[editor-config-vim-use]] === Use Manual page writers can use the following keyboard shortcuts to reformat: * Press kbd:[P] to reformat paragraphs or text that has been selected in Visual mode. * Press kbd:[T] to replace groups of eight spaces with a tab. A linter named link:https://vale.sh[Vale] has been introduced to check grammatical and cosmetic errors on the documents. Vale has support for various editors and IDEs. Vale may already be installed as a dependency of the package:textproc/docproj[] meta-port. If not, install package:textproc/vale[] with: [source,console] .... $ pkg install vale .... Install link:https://github.com/dense-analysis/ale[Ale] to integrate into package:editors/vim[], for using package:textproc/vale[]. [source,console?prompt=%] .... % mkdir -p ~/.vim/pack/vendor/start % git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.vim/pack/vendor/start/ale .... Users who are using plugin managers for package:editors/vim[] do not need the above and should follow the instructions of that plugin manager to install link:https://github.com/dense-analysis/ale[Ale]. At this moment due to a bug in link:https://vale.sh[Vale] it is necessary to copy the link:https://vale.sh[Vale] configuration to the home directory. Considering the repository was cloned into [.filename]#~/doc# copy as following: [source,console?prompt=%] .... % cp -R ~/doc/.vale* ~/ .... [[editor-config-vim-config]] === Configuration Edit [.filename]#~/.vimrc#, adding these lines to the end of the file: [source.programlisting,viml] .`~/.vimrc` .... if has("autocmd") au BufNewFile,BufRead *.adoc call Set_ADOC() au BufNewFile,BufRead *.[1-9] call Set_MAN() endif " has(autocmd) function Set_Highlights() "match ExtraWhitespace /^\s* \s*\|\s\+$/ return 0 endfunction " Set_Highlights_Adoc() function Set_Highlights_MAN() highlight default link OverLength ErrorMsg match OverLength /\%71v.\+/ return 0 endfunction " Set_Highlights_MAN() function ShowSpecial() setlocal list listchars=tab:>>,trail:*,eol:$ hi def link nontext ErrorMsg return 0 endfunction " ShowSpecial() function Set_COMMON() setlocal number setlocal shiftwidth=2 setlocal tabstop=8 setlocal softtabstop=2 setlocal formatprg="fmt -p" setlocal autoindent setlocal smartindent call ShowSpecial() call Set_Highlights() return 0 endfunction " Set_COMMON() function Set_ADOC() setlocal syntax=asciidoc setlocal filetype=asciidoc call Set_COMMON() return 0 endfunction " Set_ADOC() function Set_MAN() setlocal syntax=man setlocal filetype=man setlocal textwidth=70 " Rewrap paragraphs noremap P gqj " Replace spaces with tabs noremap T :s/ /\t/ call Set_COMMON() call Set_Highlights_MAN() return 0 endfunction " Set_Man() let g:ale_fixers = { \ '*': ['remove_trailing_lines', 'trim_whitespace'], \} let g:ale_linters = { \ 'asciidoc': ['vale'], \} let g:ale_fix_on_save = 1 .... [IMPORTANT] ====== Above configuration will automatically remove trailing line, trailing space and multiple spaces which might display additional unwanted changes in `git diff` output. In such cases properly mention that in the commit log. ====== [[editor-config-emacs]] == Emacs Install from package:editors/emacs[] or package:editors/emacs-devel[]. [[editor-config-emacs-igor]] === Automated Proofreading with Flycheck and Igor The link:https://www.flycheck.org/[Flycheck] package is available from link:https://melpa.org/[Milkypostman's Emacs Lisp Package Archive] (MELPA). If MELPA is not already in Emacs's packages-archives, it can be added by evaluating [source,emacs-lisp] .... (add-to-list 'package-archives '("melpa" . "http://stable.melpa.org/packages/") t) .... Add the line to Emacs's initialization file (one of [.filename]#~/.emacs#, [.filename]#~/.emacs.el#, or [.filename]#~.emacs.d/init.el#) to make this change permanent. To install Flycheck, evaluate [source,emacs-lisp] .... (package-install 'flycheck) .... Create a Flycheck checker for package:textproc/igor[] by evaluating [source,emacs-lisp] .... (flycheck-define-checker igor "FreeBSD Documentation Project sanity checker. See URLs https://www.freebsd.org/docproj/ and http://www.freshports.org/textproc/igor/." :command ("igor" "-X" source-inplace) :error-parser flycheck-parse-checkstyle :modes (nxml-mode) :standard-input t) (add-to-list 'flycheck-checkers 'igor 'append) .... Again, add these lines to Emacs's initialization file to make the changes permanent. [[editor-config-emacs-specifc]] === FreeBSD Documentation Specific Settings To apply settings specific to the FreeBSD documentation project, create [.filename]#.dir-locals.el# in the root directory of the documentation repository and add these lines to the file: [source,emacs-lisp] .... ;;; Directory Local Variables ;;; For more information see (info "(emacs) Directory Variables") ((nxml-mode (eval . (turn-on-auto-fill)) (fill-column . 70) (eval . (require 'flycheck)) (eval . (flycheck-mode 1)) (flycheck-checker . igor) (eval . (add-to-list 'rng-schema-locating-files "~/.emacs.d/schema/schemas.xml")))) .... [[editor-config-nano]] == nano Install from package:editors/nano[]. [[editor-config-nano-config]] === Configuration Currently there is no adoc/asciidoc syntax highlight file with nano distribution. So let's create one from scratch and use an editor to create new file or add lines in the [.filename]#~/.nanorc# with these contents: [source] .`~/.nanorc` .... syntax "asciidoc" "\.(adoc|asc|asciidoc)$" # main header color red "^====+$" # h1 color red "^==[[:space:]].*$" color red "^----+$" # h2 color magenta "^===[[:space:]].*$" color magenta "^~~~~+$" # h4 color green "^====[[:space:]].*$" color green "^\^\^\^\^+$" # h5 color brightblue "^=====[[:space:]].*$" color brightblue "^\+\+\+\++$" # attributes color brightgreen ":.*:" color brightred "\{[a-z0-9]*\}" color red "\\\{[a-z0-9]*\}" color red "\+\+\+\{[a-z0-9]*\}\+\+\+" # Paragraph Title color yellow "^\..*$" # source color magenta "^\[(source,.+|NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]" # Other markup color yellow ".*[[:space:]]\+$" color yellow "_[^_]+_" color yellow "\*[^\*]+\*" color yellow "\+[^\+]+\+" color yellow "`[^`]+`" color yellow "\^[^\^]+\^" color yellow "~[^~]+~" color yellow "'[^']+'" color cyan "`{1,2}[^']+'{1,2}" # bullets color brightmagenta "^[[:space:]]*[\*\.-]{1,5}[[:space:]]" # anchors color brightwhite "\[\[.*\]\]" color brightwhite "<<.*>>" # trailing whitespace color ,blue "[[:space:]]+$" # multiples of eight spaces at the start a line # (after zero or more tabs) should be a tab color ,blue "^([TAB]*[ ]{8})+" # tabs after spaces color ,yellow "( )+TAB" # highlight indents that have an odd number of spaces color ,red "^(([ ]{2})+|(TAB+))*[ ]{1}[^ ]{1}" .... Process the file to create embedded tabs: [source,console?prompt=%] .... % perl -i'' -pe 's/TAB/\t/g' ~/.nanorc .... [[editor-config-nano-use]] === Use Specify additional helpful options when running the editor: [source,console?prompt=%] .... % nano -AKipwz -T8 _index.adoc .... Users of man:csh[1] can define an alias in [.filename]#~/.cshrc# to automate these options: [source,shell] .... alias nano "nano -AKipwz -r 70 -T8" .... After the alias is defined, the options will be added automatically: [source,console?prompt=%] .... % nano _index.adoc .... diff --git a/documentation/content/en/books/handbook/advanced-networking/_index.adoc b/documentation/content/en/books/handbook/advanced-networking/_index.adoc index ab431aeab8..212b54a22d 100644 --- a/documentation/content/en/books/handbook/advanced-networking/_index.adoc +++ b/documentation/content/en/books/handbook/advanced-networking/_index.adoc @@ -1,2386 +1,2386 @@ --- title: Chapter 34. Advanced Networking part: IV. Network Communication prev: books/handbook/firewalls next: books/handbook/partv description: "Advanced networking in FreeBSD: basics of gateways and routes, CARP, how to configure multiple VLANs on FreeBSD, etc" tags: ["Advanced Networking", "Handbook", "gateway", "routes", "wireless", "tethering", "bluetooth", "bridging", "CARP", "VLAN"] showBookMenu: true weight: 39 path: "/books/handbook/advanced-networking/" --- [[advanced-networking]] = Advanced Networking :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 34 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/advanced-networking/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[advanced-networking-synopsis]] == Synopsis This chapter covers a number of advanced networking topics. After reading this chapter, you will know: * The basics of gateways and routes. * How to set up USB tethering. * How to set up IEEE(R) 802.11 and Bluetooth(R) devices. * How to make FreeBSD act as a bridge. * How to set up network PXE booting. * How to enable and utilize the features of the Common Address Redundancy Protocol (CARP) in FreeBSD. * How to configure multiple VLANs on FreeBSD. * Configure bluetooth headset. Before reading this chapter, you should: * Understand the basics of the [.filename]#/etc/rc# scripts. * Be familiar with basic network terminology. * Understand basic network configuration on FreeBSD (crossref:network[network,FreeBSD network]). * Know how to configure and install a new FreeBSD kernel (crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]). * Know how to install additional third-party software (crossref:ports[ports,Installing Applications: Packages and Ports]). [[network-routing]] == Gateways and Routes _Routing_ is the mechanism that allows a system to find the network path to another system. A _route_ is a defined pair of addresses which represent the "destination" and a "gateway". The route indicates that when trying to get to the specified destination, send the packets through the specified gateway. There are three types of destinations: individual hosts, subnets, and "default". The "default route" is used if no other routes apply. There are also three types of gateways: individual hosts, interfaces, also called links, and Ethernet hardware (MAC) addresses. Known routes are stored in a routing table. This section provides an overview of routing basics. It then demonstrates how to configure a FreeBSD system as a router and offers some troubleshooting tips. [[network-routing-default]] === Routing Basics To view the routing table of a FreeBSD system, use man:netstat[1]: [source,shell] .... % netstat -r Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default outside-gw UGS 37 418 em0 localhost localhost UH 0 181 lo0 test0 0:e0:b5:36:cf:4f UHLW 5 63288 re0 77 10.20.30.255 link#1 UHLW 1 2421 example.com link#1 UC 0 0 host1 0:e0:a8:37:8:1e UHLW 3 4601 lo0 host2 0:e0:a8:37:8:1e UHLW 0 5 lo0 => host2.example.com link#1 UC 0 0 224 link#1 UC 0 0 .... The entries in this example are as follows: default:: The first route in this table specifies the `default` route. When the local system needs to make a connection to a remote host, it checks the routing table to determine if a known path exists. If the remote host matches an entry in the table, the system checks to see if it can connect using the interface specified in that entry. + If the destination does not match an entry, or if all known paths fail, the system uses the entry for the default route. For hosts on a local area network, the `Gateway` field in the default route is set to the system which has a direct connection to the Internet. When reading this entry, verify that the `Flags` column indicates that the gateway is usable (`UG`). + The default route for a machine which itself is functioning as the gateway to the outside world will be the gateway machine at the Internet Service Provider (ISP). localhost:: The second route is the `localhost` route. The interface specified in the `Netif` column for `localhost` is [.filename]#lo0#, also known as the loopback device. This indicates that all traffic for this destination should be internal, rather than sending it out over the network. MAC address:: The addresses beginning with `0:e0:` are MAC addresses. FreeBSD will automatically identify any hosts, `test0` in the example, on the local Ethernet and add a route for that host over the Ethernet interface, [.filename]#re0#. This type of route has a timeout, seen in the `Expire` column, which is used if the host does not respond in a specific amount of time. When this happens, the route to this host will be automatically deleted. These hosts are identified using the Routing Information Protocol (RIP), which calculates routes to local hosts based upon a shortest path determination. subnet:: FreeBSD will automatically add subnet routes for the local subnet. In this example, `10.20.30.255` is the broadcast address for the subnet `10.20.30` and `example.com` is the domain name associated with that subnet. The designation `link#1` refers to the first Ethernet card in the machine. + Local network hosts and local subnets have their routes automatically configured by a daemon called man:routed[8]. If it is not running, only routes which are statically defined by the administrator will exist. host:: The `host1` line refers to the host by its Ethernet address. Since it is the sending host, FreeBSD knows to use the loopback interface ([.filename]#lo0#) rather than the Ethernet interface. + The two `host2` lines represent aliases which were created using man:ifconfig[8]. The `=>` symbol after the [.filename]#lo0# interface says that an alias has been set in addition to the loopback address. Such routes only show up on the host that supports the alias and all other hosts on the local network will have a `link#1` line for such routes. 224:: The final line (destination subnet `224`) deals with multicasting. Various attributes of each route can be seen in the `Flags` column. -crossref:advanced-networking[routeflags] summarizes some of these flags and their meanings: +crossref:advanced-networking[routeflags,.Commonly Seen Routing Table Flags] summarizes some of these flags and their meanings: [[routeflags]] .Commonly Seen Routing Table Flags [cols="1,1", frame="none", options="header"] |=== | Flag | Purpose |U |The route is active (up). |H |The route destination is a single host. |G |Send anything for this destination on to this gateway, which will figure out from there where to send it. |S |This route was statically configured. |C |Clones a new route based upon this route for machines to connect to. This type of route is normally used for local networks. |W |The route was auto-configured based upon a local area network (clone) route. |L |Route involves references to Ethernet (link) hardware. |=== On a FreeBSD system, the default route can defined in [.filename]#/etc/rc.conf# by specifying the IP address of the default gateway: [.programlisting] .... defaultrouter="10.20.30.1" .... It is also possible to manually add the route using `route`: [source,shell] .... # route add default 10.20.30.1 .... Note that manually added routes will not survive a reboot. For more information on manual manipulation of network routing tables, refer to man:route[8]. [[network-static-routes]] === Configuring a Router with Static Routes A FreeBSD system can be configured as the default gateway, or router, for a network if it is a dual-homed system. A dual-homed system is a host which resides on at least two different networks. Typically, each network is connected to a separate network interface, though IP aliasing can be used to bind multiple addresses, each on a different subnet, to one physical interface. In order for the system to forward packets between interfaces, FreeBSD must be configured as a router. Internet standards and good engineering practice prevent the FreeBSD Project from enabling this feature by default, but it can be configured to start at boot by adding this line to [.filename]#/etc/rc.conf#: [.programlisting] .... gateway_enable="YES" # Set to YES if this host will be a gateway .... To enable routing now, set the man:sysctl[8] variable `net.inet.ip.forwarding` to `1`. To stop routing, reset this variable to `0`. The routing table of a router needs additional routes so it knows how to reach other networks. Routes can be either added manually using static routes or routes can be automatically learned using a routing protocol. Static routes are appropriate for small networks and this section describes how to add a static routing entry for a small network. [NOTE] ==== For large networks, static routes quickly become unscalable. FreeBSD comes with the standard BSD routing daemon man:routed[8], which provides the routing protocols RIP, versions 1 and 2, and IRDP. Support for the BGP and OSPF routing protocols can be installed using the package:net/quagga[] package or port. ==== Consider the following network: image::static-routes.png[] In this scenario, `RouterA` is a FreeBSD machine that is acting as a router to the rest of the Internet. It has a default route set to `10.0.0.1` which allows it to connect with the outside world. `RouterB` is already configured to use `192.168.1.1` as its default gateway. Before adding any static routes, the routing table on `RouterA` looks like this: [source,shell] .... % netstat -nr Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default 10.0.0.1 UGS 0 49378 xl0 127.0.0.1 127.0.0.1 UH 0 6 lo0 10.0.0.0/24 link#1 UC 0 0 xl0 192.168.1.0/24 link#2 UC 0 0 xl1 .... With the current routing table, `RouterA` does not have a route to the `192.168.2.0/24` network. The following command adds the `Internal Net 2` network to ``RouterA``'s routing table using `192.168.1.2` as the next hop: [source,shell] .... # route add -net 192.168.2.0/24 192.168.1.2 .... Now, `RouterA` can reach any host on the `192.168.2.0/24` network. However, the routing information will not persist if the FreeBSD system reboots. If a static route needs to be persistent, add it to [.filename]#/etc/rc.conf#: [.programlisting] .... # Add Internal Net 2 as a persistent static route static_routes="internalnet2" route_internalnet2="-net 192.168.2.0/24 192.168.1.2" .... The `static_routes` configuration variable is a list of strings separated by a space, where each string references a route name. The variable `route_internalnet2` contains the static route for that route name. Using more than one string in `static_routes` creates multiple static routes. The following shows an example of adding static routes for the `192.168.0.0/24` and `192.168.1.0/24` networks: [.programlisting] .... static_routes="net1 net2" route_net1="-net 192.168.0.0/24 192.168.0.1" route_net2="-net 192.168.1.0/24 192.168.1.1" .... [[network-routing-troubleshooting]] === Troubleshooting When an address space is assigned to a network, the service provider configures their routing tables so that all traffic for the network will be sent to the link for the site. But how do external sites know to send their packets to the network's ISP? There is a system that keeps track of all assigned address spaces and defines their point of connection to the Internet backbone, or the main trunk lines that carry Internet traffic across the country and around the world. Each backbone machine has a copy of a master set of tables, which direct traffic for a particular network to a specific backbone carrier, and from there down the chain of service providers until it reaches a particular network. It is the task of the service provider to advertise to the backbone sites that they are the point of connection, and thus the path inward, for a site. This is known as route propagation. Sometimes, there is a problem with route propagation and some sites are unable to connect. Perhaps the most useful command for trying to figure out where routing is breaking down is `traceroute`. It is useful when `ping` fails. When using `traceroute`, include the address of the remote host to connect to. The output will show the gateway hosts along the path of the attempt, eventually either reaching the target host, or terminating because of a lack of connection. For more information, refer to man:traceroute[8]. [[network-routing-multicast]] === Multicast Considerations FreeBSD natively supports both multicast applications and multicast routing. Multicast applications do not require any special configuration in order to run on FreeBSD. Support for multicast routing requires that the following option be compiled into a custom kernel: [.programlisting] .... options MROUTING .... The multicast routing daemon, mrouted can be installed using the package:net/mrouted[] package or port. This daemon implements the DVMRP multicast routing protocol and is configured by editing [.filename]#/usr/local/etc/mrouted.conf# in order to set up the tunnels and DVMRP. The installation of mrouted also installs map-mbone and mrinfo, as well as their associated man pages. Refer to these for configuration examples. [NOTE] ==== DVMRP has largely been replaced by the PIM protocol in many multicast installations. Refer to man:pim[4] for more information. ==== [[configtuning-virtual-hosts]] == Virtual Hosts A common use of FreeBSD is virtual site hosting, where one server appears to the network as many servers. This is achieved by assigning multiple network addresses to a single interface. A given network interface has one "real" address, and may have any number of "alias" addresses. These aliases are normally added by placing alias entries in [.filename]#/etc/rc.conf#, as seen in this example: [source,shell] .... # sysrc ifconfig_fxp0_alias0="inet xxx.xxx.xxx.xxx netmask xxx.xxx.xxx.xxx" .... Alias entries must start with `alias__0__` using a sequential number such as `alias0`, `alias1`, and so on. The configuration process will stop at the first missing number. The calculation of alias netmasks is important. For a given interface, there must be one address which correctly represents the network's netmask. Any other addresses which fall within this network must have a netmask of all ``1``s, expressed as either `255.255.255.255` or `0xffffffff`. For example, consider the case where the `fxp0` interface is connected to two networks: `10.1.1.0` with a netmask of `255.255.255.0` and `202.0.75.16` with a netmask of `255.255.255.240`. The system is to be configured to appear in the ranges `10.1.1.1` through `10.1.1.5` and `202.0.75.17` through `202.0.75.20`. Only the first address in a given network range should have a real netmask. All the rest (`10.1.1.2` through `10.1.1.5` and `202.0.75.18` through `202.0.75.20`) must be configured with a netmask of `255.255.255.255`. The following [.filename]#/etc/rc.conf# entries configure the adapter correctly for this scenario: [source,shell] .... # sysrc ifconfig_fxp0="inet 10.1.1.1 netmask 255.255.255.0" # sysrc ifconfig_fxp0_alias0="inet 10.1.1.2 netmask 255.255.255.255" # sysrc ifconfig_fxp0_alias1="inet 10.1.1.3 netmask 255.255.255.255" # sysrc ifconfig_fxp0_alias2="inet 10.1.1.4 netmask 255.255.255.255" # sysrc ifconfig_fxp0_alias3="inet 10.1.1.5 netmask 255.255.255.255" # sysrc ifconfig_fxp0_alias4="inet 202.0.75.17 netmask 255.255.255.240" # sysrc ifconfig_fxp0_alias5="inet 202.0.75.18 netmask 255.255.255.255" # sysrc ifconfig_fxp0_alias6="inet 202.0.75.19 netmask 255.255.255.255" # sysrc ifconfig_fxp0_alias7="inet 202.0.75.20 netmask 255.255.255.255" .... A simpler way to express this is with a space-separated list of IP address ranges. The first address will be given the indicated subnet mask and the additional addresses will have a subnet mask of `255.255.255.255`. [source,shell] .... # sysrc ifconfig_fxp0_aliases="inet 10.1.1.1-5/24 inet 202.0.75.17-20/28" .... [[network-advanced-wireless]] == Wireless Advanced Authentication FreeBSD supports different ways of connecting to a wireless network. This section describes how to perform advanced authentication to a Wireless Network. To make a connection and basic authentication to a wireless network the section crossref:network[wireless-authentication,Connection and Authentication to a Wireless Network] in the Network Chapter describes how to do it. [[network-wireless-wpa-eap-tls]] === WPA with EAP-TLS The second way to use WPA is with an 802.1X backend authentication server. In this case, WPA is called WPA Enterprise to differentiate it from the less secure WPA Personal. Authentication in WPA Enterprise is based on the Extensible Authentication Protocol (EAP). EAP does not come with an encryption method. Instead, EAP is embedded inside an encrypted tunnel. There are many EAP authentication methods, but EAP-TLS, EAP-TTLS, and EAP-PEAP are the most common. EAP with Transport Layer Security (EAP-TLS) is a well-supported wireless authentication protocol since it was the first EAP method to be certified by the http://www.wi-fi.org/[Wi-Fi Alliance]. EAP-TLS requires three certificates to run: the certificate of the Certificate Authority (CA) installed on all machines, the server certificate for the authentication server, and one client certificate for each wireless client. In this EAP method, both the authentication server and wireless client authenticate each other by presenting their respective certificates, and then verify that these certificates were signed by the organization's CA. As previously, the configuration is done via [.filename]#/etc/wpa_supplicant.conf#: [.programlisting] .... network={ ssid="freebsdap" <.> proto=RSN <.> key_mgmt=WPA-EAP <.> eap=TLS <.> identity="loader" <.> ca_cert="/etc/certs/cacert.pem" <.> client_cert="/etc/certs/clientcert.pem" <.> private_key="/etc/certs/clientkey.pem" <.> private_key_passwd="freebsdmallclient" <.> } .... <.> This field indicates the network name (SSID). <.> This example uses the RSN IEEE(R) 802.11i protocol, also known as WPA2. <.> The `key_mgmt` line refers to the key management protocol to use. In this example, it is WPA using EAP authentication. <.> This field indicates the EAP method for the connection. <.> The `identity` field contains the identity string for EAP. <.> The `ca_cert` field indicates the pathname of the CA certificate file. This file is needed to verify the server certificate. <.> The `client_cert` line gives the pathname to the client certificate file. This certificate is unique to each wireless client of the network. <.> The `private_key` field is the pathname to the client certificate private key file. <.> The `private_key_passwd` field contains the passphrase for the private key. Then, add the following lines to [.filename]#/etc/rc.conf#: [.programlisting] .... wlans_ath0="wlan0" ifconfig_wlan0="WPA DHCP" .... The next step is to bring up the interface: [source,shell] .... # service netif start Starting wpa_supplicant. DHCPREQUEST on wlan0 to 255.255.255.255 port 67 interval 7 DHCPREQUEST on wlan0 to 255.255.255.255 port 67 interval 15 DHCPACK from 192.168.0.20 bound to 192.168.0.254 -- renewal in 300 seconds. wlan0: flags=8843 mtu 1500 ether 00:11:95:d5:43:62 inet 192.168.0.254 netmask 0xffffff00 broadcast 192.168.0.255 media: IEEE 802.11 Wireless Ethernet DS/11Mbps mode 11g status: associated ssid freebsdap channel 1 (2412 Mhz 11g) bssid 00:11:95:c3:0d:ac country US ecm authmode WPA2/802.11i privacy ON deftxkey UNDEF AES-CCM 3:128-bit txpower 21.5 bmiss 7 scanvalid 450 bgscan bgscanintvl 300 bgscanidle 250 roam:rssi 7 roam:rate 5 protmode CTS wme burst roaming MANUAL .... It is also possible to bring up the interface manually using man:wpa_supplicant[8] and man:ifconfig[8]. [[network-wireless-wpa-eap-ttls]] === WPA with EAP-TTLS With EAP-TLS, both the authentication server and the client need a certificate. With EAP-TTLS, a client certificate is optional. This method is similar to a web server which creates a secure SSL tunnel even if visitors do not have client-side certificates. EAP-TTLS uses an encrypted TLS tunnel for safe transport of the authentication data. The required configuration can be added to [.filename]#/etc/wpa_supplicant.conf#: [.programlisting] .... network={ ssid="freebsdap" proto=RSN key_mgmt=WPA-EAP eap=TTLS <.> identity="test" <.> password="test" <.> ca_cert="/etc/certs/cacert.pem" <.> phase2="auth=MD5" <.> } .... <.> This field specifies the EAP method for the connection. <.> The `identity` field contains the identity string for EAP authentication inside the encrypted TLS tunnel. <.> The `password` field contains the passphrase for the EAP authentication. <.> The `ca_cert` field indicates the pathname of the CA certificate file. This file is needed to verify the server certificate. <.> This field specifies the authentication method used in the encrypted TLS tunnel. In this example, EAP with MD5-Challenge is used. The "inner authentication" phase is often called "phase2". Next, add the following lines to [.filename]#/etc/rc.conf#: [.programlisting] .... wlans_ath0="wlan0" ifconfig_wlan0="WPA DHCP" .... The next step is to bring up the interface: [source,shell] .... # service netif start Starting wpa_supplicant. DHCPREQUEST on wlan0 to 255.255.255.255 port 67 interval 7 DHCPREQUEST on wlan0 to 255.255.255.255 port 67 interval 15 DHCPREQUEST on wlan0 to 255.255.255.255 port 67 interval 21 DHCPACK from 192.168.0.20 bound to 192.168.0.254 -- renewal in 300 seconds. wlan0: flags=8843 mtu 1500 ether 00:11:95:d5:43:62 inet 192.168.0.254 netmask 0xffffff00 broadcast 192.168.0.255 media: IEEE 802.11 Wireless Ethernet DS/11Mbps mode 11g status: associated ssid freebsdap channel 1 (2412 Mhz 11g) bssid 00:11:95:c3:0d:ac country US ecm authmode WPA2/802.11i privacy ON deftxkey UNDEF AES-CCM 3:128-bit txpower 21.5 bmiss 7 scanvalid 450 bgscan bgscanintvl 300 bgscanidle 250 roam:rssi 7 roam:rate 5 protmode CTS wme burst roaming MANUAL .... [[network-wireless-wpa-eap-peap]] === WPA with EAP-PEAP [NOTE] ==== PEAPv0/EAP-MSCHAPv2 is the most common PEAP method. In this chapter, the term PEAP is used to refer to that method. ==== Protected EAP (PEAP) is designed as an alternative to EAP-TTLS and is the most used EAP standard after EAP-TLS. In a network with mixed operating systems, PEAP should be the most supported standard after EAP-TLS. PEAP is similar to EAP-TTLS as it uses a server-side certificate to authenticate clients by creating an encrypted TLS tunnel between the client and the authentication server, which protects the ensuing exchange of authentication information. PEAP authentication differs from EAP-TTLS as it broadcasts the username in the clear and only the password is sent in the encrypted TLS tunnel. EAP-TTLS will use the TLS tunnel for both the username and password. Add the following lines to [.filename]#/etc/wpa_supplicant.conf# to configure the EAP-PEAP related settings: [.programlisting] .... network={ ssid="freebsdap" proto=RSN key_mgmt=WPA-EAP eap=PEAP <.> identity="test" <.> password="test" <.> ca_cert="/etc/certs/cacert.pem" <.> phase1="peaplabel=0" <.> phase2="auth=MSCHAPV2" <.> } .... <.> This field specifies the EAP method for the connection. <.> The `identity` field contains the identity string for EAP authentication inside the encrypted TLS tunnel. <.> The `password` field contains the passphrase for the EAP authentication. <.> The `ca_cert` field indicates the pathname of the CA certificate file. This file is needed to verify the server certificate. <.> This field contains the parameters for the first phase of authentication, the TLS tunnel. According to the authentication server used, specify a specific label for authentication. Most of the time, the label will be "client EAP encryption" which is set by using `peaplabel=0`. More information can be found in man:wpa_supplicant.conf[5]. <.> This field specifies the authentication protocol used in the encrypted TLS tunnel. In the case of PEAP, it is `auth=MSCHAPV2`. Add the following to [.filename]#/etc/rc.conf#: [.programlisting] .... wlans_ath0="wlan0" ifconfig_wlan0="WPA DHCP" .... Then, bring up the interface: [source,shell] .... # service netif start Starting wpa_supplicant. DHCPREQUEST on wlan0 to 255.255.255.255 port 67 interval 7 DHCPREQUEST on wlan0 to 255.255.255.255 port 67 interval 15 DHCPREQUEST on wlan0 to 255.255.255.255 port 67 interval 21 DHCPACK from 192.168.0.20 bound to 192.168.0.254 -- renewal in 300 seconds. wlan0: flags=8843 mtu 1500 ether 00:11:95:d5:43:62 inet 192.168.0.254 netmask 0xffffff00 broadcast 192.168.0.255 media: IEEE 802.11 Wireless Ethernet DS/11Mbps mode 11g status: associated ssid freebsdap channel 1 (2412 Mhz 11g) bssid 00:11:95:c3:0d:ac country US ecm authmode WPA2/802.11i privacy ON deftxkey UNDEF AES-CCM 3:128-bit txpower 21.5 bmiss 7 scanvalid 450 bgscan bgscanintvl 300 bgscanidle 250 roam:rssi 7 roam:rate 5 protmode CTS wme burst roaming MANUAL .... [[wireless-ad-hoc-mode]] == Wireless Ad-hoc Mode IBSS mode, also called ad-hoc mode, is designed for point to point connections. For example, to establish an ad-hoc network between the machines `A` and `B`, choose two IP addresses and a SSID. On `A`: [source,shell] .... # ifconfig wlan0 create wlandev ath0 wlanmode adhoc # ifconfig wlan0 inet 192.168.0.1 netmask 255.255.255.0 ssid freebsdap # ifconfig wlan0 wlan0: flags=8843 metric 0 mtu 1500 ether 00:11:95:c3:0d:ac inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255 media: IEEE 802.11 Wireless Ethernet autoselect mode 11g status: running ssid freebsdap channel 2 (2417 Mhz 11g) bssid 02:11:95:c3:0d:ac country US ecm authmode OPEN privacy OFF txpower 21.5 scanvalid 60 protmode CTS wme burst .... The `adhoc` parameter indicates that the interface is running in IBSS mode. `B` should now be able to detect `A`: [source,shell] .... # ifconfig wlan0 create wlandev ath0 wlanmode adhoc # ifconfig wlan0 up scan SSID/MESH ID BSSID CHAN RATE S:N INT CAPS freebsdap 02:11:95:c3:0d:ac 2 54M -64:-96 100 IS WME .... The `I` in the output confirms that `A` is in ad-hoc mode. Now, configure `B` with a different IP address: [source,shell] .... # ifconfig wlan0 inet 192.168.0.2 netmask 255.255.255.0 ssid freebsdap # ifconfig wlan0 wlan0: flags=8843 metric 0 mtu 1500 ether 00:11:95:d5:43:62 inet 192.168.0.2 netmask 0xffffff00 broadcast 192.168.0.255 media: IEEE 802.11 Wireless Ethernet autoselect mode 11g status: running ssid freebsdap channel 2 (2417 Mhz 11g) bssid 02:11:95:c3:0d:ac country US ecm authmode OPEN privacy OFF txpower 21.5 scanvalid 60 protmode CTS wme burst .... Both `A` and `B` are now ready to exchange information. [[network-wireless-ap]] === FreeBSD Host Access Points FreeBSD can act as an Access Point (AP) which eliminates the need to buy a hardware AP or run an ad-hoc network. This can be particularly useful when a FreeBSD machine is acting as a gateway to another network such as the Internet. [[network-wireless-ap-basic]] ==== Basic Settings Before configuring a FreeBSD machine as an AP, the kernel must be configured with the appropriate networking support for the wireless card as well as the security protocols being used. For more details, see crossref:advanced-networking[network-wireless-basic]. [NOTE] ==== The NDIS driver wrapper for Windows(R) drivers does not currently support AP operation. Only native FreeBSD wireless drivers support AP mode. ==== Once wireless networking support is loaded, check if the wireless device supports the host-based access point mode, also known as hostap mode: [source,shell] .... # ifconfig wlan0 create wlandev ath0 # ifconfig wlan0 list caps drivercaps=6f85edc1 cryptocaps=1f .... This output displays the card's capabilities. The `HOSTAP` word confirms that this wireless card can act as an AP. Various supported ciphers are also listed: WEP, TKIP, and AES. This information indicates which security protocols can be used on the AP. The wireless device can only be put into hostap mode during the creation of the network pseudo-device, so a previously created device must be destroyed first: [source,shell] .... # ifconfig wlan0 destroy .... then regenerated with the correct option before setting the other parameters: [source,shell] .... # ifconfig wlan0 create wlandev ath0 wlanmode hostap # ifconfig wlan0 inet 192.168.0.1 netmask 255.255.255.0 ssid freebsdap mode 11g channel 1 .... Use man:ifconfig[8] again to see the status of the [.filename]#wlan0# interface: [source,shell] .... # ifconfig wlan0 wlan0: flags=8843 metric 0 mtu 1500 ether 00:11:95:c3:0d:ac inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255 media: IEEE 802.11 Wireless Ethernet autoselect mode 11g status: running ssid freebsdap channel 1 (2412 Mhz 11g) bssid 00:11:95:c3:0d:ac country US ecm authmode OPEN privacy OFF txpower 21.5 scanvalid 60 protmode CTS wme burst dtimperiod 1 -dfs .... The `hostap` parameter indicates the interface is running in the host-based access point mode. The interface configuration can be done automatically at boot time by adding the following lines to [.filename]#/etc/rc.conf#: [.programlisting] .... wlans_ath0="wlan0" create_args_wlan0="wlanmode hostap" ifconfig_wlan0="inet 192.168.0.1 netmask 255.255.255.0 ssid freebsdap mode 11g channel 1" .... ==== Host-based Access Point Without Authentication or Encryption Although it is not recommended to run an AP without any authentication or encryption, this is a simple way to check if the AP is working. This configuration is also important for debugging client issues. Once the AP is configured, initiate a scan from another wireless machine to find the AP: [source,shell] .... # ifconfig wlan0 create wlandev ath0 # ifconfig wlan0 up scan SSID/MESH ID BSSID CHAN RATE S:N INT CAPS freebsdap 00:11:95:c3:0d:ac 1 54M -66:-96 100 ES WME .... The client machine found the AP and can be associated with it: [source,shell] .... # ifconfig wlan0 inet 192.168.0.2 netmask 255.255.255.0 ssid freebsdap # ifconfig wlan0 wlan0: flags=8843 metric 0 mtu 1500 ether 00:11:95:d5:43:62 inet 192.168.0.2 netmask 0xffffff00 broadcast 192.168.0.255 media: IEEE 802.11 Wireless Ethernet OFDM/54Mbps mode 11g status: associated ssid freebsdap channel 1 (2412 Mhz 11g) bssid 00:11:95:c3:0d:ac country US ecm authmode OPEN privacy OFF txpower 21.5 bmiss 7 scanvalid 60 bgscan bgscanintvl 300 bgscanidle 250 roam:rssi 7 roam:rate 5 protmode CTS wme burst .... [[network-wireless-ap-wpa]] ==== WPA2 Host-based Access Point This section focuses on setting up a FreeBSD access point using the WPA2 security protocol. More details regarding WPA and the configuration of WPA-based wireless clients can be found in crossref:advanced-networking[network-wireless-wpa]. The man:hostapd[8] daemon is used to deal with client authentication and key management on the WPA2-enabled AP. The following configuration operations are performed on the FreeBSD machine acting as the AP. Once the AP is correctly working, man:hostapd[8] can be automatically started at boot with this line in [.filename]#/etc/rc.conf#: [.programlisting] .... hostapd_enable="YES" .... Before trying to configure man:hostapd[8], first configure the basic settings -introduced in crossref:advanced-networking[network-wireless-ap-basic]. +introduced in crossref:advanced-networking[network-wireless-ap-basic, Basic Settings]. ===== WPA2-PSK WPA2-PSK is intended for small networks where the use of a backend authentication server is not possible or desired. The configuration is done in [.filename]#/etc/hostapd.conf#: [.programlisting] .... interface=wlan0 <.> debug=1 <.> ctrl_interface=/var/run/hostapd <.> ctrl_interface_group=wheel <.> ssid=freebsdap <.> wpa=2 <.> wpa_passphrase=freebsdmall <.> wpa_key_mgmt=WPA-PSK <.> wpa_pairwise=CCMP <.> .... <.> Wireless interface used for the access point. <.> Level of verbosity used during the execution of man:hostapd[8]. A value of `1` represents the minimal level. <.> Pathname of the directory used by man:hostapd[8] to store domain socket files for communication with external programs such as man:hostapd_cli[8]. The default value is used in this example. <.> The group allowed to access the control interface files. <.> The wireless network name, or SSID, that will appear in wireless scans. <.> Enable WPA and specify which WPA authentication protocol will be required. A value of `2` configures the AP for WPA2 and is recommended. Set to `1` only if the obsolete WPA is required. <.> ASCII passphrase for WPA authentication. <.> The key management protocol to use. This example sets WPA-PSK. <.> Encryption algorithms accepted by the access point. In this example, only the CCMP (AES) cipher is accepted. CCMP is an alternative to TKIP and is strongly preferred when possible. TKIP should be allowed only when there are stations incapable of using CCMP. The next step is to start man:hostapd[8]: [source,shell] .... # service hostapd forcestart .... [source,shell] .... # ifconfig wlan0 wlan0: flags=8943 metric 0 mtu 1500 ether 04:f0:21:16:8e:10 inet6 fe80::6f0:21ff:fe16:8e10%wlan0 prefixlen 64 scopeid 0x9 nd6 options=21 media: IEEE 802.11 Wireless Ethernet autoselect mode 11na status: running ssid No5ignal channel 36 (5180 MHz 11a ht/40+) bssid 04:f0:21:16:8e:10 country US ecm authmode WPA2/802.11i privacy MIXED deftxkey 2 AES-CCM 2:128-bit AES-CCM 3:128-bit txpower 17 mcastrate 6 mgmtrate 6 scanvalid 60 ampdulimit 64k ampdudensity 8 shortgi wme burst dtimperiod 1 -dfs groups: wlan .... Once the AP is running, the clients can associate with it. See crossref:advanced-networking[network-wireless-wpa] for more details. It is possible to see the stations associated with the AP using `ifconfig _wlan0_ list sta`. [[network-usb-tethering]] == USB Tethering Many cellphones provide the option to share their data connection over USB (often called "tethering"). This feature uses one of RNDIS, CDC, or a custom Apple(R) iPhone(R)/iPad(R) protocol. * Android(TM) devices generally use the man:urndis[4] driver. * Apple(R) devices use the man:ipheth[4] driver. * Older devices will often use the man:cdce[4] driver. Before attaching a device, load the appropriate driver into the kernel: [source,shell] .... # kldload if_urndis # kldload if_cdce # kldload if_ipheth .... Once the device is attached ``ue``_0_ will be available for use like a normal network device. Be sure that the "USB tethering" option is enabled on the device. To make this change permanent and load the driver as a module at boot time, place the appropriate line of the following in [.filename]#/boot/loader.conf#: [source,shell] .... if_urndis_load="YES" if_cdce_load="YES" if_ipheth_load="YES" .... [[network-bluetooth]] == Bluetooth Bluetooth is a wireless technology for creating personal networks operating in the 2.4 GHz unlicensed band, with a range of 10 meters. Networks are usually formed ad-hoc from portable devices such as cellular phones, handhelds, and laptops. Unlike Wi-Fi wireless technology, Bluetooth offers higher level service profiles, such as FTP-like file servers, file pushing, voice transport, serial line emulation, and more. This section describes the use of a USB Bluetooth dongle on a FreeBSD system. It then describes the various Bluetooth protocols and utilities. === Loading Bluetooth Support The Bluetooth stack in FreeBSD is implemented using the man:netgraph[4] framework. A broad variety of Bluetooth USB dongles is supported by man:ng_ubt[4]. Broadcom BCM2033 based Bluetooth devices are supported by the man:ubtbcmfw[4] and man:ng_ubt[4] drivers. The 3Com Bluetooth PC Card 3CRWB60-A is supported by the man:ng_bt3c[4] driver. Serial and UART based Bluetooth devices are supported by man:sio[4], man:ng_h4[4], and man:hcseriald[8]. Before attaching a device, determine which of the above drivers it uses, then load the driver. For example, if the device uses the man:ng_ubt[4] driver: [source,shell] .... # kldload ng_ubt .... If the Bluetooth device will be attached to the system during system startup, the system can be configured to load the module at boot time by adding the driver to [.filename]#/boot/loader.conf#: [.programlisting] .... ng_ubt_load="YES" .... Once the driver is loaded, plug in the USB dongle. If the driver load was successful, output similar to the following should appear on the console and in [.filename]#/var/log/messages#: [source,shell] .... ubt0: vendor 0x0a12 product 0x0001, rev 1.10/5.25, addr 2 ubt0: Interface 0 endpoints: interrupt=0x81, bulk-in=0x82, bulk-out=0x2 ubt0: Interface 1 (alt.config 5) endpoints: isoc-in=0x83, isoc-out=0x3, wMaxPacketSize=49, nframes=6, buffer size=294 .... To start and stop the Bluetooth stack, use its startup script. It is a good idea to stop the stack before unplugging the device. Starting the bluetooth stack might require man:hcsecd[8] to be started. When starting the stack, the output should be similar to the following: [source,shell] .... # service bluetooth start ubt0 BD_ADDR: 00:02:72:00:d4:1a Features: 0xff 0xff 0xf 00 00 00 00 00 <3-Slot> <5-Slot> Max. ACL packet size: 192 bytes Number of ACL packets: 8 Max. SCO packet size: 64 bytes Number of SCO packets: 8 .... === Finding Other Bluetooth Devices The Host Controller Interface (HCI) provides a uniform method for accessing Bluetooth baseband capabilities. In FreeBSD, a netgraph HCI node is created for each Bluetooth device. For more details, refer to man:ng_hci[4]. One of the most common tasks is discovery of Bluetooth devices within RF proximity. This operation is called _inquiry_. Inquiry and other HCI related operations are done using man:hccontrol[8]. The example below shows how to find out which Bluetooth devices are in range. The list of devices should be displayed in a few seconds. Note that a remote device will only answer the inquiry if it is set to _discoverable_ mode. [source,shell] .... % hccontrol -n ubt0hci inquiry Inquiry result, num_responses=1 Inquiry result #0 BD_ADDR: 00:80:37:29:19:a4 Page Scan Rep. Mode: 0x1 Page Scan Period Mode: 00 Page Scan Mode: 00 Class: 52:02:04 Clock offset: 0x78ef Inquiry complete. Status: No error [00] .... The `BD_ADDR` is the unique address of a Bluetooth device, similar to the MAC address of a network card. This address is needed for further communication with a device and it is possible to assign a human readable name to a `BD_ADDR`. Information regarding the known Bluetooth hosts is contained in [.filename]#/etc/bluetooth/hosts#. The following example shows how to obtain the human readable name that was assigned to the remote device: [source,shell] .... % hccontrol -n ubt0hci remote_name_request 00:80:37:29:19:a4 BD_ADDR: 00:80:37:29:19:a4 Name: Pav's T39 .... If an inquiry is performed on a remote Bluetooth device, it will find the computer as "your.host.name (ubt0)". The name assigned to the local device can be changed at any time. Remote devices can be assigned aliases in [.filename]#/etc/bluetooth/hosts#. More information about [.filename]#/etc/bluetooth/hosts# file might be found in man:bluetooth.hosts[5]. The Bluetooth system provides a point-to-point connection between two Bluetooth units, or a point-to-multipoint connection which is shared among several Bluetooth devices. The following example shows how to create a connection to a remote device: [source,shell] .... % hccontrol -n ubt0hci create_connection BT_ADDR .... `create_connection` accepts `BT_ADDR` as well as host aliases in [.filename]#/etc/bluetooth/hosts#. The following example shows how to obtain the list of active baseband connections for the local device: [source,shell] .... % hccontrol -n ubt0hci read_connection_list Remote BD_ADDR Handle Type Mode Role Encrypt Pending Queue State 00:80:37:29:19:a4 41 ACL 0 MAST NONE 0 0 OPEN .... A _connection handle_ is useful when termination of the baseband connection is required, though it is normally not required to do this by hand. The stack will automatically terminate inactive baseband connections. [source,shell] .... # hccontrol -n ubt0hci disconnect 41 Connection handle: 41 Reason: Connection terminated by local host [0x16] .... Type `hccontrol help` for a complete listing of available HCI commands. Most of the HCI commands do not require superuser privileges. === Device Pairing By default, Bluetooth communication is not authenticated, and any device can talk to any other device. A Bluetooth device, such as a cellular phone, may choose to require authentication to provide a particular service. Bluetooth authentication is normally done with a _PIN code_, an ASCII string up to 16 characters in length. The user is required to enter the same PIN code on both devices. Once the user has entered the PIN code, both devices will generate a _link key_. After that, the link key can be stored either in the devices or in a persistent storage. Next time, both devices will use the previously generated link key. This procedure is called _pairing_. Note that if the link key is lost by either device, the pairing must be repeated. The man:hcsecd[8] daemon is responsible for handling Bluetooth authentication requests. The default configuration file is [.filename]#/etc/bluetooth/hcsecd.conf#. An example section for a cellular phone with the PIN code set to `1234` is shown below: [.programlisting] .... device { bdaddr 00:80:37:29:19:a4; name "Pav's T39"; key nokey; pin "1234"; } .... The only limitation on PIN codes is length. Some devices, such as Bluetooth headsets, may have a fixed PIN code built in. The `-d` switch forces man:hcsecd[8] to stay in the foreground, so it is easy to see what is happening. Set the remote device to receive pairing and initiate the Bluetooth connection to the remote device. The remote device should indicate that pairing was accepted and request the PIN code. Enter the same PIN code listed in [.filename]#hcsecd.conf#. Now the computer and the remote device are paired. Alternatively, pairing can be initiated on the remote device. The following line can be added to [.filename]#/etc/rc.conf# to configure man:hcsecd[8] to start automatically on system start: [.programlisting] .... hcsecd_enable="YES" .... The following is a sample of the man:hcsecd[8] daemon output: [.programlisting] .... hcsecd[16484]: Got Link_Key_Request event from 'ubt0hci', remote bdaddr 0:80:37:29:19:a4 hcsecd[16484]: Found matching entry, remote bdaddr 0:80:37:29:19:a4, name 'Pav's T39', link key doesn't exist hcsecd[16484]: Sending Link_Key_Negative_Reply to 'ubt0hci' for remote bdaddr 0:80:37:29:19:a4 hcsecd[16484]: Got PIN_Code_Request event from 'ubt0hci', remote bdaddr 0:80:37:29:19:a4 hcsecd[16484]: Found matching entry, remote bdaddr 0:80:37:29:19:a4, name 'Pav's T39', PIN code exists hcsecd[16484]: Sending PIN_Code_Reply to 'ubt0hci' for remote bdaddr 0:80:37:29:19:a4 .... === Network Access with PPP Profiles A Dial-Up Networking (DUN) profile can be used to configure a cellular phone as a wireless modem for connecting to a dial-up Internet access server. It can also be used to configure a computer to receive data calls from a cellular phone. Network access with a PPP profile can be used to provide LAN access for a single Bluetooth device or multiple Bluetooth devices. It can also provide PC to PC connection using PPP networking over serial cable emulation. In FreeBSD, these profiles are implemented with man:ppp[8] and the man:rfcomm_pppd[8] wrapper which converts a Bluetooth connection into something PPP can use. Before a profile can be used, a new PPP label must be created in [.filename]#/etc/ppp/ppp.conf#. Consult man:rfcomm_pppd[8] for examples. In this example, man:rfcomm_pppd[8] is used to open a connection to a remote device with a `BD_ADDR` of `00:80:37:29:19:a4` on a DUNRFCOMM channel: [source,shell] .... # rfcomm_pppd -a 00:80:37:29:19:a4 -c -C dun -l rfcomm-dialup .... The actual channel number will be obtained from the remote device using the SDP protocol. It is possible to specify the RFCOMM channel by hand, and in this case man:rfcomm_pppd[8] will not perform the SDP query. Use man:sdpcontrol[8] to find out the RFCOMM channel on the remote device. In order to provide network access with the PPPLAN service, man:sdpd[8] must be running and a new entry for LAN clients must be created in [.filename]#/etc/ppp/ppp.conf#. Consult man:rfcomm_pppd[8] for examples. Finally, start the RFCOMMPPP server on a valid RFCOMM channel number. The RFCOMMPPP server will automatically register the Bluetooth LAN service with the local SDP daemon. The example below shows how to start the RFCOMMPPP server. [source,shell] .... # rfcomm_pppd -s -C 7 -l rfcomm-server .... === Bluetooth Protocols This section provides an overview of the various Bluetooth protocols, their function, and associated utilities. ==== Logical Link Control and Adaptation Protocol (L2CAP) The Logical Link Control and Adaptation Protocol (L2CAP) provides connection-oriented and connectionless data services to upper layer protocols. L2CAP permits higher level protocols and applications to transmit and receive L2CAP data packets up to 64 kilobytes in length. L2CAP is based around the concept of _channels_. A channel is a logical connection on top of a baseband connection, where each channel is bound to a single protocol in a many-to-one fashion. Multiple channels can be bound to the same protocol, but a channel cannot be bound to multiple protocols. Each L2CAP packet received on a channel is directed to the appropriate higher level protocol. Multiple channels can share the same baseband connection. In FreeBSD, a netgraph L2CAP node is created for each Bluetooth device. This node is normally connected to the downstream Bluetooth HCI node and upstream Bluetooth socket nodes. The default name for the L2CAP node is "devicel2cap". For more details refer to man:ng_l2cap[4]. A useful command is man:l2ping[8], which can be used to ping other devices. Some Bluetooth implementations might not return all of the data sent to them, so `0 bytes` in the following example is normal. [source,shell] .... # l2ping -a 00:80:37:29:19:a4 0 bytes from 0:80:37:29:19:a4 seq_no=0 time=48.633 ms result=0 0 bytes from 0:80:37:29:19:a4 seq_no=1 time=37.551 ms result=0 0 bytes from 0:80:37:29:19:a4 seq_no=2 time=28.324 ms result=0 0 bytes from 0:80:37:29:19:a4 seq_no=3 time=46.150 ms result=0 .... The man:l2control[8] utility is used to perform various operations on L2CAP nodes. This example shows how to obtain the list of logical connections (channels) and the list of baseband connections for the local device: [source,shell] .... % l2control -a 00:02:72:00:d4:1a read_channel_list L2CAP channels: Remote BD_ADDR SCID/ DCID PSM IMTU/ OMTU State 00:07:e0:00:0b:ca 66/ 64 3 132/ 672 OPEN % l2control -a 00:02:72:00:d4:1a read_connection_list L2CAP connections: Remote BD_ADDR Handle Flags Pending State 00:07:e0:00:0b:ca 41 O 0 OPEN .... Another diagnostic tool is man:btsockstat[1]. It is similar to man:netstat[1], but for Bluetooth network-related data structures. The example below shows the same logical connection as man:l2control[8] above. [source,shell] .... % btsockstat Active L2CAP sockets PCB Recv-Q Send-Q Local address/PSM Foreign address CID State c2afe900 0 0 00:02:72:00:d4:1a/3 00:07:e0:00:0b:ca 66 OPEN Active RFCOMM sessions L2PCB PCB Flag MTU Out-Q DLCs State c2afe900 c2b53380 1 127 0 Yes OPEN Active RFCOMM sockets PCB Recv-Q Send-Q Local address Foreign address Chan DLCI State c2e8bc80 0 250 00:02:72:00:d4:1a 00:07:e0:00:0b:ca 3 6 OPEN .... ==== Radio Frequency Communication (RFCOMM) The RFCOMM protocol provides emulation of serial ports over the L2CAP protocol. RFCOMM is a simple transport protocol, with additional provisions for emulating the 9 circuits of RS-232 (EIATIA-232-E) serial ports. It supports up to 60 simultaneous connections (RFCOMM channels) between two Bluetooth devices. For the purposes of RFCOMM, a complete communication path involves two applications running on the communication endpoints with a communication segment between them. RFCOMM is intended to cover applications that make use of the serial ports of the devices in which they reside. The communication segment is a direct connect Bluetooth link from one device to another. RFCOMM is only concerned with the connection between the devices in the direct connect case, or between the device and a modem in the network case. RFCOMM can support other configurations, such as modules that communicate via Bluetooth wireless technology on one side and provide a wired interface on the other side. In FreeBSD, RFCOMM is implemented at the Bluetooth sockets layer. ==== Service Discovery Protocol (SDP) The Service Discovery Protocol (SDP) provides the means for client applications to discover the existence of services provided by server applications as well as the attributes of those services. The attributes of a service include the type or class of service offered and the mechanism or protocol information needed to utilize the service. SDP involves communication between a SDP server and a SDP client. The server maintains a list of service records that describe the characteristics of services associated with the server. Each service record contains information about a single service. A client may retrieve information from a service record maintained by the SDP server by issuing a SDP request. If the client, or an application associated with the client, decides to use a service, it must open a separate connection to the service provider in order to utilize the service. SDP provides a mechanism for discovering services and their attributes, but it does not provide a mechanism for utilizing those services. Normally, a SDP client searches for services based on some desired characteristics of the services. However, there are times when it is desirable to discover which types of services are described by an SDP server's service records without any prior information about the services. This process of looking for any offered services is called _browsing_. The Bluetooth SDP server, man:sdpd[8], and command line client, man:sdpcontrol[8], are included in the standard FreeBSD installation. The following example shows how to perform a SDP browse query. [source,shell] .... % sdpcontrol -a 00:01:03:fc:6e:ec browse Record Handle: 00000000 Service Class ID List: Service Discovery Server (0x1000) Protocol Descriptor List: L2CAP (0x0100) Protocol specific parameter #1: u/int/uuid16 1 Protocol specific parameter #2: u/int/uuid16 1 Record Handle: 0x00000001 Service Class ID List: Browse Group Descriptor (0x1001) Record Handle: 0x00000002 Service Class ID List: LAN Access Using PPP (0x1102) Protocol Descriptor List: L2CAP (0x0100) RFCOMM (0x0003) Protocol specific parameter #1: u/int8/bool 1 Bluetooth Profile Descriptor List: LAN Access Using PPP (0x1102) ver. 1.0 .... Note that each service has a list of attributes, such as the RFCOMM channel. Depending on the service, the user might need to make note of some of the attributes. Some Bluetooth implementations do not support service browsing and may return an empty list. In this case, it is possible to search for the specific service. The example below shows how to search for the OBEX Object Push (OPUSH) service: [source,shell] .... % sdpcontrol -a 00:01:03:fc:6e:ec search OPUSH .... Offering services on FreeBSD to Bluetooth clients is done with the man:sdpd[8] server. The following line can be added to [.filename]#/etc/rc.conf#: [.programlisting] .... sdpd_enable="YES" .... Then the man:sdpd[8] daemon can be started with: [source,shell] .... # service sdpd start .... The local server application that wants to provide a Bluetooth service to remote clients will register the service with the local SDP daemon. An example of such an application is man:rfcomm_pppd[8]. Once started, it will register the Bluetooth LAN service with the local SDP daemon. The list of services registered with the local SDP server can be obtained by issuing a SDP browse query via the local control channel: [source,shell] .... # sdpcontrol -l browse .... ==== OBEX Object Push (OPUSH) Object Exchange (OBEX) is a widely used protocol for simple file transfers between mobile devices. Its main use is in infrared communication, where it is used for generic file transfers between notebooks or PDAs, and for sending business cards or calendar entries between cellular phones and other devices with Personal Information Manager (PIM) applications. The OBEX server and client are implemented by obexapp, which can be installed using the package:comms/obexapp[] package or port. The OBEX client is used to push and/or pull objects from the OBEX server. An example object is a business card or an appointment. The OBEX client can obtain the RFCOMM channel number from the remote device via SDP. This can be done by specifying the service name instead of the RFCOMM channel number. Supported service names are: `IrMC`, `FTRN`, and `OPUSH`. It is also possible to specify the RFCOMM channel as a number. Below is an example of an OBEX session where the device information object is pulled from the cellular phone, and a new object, the business card, is pushed into the phone's directory. [source,shell] .... % obexapp -a 00:80:37:29:19:a4 -C IrMC obex> get telecom/devinfo.txt devinfo-t39.txt Success, response: OK, Success (0x20) obex> put new.vcf Success, response: OK, Success (0x20) obex> di Success, response: OK, Success (0x20) .... In order to provide the OPUSH service, man:sdpd[8] must be running and a root folder, where all incoming objects will be stored, must be created. The default path to the root folder is [.filename]#/var/spool/obex#. Finally, start the OBEX server on a valid RFCOMM channel number. The OBEX server will automatically register the OPUSH service with the local SDP daemon. The example below shows how to start the OBEX server. [source,shell] .... # obexapp -s -C 10 .... ==== Serial Port Profile (SPP) The Serial Port Profile (SPP) allows Bluetooth devices to perform serial cable emulation. This profile allows legacy applications to use Bluetooth as a cable replacement, through a virtual serial port abstraction. In FreeBSD, man:rfcomm_sppd[1] implements SPP and a pseudo tty is used as a virtual serial port abstraction. The example below shows how to connect to a remote device's serial port service. A RFCOMM channel does not have to be specified as man:rfcomm_sppd[1] can obtain it from the remote device via SDP. To override this, specify a RFCOMM channel on the command line. [source,shell] .... # rfcomm_sppd -a 00:07:E0:00:0B:CA -t rfcomm_sppd[94692]: Starting on /dev/pts/6... /dev/pts/6 .... Once connected, the pseudo tty can be used as serial port: [source,shell] .... # cu -l /dev/pts/6 .... The pseudo tty is printed on stdout and can be read by wrapper scripts: [.programlisting] .... PTS=`rfcomm_sppd -a 00:07:E0:00:0B:CA -t` cu -l $PTS .... === Troubleshooting By default, when FreeBSD is accepting a new connection, it tries to perform a role switch and become master. Some older Bluetooth devices which do not support role switching will not be able to connect. Since role switching is performed when a new connection is being established, it is not possible to ask the remote device if it supports role switching. However, there is a HCI option to disable role switching on the local side: [source,shell] .... # hccontrol -n ubt0hci write_node_role_switch 0 .... To display Bluetooth packets, use the third-party package hcidump, which can be installed using the package:comms/hcidump[] package or port. This utility is similar to man:tcpdump[1] and can be used to display the contents of Bluetooth packets on the terminal and to dump the Bluetooth packets to a file. [[network-bridging]] == Bridging It is sometimes useful to divide a network, such as an Ethernet segment, into network segments without having to create IP subnets and use a router to connect the segments together. A device that connects two networks together in this fashion is called a "bridge". A bridge works by learning the MAC addresses of the devices on each of its network interfaces. It forwards traffic between networks only when the source and destination MAC addresses are on different networks. In many respects, a bridge is like an Ethernet switch with very few ports. A FreeBSD system with multiple network interfaces can be configured to act as a bridge. Bridging can be useful in the following situations: Connecting Networks:: The basic operation of a bridge is to join two or more network segments. There are many reasons to use a host-based bridge instead of networking equipment, such as cabling constraints or firewalling. A bridge can also connect a wireless interface running in hostap mode to a wired network and act as an access point. Filtering/Traffic Shaping Firewall:: A bridge can be used when firewall functionality is needed without routing or Network Address Translation (NAT). + An example is a small company that is connected via DSL or ISDN to an ISP. There are thirteen public IP addresses from the ISP and ten computers on the network. In this situation, using a router-based firewall is difficult because of subnetting issues. A bridge-based firewall can be configured without any IP addressing issues. Network Tap:: A bridge can join two network segments in order to inspect all Ethernet frames that pass between them using man:bpf[4] and man:tcpdump[1] on the bridge interface, or by sending a copy of all frames out on an additional interface known as a span port. Layer 2 VPN:: Two Ethernet networks can be joined across an IP link by bridging the networks to an EtherIP tunnel or a man:tap[4] based solution such as OpenVPN. Layer 2 Redundancy:: A network can be connected together with multiple links and use the Spanning Tree Protocol (STP) to block redundant paths. This section describes how to configure a FreeBSD system as a bridge using man:if_bridge[4]. A netgraph bridging driver is also available, and is described in man:ng_bridge[4]. [NOTE] ==== Packet filtering can be used with any firewall package that hooks into the man:pfil[9] framework. The bridge can be used as a traffic shaper with man:altq[4] or man:dummynet[4]. ==== === Enabling the Bridge In FreeBSD, man:if_bridge[4] is a kernel module which is automatically loaded by man:ifconfig[8] when creating a bridge interface. It is also possible to compile bridge support into a custom kernel by adding `device if_bridge` to the custom kernel configuration file. The bridge is created using interface cloning. To create the bridge interface: [source,shell] .... # ifconfig bridge create bridge0 # ifconfig bridge0 bridge0: flags=8802 metric 0 mtu 1500 ether 96:3d:4b:f1:79:7a id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200 root id 00:00:00:00:00:00 priority 0 ifcost 0 port 0 .... When a bridge interface is created, it is automatically assigned a randomly generated Ethernet address. The `maxaddr` and `timeout` parameters control how many MAC addresses the bridge will keep in its forwarding table and how many seconds before each entry is removed after it is last seen. The other parameters control how STP operates. Next, specify which network interfaces to add as members of the bridge. For the bridge to forward packets, all member interfaces and the bridge need to be up: [source,shell] .... # ifconfig bridge0 addm fxp0 addm fxp1 up # ifconfig fxp0 up # ifconfig fxp1 up .... The bridge can now forward Ethernet frames between [.filename]#fxp0# and [.filename]#fxp1#. Add the following lines to [.filename]#/etc/rc.conf# so the bridge is created at startup: [.programlisting] .... cloned_interfaces="bridge0" ifconfig_bridge0="addm fxp0 addm fxp1 up" ifconfig_fxp0="up" ifconfig_fxp1="up" .... If the bridge host needs an IP address, set it on the bridge interface, not on the member interfaces. The address can be set statically or via DHCP. This example sets a static IP address: [source,shell] .... # ifconfig bridge0 inet 192.168.0.1/24 .... It is also possible to assign an IPv6 address to a bridge interface. To make the changes permanent, add the addressing information to [.filename]#/etc/rc.conf#. [NOTE] ==== When packet filtering is enabled, bridged packets will pass through the filter inbound on the originating interface on the bridge interface, and outbound on the appropriate interfaces. Either stage can be disabled. When direction of the packet flow is important, it is best to firewall on the member interfaces rather than the bridge itself. The bridge has several configurable settings for passing non-IP and IP packets, and layer2 firewalling with man:ipfw[8]. See man:if_bridge[4] for more information. ==== === Enabling Spanning Tree For an Ethernet network to function properly, only one active path can exist between two devices. The STP protocol detects loops and puts redundant links into a blocked state. Should one of the active links fail, STP calculates a different tree and enables one of the blocked paths to restore connectivity to all points in the network. The Rapid Spanning Tree Protocol (RSTP or 802.1w) provides backwards compatibility with legacy STP. RSTP provides faster convergence and exchanges information with neighboring switches to quickly transition to forwarding mode without creating loops. FreeBSD supports RSTP and STP as operating modes, with RSTP being the default mode. STP can be enabled on member interfaces using man:ifconfig[8]. For a bridge with [.filename]#fxp0# and [.filename]#fxp1# as the current interfaces, enable STP with: [source,shell] .... # ifconfig bridge0 stp fxp0 stp fxp1 bridge0: flags=8843 metric 0 mtu 1500 ether d6:cf:d5:a0:94:6d id 00:01:02:4b:d4:50 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200 root id 00:01:02:4b:d4:50 priority 32768 ifcost 0 port 0 member: fxp0 flags=1c7 port 3 priority 128 path cost 200000 proto rstp role designated state forwarding member: fxp1 flags=1c7 port 4 priority 128 path cost 200000 proto rstp role designated state forwarding .... This bridge has a spanning tree ID of `00:01:02:4b:d4:50` and a priority of `32768`. As the `root id` is the same, it indicates that this is the root bridge for the tree. Another bridge on the network also has STP enabled: [source,shell] .... bridge0: flags=8843 metric 0 mtu 1500 ether 96:3d:4b:f1:79:7a id 00:13:d4:9a:06:7a priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200 root id 00:01:02:4b:d4:50 priority 32768 ifcost 400000 port 4 member: fxp0 flags=1c7 port 4 priority 128 path cost 200000 proto rstp role root state forwarding member: fxp1 flags=1c7 port 5 priority 128 path cost 200000 proto rstp role designated state forwarding .... The line `root id 00:01:02:4b:d4:50 priority 32768 ifcost 400000 port 4` shows that the root bridge is `00:01:02:4b:d4:50` and has a path cost of `400000` from this bridge. The path to the root bridge is via `port 4` which is [.filename]#fxp0#. === Bridge Interface Parameters Several `ifconfig` parameters are unique to bridge interfaces. This section summarizes some common uses for these parameters. The complete list of available parameters is described in man:ifconfig[8]. private:: A private interface does not forward any traffic to any other port that is also designated as a private interface. The traffic is blocked unconditionally so no Ethernet frames will be forwarded, including ARP packets. If traffic needs to be selectively blocked, a firewall should be used instead. span:: A span port transmits a copy of every Ethernet frame received by the bridge. The number of span ports configured on a bridge is unlimited, but if an interface is designated as a span port, it cannot also be used as a regular bridge port. This is most useful for snooping a bridged network passively on another host connected to one of the span ports of the bridge. For example, to send a copy of all frames out the interface named [.filename]#fxp4#: + [source,shell] .... # ifconfig bridge0 span fxp4 .... sticky:: If a bridge member interface is marked as sticky, dynamically learned address entries are treated as static entries in the forwarding cache. Sticky entries are never aged out of the cache or replaced, even if the address is seen on a different interface. This gives the benefit of static address entries without the need to pre-populate the forwarding table. Clients learned on a particular segment of the bridge cannot roam to another segment. + An example of using sticky addresses is to combine the bridge with VLANs in order to isolate customer networks without wasting IP address space. Consider that `CustomerA` is on `vlan100`, `CustomerB` is on `vlan101`, and the bridge has the address `192.168.0.1`: + [source,shell] .... # ifconfig bridge0 addm vlan100 sticky vlan100 addm vlan101 sticky vlan101 # ifconfig bridge0 inet 192.168.0.1/24 .... + In this example, both clients see `192.168.0.1` as their default gateway. Since the bridge cache is sticky, one host cannot spoof the MAC address of the other customer in order to intercept their traffic. + Any communication between the VLANs can be blocked using a firewall or, as seen in this example, private interfaces: + [source,shell] .... # ifconfig bridge0 private vlan100 private vlan101 .... + The customers are completely isolated from each other and the full `/24` address range can be allocated without subnetting. + The number of unique source MAC addresses behind an interface can be limited. Once the limit is reached, packets with unknown source addresses are dropped until an existing host cache entry expires or is removed. + The following example sets the maximum number of Ethernet devices for `CustomerA` on `vlan100` to 10: + [source,shell] .... # ifconfig bridge0 ifmaxaddr vlan100 10 .... Bridge interfaces also support monitor mode, where the packets are discarded after man:bpf[4] processing and are not processed or forwarded further. This can be used to multiplex the input of two or more interfaces into a single man:bpf[4] stream. This is useful for reconstructing the traffic for network taps that transmit the RX/TX signals out through two separate interfaces. For example, to read the input from four network interfaces as one stream: [source,shell] .... # ifconfig bridge0 addm fxp0 addm fxp1 addm fxp2 addm fxp3 monitor up # tcpdump -i bridge0 .... === SNMP Monitoring The bridge interface and STP parameters can be monitored via man:bsnmpd[1] which is included in the FreeBSD base system. The exported bridge MIBs conform to IETF standards so any SNMP client or monitoring package can be used to retrieve the data. To enable monitoring on the bridge, uncomment this line in [.filename]#/etc/snmpd.config# by removing the beginning `+#+` symbol: [.programlisting] .... begemotSnmpdModulePath."bridge" = "/usr/lib/snmp_bridge.so" .... Other configuration settings, such as community names and access lists, may need to be modified in this file. See man:bsnmpd[1] and man:snmp_bridge[3] for more information. Once these edits are saved, add this line to [.filename]#/etc/rc.conf#: [.programlisting] .... bsnmpd_enable="YES" .... Then, start man:bsnmpd[1]: [source,shell] .... # service bsnmpd start .... The following examples use the Net-SNMP software (package:net-mgmt/net-snmp[]) to query a bridge from a client system. The package:net-mgmt/bsnmptools[] port can also be used. From the SNMP client which is running Net-SNMP, add the following lines to [.filename]#$HOME/.snmp/snmp.conf# in order to import the bridge MIB definitions: [.programlisting] .... mibdirs +/usr/share/snmp/mibs mibs +BRIDGE-MIB:RSTP-MIB:BEGEMOT-MIB:BEGEMOT-BRIDGE-MIB .... To monitor a single bridge using the IETF BRIDGE-MIB (RFC4188): [source,shell] .... % snmpwalk -v 2c -c public bridge1.example.com mib-2.dot1dBridge BRIDGE-MIB::dot1dBaseBridgeAddress.0 = STRING: 66:fb:9b:6e:5c:44 BRIDGE-MIB::dot1dBaseNumPorts.0 = INTEGER: 1 ports BRIDGE-MIB::dot1dStpTimeSinceTopologyChange.0 = Timeticks: (189959) 0:31:39.59 centi-seconds BRIDGE-MIB::dot1dStpTopChanges.0 = Counter32: 2 BRIDGE-MIB::dot1dStpDesignatedRoot.0 = Hex-STRING: 80 00 00 01 02 4B D4 50 ... BRIDGE-MIB::dot1dStpPortState.3 = INTEGER: forwarding(5) BRIDGE-MIB::dot1dStpPortEnable.3 = INTEGER: enabled(1) BRIDGE-MIB::dot1dStpPortPathCost.3 = INTEGER: 200000 BRIDGE-MIB::dot1dStpPortDesignatedRoot.3 = Hex-STRING: 80 00 00 01 02 4B D4 50 BRIDGE-MIB::dot1dStpPortDesignatedCost.3 = INTEGER: 0 BRIDGE-MIB::dot1dStpPortDesignatedBridge.3 = Hex-STRING: 80 00 00 01 02 4B D4 50 BRIDGE-MIB::dot1dStpPortDesignatedPort.3 = Hex-STRING: 03 80 BRIDGE-MIB::dot1dStpPortForwardTransitions.3 = Counter32: 1 RSTP-MIB::dot1dStpVersion.0 = INTEGER: rstp(2) .... The `dot1dStpTopChanges.0` value is two, indicating that the STP bridge topology has changed twice. A topology change means that one or more links in the network have changed or failed and a new tree has been calculated. The `dot1dStpTimeSinceTopologyChange.0` value will show when this happened. To monitor multiple bridge interfaces, the private BEGEMOT-BRIDGE-MIB can be used: [source,shell] .... % snmpwalk -v 2c -c public bridge1.example.com enterprises.fokus.begemot.begemotBridge BEGEMOT-BRIDGE-MIB::begemotBridgeBaseName."bridge0" = STRING: bridge0 BEGEMOT-BRIDGE-MIB::begemotBridgeBaseName."bridge2" = STRING: bridge2 BEGEMOT-BRIDGE-MIB::begemotBridgeBaseAddress."bridge0" = STRING: e:ce:3b:5a:9e:13 BEGEMOT-BRIDGE-MIB::begemotBridgeBaseAddress."bridge2" = STRING: 12:5e:4d:74:d:fc BEGEMOT-BRIDGE-MIB::begemotBridgeBaseNumPorts."bridge0" = INTEGER: 1 BEGEMOT-BRIDGE-MIB::begemotBridgeBaseNumPorts."bridge2" = INTEGER: 1 ... BEGEMOT-BRIDGE-MIB::begemotBridgeStpTimeSinceTopologyChange."bridge0" = Timeticks: (116927) 0:19:29.27 centi-seconds BEGEMOT-BRIDGE-MIB::begemotBridgeStpTimeSinceTopologyChange."bridge2" = Timeticks: (82773) 0:13:47.73 centi-seconds BEGEMOT-BRIDGE-MIB::begemotBridgeStpTopChanges."bridge0" = Counter32: 1 BEGEMOT-BRIDGE-MIB::begemotBridgeStpTopChanges."bridge2" = Counter32: 1 BEGEMOT-BRIDGE-MIB::begemotBridgeStpDesignatedRoot."bridge0" = Hex-STRING: 80 00 00 40 95 30 5E 31 BEGEMOT-BRIDGE-MIB::begemotBridgeStpDesignatedRoot."bridge2" = Hex-STRING: 80 00 00 50 8B B8 C6 A9 .... To change the bridge interface being monitored via the `mib-2.dot1dBridge` subtree: [source,shell] .... % snmpset -v 2c -c private bridge1.example.com BEGEMOT-BRIDGE-MIB::begemotBridgeDefaultBridgeIf.0 s bridge2 .... [[network-aggregation]] == Link Aggregation and Failover FreeBSD provides the man:lagg[4] interface which can be used to aggregate multiple network interfaces into one virtual interface in order to provide failover and link aggregation. Failover allows traffic to continue to flow as long as at least one aggregated network interface has an established link. Link aggregation works best on switches which support LACP, as this protocol distributes traffic bi-directionally while responding to the failure of individual links. The aggregation protocols supported by the lagg interface determine which ports are used for outgoing traffic and whether or not a specific port accepts incoming traffic. The following protocols are supported by man:lagg[4]: failover:: This mode sends and receives traffic only through the master port. If the master port becomes unavailable, the next active port is used. The first interface added to the virtual interface is the master port and all subsequently added interfaces are used as failover devices. If failover to a non-master port occurs, the original port becomes master once it becomes available again. loadbalance:: This provides a static setup and does not negotiate aggregation with the peer or exchange frames to monitor the link. If the switch supports LACP, that should be used instead. lacp:: The IEEE(R) 802.3ad Link Aggregation Control Protocol (LACP) negotiates a set of aggregable links with the peer into one or more Link Aggregated Groups (LAGs). Each LAG is composed of ports of the same speed, set to full-duplex operation, and traffic is balanced across the ports in the LAG with the greatest total speed. Typically, there is only one LAG which contains all the ports. In the event of changes in physical connectivity, LACP will quickly converge to a new configuration. + LACP balances outgoing traffic across the active ports based on hashed protocol header information and accepts incoming traffic from any active port. The hash includes the Ethernet source and destination address and, if available, the VLAN tag, and the IPv4 or IPv6 source and destination address. roundrobin:: This mode distributes outgoing traffic using a round-robin scheduler through all active ports and accepts incoming traffic from any active port. Since this mode violates Ethernet frame ordering, it should be used with caution. broadcast:: This mode sends outgoing traffic to all ports configured on the lagg interface, and receives frames on any port. === Configuration Examples This section demonstrates how to configure a Cisco(R) switch and a FreeBSD system for LACP load balancing. It then shows how to configure two Ethernet interfaces in failover mode as well as how to configure failover mode between an Ethernet and a wireless interface. [[networking-lacp-aggregation-cisco]] .LACP Aggregation with a Cisco(R) Switch [example] ==== This example connects two man:fxp[4] Ethernet interfaces on a FreeBSD machine to the first two Ethernet ports on a Cisco(R) switch as a single load balanced and fault tolerant link. More interfaces can be added to increase throughput and fault tolerance. Replace the names of the Cisco(R) ports, Ethernet devices, channel group number, and IP address shown in the example to match the local configuration. Frame ordering is mandatory on Ethernet links and any traffic between two stations always flows over the same physical link, limiting the maximum speed to that of one interface. The transmit algorithm attempts to use as much information as it can to distinguish different traffic flows and balance the flows across the available interfaces. On the Cisco(R) switch, add the _FastEthernet0/1_ and _FastEthernet0/2_ interfaces to channel group _1_: [source,shell] .... interface FastEthernet0/1 channel-group 1 mode active channel-protocol lacp ! interface FastEthernet0/2 channel-group 1 mode active channel-protocol lacp .... On the FreeBSD system, create the man:lagg[4] interface using the physical interfaces _fxp0_ and _fxp1_ and bring the interfaces up with an IP address of _10.0.0.3/24_: [source,shell] .... # ifconfig fxp0 up # ifconfig fxp1 up # ifconfig lagg0 create # ifconfig lagg0 up laggproto lacp laggport fxp0 laggport fxp1 10.0.0.3/24 .... Next, verify the status of the virtual interface: [source,shell] .... # ifconfig lagg0 lagg0: flags=8843 metric 0 mtu 1500 options=8 ether 00:05:5d:71:8d:b8 inet 10.0.0.3 netmask 0xffffff00 broadcast 10.0.0.255 media: Ethernet autoselect status: active laggproto lacp laggport: fxp1 flags=1c laggport: fxp0 flags=1c .... Ports marked as `ACTIVE` are part of the LAG that has been negotiated with the remote switch. Traffic will be transmitted and received through these active ports. Add `-v` to the above command to view the LAG identifiers. To see the port status on the Cisco(R) switch: [source,shell] .... switch# show lacp neighbor Flags: S - Device is requesting Slow LACPDUs F - Device is requesting Fast LACPDUs A - Device is in Active mode P - Device is in Passive mode Channel group 1 neighbors Partner's information: LACP port Oper Port Port Port Flags Priority Dev ID Age Key Number State Fa0/1 SA 32768 0005.5d71.8db8 29s 0x146 0x3 0x3D Fa0/2 SA 32768 0005.5d71.8db8 29s 0x146 0x4 0x3D .... For more detail, type `show lacp neighbor detail`. To retain this configuration across reboots, add the following entries to [.filename]#/etc/rc.conf# on the FreeBSD system: [.programlisting] .... ifconfig_fxp0="up" ifconfig_fxp1="up" cloned_interfaces="lagg0" ifconfig_lagg0="laggproto lacp laggport fxp0 laggport fxp1 10.0.0.3/24" .... ==== [[networking-lagg-failover]] .Failover Mode [example] ==== Failover mode can be used to switch over to a secondary interface if the link is lost on the master interface. To configure failover, make sure that the underlying physical interfaces are up, then create the man:lagg[4] interface. In this example, _fxp0_ is the master interface, _fxp1_ is the secondary interface, and the virtual interface is assigned an IP address of _10.0.0.15/24_: [source,shell] .... # ifconfig fxp0 up # ifconfig fxp1 up # ifconfig lagg0 create # ifconfig lagg0 up laggproto failover laggport fxp0 laggport fxp1 10.0.0.15/24 .... The virtual interface should look something like this: [source,shell] .... # ifconfig lagg0 lagg0: flags=8843 metric 0 mtu 1500 options=8 ether 00:05:5d:71:8d:b8 inet 10.0.0.15 netmask 0xffffff00 broadcast 10.0.0.255 media: Ethernet autoselect status: active laggproto failover laggport: fxp1 flags=0<> laggport: fxp0 flags=5 .... Traffic will be transmitted and received on _fxp0_. If the link is lost on _fxp0_, _fxp1_ will become the active link. If the link is restored on the master interface, it will once again become the active link. To retain this configuration across reboots, add the following entries to [.filename]#/etc/rc.conf#: [.programlisting] .... ifconfig_fxp0="up" ifconfig_fxp1="up" cloned_interfaces="lagg0" ifconfig_lagg0="laggproto failover laggport fxp0 laggport fxp1 10.0.0.15/24" .... ==== [[networking-lagg-wired-and-wireless]] .Failover Mode Between Ethernet and Wireless Interfaces [example] ==== For laptop users, it is usually desirable to configure the wireless device as a secondary which is only used when the Ethernet connection is not available. With man:lagg[4], it is possible to configure a failover which prefers the Ethernet connection for both performance and security reasons, while maintaining the ability to transfer data over the wireless connection. This is achieved by overriding the Ethernet interface's MAC address with that of the wireless interface. [NOTE] **** In theory, either the Ethernet or wireless MAC address can be changed to match the other. However, some popular wireless interfaces lack support for overriding the MAC address. We therefore recommend overriding the Ethernet MAC address for this purpose. **** [NOTE] **** If the driver for the wireless interface is not loaded in the `GENERIC` or custom kernel, and the computer is running FreeBSD {rel121-current}, load the corresponding [.filename]#.ko# in [.filename]#/boot/loader.conf# by adding `*driver_load="YES"*` to that file and rebooting. Another, better way is to load the driver in [.filename]#/etc/rc.conf# by adding it to `kld_list` (see man:rc.conf[5] for details) in that file and rebooting. This is needed because otherwise the driver is not loaded yet at the time the man:lagg[4] interface is set up. **** In this example, the Ethernet interface, _re0_, is the master and the wireless interface, _wlan0_, is the failover. The _wlan0_ interface was created from the _ath0_ physical wireless interface, and the Ethernet interface will be configured with the MAC address of the wireless interface. First, bring the wireless interface up (replacing _FR_ with your own 2-letter country code), but do not set an IP address. Replace _wlan0_ to match the system's wireless interface name: [source,shell] .... # ifconfig wlan0 create wlandev ath0 country FR ssid my_router up .... Now you can determine the MAC address of the wireless interface: [source,shell] .... # ifconfig wlan0 wlan0: flags=8843 metric 0 mtu 1500 ether b8:ee:65:5b:32:59 groups: wlan ssid Bbox-A3BD2403 channel 6 (2437 MHz 11g ht/20) bssid 00:37:b7:56:4b:60 regdomain ETSI country FR indoor ecm authmode WPA2/802.11i privacy ON deftxkey UNDEF AES-CCM 2:128-bit txpower 30 bmiss 7 scanvalid 60 protmode CTS ampdulimit 64k ampdudensity 8 shortgi -stbctx stbcrx -ldpc wme burst roaming MANUAL media: IEEE 802.11 Wireless Ethernet MCS mode 11ng status: associated nd6 options=29 .... The `ether` line will contain the MAC address of the specified interface. Now, change the MAC address of the Ethernet interface to match: [source,shell] .... # ifconfig re0 ether b8:ee:65:5b:32:59 .... Make sure the _re0_ interface is up, then create the man:lagg[4] interface with _re0_ as master with failover to _wlan0_: [source,shell] .... # ifconfig re0 up # ifconfig lagg0 create # ifconfig lagg0 up laggproto failover laggport re0 laggport wlan0 .... The virtual interface should look something like this: [source,shell] .... # ifconfig lagg0 lagg0: flags=8843 metric 0 mtu 1500 options=8 ether b8:ee:65:5b:32:59 laggproto failover lagghash l2,l3,l4 laggport: re0 flags=5 laggport: wlan0 flags=0<> groups: lagg media: Ethernet autoselect status: active .... Then, start the DHCP client to obtain an IP address: [source,shell] .... # dhclient lagg0 .... To retain this configuration across reboots, add the following entries to [.filename]#/etc/rc.conf#: [.programlisting] .... ifconfig_re0="ether b8:ee:65:5b:32:59" wlans_ath0="wlan0" ifconfig_wlan0="WPA" create_args_wlan0="country FR" cloned_interfaces="lagg0" ifconfig_lagg0="up laggproto failover laggport re0 laggport wlan0 DHCP" .... ==== [[network-diskless]] == Diskless Operation with PXE The Intel(R) Preboot eXecution Environment (PXE) allows an operating system to boot over the network. For example, a FreeBSD system can boot over the network and operate without a local disk, using file systems mounted from an NFS server. PXE support is usually available in the BIOS. To use PXE when the machine starts, select the `Boot from network` option in the BIOS setup or type a function key during system initialization. In order to provide the files needed for an operating system to boot over the network, a PXE setup also requires properly configured DHCP, TFTP, and NFS servers, where: * Initial parameters, such as an IP address, executable boot filename and location, server name, and root path are obtained from the DHCP server. * The operating system loader file is booted using TFTP. * The file systems are loaded using NFS. When a computer PXE boots, it receives information over DHCP about where to obtain the initial boot loader file. After the host computer receives this information, it downloads the boot loader via TFTP and then executes the boot loader. In FreeBSD, the boot loader file is [.filename]#/boot/pxeboot#. After [.filename]#/boot/pxeboot# executes, the FreeBSD kernel is loaded and the rest of the FreeBSD bootup sequence proceeds, as described in crossref:boot[boot,The FreeBSD Booting Process]. [NOTE] ==== For UEFI PXE based boot, the actual boot loader file to use is [.filename]#/boot/loader.efi#. See the below section crossref:advanced-networking[_debugging_pxe_problems,Debugging PXE Problems] on how to use [.filename]#/boot/loader.efi#. ==== This section describes how to configure these services on a FreeBSD system so that other systems can PXE boot into FreeBSD. Refer to man:diskless[8] for more information. [CAUTION] ==== As described, the system providing these services is insecure. It should live in a protected area of a network and be untrusted by other hosts. ==== [[network-pxe-nfs]] === Setting Up the PXE Environment The steps shown in this section configure the built-in NFS and TFTP servers. The next section demonstrates how to install and configure the DHCP server. In this example, the directory which will contain the files used by PXE users is [.filename]#/b/tftpboot/FreeBSD/install#. It is important that this directory exists and that the same directory name is set in both [.filename]#/etc/inetd.conf# and [.filename]#/usr/local/etc/dhcpd.conf#. [NOTE] ==== The command examples below assume use of the man:sh[1] shell. man:csh[1] and man:tcsh[1] users will need to start a man:sh[1] shell or adapt the commands to man:csh[1] syntax. ==== [.procedure] . Create the root directory which will contain a FreeBSD installation to be NFS mounted: + [source,shell] .... # export NFSROOTDIR=/b/tftpboot/FreeBSD/install # mkdir -p ${NFSROOTDIR} .... . Enable the NFS server by adding this line to [.filename]#/etc/rc.conf#: + [.programlisting] .... nfs_server_enable="YES" .... . Export the diskless root directory via NFS by adding the following to [.filename]#/etc/exports#: + [.programlisting] .... /b -ro -alldirs -maproot=root .... . Start the NFS server: + [source,shell] .... # service nfsd start .... . Enable man:inetd[8] by adding the following line to [.filename]#/etc/rc.conf#: + [.programlisting] .... inetd_enable="YES" .... . Uncomment the following line in [.filename]#/etc/inetd.conf# by making sure it does not start with a `+#+` symbol: + [.programlisting] .... tftp dgram udp wait root /usr/libexec/tftpd tftpd blocksize 1468 -l -s /b/tftpboot .... + [NOTE] ==== The specified tftp blocksize, e.g. 1468 bytes, replaces the default size 512 bytes. Some PXE versions require the TCP version of TFTP. In this case, uncomment the second `tftp` line which contains `stream tcp`. ==== . Start man:inetd[8]: + [source,shell] .... # service inetd start .... . Install the base system into [.filename]#${NFSROOTDIR}#, either by decompressing the official archives or by rebuilding the FreeBSD kernel and userland (refer to crossref:cutting-edge[makeworld,“Updating FreeBSD from Source”] for more detailed instructions, but do not forget to add `DESTDIR=_${NFSROOTDIR}_` when running the `make installkernel` and `make installworld` commands. . Test that the TFTP server works and can download the boot loader which will be obtained via PXE: + [source,shell] .... # tftp localhost tftp> get FreeBSD/install/boot/pxeboot Received 264951 bytes in 0.1 seconds .... . Edit [.filename]#${NFSROOTDIR}/etc/fstab# and create an entry to mount the root file system over NFS: + [.programlisting] .... # Device Mountpoint FSType Options Dump Pass myhost.example.com:/b/tftpboot/FreeBSD/install / nfs ro 0 0 .... + Replace _myhost.example.com_ with the hostname or IP address of the NFS server. In this example, the root file system is mounted read-only in order to prevent NFS clients from potentially deleting the contents of the root file system. . Set the root password in the PXE environment for client machines which are PXE booting : + [source,shell] .... # chroot ${NFSROOTDIR} # passwd .... . If needed, enable man:ssh[1] root logins for client machines which are PXE booting by editing [.filename]#${NFSROOTDIR}/etc/ssh/sshd_config# and enabling `PermitRootLogin`. This option is documented in man:sshd_config[5]. . Perform any other needed customizations of the PXE environment in [.filename]#${NFSROOTDIR}#. These customizations could include things like installing packages or editing the password file with man:vipw[8]. When booting from an NFS root volume, [.filename]#/etc/rc# detects the NFS boot and runs [.filename]#/etc/rc.initdiskless#. In this case, [.filename]#/etc# and [.filename]#/var# need to be memory backed file systems so that these directories are writable but the NFS root directory is read-only: [source,shell] .... # chroot ${NFSROOTDIR} # mkdir -p conf/base # tar -c -v -f conf/base/etc.cpio.gz --format cpio --gzip etc # tar -c -v -f conf/base/var.cpio.gz --format cpio --gzip var .... When the system boots, memory file systems for [.filename]#/etc# and [.filename]#/var# will be created and mounted and the contents of the [.filename]#cpio.gz# files will be copied into them. By default, these file systems have a maximum capacity of 5 megabytes. If your archives do not fit, which is usually the case for [.filename]#/var# when binary packages have been installed, request a larger size by putting the number of 512 byte sectors needed (e.g., 5 megabytes is 10240 sectors) in [.filename]#${NFSROOTDIR}/conf/base/etc/md_size# and [.filename]#${NFSROOTDIR}/conf/base/var/md_size# files for [.filename]#/etc# and [.filename]#/var# file systems respectively. [[network-pxe-setting-up-dhcp]] === Configuring the DHCP Server The DHCP server does not need to be the same machine as the TFTP and NFS server, but it needs to be accessible in the network. DHCP is not part of the FreeBSD base system but can be installed using the package:net/isc-dhcp44-server[] port or package. Once installed, edit the configuration file, [.filename]#/usr/local/etc/dhcpd.conf#. Configure the `next-server`, `filename`, and `root-path` settings as seen in this example: [.programlisting] .... subnet 192.168.0.0 netmask 255.255.255.0 { range 192.168.0.2 192.168.0.3 ; option subnet-mask 255.255.255.0 ; option routers 192.168.0.1 ; option broadcast-address 192.168.0.255 ; option domain-name-servers 192.168.35.35, 192.168.35.36 ; option domain-name "example.com"; # IP address of TFTP server next-server 192.168.0.1 ; # path of boot loader obtained via tftp filename "FreeBSD/install/boot/pxeboot" ; # pxeboot boot loader will try to NFS mount this directory for root FS option root-path "192.168.0.1:/b/tftpboot/FreeBSD/install/" ; } .... The `next-server` directive is used to specify the IP address of the TFTP server. The `filename` directive defines the path to [.filename]#/boot/pxeboot#. A relative filename is used, meaning that [.filename]#/b/tftpboot# is not included in the path. The `root-path` option defines the path to the NFS root file system. Once the edits are saved, enable DHCP at boot time by adding the following line to [.filename]#/etc/rc.conf#: [.programlisting] .... dhcpd_enable="YES" .... Then start the DHCP service: [source,shell] .... # service isc-dhcpd start .... === Debugging PXE Problems Once all of the services are configured and started, PXE clients should be able to automatically load FreeBSD over the network. If a particular client is unable to connect, when that client machine boots up, enter the BIOS configuration menu and confirm that it is set to boot from the network. This section describes some troubleshooting tips for isolating the source of the configuration problem should no clients be able to PXE boot. [.procedure] **** . Use the package:net/wireshark[] package or port to debug the network traffic involved during the PXE booting process, which is illustrated in the diagram below. + .PXE Booting Process with NFS Root Mount image::pxe-nfs.png[] + 1. Client broadcasts a DHCPDISCOVER message. + 2. The DHCP server responds with the IP address, next-server, filename, and root-path values. + 3. The client sends a TFTP request to next-server, asking to retrieve filename. + 4. The TFTP server responds and sends filename to client. + 5. The client executes filename, which is pxeboot(8), which then loads the kernel. When the kernel executes, the root file system specified by root-path is mounted over NFS. + . On the TFTP server, read [.filename]#/var/log/xferlog# to ensure that [.filename]#pxeboot# is being retrieved from the correct location. To test this example configuration: + [source,shell] .... # tftp 192.168.0.1 tftp> get FreeBSD/install/boot/pxeboot Received 264951 bytes in 0.1 seconds .... + The `BUGS` sections in man:tftpd[8] and man:tftp[1] document some limitations with TFTP. . Make sure that the root file system can be mounted via NFS. To test this example configuration: + [source,shell] .... # mount -t nfs 192.168.0.1:/b/tftpboot/FreeBSD/install /mnt .... + . For UEFI PXE based booting, replace the [.filename]#boot/pxeboot# file with the [.filename]#boot/loader.efi# file: [source,shell] .... # chroot ${NFSROOTDIR} # mv boot/pxeboot boot/pxeboot.original # cp boot/loader.efi boot/pxeboot .... **** [[carp]] == Common Address Redundancy Protocol (CARP) The Common Address Redundancy Protocol (CARP) allows multiple hosts to share the same IP address and Virtual Host ID (VHID) in order to provide _high availability_ for one or more services. This means that one or more hosts can fail, and the other hosts will transparently take over so that users do not see a service failure. In addition to the shared IP address, each host has its own IP address for management and configuration. All of the machines that share an IP address have the same VHID. The VHID for each virtual IP address must be unique across the broadcast domain of the network interface. High availability using CARP is built into FreeBSD, though the steps to configure it vary slightly depending upon the FreeBSD version. This section provides the same example configuration for versions before and equal to or after FreeBSD 10. This example configures failover support with three hosts, all with unique IP addresses, but providing the same web content. It has two different masters named `hosta.example.org` and `hostb.example.org`, with a shared backup named `hostc.example.org`. These machines are load balanced with a Round Robin DNS configuration. The master and backup machines are configured identically except for their hostnames and management IP addresses. These servers must have the same configuration and run the same services. When the failover occurs, requests to the service on the shared IP address can only be answered correctly if the backup server has access to the same content. The backup machine has two additional CARP interfaces, one for each of the master content server's IP addresses. When a failure occurs, the backup server will pick up the failed master machine's IP address. [[carp-10x]] === Using CARP Enable boot-time support for CARP by adding an entry for the [.filename]#carp.ko# kernel module in [.filename]#/boot/loader.conf#: [.programlisting] .... carp_load="YES" .... To load the module now without rebooting: [source,shell] .... # kldload carp .... For users who prefer to use a custom kernel, include the following line in the custom kernel configuration file and compile the kernel as described in crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]: [.programlisting] .... device carp .... The hostname, management IP address and subnet mask, shared IP address, and VHID are all set by adding entries to [.filename]#/etc/rc.conf#. This example is for `hosta.example.org`: [.programlisting] .... hostname="hosta.example.org" ifconfig_em0="inet 192.168.1.3 netmask 255.255.255.0" ifconfig_em0_alias0="inet vhid 1 pass testpass alias 192.168.1.50/32" .... The next set of entries are for `hostb.example.org`. Since it represents a second master, it uses a different shared IP address and VHID. However, the passwords specified with `pass` must be identical as CARP will only listen to and accept advertisements from machines with the correct password. [.programlisting] .... hostname="hostb.example.org" ifconfig_em0="inet 192.168.1.4 netmask 255.255.255.0" ifconfig_em0_alias0="inet vhid 2 pass testpass alias 192.168.1.51/32" .... The third machine, `hostc.example.org`, is configured to handle failover from either master. This machine is configured with two CARPVHIDs, one to handle the virtual IP address for each of the master hosts. The CARP advertising skew, `advskew`, is set to ensure that the backup host advertises later than the master, since `advskew` controls the order of precedence when there are multiple backup servers. [.programlisting] .... hostname="hostc.example.org" ifconfig_em0="inet 192.168.1.5 netmask 255.255.255.0" ifconfig_em0_alias0="inet vhid 1 advskew 100 pass testpass alias 192.168.1.50/32" ifconfig_em0_alias1="inet vhid 2 advskew 100 pass testpass alias 192.168.1.51/32" .... Having two CARPVHIDs configured means that `hostc.example.org` will notice if either of the master servers becomes unavailable. If a master fails to advertise before the backup server, the backup server will pick up the shared IP address until the master becomes available again. [NOTE] ==== If the original master server becomes available again, `hostc.example.org` will not release the virtual IP address back to it automatically. For this to happen, preemption has to be enabled. The feature is disabled by default, it is controlled via the man:sysctl[8] variable `net.inet.carp.preempt`. The administrator can force the backup server to return the IP address to the master: [source,shell] .... # ifconfig em0 vhid 1 state backup .... ==== Once the configuration is complete, either restart networking or reboot each system. High availability is now enabled. CARP functionality can be controlled via several man:sysctl[8] variables documented in the man:carp[4] manual pages. Other actions can be triggered from CARP events by using man:devd[8]. [[network-vlan]] == VLANs VLANs are a way of virtually dividing up a network into many different subnetworks, also referred to as segmenting. Each segment will have its own broadcast domain and be isolated from other VLANs. On FreeBSD, VLANs must be supported by the network card driver. To see which drivers support vlans, refer to the man:vlan[4] manual page. When configuring a VLAN, a couple pieces of information must be known. First, which network interface? Second, what is the VLAN tag? To configure VLANs at run time, with a NIC of `em0` and a VLAN tag of `5` the command would look like this: [source,shell] .... # ifconfig em0.5 create vlan 5 vlandev em0 inet 192.168.20.20/24 .... [NOTE] ==== See how the interface name includes the NIC driver name and the VLAN tag, separated by a period? This is a best practice to make maintaining the VLAN configuration easy when many VLANs are present on a machine. ==== [NOTE] ==== When defining VLANs, ensure that the parent network interface is also configured and enabled. The minimum configuration for the above example would be: [source,shell] .... # ifconfig em0 up .... ==== To configure VLANs at boot time, [.filename]#/etc/rc.conf# must be updated. To duplicate the configuration above, the following will need to be added: [.programlisting] .... vlans_em0="5" ifconfig_em0_5="inet 192.168.20.20/24" .... Additional VLANs may be added, by simply adding the tag to the `vlans_em0` field and adding an additional line configuring the network on that VLAN tag's interface. [NOTE] ==== When defining VLANs in [.filename]#/etc/rc.conf#, make sure that the parent network interface is configured and enabled as well. The minimum configuration for the above example would be: [.programlisting] .... ifconfig_em0="up" .... ==== It is useful to assign a symbolic name to an interface so that when the associated hardware is changed, only a few configuration variables need to be updated. For example, security cameras need to be run over VLAN 1 on `em0`. Later, if the `em0` card is replaced with a card that uses the man:ixgb[4] driver, all references to `em0.1` will not have to change to `ixgb0.1`. To configure VLAN `5`, on the NIC `em0`, assign the interface name `cameras`, and assign the interface an IP address of `_192.168.20.20_` with a `24`-bit prefix, use this command: [source,shell] .... # ifconfig em0.5 create vlan 5 vlandev em0 name cameras inet 192.168.20.20/24 .... For an interface named `video`, use the following: [source,shell] .... # ifconfig video.5 create vlan 5 vlandev video name cameras inet 192.168.20.20/24 .... To apply the changes at boot time, add the following lines to [.filename]#/etc/rc.conf#: [.programlisting] .... vlans_video="cameras" create_args_cameras="vlan 5" ifconfig_cameras="inet 192.168.20.20/24" .... diff --git a/documentation/content/en/books/handbook/audit/_index.adoc b/documentation/content/en/books/handbook/audit/_index.adoc index 4bf987fe02..9bd9c84cc5 100644 --- a/documentation/content/en/books/handbook/audit/_index.adoc +++ b/documentation/content/en/books/handbook/audit/_index.adoc @@ -1,458 +1,458 @@ --- title: Chapter 19. Security Event Auditing part: Part III. System Administration prev: books/handbook/mac next: books/handbook/disks description: FreeBSD security event auditing supports reliable, fine-grained, and configurable logging of a variety of security-relevant system events, including logins, configuration changes, and file and network access tags: ["audit", "terms", "configuration", "guide", "audit trails"] showBookMenu: true weight: 23 path: "/books/handbook/audit/" --- [[audit]] = Security Event Auditing :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 19 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/audit/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[audit-synopsis]] == Synopsis The FreeBSD operating system includes support for security event auditing. Event auditing supports reliable, fine-grained, and configurable logging of a variety of security-relevant system events, including logins, configuration changes, and file and network access. These log records can be invaluable for live system monitoring, intrusion detection, and postmortem analysis. FreeBSD implements Sun(TM)'s published Basic Security Module (BSM) Application Programming Interface (API) and file format, and is interoperable with the Solaris(TM) and Mac OS(R) X audit implementations. This chapter focuses on the installation and configuration of event auditing. It explains audit policies and provides an example audit configuration. After reading this chapter, you will know: * What event auditing is and how it works. * How to configure event auditing on FreeBSD for users and processes. * How to review the audit trail using the audit reduction and review tools. Before reading this chapter, you should: * Understand UNIX(R) and FreeBSD basics (crossref:basics[basics,FreeBSD Basics]). * Be familiar with the basics of kernel configuration/compilation (crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]). * Have some familiarity with security and how it pertains to FreeBSD (crossref:security[security,Security]). [WARNING] ==== The audit facility has some known limitations. Not all security-relevant system events are auditable and some login mechanisms, such as Xorg-based display managers and third-party daemons, do not properly configure auditing for user login sessions. The security event auditing facility is able to generate very detailed logs of system activity. On a busy system, trail file data can be very large when configured for high detail, exceeding gigabytes a week in some configurations. Administrators should take into account the disk space requirements associated with high volume audit configurations. For example, it may be desirable to dedicate a file system to [.filename]#/var/audit# so that other file systems are not affected if the audit file system becomes full. ==== [[audit-inline-glossary]] == Key Terms The following terms are related to security event auditing: * _event_: an auditable event is any event that can be logged using the audit subsystem. Examples of security-relevant events include the creation of a file, the building of a network connection, or a user logging in. Events are either "attributable", meaning that they can be traced to an authenticated user, or "non-attributable". Examples of non-attributable events are any events that occur before authentication in the login process, such as bad password attempts. * _class_: a named set of related events which are used in selection expressions. Commonly used classes of events include "file creation" (fc), "exec" (ex), and "login_logout" (lo). * _record_: an audit log entry describing a security event. Records contain a record event type, information on the subject (user) performing the action, date and time information, information on any objects or arguments, and a success or failure condition. * _trail_: a log file consisting of a series of audit records describing security events. Trails are in roughly chronological order with respect to the time events completed. Only authorized processes are allowed to commit records to the audit trail. * _selection expression_: a string containing a list of prefixes and audit event class names used to match events. * _preselection_: the process by which the system identifies which events are of interest to the administrator. The preselection configuration uses a series of selection expressions to identify which classes of events to audit for which users, as well as global settings that apply to both authenticated and unauthenticated processes. * _reduction_: the process by which records from existing audit trails are selected for preservation, printing, or analysis. Likewise, the process by which undesired audit records are removed from the audit trail. Using reduction, administrators can implement policies for the preservation of audit data. For example, detailed audit trails might be kept for one month, but after that, trails might be reduced in order to preserve only login information for archival purposes. [[audit-config]] == Audit Configuration User space support for event auditing is installed as part of the base FreeBSD operating system. Kernel support is available in the [.filename]#GENERIC# kernel by default, and man:auditd[8] can be enabled by adding the following line to [.filename]#/etc/rc.conf#: [.programlisting] .... auditd_enable="YES" .... Then, start the audit daemon: [source,shell] .... # service auditd start .... Users who prefer to compile a custom kernel must include the following line in their custom kernel configuration file: [.programlisting] .... options AUDIT .... === Event Selection Expressions Selection expressions are used in a number of places in the audit configuration to determine which events should be audited. Expressions contain a list of event classes to match. Selection expressions are evaluated from left to right, and two expressions are combined by appending one onto the other. -crossref:audit[event-selection] summarizes the default audit event classes: +crossref:audit[event-selection,.Default Audit Event Classes] summarizes the default audit event classes: [[event-selection]] .Default Audit Event Classes [cols="1,1,1", frame="none", options="header"] |=== | Class Name | Description | Action |all |all |Match all event classes. |aa |authentication and authorization | |ad |administrative |Administrative actions performed on the system as a whole. |ap |application |Application defined action. |cl |file close |Audit calls to the `close` system call. |ex |exec |Audit program execution. Auditing of command line arguments and environmental variables is controlled via man:audit_control[5] using the `argv` and `envv` parameters to the `policy` setting. |fa |file attribute access |Audit the access of object attributes such as man:stat[1] and man:pathconf[2]. |fc |file create |Audit events where a file is created as a result. |fd |file delete |Audit events where file deletion occurs. |fm |file attribute modify |Audit events where file attribute modification occurs, such as by man:chown[8], man:chflags[1], and man:flock[2]. |fr |file read |Audit events in which data is read or files are opened for reading. |fw |file write |Audit events in which data is written or files are written or modified. |io |ioctl |Audit use of the `ioctl` system call. |ip |ipc |Audit various forms of Inter-Process Communication, including POSIX pipes and System V IPC operations. |lo |login_logout |Audit man:login[1] and man:logout[1] events. |na |non attributable |Audit non-attributable events. |no |invalid class |Match no audit events. |nt |network |Audit events related to network actions such as man:connect[2] and man:accept[2]. |ot |other |Audit miscellaneous events. |pc |process |Audit process operations such as man:exec[3] and man:exit[3]. |=== These audit event classes may be customized by modifying the [.filename]#audit_class# and [.filename]#audit_event# configuration files. Each audit event class may be combined with a prefix indicating whether successful/failed operations are matched, and whether the entry is adding or removing matching for the class and type. -crossref:audit[event-prefixes] summarizes the available prefixes: +crossref:audit[event-prefixes,.Prefixes for Audit Event Classes] summarizes the available prefixes: [[event-prefixes]] .Prefixes for Audit Event Classes [cols="1,1", frame="none", options="header"] |=== | Prefix | Action |+ |Audit successful events in this class. |- |Audit failed events in this class. |^ |Audit neither successful nor failed events in this class. |^+ |Do not audit successful events in this class. |^- |Do not audit failed events in this class. |=== If no prefix is present, both successful and failed instances of the event will be audited. The following example selection string selects both successful and failed login/logout events, but only successful execution events: [.programlisting] .... lo,+ex .... === Configuration Files The following configuration files for security event auditing are found in [.filename]#/etc/security#: * [.filename]#audit_class#: contains the definitions of the audit classes. * [.filename]#audit_control#: controls aspects of the audit subsystem, such as default audit classes, minimum disk space to leave on the audit log volume, and maximum audit trail size. * [.filename]#audit_event#: textual names and descriptions of system audit events and a list of which classes each event is in. * [.filename]#audit_user#: user-specific audit requirements to be combined with the global defaults at login. * [.filename]#audit_warn#: a customizable shell script used by man:auditd[8] to generate warning messages in exceptional situations, such as when space for audit records is running low or when the audit trail file has been rotated. [WARNING] ==== Audit configuration files should be edited and maintained carefully, as errors in configuration may result in improper logging of events. ==== In most cases, administrators will only need to modify [.filename]#audit_control# and [.filename]#audit_user#. The first file controls system-wide audit properties and policies and the second file may be used to fine-tune auditing by user. [[audit-auditcontrol]] ==== The [.filename]#audit_control# File A number of defaults for the audit subsystem are specified in [.filename]#audit_control#: [.programlisting] .... dir:/var/audit dist:off flags:lo,aa minfree:5 naflags:lo,aa policy:cnt,argv filesz:2M expire-after:10M .... The `dir` entry is used to set one or more directories where audit logs will be stored. If more than one directory entry appears, they will be used in order as they fill. It is common to configure audit so that audit logs are stored on a dedicated file system, in order to prevent interference between the audit subsystem and other subsystems if the file system fills. If the `dist` field is set to `on` or `yes`, hard links will be created to all trail files in [.filename]#/var/audit/dist#. The `flags` field sets the system-wide default preselection mask for attributable events. In the example above, successful and failed login/logout events as well as authentication and authorization are audited for all users. The `minfree` entry defines the minimum percentage of free space for the file system where the audit trail is stored. The `naflags` entry specifies audit classes to be audited for non-attributed events, such as the login/logout process and authentication and authorization. The `policy` entry specifies a comma-separated list of policy flags controlling various aspects of audit behavior. The `cnt` indicates that the system should continue running despite an auditing failure (this flag is highly recommended). The other flag, `argv`, causes command line arguments to the man:execve[2] system call to be audited as part of command execution. The `filesz` entry specifies the maximum size for an audit trail before automatically terminating and rotating the trail file. A value of `0` disables automatic log rotation. If the requested file size is below the minimum of 512k, it will be ignored and a log message will be generated. The `expire-after` field specifies when audit log files will expire and be removed. [[audit-audituser]] ==== The [.filename]#audit_user# File The administrator can specify further audit requirements for specific users in [.filename]#audit_user#. Each line configures auditing for a user via two fields: the `alwaysaudit` field specifies a set of events that should always be audited for the user, and the `neveraudit` field specifies a set of events that should never be audited for the user. The following example entries audit login/logout events and successful command execution for `root` and file creation and successful command execution for `www`. If used with the default [.filename]#audit_control#, the `lo` entry for `root` is redundant, and login/logout events will also be audited for `www`. [.programlisting] .... root:lo,+ex:no www:fc,+ex:no .... [[audit-administration]] == Working with Audit Trails Since audit trails are stored in the BSM binary format, several built-in tools are available to modify or convert these trails to text. To convert trail files to a simple text format, use `praudit`. To reduce the audit trail file for analysis, archiving, or printing purposes, use `auditreduce`. This utility supports a variety of selection parameters, including event type, event class, user, date or time of the event, and the file path or object acted on. For example, to dump the entire contents of a specified audit log in plain text: [source,shell] .... # praudit /var/audit/AUDITFILE .... Where _AUDITFILE_ is the audit log to dump. Audit trails consist of a series of audit records made up of tokens, which `praudit` prints sequentially, one per line. Each token is of a specific type, such as `header` (an audit record header) or `path` (a file path from a name lookup). The following is an example of an `execve` event: [.programlisting] .... header,133,10,execve(2),0,Mon Sep 25 15:58:03 2006, + 384 msec exec arg,finger,doug path,/usr/bin/finger attribute,555,root,wheel,90,24918,104944 subject,robert,root,wheel,root,wheel,38439,38032,42086,128.232.9.100 return,success,0 trailer,133 .... This audit represents a successful `execve` call, in which the command `finger doug` has been run. The `exec arg` token contains the processed command line presented by the shell to the kernel. The `path` token holds the path to the executable as looked up by the kernel. The `attribute` token describes the binary and includes the file mode. The `subject` token stores the audit user ID, effective user ID and group ID, real user ID and group ID, process ID, session ID, port ID, and login address. Notice that the audit user ID and real user ID differ as the user `robert` switched to the `root` account before running this command, but it is audited using the original authenticated user. The `return` token indicates the successful execution and the `trailer` concludes the record. XML output format is also supported and can be selected by including `-x`. Since audit logs may be very large, a subset of records can be selected using `auditreduce`. This example selects all audit records produced for the user `trhodes` stored in [.filename]#AUDITFILE#: [source,shell] .... # auditreduce -u trhodes /var/audit/AUDITFILE | praudit .... Members of the `audit` group have permission to read audit trails in [.filename]#/var/audit#. By default, this group is empty, so only the `root` user can read audit trails. Users may be added to the `audit` group in order to delegate audit review rights. As the ability to track audit log contents provides significant insight into the behavior of users and processes, it is recommended that the delegation of audit review rights be performed with caution. === Live Monitoring Using Audit Pipes Audit pipes are cloning pseudo-devices which allow applications to tap the live audit record stream. This is primarily of interest to authors of intrusion detection and system monitoring applications. However, the audit pipe device is a convenient way for the administrator to allow live monitoring without running into problems with audit trail file ownership or log rotation interrupting the event stream. To track the live audit event stream: [source,shell] .... # praudit /dev/auditpipe .... By default, audit pipe device nodes are accessible only to the `root` user. To make them accessible to the members of the `audit` group, add a `devfs` rule to [.filename]#/etc/devfs.rules#: [.programlisting] .... add path 'auditpipe*' mode 0440 group audit .... See man:devfs.rules[5] for more information on configuring the devfs file system. [WARNING] ==== It is easy to produce audit event feedback cycles, in which the viewing of each audit event results in the generation of more audit events. For example, if all network I/O is audited, and `praudit` is run from an SSH session, a continuous stream of audit events will be generated at a high rate, as each event being printed will generate another event. For this reason, it is advisable to run `praudit` on an audit pipe device from sessions without fine-grained I/O auditing. ==== === Rotating and Compressing Audit Trail Files Audit trails are written to by the kernel and managed by the audit daemon, man:auditd[8]. Administrators should not attempt to use man:newsyslog.conf[5] or other tools to directly rotate audit logs. Instead, `audit` should be used to shut down auditing, reconfigure the audit system, and perform log rotation. The following command causes the audit daemon to create a new audit log and signal the kernel to switch to using the new log. The old log will be terminated and renamed, at which point it may then be manipulated by the administrator: [source,shell] .... # audit -n .... If man:auditd[8] is not currently running, this command will fail and an error message will be produced. Adding the following line to [.filename]#/etc/crontab# will schedule this rotation every twelve hours: [.programlisting] .... 0 */12 * * * root /usr/sbin/audit -n .... The change will take effect once [.filename]#/etc/crontab# is saved. Automatic rotation of the audit trail file based on file size is possible using `filesz` in [.filename]#audit_control# as described in crossref:audit[audit-auditcontrol]. As audit trail files can become very large, it is often desirable to compress or otherwise archive trails once they have been closed by the audit daemon. The [.filename]#audit_warn# script can be used to perform customized operations for a variety of audit-related events, including the clean termination of audit trails when they are rotated. For example, the following may be added to [.filename]#/etc/security/audit_warn# to compress audit trails on close: [.programlisting] .... # # Compress audit trail files on close. # if [ "$1" = closefile ]; then gzip -9 $2 fi .... Other archiving activities might include copying trail files to a centralized server, deleting old trail files, or reducing the audit trail to remove unneeded records. This script will be run only when audit trail files are cleanly terminated. It will not be run on trails left unterminated following an improper shutdown. diff --git a/documentation/content/en/books/handbook/basics/_index.adoc b/documentation/content/en/books/handbook/basics/_index.adoc index b86f4cbf8a..4351d68819 100644 --- a/documentation/content/en/books/handbook/basics/_index.adoc +++ b/documentation/content/en/books/handbook/basics/_index.adoc @@ -1,1962 +1,1962 @@ --- title: Chapter 3. FreeBSD Basics part: Part I. Getting Started prev: books/handbook/bsdinstall next: books/handbook/ports description: Basic commands and functionality of the FreeBSD operating system tags: ["basics", "virtual consoles", "users", "management", "permissions", "directory structure", "disk organization", "mounting", "processes", "daemons", "shell", "editor", "manual pages", "devices"] showBookMenu: true weight: 5 path: "/books/handbook/basics/" --- [[basics]] = FreeBSD Basics :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 3 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/basics/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[basics-synopsis]] == Synopsis This chapter covers the basic commands and functionality of the FreeBSD operating system. Much of this material is relevant for any UNIX(R)-like operating system. New FreeBSD users are encouraged to read through this chapter carefully. After reading this chapter, you will know: * How to use and configure virtual consoles. * How to create and manage users and groups on FreeBSD. * How UNIX(R) file permissions and FreeBSD file flags work. * The default FreeBSD file system layout. * The FreeBSD disk organization. * How to mount and unmount file systems. * What processes, daemons, and signals are. * What a shell is, and how to change the default login environment. * How to use basic text editors. * What devices and device nodes are. * How to read manual pages for more information. [[consoles]] == Virtual Consoles and Terminals Unless FreeBSD has been configured to automatically start a graphical environment during startup, the system will boot into a command line login prompt, as seen in this example: [.programlisting] .... FreeBSD/amd64 (pc3.example.org) (ttyv0) login: .... The first line contains some information about the system. The `amd64` indicates that FreeBSD is running on a 64-bit x86 system. The hostname is `pc3.example.org`, and `ttyv0` indicates that this is the "system console". The second line is the login prompt. Since FreeBSD is a multiuser system, it needs some way to distinguish between different users. This is accomplished by requiring every user to log into the system before gaining access to the programs on the system. Every user has a unique "username" and a personal "password". To log into the system console, type the username that was configured during system installation, as described in crossref:bsdinstall[bsdinstall-addusers,Add Users], and press kbd:[Enter]. Then enter the password associated with the username and press kbd:[Enter]. The password is _not echoed_ for security reasons. Once the correct password is input, the message of the day (MOTD) will be displayed followed by a command prompt. Depending upon the shell that was selected when the user was created, this prompt will be a `+#+`, `$`, or `%` character. The prompt indicates that the user is now logged into the FreeBSD system console and ready to try the available commands. [[consoles-virtual]] === Virtual Consoles While the system console can be used to interact with the system, a user working from the command line at the keyboard of a FreeBSD system will typically instead log into a virtual console. This is because system messages are configured by default to display on the system console. These messages will appear over the command or file that the user is working on, making it difficult to concentrate on the work at hand. By default, FreeBSD is configured to provide several virtual consoles for inputting commands. Each virtual console has its own login prompt and shell and it is easy to switch between virtual consoles. This essentially provides the command line equivalent of having several windows open at the same time in a graphical environment. The key combinations kbd:[Alt+F1] through kbd:[Alt+F8] have been reserved by FreeBSD for switching between virtual consoles. Use kbd:[Alt+F1] to switch to the system console (`ttyv0`), kbd:[Alt+F2] to access the first virtual console (`ttyv1`), kbd:[Alt+F3] to access the second virtual console (`ttyv2`), and so on. When using Xorg as a graphical console, the combination becomes kbd:[Ctrl+Alt+F1] to return to a text-based virtual console. When switching from one console to the next, FreeBSD manages the screen output. The result is an illusion of having multiple virtual screens and keyboards that can be used to type commands for FreeBSD to run. The programs that are launched in one virtual console do not stop running when the user switches to a different virtual console. Refer to man:kbdcontrol[1], man:vidcontrol[1], man:atkbd[4], man:syscons[4], and man:vt[4] for a more technical description of the FreeBSD console and its keyboard drivers. In FreeBSD, the number of available virtual consoles is configured in this section of `/etc/ttys`: [.programlisting] .... # name getty type status comments # ttyv0 "/usr/libexec/getty Pc" xterm on secure # Virtual terminals ttyv1 "/usr/libexec/getty Pc" xterm on secure ttyv2 "/usr/libexec/getty Pc" xterm on secure ttyv3 "/usr/libexec/getty Pc" xterm on secure ttyv4 "/usr/libexec/getty Pc" xterm on secure ttyv5 "/usr/libexec/getty Pc" xterm on secure ttyv6 "/usr/libexec/getty Pc" xterm on secure ttyv7 "/usr/libexec/getty Pc" xterm on secure ttyv8 "/usr/X11R6/bin/xdm -nodaemon" xterm off secure .... To disable a virtual console, put a comment symbol (`+#+`) at the beginning of the line representing that virtual console. For example, to reduce the number of available virtual consoles from eight to four, put a `+#+` in front of the last four lines representing virtual consoles `ttyv5` through `ttyv8`. _Do not_ comment out the line for the system console `ttyv0`. Note that the last virtual console (`ttyv8`) is used to access the graphical environment if Xorg has been installed and configured as described in crossref:x11[x11,The X Window System]. For a detailed description of every column in this file and the available options for the virtual consoles, refer to man:ttys[5]. [[consoles-singleuser]] === Single User Mode The FreeBSD boot menu provides an option labelled as "Boot Single User". If this option is selected, the system will boot into a special mode known as "single user mode". This mode is typically used to repair a system that will not boot or to reset the `root` password when it is not known. While in single user mode, networking and other virtual consoles are not available. However, full `root` access to the system is available, and by default, the `root` password is not needed. For these reasons, physical access to the keyboard is needed to boot into this mode and determining who has physical access to the keyboard is something to consider when securing a FreeBSD system. The settings which control single user mode are found in this section of `/etc/ttys`: [.programlisting] .... # name getty type status comments # # If console is marked "insecure", then init will ask for the root password # when going to single-user mode. console none unknown off secure .... By default, the status is set to `secure`. This assumes that who has physical access to the keyboard is either not important or it is controlled by a physical security policy. If this setting is changed to `insecure`, the assumption is that the environment itself is insecure because anyone can access the keyboard. When this line is changed to `insecure`, FreeBSD will prompt for the `root` password when a user selects to boot into single user mode. [NOTE] ==== _Be careful when changing this setting to `insecure`!_ If the `root` password is forgotten, booting into single user mode is still possible, but may be difficult for someone who is not familiar with the FreeBSD booting process. ==== [[consoles-vidcontrol]] === Changing Console Video Modes The FreeBSD console default video mode may be adjusted to 1024x768, 1280x1024, or any other size supported by the graphics chip and monitor. To use a different video mode load the `VESA` module: [source,shell] .... # kldload vesa .... To determine which video modes are supported by the hardware, use man:vidcontrol[1]. To get a list of supported video modes issue the following: [source,shell] .... # vidcontrol -i mode .... The output of this command lists the video modes that are supported by the hardware. To select a new video mode, specify the mode using man:vidcontrol[1] as the `root` user: [source,shell] .... # vidcontrol MODE_279 .... If the new video mode is acceptable, it can be permanently set on boot by adding it to `/etc/rc.conf`: [.programlisting] .... allscreens_flags="MODE_279" .... [[users-synopsis]] == Users and Basic Account Management FreeBSD allows multiple users to use the computer at the same time. While only one user can sit in front of the screen and use the keyboard at any one time, any number of users can log in to the system through the network. To use the system, each user should have their own user account. This chapter describes: * The different types of user accounts on a FreeBSD system. * How to add, remove, and modify user accounts. * How to set limits to control the resources that users and groups are allowed to access. * How to create groups and add users as members of a group. [[users-introduction]] === Account Types Since all access to the FreeBSD system is achieved using accounts and all processes are run by users, user and account management is important. There are three main types of accounts: system accounts, user accounts, and the superuser account. [[users-system]] ==== System Accounts System accounts are used to run services such as DNS, mail, and web servers. The reason for this is security; if all services ran as the superuser, they could act without restriction. Examples of system accounts are `daemon`, `operator`, `bind`, `news`, and `www`. `nobody` is the generic unprivileged system account. However, the more services that use `nobody`, the more files and processes that user will become associated with, and hence the more privileged that user becomes. [[users-user]] ==== User Accounts User accounts are assigned to real people and are used to log in and use the system. Every person accessing the system should have a unique user account. This allows the administrator to find out who is doing what and prevents users from clobbering the settings of other users. Each user can set up their own environment to accommodate their use of the system, by configuring their default shell, editor, key bindings, and language settings. Every user account on a FreeBSD system has certain information associated with it: User name:: The user name is typed at the `login:` prompt. Each user must have a unique user name. There are a number of rules for creating valid user names which are documented in man:passwd[5]. It is recommended to use user names that consist of eight or fewer, all lower case characters in order to maintain backwards compatibility with applications. Password:: Each account has an associated password. User ID (UID):: The User ID (UID) is a number used to uniquely identify the user to the FreeBSD system. Commands that allow a user name to be specified will first convert it to the UID. It is recommended to use a UID less than 65535, since higher values may cause compatibility issues with some software. Group ID (GID):: The Group ID (GID) is a number used to uniquely identify the primary group that the user belongs to. Groups are a mechanism for controlling access to resources based on a user's GID rather than their UID. This can significantly reduce the size of some configuration files and allows users to be members of more than one group. It is recommended to use a GID of 65535 or lower as higher GIDs may break some software. Login class:: Login classes are an extension to the group mechanism that provide additional flexibility when tailoring the system to different users. Login classes are discussed further in crossref:security[users-limiting,Configuring Login Classes]. Password change time:: By default, passwords do not expire. However, password expiration can be enabled on a per-user basis, forcing some or all users to change their passwords after a certain amount of time has elapsed. Account expiration time:: By default, FreeBSD does not expire accounts. When creating accounts that need a limited lifespan, such as student accounts in a school, specify the account expiry date using man:pw[8]. After the expiry time has elapsed, the account cannot be used to log in to the system, although the account's directories and files will remain. User's full name:: The user name uniquely identifies the account to FreeBSD, but does not necessarily reflect the user's real name. Similar to a comment, this information can contain spaces, uppercase characters, and be more than 8 characters long. Home directory:: The home directory is the full path to a directory on the system. This is the user's starting directory when the user logs in. A common convention is to put all user home directories under `/home/username` or `/usr/home/username`. Each user stores their personal files and subdirectories in their own home directory. User shell:: The shell provides the user's default environment for interacting with the system. There are many different kinds of shells and experienced users will have their own preferences, which can be reflected in their account settings. [[users-superuser]] ==== The Superuser Account The superuser account, usually called `root`, is used to manage the system with no limitations on privileges. For this reason, it should not be used for day-to-day tasks like sending and receiving mail, general exploration of the system, or programming. The superuser, unlike other user accounts, can operate without limits, and misuse of the superuser account may result in spectacular disasters. User accounts are unable to destroy the operating system by mistake, so it is recommended to login as a user account and to only become the superuser when a command requires extra privilege. Always double and triple-check any commands issued as the superuser, since an extra space or missing character can mean irreparable data loss. There are several ways to gain superuser privilege. While one can log in as `root`, this is highly discouraged. Instead, use man:su[1] to become the superuser. If `-` is specified when running this command, the user will also inherit the root user's environment. The user running this command must be in the `wheel` group or else the command will fail. The user must also know the password for the `root` user account. In this example, the user only becomes superuser in order to run `make install` as this step requires superuser privilege. Once the command completes, the user types `exit` to leave the superuser account and return to the privilege of their user account. .Install a Program As the Superuser [example] ==== [source,shell] .... % configure % make % su - Password: # make install # exit % .... ==== The built-in man:su[1] framework works well for single systems or small networks with just one system administrator. An alternative is to install the package:security/sudo[] package or port. This software provides activity logging and allows the administrator to configure which users can run which commands as the superuser. [[users-modifying]] === Managing Accounts FreeBSD provides a variety of different commands to manage user accounts. The most common commands are summarized in -crossref:basics[users-modifying-utilities], followed by some examples of their usage. +crossref:basics[users-modifying-utilities,.Utilities for Managing User Accounts], followed by some examples of their usage. See the manual page for each utility for more details and usage examples. [[users-modifying-utilities]] .Utilities for Managing User Accounts [cols="25h,~"] |=== | Command | Summary |man:adduser[8] |The recommended command-line application for adding new users. |man:rmuser[8] |The recommended command-line application for removing users. |man:chpass[1] |A flexible tool for changing user database information. |man:passwd[1] |The command-line tool to change user passwords. |man:pw[8] |A powerful and flexible tool for modifying all aspects of user accounts. |man:bsdconfig[8] |A system configuration utility with account management support. |=== [[users-adduser]] ==== Adding a user The recommended program for adding new users is man:adduser[8]. When a new user is added, this program automatically updates `/etc/passwd` and `/etc/group`. It also creates a home directory for the new user, copies in the default configuration files from `/usr/share/skel`, and can optionally mail the new user a welcome message. This utility must be run as the superuser. The man:adduser[8] utility is interactive and walks through the steps for creating a new user account. As seen in crossref:basics[users-modifying-adduser], either input the required information or press kbd:[Return] to accept the default value shown in square brackets. In this example, the user has been invited into the `wheel` group, allowing them to become the superuser with man:su[1]. When finished, the utility will prompt to either create another user or to exit. [[users-modifying-adduser]] .Adding a User on FreeBSD [example] ==== [source,shell] .... # adduser .... The output should be similar to the following: [.programlisting] .... Username: jru Full name: J. Random User Uid (Leave empty for default): Login group [jru]: Login group is jru. Invite jru into other groups? []: wheel Login class [default]: Shell (sh csh tcsh zsh nologin) [sh]: zsh Home directory [/home/jru]: Home directory permissions (Leave empty for default): Use password-based authentication? [yes]: Use an empty password? (yes/no) [no]: Use a random password? (yes/no) [no]: Enter password: Enter password again: Lock out the account after creation? [no]: Username : jru Password : **** Full Name : J. Random User Uid : 1001 Class : Groups : jru wheel Home : /home/jru Shell : /usr/local/bin/zsh Locked : no OK? (yes/no): yes adduser: INFO: Successfully added (jru) to the user database. Add another user? (yes/no): no Goodbye! .... ==== [NOTE] ==== Since the password is not echoed when typed, be careful to not mistype the password when creating the user account. ==== [[users-rmuser]] ==== Removing a user To completely remove a user from the system, run man:rmuser[8] as the superuser. This command performs the following steps: [.procedure] ==== . Removes the user's man:crontab[1] entry, if one exists. . Removes any man:at[1] jobs belonging to the user. . Sends a SIGKILL signal to all processes owned by the user. . Removes the user from the system's local password file. . Removes the user's home directory (if it is owned by the user), including handling of symbolic links in the path to the actual home directory. . Removes the incoming mail files belonging to the user from `/var/mail`. . Removes all files owned by the user from `/tmp`, `/var/tmp`, and `/var/tmp/vi.recover`. . Removes the username from all groups to which it belongs in `/etc/group`. (If a group becomes empty and the group name is the same as the username, the group is removed; this complements man:adduser[8]'s per-user unique groups.) . Removes all message queues, shared memory segments and semaphores owned by the user. ==== man:rmuser[8] cannot be used to remove superuser accounts since that is almost always an indication of massive destruction. By default, an interactive mode is used, as shown in the following example. .`rmuser` Interactive Account Removal [example] ==== [source,shell] .... # rmuser jru .... The output should be similar to the following: [.programlisting] .... Matching password entry: jru:*:1001:1001::0:0:J. Random User:/home/jru:/usr/local/bin/zsh Is this the entry you wish to remove? y Remove user's home directory (/home/jru)? y Removing user (jru): mailspool home passwd. .... ==== [[users-chpass]] ==== Change user information Any user can use man:chpass[1] to change their default shell and personal information associated with their user account. The superuser can use this utility to change additional account information for any user. When passed no options, aside from an optional username, man:chpass[1] displays an editor containing user information. When the user exits from the editor, the user database is updated with the new information. [NOTE] ==== This utility will prompt for the user's password when exiting the editor, unless the utility is run as the superuser. ==== -In crossref:basics[users-modifying-chpass-su], the superuser has typed `chpass jru` and is now viewing the fields that can be changed for this user. +In crossref:basics[users-modifying-chpass-su,.Using `chpass` as Superuser], the superuser has typed `chpass jru` and is now viewing the fields that can be changed for this user. If `jru` runs this command instead, only the last six fields will be displayed and available for editing. -This is shown in crossref:basics[users-modifying-chpass-ru]. +This is shown in crossref:basics[users-modifying-chpass-ru,.Using `chpass` as Regular User]. [[users-modifying-chpass-su]] .Using `chpass` as Superuser [example] ==== [source,shell] .... # chpass .... The output should be similar to the following: [.programlisting] .... # Changing user database information for jru. Login: jru Password: * Uid [#]: 1001 Gid [# or name]: 1001 Change [month day year]: Expire [month day year]: Class: Home directory: /home/jru Shell: /usr/local/bin/zsh Full Name: J. Random User Office Location: Office Phone: Home Phone: Other information: .... ==== [[users-modifying-chpass-ru]] .Using `chpass` as Regular User [example] ==== [source,shell] .... #Changing user database information for jru. Shell: /usr/local/bin/zsh Full Name: J. Random User Office Location: Office Phone: Home Phone: Other information: .... ==== [NOTE] ==== The commands man:chfn[1] and man:chsh[1] are links to man:chpass[1], as are man:ypchpass[1], man:ypchfn[1], and man:ypchsh[1]. Since NIS support is automatic, specifying the `yp` before the command is not necessary. How to configure NIS is covered in crossref:network-servers[network-servers,Network Servers]. ==== [[users-passwd]] ==== Change user password Any user can easily change their password using man:passwd[1]. To prevent accidental or unauthorized changes, this command will prompt for the user's original password before a new password can be set: .Changing Your Password [example] ==== [source,shell] .... % passwd .... The output should be similar to the following: [.programlisting] .... Changing local password for jru. Old password: New password: Retype new password: passwd: updating the database... passwd: done .... ==== The superuser can change any user's password by specifying the username when running man:passwd[1]. When this utility is run as the superuser, it will not prompt for the user's current password. This allows the password to be changed when a user cannot remember the original password. .Changing Another User's Password as the Superuser [example] ==== [source,shell] .... # passwd jru .... The output should be similar to the following: [.programlisting] .... Changing local password for jru. New password: Retype new password: passwd: updating the database... passwd: done .... ==== [NOTE] ==== As with man:chpass[1], man:yppasswd[1] is a link to man:passwd[1], so NIS works with either command. ==== [[users-pw]] ==== Create, remove, modify and display system users and groups The man:pw[8] utility can create, remove, modify, and display users and groups. It functions as a front end to the system user and group files. man:pw[8] has a very powerful set of command line options that make it suitable for use in shell scripts, but new users may find it more complicated than the other commands presented in this section. [[users-groups]] === Managing Groups A group is a list of users. A group is identified by its group name and GID. In FreeBSD, the kernel uses the UID of a process, and the list of groups it belongs to, to determine what the process is allowed to do. Most of the time, the GID of a user or process usually means the first group in the list. The group name to GID mapping is listed in `/etc/group`. This is a plain text file with four colon-delimited fields. The first field is the group name, the second is the encrypted password, the third the GID, and the fourth the comma-delimited list of members. For a complete description of the syntax, refer to man:group[5]. The superuser can modify `/etc/group` using a text editor, although editing the group file using man:vigr[8] is preferred because it can catch some common mistakes. Alternatively, man:pw[8] can be used to add and edit groups. For example, to add a group called `teamtwo` and then confirm that it exists: [WARNING] ==== Care must be taken when using the operator group, as unintended superuser-like access privileges may be granted, including but not limited to shutdown, reboot, and access to all items in `/dev` in the group. ==== .Adding a Group Using man:pw[8] [example] ==== [source,shell] .... # pw groupadd teamtwo # pw groupshow teamtwo .... The output should be similar to the following: [.programlisting] .... teamtwo:*:1100: .... ==== In this example, `1100` is the GID of `teamtwo`. Right now, `teamtwo` has no members. This command will add `jru` as a member of `teamtwo`. .Adding User Accounts to a New Group Using man:pw[8] [example] ==== [source,shell] .... # pw groupmod teamtwo -M jru # pw groupshow teamtwo .... The output should be similar to the following: [.programlisting] .... teamtwo:*:1100:jru .... ==== The argument to `-M` is a comma-delimited list of users to be added to a new (empty) group or to replace the members of an existing group. To the user, this group membership is different from (and in addition to) the user's primary group listed in the password file. This means that the user will not show up as a member when using `groupshow` with man:pw[8], but will show up when the information is queried via man:id[1] or a similar tool. When man:pw[8] is used to add a user to a group, it only manipulates `/etc/group` and does not attempt to read additional data from `/etc/passwd`. .Adding a New Member to a Group Using man:pw[8] [example] ==== [source,shell] .... # pw groupmod teamtwo -m db # pw groupshow teamtwo .... The output should be similar to the following: [.programlisting] .... teamtwo:*:1100:jru,db .... ==== In this example, the argument to `-m` is a comma-delimited list of users who are to be added to the group. Unlike the previous example, these users are appended to the group and do not replace existing users in the group. .Using man:id[1] to Determine Group Membership [example] ==== [source,shell] .... % id jru .... The output should be similar to the following: [.programlisting] .... uid=1001(jru) gid=1001(jru) groups=1001(jru), 1100(teamtwo) .... ==== In this example, `jru` is a member of the groups `jru` and `teamtwo`. For more information about this command and the format of `/etc/group`, refer to man:pw[8] and man:group[5]. [[permissions]] == Permissions In FreeBSD, every file and directory has an associated set of permissions and several utilities are available for viewing and modifying these permissions. Understanding how permissions work is necessary to make sure that users are able to access the files that they need and are unable to improperly access the files used by the operating system or owned by other users. This section discusses the traditional UNIX(R) permissions used in FreeBSD. For finer-grained file system access control, refer to crossref:security[fs-acl,Access Control Lists]. In UNIX(R), basic permissions are assigned using three types of access: read, write, and execute. These access types are used to determine file access to the file's owner, group, and others (everyone else). The read, write, and execute permissions can be represented as the letters `r`, `w`, and `x`. They can also be represented as binary numbers as each permission is either on or off (`0`). When represented as a number, the order is always read as `rwx`, where `r` has an on value of `4`, `w` has an on value of `2` and `x` has an on value of `1`. Table 4.1 summarizes the possible numeric and alphabetic possibilities. When reading the "Directory Listing" column, a `-` is used to represent a permission that is set to off. .UNIX(R) Permissions [cols="1,1,1", frame="none", options="header"] |=== | Value | Permission | Directory Listing |0 |No read, no write, no execute |`---` |1 |No read, no write, execute |`--x` |2 |No read, write, no execute |`-w-` |3 |No read, write, execute |`-wx` |4 |Read, no write, no execute |`r--` |5 |Read, no write, execute |`r-x` |6 |Read, write, no execute |`rw-` |7 |Read, write, execute |`rwx` |=== Use the `-l` argument with man:ls[1] to view a long directory listing that includes a column of information about a file's permissions for the owner, group, and everyone else. For example, `ls -l` in an arbitrary directory may show: [source,shell] .... % ls -l .... The output should be similar to the following: [.programlisting] .... total 530 -rw-r--r-- 1 root wheel 512 Sep 5 12:31 myfile -rw-r--r-- 1 root wheel 512 Sep 5 12:31 otherfile -rw-r--r-- 1 root wheel 7680 Sep 5 12:31 email.txt .... Focusing on the line for `myfile`, the first `(leftmost)` character indicates whether this file is a regular file, a directory, a special character device, a socket, or any other special pseudo-file device. In this example, the `-` indicates a regular file. The next three characters, `rw-` in this example, give the permissions for the owner of the file. The next three characters, `r--`, give the permissions for the group that the file belongs to. The final three characters, `r--`, give the permissions for the rest of the world. A dash means that the permission is turned off. In this example, the permissions are set so the owner can read and write to the file, the group can read the file, and the rest of the world can only read the file. According to the table above, the permissions for this file would be `644`, where each digit represents the three parts of the file's permission. How does the system control permissions on devices? FreeBSD treats most hardware devices as a file that programs can open, read, and write data to. These special device files are stored in `/dev/`. Directories are also treated as files. They have read, write, and execute permissions. The executable bit for a directory has a slightly different meaning than that of files. When a directory is marked executable, it means it is possible to change into that directory using man:cd[1]. This also means that it is possible to access the files within that directory, subject to the permissions on the files themselves. In order to perform a directory listing, the read permission must be set on the directory. In order to delete a file that one knows the name of, it is necessary to have write _and_ execute permissions to the directory containing the file. There are more permission bits, but they are primarily used in special circumstances such as setuid binaries and sticky directories. For more information on file permissions and how to set them, refer to man:chmod[1]. === Symbolic Permissions Symbolic permissions use characters instead of octal values to assign permissions to files or directories. Symbolic permissions use the syntax of (who) (action) (permissions), where the following values are available: [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Option | Letter | Represents |(who) |u |User |(who) |g |Group owner |(who) |o |Other |(who) |a |All ("world") |(action) |+ |Adding permissions |(action) |- |Removing permissions |(action) |= |Explicitly set permissions |(permissions) |r |Read |(permissions) |w |Write |(permissions) |x |Execute |(permissions) |t |Sticky bit |(permissions) |s |Set UID or GID |=== These values are used with man:chmod[1], but with letters instead of numbers. For example, the following command would block both members of the group associated with _FILE_ and all other users from accessing _FILE_: [source,shell] .... % chmod go= FILE .... A comma separated list can be provided when more than one set of changes to a file must be made. For example, the following command removes the group and "world" write permission on _FILE_, and adds the execute permissions for everyone: [source,shell] .... % chmod go-w,a+x FILE .... === FreeBSD File Flags In addition to file permissions, FreeBSD supports the use of "file flags". These flags add an additional level of security and control over files, but not directories. With file flags, even `root` can be prevented from removing or altering files. File flags are modified using man:chflags[1]. For example, to enable the system undeletable flag on the file `file1`, issue the following command: [source,shell] .... # chflags sunlink file1 .... To disable the system undeletable flag, put a "no" in front of the `sunlink`: [source,shell] .... # chflags nosunlink file1 .... To view the flags of a file, use `-lo` with man:ls[1]: [source,shell] .... # ls -lo file1 .... [.programlisting] .... -rw-r--r-- 1 trhodes trhodes sunlnk 0 Mar 1 05:54 file1 .... Several file flags may only be added or removed by the `root` user. In other cases, the file owner may set its file flags. Refer to man:chflags[1] and man:chflags[2] for more information. === The setuid, setgid, and sticky Permissions Other than the permissions already discussed, there are three other specific settings that all administrators should know about. They are the `setuid`, `setgid`, and `sticky` permissions. These settings are important for some UNIX(R) operations as they provide functionality not normally granted to normal users. To understand them, the difference between the real user ID and effective user ID must be noted. The real user ID is the UID who owns or starts the process. The effective UID is the user ID the process runs as. As an example, man:passwd[1] runs with the real user ID when a user changes their password. However, in order to update the password database, the command runs as the effective ID of the `root` user. This allows users to change their passwords without seeing a `Permission Denied` error. The setuid permission may be added symbolically by adding the `s` permission for the user as in the following example: [source,shell] .... # chmod u+s suidexample.sh .... The setuid permission may also be set by prefixing a permission set with the number four (4) as shown in the following example: [source,shell] .... # chmod 4755 suidexample.sh .... The permissions on `suidexample.sh` now look like the following: [.programlisting] .... -rwsr-xr-x 1 trhodes trhodes 63 Aug 29 06:36 suidexample.sh .... Note that a `s` is now part of the permission set designated for the file owner, replacing the executable bit. This allows utilities which need elevated permissions, such as man:passwd[1]. [NOTE] ==== The `nosuid` man:mount[8] option will cause such binaries to silently fail without alerting the user. That option is not completely reliable as a `nosuid` wrapper may be able to circumvent it. ==== To view this in real time, open two terminals. On one, type `passwd` as a normal user. While it waits for a new password, check the process table and look at the user information for man:passwd[1]: In terminal A: [source,shell] .... Changing local password for trhodes Old Password: .... In terminal B: [source,shell] .... # ps aux | grep passwd .... [source,shell] .... trhodes 5232 0.0 0.2 3420 1608 0 R+ 2:10AM 0:00.00 grep passwd root 5211 0.0 0.2 3620 1724 2 I+ 2:09AM 0:00.01 passwd .... Although man:passwd[1] is run as a normal user, it is using the effective UID of `root`. The `setgid` permission performs the same function as the `setuid` permission; except that it alters the group settings. When an application or utility executes with this setting, it will be granted the permissions based on the group that owns the file, not the user who started the process. To set the `setgid` permission on a file symbolically, add the `s` permission for the group with man:chmod[1]: [source,shell] .... # chmod g+s sgidexample.sh .... Alternatively, provide man:chmod[1] with a leading two (2): [source,shell] .... # chmod 2755 sgidexample.sh .... In the following listing, notice that the `s` is now in the field designated for the group permission settings: [source,shell] .... -rwxr-sr-x 1 trhodes trhodes 44 Aug 31 01:49 sgidexample.sh .... [NOTE] ==== In these examples, even though the shell script in question is an executable file, it will not run with a different EUID or effective user ID. This is because shell scripts may not access the man:setuid[2] system calls. ==== The `setuid` and `setgid` permission bits may lower system security, by allowing for elevated permissions. The third special permission, the `sticky bit`, can strengthen the security of a system. When the `sticky bit` is set on a directory, it allows file deletion only by the file owner. This is useful to prevent file deletion in public directories, such as `/tmp`, by users who do not own the file. To utilize this permission, add the `t` mode to the file: [source,shell] .... # chmod +t /tmp .... Alternatively, prefix the permission set with a one (1): [source,shell] .... # chmod 1777 /tmp .... The `sticky bit` permission will display as a `t` at the very end of the permission set: [source,shell] .... # ls -al / | grep tmp .... [source,shell] .... drwxrwxrwt 10 root wheel 512 Aug 31 01:49 tmp .... [[dirstructure]] == Directory Structure The FreeBSD directory hierarchy is fundamental to obtaining an overall understanding of the system. The most important directory is root or, "/". This directory is the first one mounted at boot time and it contains the base system necessary to prepare the operating system for multi-user operation. The root directory also contains mount points for other file systems that are mounted during the transition to multi-user operation. A mount point is a directory where additional file systems can be grafted onto a parent file system (usually the root file system). -This is further described in crossref:basics[disk-organization]. +This is further described in crossref:basics[disk-organization, Disk Organization]. Standard mount points include `/usr/`, `/var/`, `/tmp/`, `/mnt/`, and `/cdrom/`. These directories are usually referenced to entries in `/etc/fstab`. This file is a table of various file systems and mount points and is read by the system. Most of the file systems in `/etc/fstab` are mounted automatically at boot time from the script man:rc[8] unless their entry includes `noauto`. -Details can be found in crossref:basics[disks-fstab]. +Details can be found in crossref:basics[disks-fstab, The fstab File]. A complete description of the file system hierarchy is available in man:hier[7]. The following table provides a brief overview of the most common directories. [cols="25h,~"] |=== | Directory | Description |`/` |Root directory of the file system. |`/bin/` |User utilities fundamental to both single-user and multi-user environments. |`/boot/` |Programs and configuration files used during operating system bootstrap. |`/boot/defaults/` |Default boot configuration files. Refer to man:loader.conf[5] for details. |`/dev/` |Device special files managed by man:devfs[5] |`/etc/` |System configuration files and scripts. |`/etc/defaults/` |Default system configuration files. Refer to man:rc[8] for details. |`/etc/periodic/` |Scripts that run daily, weekly, and monthly, via man:cron[8]. Refer to man:periodic[8] for details. |`/lib/` |Critical system libraries needed for binaries in `/bin` and `/sbin` |`/libexec/` |Critical system files |`/media/` |Contains subdirectories to be used as mount points for removable media such as CDs, USB drives, and floppy disks |`/mnt/` |Empty directory commonly used by system administrators as a temporary mount point. |`/net/` |Automounted NFS shares; see man:auto_master[5] |`/proc/` |Process file system. Refer to man:procfs[5], man:mount_procfs[8] for details. |`/rescue/` |Statically linked programs for emergency recovery as described in man:rescue[8]. |`/root/` |Home directory for the `root` account. |`/sbin/` |System programs and administration utilities fundamental to both single-user and multi-user environments. |`/tmp/` |Temporary files which are usually _not_ preserved across a system reboot. A memory-based file system is often mounted at `/tmp`. This can be automated using the tmpmfs-related variables of man:rc.conf[5] or with an entry in `/etc/fstab`; refer to man:mdmfs[8] for details. |`/usr/` |The majority of user utilities and applications. |`/usr/bin/` |Common utilities, programming tools, and applications. |`/usr/include/` |Standard C include files. |`/usr/lib/` |Archive libraries. |`/usr/libdata/` |Miscellaneous utility data files. |`/usr/libexec/` |System daemons and system utilities executed by other programs. |`/usr/local/` |Local executables and libraries. Also used as the default destination for the FreeBSD ports framework. Within `/usr/local`, the general layout sketched out by man:hier[7] for `/usr` should be used. Exceptions are the man directory, which is directly under `/usr/local` rather than under `/usr/local/share`, and the ports documentation is in `share/doc/port`. |`/usr/ports/` |The FreeBSD Ports Collection (optional). |`/usr/sbin/` |System daemons and system utilities executed by users. |`/usr/share/` |Architecture-independent files. |`/usr/src/` |BSD and/or local source files. |`/var/` |Multi-purpose log, temporary, transient, and spool files. |`/var/log/` |Miscellaneous system log files. |`/var/tmp/` |Temporary files which are usually preserved across a system reboot. |=== [[disk-organization]] == Disk Organization The smallest unit of organization that FreeBSD uses to find files is the filename. Filenames are case-sensitive, which means that `readme.txt` and `README.TXT` are two separate files. FreeBSD does not use the extension of a file to determine whether the file is a program, document, or some other form of data. Files are stored in directories. A directory may contain no files, or it may contain many hundreds of files. A directory can also contain other directories, allowing a hierarchy of directories within one another in order to organize data. Files and directories are referenced by giving the file or directory name, followed by a forward slash, `/`, followed by any other directory names that are necessary. For example, if the directory `foo` contains a directory `bar` which contains the file `readme.txt`, the full name, or _path_, to the file is `foo/bar/readme.txt`. Note that this is different from Windows(R) which uses `\` to separate file and directory names. FreeBSD does not use drive letters, or other drive names in the path. For example, one would not type `c:\foo\bar\readme.txt` on FreeBSD. [[disks-file-systems]] === File systems Directories and files are stored in a file system. Each file system contains exactly one directory at the very top level, called the _root directory_ for that file system. This root directory can contain other directories. One file system is designated the _root file system_ or `/`. Every other file system is _mounted_ under the root file system. No matter how many disks are on the FreeBSD system, every directory appears to be part of the same disk. Consider three file systems, called `A`, `B`, and `C`. Each file system has one root directory, which contains two other directories, called `A1`, `A2` (and likewise `B1`, `B2` and `C1`, `C2`). Call `A` the root file system. If man:ls[1] is used to view the contents of this directory, it will show two subdirectories, `A1` and `A2`. The directory tree looks like this: image::example-dir1.png[Directory tree with the root directory and two subdirectories, A1 and A2] A file system must be mounted on to a directory in another file system. When mounting file system `B` on to the directory `A1`, the root directory of `B` replaces `A1`, and the directories in `B` appear accordingly: image::example-dir2.png[Directory tree with the root directory and two subdirectories, A1 and A2. And more subdirectories, B1 and B2 hanging from A1] Any files that are in the `B1` or `B2` directories can be reached with the path `/A1/B1` or `/A1/B2` as necessary. Any files that were in `/A1` have been temporarily hidden. They will reappear if `B` is _unmounted_ from `A`. If `B` had been mounted on `A2` then the diagram would look like this: image::example-dir3.png[Directory tree with the root directory and two subdirectories, A1 and A2. And more subdirectories, B1 and B2 hanging from A2] and the paths would be `/A2/B1` and `/A2/B2` respectively. File systems can be mounted on top of one another. Continuing the last example, the `C` file system could be mounted on top of the `B1` directory in the `B` file system, leading to this arrangement: image::example-dir4.png[A complex directory tree. With different subdirectories hanging from root.] Or `C` could be mounted directly on to the `A` file system, under the `A1` directory: image::example-dir5.png[A complex directory tree. With different subdirectories hanging from root.] It is entirely possible to have one large root file system, and not need to create any others. There are some drawbacks to this approach, and one advantage. .Benefits of Multiple File Systems * Different file systems can have different _mount options_. For example, the root file system can be mounted read-only, making it impossible for users to inadvertently delete or edit a critical file. Separating user-writable file systems, such as `/home`, from other file systems allows them to be mounted _nosuid_. This option prevents the _suid_/_guid_ bits on executables stored on the file system from taking effect, possibly improving security. * FreeBSD automatically optimizes the layout of files on a file system, depending on how the file system is being used. So a file system that contains many small files that are written frequently will have a different optimization to one that contains fewer, larger files. By having one big file system this optimization breaks down. * FreeBSD's file systems are robust if power is lost. However, a power loss at a critical point could still damage the structure of the file system. By splitting data over multiple file systems it is more likely that the system will still come up, making it easier to restore from backup as necessary. .Benefit of a Single File System * File systems are a fixed size. If you create a file system when you install FreeBSD and give it a specific size, you may later discover that you need to make the partition bigger. This is not easily accomplished without backing up, recreating the file system with the new size, and then restoring the backed up data. + [IMPORTANT] ==== FreeBSD features the man:growfs[8] command, which makes it possible to increase the size of file system on the fly, removing this limitation. A file system can only be expanded into free space in the partition in which it resides. If there is space after the partition, the partition can be expanded with man:gpart[8]. If the partition is the last one on a virtual disk, and the disk is expanded, the partition can then be expanded. ==== [[disks-partitions]] === Disk partitions File systems are contained in _partitions_. Disks are divided into partitions using one of several partitioning schemes; see crossref:basics[bsdinstall-part-manual]. The newer scheme is GPT; older BIOS-based computers use MBR. GPT supports division of a disk into partitions with a size, offset, and type. It supports a large number of partitions and partition types, and is recommended whenever its use is possible. GPT partitions use the disk name with a suffix, where the suffix is `p1` for the first partition, `p2` for the second, and so on. MBR, however, supports only a small number of partitions. The MBR partitions are known in FreeBSD as `slices`. Slices may be used for different operating systems. FreeBSD slices are subdivided into partitions using BSD labels (see man:bsdlabel[8]). Slice numbers follow the device name, prefixed with an `s`, starting at 1. So "da0__s1__" is the first slice on the first SCSI drive. There can only be four physical slices on a disk, but there can be logical slices inside physical slices of the appropriate type. These extended slices are numbered starting at 5, so "ada0__s5__" is the first extended slice on the first SATA disk. These devices are used by file systems that expect to occupy a slice. Each GPT or BSD partition can contain only one file system, which means that file systems are often described by either their typical mount point in the file system hierarchy, or the name of the partition they are contained in. FreeBSD also uses disk space for _swap space_ to provide _virtual memory_. This allows your computer to behave as though it has much more memory than it actually does. When FreeBSD runs out of memory, it moves some of the data that is not currently being used to the swap space, and moves it back in (moving something else out) when it needs it. This is called _paging_. Some BSD partitions have certain conventions associated with them. [cols="25h,~"] |=== | Partition | Convention |`a` |Normally contains the root file system. |`b` |Normally contains swap space. |`c` |Normally the same size as the enclosing slice. This allows utilities that need to work on the entire slice, such as a bad block scanner, to work on the `c` partition. A file system would not normally be created on this partition. |`d` |Partition `d` used to have a special meaning associated with it, although that is now gone and `d` may work as any normal partition. |=== Slices and "dangerously dedicated" physical drives contain BSD partitions, which are represented as letters from `a` to `h`. This letter is appended to the device name, so "da0__a__" is the `a` partition on the first `da` drive, which is "dangerously dedicated". "ada1s3__e__" is the fifth partition in the third slice of the second SATA disk drive. Finally, each disk on the system is identified. A disk name starts with a code that indicates the type of disk, and then a number, indicating which disk it is. Unlike partitions and slices, disk numbering starts at 0. -Common codes are listed in crossref:basics[disks-naming]. +Common codes are listed in crossref:basics[disks-naming,.Disk Device Names]. When referring to a partition in a slice, include the disk name, `s`, the slice number, and then the partition letter. -Examples are shown in crossref:basics[basics-disk-slice-part]. +Examples are shown in crossref:basics[basics-disk-slice-part,.Sample Disk, Slice, and Partition Names]. GPT partitions include the disk name, `p`, and then the partition number. -crossref:basics[basics-concept-disk-model] shows a conceptual model of a disk layout using MBR slices. +crossref:basics[basics-concept-disk-model,.Conceptual Model of a Disk] shows a conceptual model of a disk layout using MBR slices. When installing FreeBSD, configure the disk slices if using MBR, and create partitions within the slice to be used for FreeBSD. If using GPT, configure partitions for each file system. In either case, create a file system or swap space in each partition, and decide where each file system will be mounted. See man:gpart[8] for information on manipulating partitions. [[disks-naming]] .Disk Device Names [cols="1,1", frame="none", options="header"] |=== | Drive Type | Drive Device Name |SATA and IDE hard drives |`ada` |SCSI hard drives and USB storage devices |`da` |NVMe storage |`nvd` or `nda` |SATA and IDE CD-ROM drives |`cd` |SCSI CD-ROM drives |`cd` |Floppy drives |`fd` |SCSI tape drives |`sa` |RAID drives |Examples include `aacd` for Adaptec(R) AdvancedRAID, `mlxd` and `mlyd` for Mylex(R), `amrd` for AMI MegaRAID(R), `idad` for Compaq Smart RAID, `twed` for 3ware(R) RAID. |=== [example] ==== [[basics-disk-slice-part]] .Sample Disk, Slice, and Partition Names [.informaltable] [cols="1,1", frame="none", options="header"] |=== | Name | Meaning |`ada0s1a` |The first partition (`a`) on the first slice (`s1`) on the first SATA disk (`ada0`). |`da1s2e` |The fifth partition (`e`) on the second slice (`s2`) on the second SCSI disk (`da1`). |=== ==== [[basics-concept-disk-model]] .Conceptual Model of a Disk [example] ==== This diagram shows FreeBSD's view of the first SATA disk attached to the system. Assume that the disk is 250 GB in size, and contains an 80 GB slice and a 170 GB slice (MS-DOS(R) partitions). The first slice contains a Windows(R) NTFS file system, `C:`, and the second slice contains a FreeBSD installation. This example FreeBSD installation has four data partitions and a swap partition. The four partitions each hold a file system. Partition `a` is used for the root file system, `d` for `/var/`, `e` for `/tmp/`, and `f` for `/usr/`. Partition letter `c` refers to the entire slice, and so is not used for ordinary partitions. image::disk-layout.png[Layout of a shared drive between Windows and FreeBSD] ==== [[mount-unmount]] == Mounting and Unmounting File Systems The file system is best visualized as a tree, rooted, as it were, at `/`. `/dev`, `/usr`, and the other directories in the root directory are branches, which may have their own branches, such as `/usr/local`, and so on. There are various reasons to house some of these directories on separate file systems. `/var` contains the directories `log/`, `spool/`, and various types of temporary files, and as such, may get filled up. Filling up the root file system is not a good idea, so splitting `/var` from `/` is often favorable. Another common reason to contain certain directory trees on other file systems is if they are to be housed on separate physical disks, or are separate virtual disks, such as Network File System mounts, described in crossref:network-servers[network-nfs,“Network File System (NFS)”], or CDROM drives. [[disks-fstab]] === The fstab File During the boot process (crossref:boot[boot,The FreeBSD Booting Process]), file systems listed in `/etc/fstab` are automatically mounted except for the entries containing `noauto`. This file contains entries in the following format: [.programlisting] .... device /mount-point fstype options dumpfreq passno .... `device`:: -An existing device name as explained in crossref:basics[disks-naming]. +An existing device name as explained in crossref:basics[disks-naming,.Disk Device Names]. `mount-point`:: An existing directory on which to mount the file system. `fstype`:: The file system type to pass to man:mount[8]. The default FreeBSD file system is `ufs`. `options`:: Either `rw` for read-write file systems, or `ro` for read-only file systems, followed by any other options that may be needed. A common option is `noauto` for file systems not normally mounted during the boot sequence. Other options are listed in man:mount[8]. `dumpfreq`:: Used by man:dump[8] to determine which file systems require dumping. If the field is missing, a value of zero is assumed. `passno`:: Determines the order in which UFS file systems should be checked by man:fsck[8] after a reboot. File systems that should be skipped should have their `passno` set to zero. The root file system needs to be checked before everything else and should have its `passno` set to one. The other file systems should be set to values greater than one. If more than one file system has the same `passno`, man:fsck[8] will attempt to check file systems in parallel if possible. Refer to man:fstab[5] for more information on the format of `/etc/fstab` and its options. [[disks-mount]] === Using man:mount[8] File systems are mounted using man:mount[8]. The most basic syntax is as follows: [example] ==== [source,shell] .... # mount device mountpoint .... ==== A file system listed in `/etc/fstab` can also be mounted by providing just the mountpoint. This command provides many options which are described in man:mount[8]. The most commonly used options include: .Mount Options `-a`:: Mount all the file systems listed in `/etc/fstab`, except those marked as "noauto", excluded by the `-t` flag, or those that are already mounted. `-d`:: Do everything except for the actual mount system call. This option is useful in conjunction with the `-v` flag to determine what man:mount[8] is actually trying to do. `-f`:: Force the mount of an unclean file system (dangerous), or the revocation of write access when downgrading a file system's mount status from read-write to read-only. `-r`:: Mount the file system read-only. This is identical to using `-o ro`. ``-t _fstype_``:: Mount the specified file system type or mount only file systems of the given type, if `-a` is included. "ufs" is the default file system type. `-u`:: Update mount options on the file system. `-v`:: Be verbose. `-w`:: Mount the file system read-write. The following options can be passed to `-o` as a comma-separated list: nosuid:: Do not interpret setuid or setgid flags on the file system. This is also a useful security option. [[disks-umount]] === Using man:umount[8] To unmount a file system use man:umount[8]. This command takes one parameter which can be a mountpoint, device name, `-a` or `-A`. All forms take `-f` to force unmounting, and `-v` for verbosity. Be warned that `-f` is not generally a good idea as it might crash the computer or damage data on the file system. To unmount all mounted file systems, or just the file system types listed after `-t`, use `-a` or `-A`. Note that `-A` does not attempt to unmount the root file system. [[basics-processes]] == Processes and Daemons FreeBSD is a multi-tasking operating system. Each program running at any one time is called a _process_. Every running command starts at least one new process and there are a number of system processes that are run by FreeBSD. Each process is uniquely identified by a number called a _process ID_ (PID). Similar to files, each process has one owner and group, and the owner and group permissions are used to determine which files and devices the process can open. Most processes also have a parent process that started them. For example, the shell is a process, and any command started in the shell is a process which has the shell as its parent process. The exception is a special process called man:init[8] which is always the first process to start at boot time and which always has a PID of `1`. Some programs are not designed to be run with continuous user input and disconnect from the terminal at the first opportunity. For example, a web server responds to web requests, rather than user input. Mail servers are another example of this type of application. These types of programs are known as _daemons_. The term daemon comes from Greek mythology and represents an entity that is neither good nor evil, and which invisibly performs useful tasks. This is why the BSD mascot is the cheerful-looking daemon with sneakers and a pitchfork. There is a convention to name programs that normally run as daemons with a trailing "d". For example, BIND is the Berkeley Internet Name Domain, but the actual program that executes is `named`. The Apache web server program is `httpd` and the line printer spooling daemon is `lpd`. This is only a naming convention. For example, the main mail daemon for the Sendmail application is `sendmail`, and not `maild`. === Viewing Processes To see the processes running on the system, use man:ps[1] or man:top[1]. To display a static list of the currently running processes, their PIDs, how much memory they are using, and the command they were started with, use man:ps[1]. To display all the running processes and update the display every few seconds in order to interactively see what the computer is doing, use man:top[1]. By default, man:ps[1] only shows the commands that are running and owned by the user. For example: [source,shell] .... % ps .... The output should be similar to the following: [.programlisting] .... PID TT STAT TIME COMMAND 8203 0 Ss 0:00.59 /bin/csh 8895 0 R+ 0:00.00 ps .... The output from man:ps[1] is organized into a number of columns. The `PID` column displays the process ID. PIDs are assigned starting at 1, go up to 99999, then wrap around back to the beginning. However, a PID is not reassigned if it is already in use. The `TT` column shows the tty the program is running on and `STAT` shows the program's state. `TIME` is the amount of time the program has been running on the CPU. This is usually not the elapsed time since the program was started, as most programs spend a lot of time waiting for things to happen before they need to spend time on the CPU. Finally, `COMMAND` is the command that was used to start the program. A number of different options are available to change the information that is displayed. One of the most useful sets is `auxww`, where `a` displays information about all the running processes of all users, `u` displays the username and memory usage of the process' owner, `x` displays information about daemon processes, and `ww` causes man:ps[1] to display the full command line for each process, rather than truncating it once it gets too long to fit on the screen. The output from man:top[1] is similar: [source,shell] .... % top .... The output should be similar to the following: [.programlisting] .... last pid: 9609; load averages: 0.56, 0.45, 0.36 up 0+00:20:03 10:21:46 107 processes: 2 running, 104 sleeping, 1 zombie CPU: 6.2% user, 0.1% nice, 8.2% system, 0.4% interrupt, 85.1% idle Mem: 541M Active, 450M Inact, 1333M Wired, 4064K Cache, 1498M Free ARC: 992M Total, 377M MFU, 589M MRU, 250K Anon, 5280K Header, 21M Other Swap: 2048M Total, 2048M Free PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND 557 root 1 -21 r31 136M 42296K select 0 2:20 9.96% Xorg 8198 dru 2 52 0 449M 82736K select 3 0:08 5.96% kdeinit4 8311 dru 27 30 0 1150M 187M uwait 1 1:37 0.98% firefox 431 root 1 20 0 14268K 1728K select 0 0:06 0.98% moused 9551 dru 1 21 0 16600K 2660K CPU3 3 0:01 0.98% top 2357 dru 4 37 0 718M 141M select 0 0:21 0.00% kdeinit4 8705 dru 4 35 0 480M 98M select 2 0:20 0.00% kdeinit4 8076 dru 6 20 0 552M 113M uwait 0 0:12 0.00% soffice.bin 2623 root 1 30 10 12088K 1636K select 3 0:09 0.00% powerd 2338 dru 1 20 0 440M 84532K select 1 0:06 0.00% kwin 1427 dru 5 22 0 605M 86412K select 1 0:05 0.00% kdeinit4 .... The output is split into two sections. The header (the first five or six lines) shows the PID of the last process to run, the system load averages (which are a measure of how busy the system is), the system uptime (time since the last reboot) and the current time. The other figures in the header relate to how many processes are running, how much memory and swap space has been used, and how much time the system is spending in different CPU states. If the ZFS file system module has been loaded, an `ARC` line indicates how much data was read from the memory cache instead of from disk. Below the header is a series of columns containing similar information to the output from man:ps[1], such as the PID, username, amount of CPU time, and the command that started the process. By default, man:top[1] also displays the amount of memory space taken by the process. This is split into two columns: one for total size and one for resident size. Total size is how much memory the application has needed and the resident size is how much it is actually using now. man:top[1] automatically updates the display every two seconds. A different interval can be specified with `-s`. [[basics-daemons]] === Killing Processes One way to communicate with any running process or daemon is to send a _signal_ using man:kill[1]. There are a number of different signals; some have a specific meaning while others are described in the application's documentation. A user can only send a signal to a process they own and sending a signal to someone else's process will result in a permission denied error. The exception is the `root` user, who can send signals to anyone's processes. The operating system can also send a signal to a process. If an application is badly written and tries to access memory that it is not supposed to, FreeBSD will send the process the "Segmentation Violation" signal (`SIGSEGV`). If an application has been written to use the man:alarm[3] system call to be alerted after a period of time has elapsed, it will be sent the "Alarm" signal (`SIGALRM`). Two signals can be used to stop a process: `SIGTERM` and `SIGKILL`. `SIGTERM` is the polite way to kill a process as the process can read the signal, close any log files it may have open, and attempt to finish what it is doing before shutting down. In some cases, a process may ignore `SIGTERM` if it is in the middle of some task that cannot be interrupted. `SIGKILL` cannot be ignored by a process. Sending a `SIGKILL` to a process will usually stop that process there and then. footnote:[There are a few tasks that cannot be interrupted. For example, if the process is trying to read from a file that is on another computer on the network, and the other computer is unavailable, the process is said to be uninterruptible. Eventually the process will time out, typically after two minutes. As soon as this time out occurs the process will be killed.]. Other commonly used signals are `SIGHUP`, `SIGUSR1`, and `SIGUSR2`. Since these are general purpose signals, different applications will respond differently. For example, after changing a web server's configuration file, the web server needs to be told to re-read its configuration. Restarting `httpd` would result in a brief outage period on the web server. Instead, send the daemon the `SIGHUP` signal. Be aware that different daemons will have different behavior, so refer to the documentation for the daemon to determine if `SIGHUP` will achieve the desired results. [IMPORTANT] ==== Killing a random process on the system is a bad idea. In particular, man:init[8], PID 1, is special. Running `/bin/kill -s KILL 1` is a quick, and unrecommended, way to shutdown the system. _Always_ double check the arguments to man:kill[1] _before_ pressing kbd:[Return]. ==== [[shells]] == Shells A _shell_ provides a command line interface for interacting with the operating system. A shell receives commands from the input channel and executes them. Many shells provide built in functions to help with everyday tasks such as file management, file globbing, command line editing, command macros, and environment variables. FreeBSD comes with several shells, including the Bourne shell (man:sh[1]) and the extended C shell (man:tcsh[1]). Other shells are available from the FreeBSD Ports Collection, such as `zsh` and `bash`. The shell that is used is really a matter of taste. A C programmer might feel more comfortable with a C-like shell such as man:tcsh[1]. A Linux(R) user might prefer `bash`. Each shell has unique properties that may or may not work with a user's preferred working environment, which is why there is a choice of which shell to use. One common shell feature is filename completion. After a user types the first few letters of a command or filename and presses kbd:[Tab], the shell completes the rest of the command or filename. Consider two files called `foobar` and `football`. To delete `foobar`, the user might type `rm foo` and press kbd:[Tab] to complete the filename. But the shell only shows `rm foo`. It was unable to complete the filename because both `foobar` and `football` start with `foo`. Some shells sound a beep or show all the choices if more than one name matches. The user must then type more characters to identify the desired filename. Typing a `t` and pressing kbd:[Tab] again is enough to let the shell determine which filename is desired and fill in the rest. Another feature of the shell is the use of environment variables. Environment variables are a variable/key pair stored in the shell's environment. This environment can be read by any program invoked by the shell, and thus contains a lot of program configuration. -crossref:basics[shell-env-vars] provides a list of common environment variables and their meanings. +crossref:basics[shell-env-vars,.Common Environment Variables] provides a list of common environment variables and their meanings. Note that the names of environment variables are always in uppercase. [[shell-env-vars]] .Common Environment Variables [cols="25h,~"] |=== | Variable | Description |`USER` |Current logged in user's name. |`PATH` |Colon-separated list of directories to search for binaries. |`DISPLAY` |Network name of the Xorg display to connect to, if available. |`SHELL` |The current shell. |`TERM` |The name of the user's type of terminal. Used to determine the capabilities of the terminal. |`TERMCAP` |Database entry of the terminal escape codes to perform various terminal functions. |`OSTYPE` |Type of operating system. |`MACHTYPE` |The system's CPU architecture. |`EDITOR` |The user's preferred text editor. |`PAGER` |The user's preferred utility for viewing text one page at a time. |`MANPATH` |Colon-separated list of directories to search for manual pages. |=== How to set an environment variable differs between shells. In man:tcsh[1] and man:csh[1], use `setenv` to set environment variables. In man:sh[1] and `bash`, use `export` to set the current environment variables. This example sets the default `EDITOR` to `/usr/local/bin/emacs` for the man:tcsh[1] shell: [source,shell] .... % setenv EDITOR /usr/local/bin/emacs .... The equivalent command for `bash` would be: [source,shell] .... % export EDITOR="/usr/local/bin/emacs" .... To expand an environment variable in order to see its current setting, type a `$` character in front of its name on the command line. For example, `echo $TERM` displays the current `$TERM` setting. Shells treat special characters, known as meta-characters, as special representations of data. The most common meta-character is `\*`, which represents any number of characters in a filename. Meta-characters can be used to perform filename globbing. For example, `echo *` is equivalent to `ls` because the shell takes all the files that match `*` and `echo` lists them on the command line. To prevent the shell from interpreting a special character, escape it from the shell by starting it with a backslash (`\`). For example, `echo $TERM` prints the terminal setting whereas `echo \$TERM` literally prints the string `$TERM`. [[changing-shells]] === Changing the Shell The easiest way to permanently change the default shell is to use `chsh`. Running this command will open the editor that is configured in the `EDITOR` environment variable, which by default is set to man:vi[1]. Change the `Shell:` line to the full path of the new shell. Alternately, use `chsh -s` which will set the specified shell without opening an editor. For example, to change the shell to `bash`: [source,shell] .... % chsh -s /usr/local/bin/bash .... Enter your password at the prompt and press kbd:[Return] to change your shell. Log off and log in again to start using the new shell. [NOTE] ==== The new shell _must_ be present in `/etc/shells`. If the shell was installed from the FreeBSD Ports Collection as described in crossref:ports[ports,Installing Applications: Packages and Ports], it should be automatically added to this file. If it is missing, add it using this command, replacing the path with the path of the shell: [source,shell] .... # echo /usr/local/bin/bash >> /etc/shells .... Then, rerun man:chsh[1]. ==== === Advanced Shell Techniques The UNIX(R) shell is not just a command interpreter, it acts as a powerful tool which allows users to execute commands, redirect their output, redirect their input and chain commands together to improve the final command output. When this functionality is mixed with built in commands, the user is provided with an environment that can maximize efficiency. Shell redirection is the action of sending the output or the input of a command into another command or into a file. To capture the output of the man:ls[1] command, for example, into a file, redirect the output: [source,shell] .... % ls > directory_listing.txt .... The directory contents will now be listed in `directory_listing.txt`. Some commands can be used to read input, such as man:sort[1]. To sort this listing, redirect the input: [source,shell] .... % sort < directory_listing.txt .... The input will be sorted and placed on the screen. To redirect that input into another file, one could redirect the output of man:sort[1] by mixing the direction: [source,shell] .... % sort < directory_listing.txt > sorted.txt .... In all of the previous examples, the commands are performing redirection using file descriptors. Every UNIX(R) system has file descriptors, which include standard input (stdin), standard output (stdout), and standard error (stderr). Each one has a purpose, where input could be a keyboard or a mouse, something that provides input. Output could be a screen or paper in a printer. And error would be anything that is used for diagnostic or error messages. All three are considered I/O based file descriptors and sometimes considered streams. Through the use of these descriptors, the shell allows output and input to be passed around through various commands and redirected to or from a file. Another method of redirection is the pipe operator. The UNIX(R) pipe operator, "|" allows the output of one command to be directly passed or directed to another program. Basically, a pipe allows the standard output of a command to be passed as standard input to another command, for example: [source,shell] .... % cat directory_listing.txt | sort | less .... In that example, the contents of `directory_listing.txt` will be sorted and the output passed to man:less[1]. This allows the user to scroll through the output at their own pace and prevent it from scrolling off the screen. [[editors]] == Text Editors Most FreeBSD configuration is done by editing text files, so it is a good idea to become familiar with a text editor. FreeBSD comes with a few as part of the base system, and many more are available in the Ports Collection. A simple editor to learn is man:ee[1], which stands for easy editor. To start this editor, type `ee _filename_` where _filename_ is the name of the file to be edited. Once inside the editor, all of the commands for manipulating the editor's functions are listed at the top of the display. The caret (`^`) represents kbd:[Ctrl], so `^e` expands to kbd:[Ctrl+e]. To leave man:ee[1], press kbd:[Esc], then choose the "leave editor" option from the main menu. The editor will prompt to save any changes if the file has been modified. FreeBSD also comes with more powerful text editors, such as man:vi[1], as part of the base system. Other editors, like package:editors/emacs[] and package:editors/vim[], are part of the FreeBSD Ports Collection. These editors offer more functionality at the expense of being more complicated to learn. Learning a more powerful editor such as vim or Emacs can save more time in the long run. Many applications which modify files or require typed input will automatically open a text editor. To change the default editor, set the `EDITOR` environment variable as described -in crossref:basics[shells]. +in crossref:basics[shells, Shells]. [[basics-devices]] == Devices and Device Nodes A device is a term used mostly for hardware-related activities in a system, including disks, printers, graphics cards, and keyboards. When FreeBSD boots, the majority of the boot messages refer to devices being detected. A copy of the boot messages is saved to `/var/run/dmesg.boot`. Each device has a device name and number. For example, `ada0` is the first SATA hard drive, while `kbd0` represents the keyboard. Most devices in FreeBSD must be accessed through special files called device nodes, which are located in `/dev`. [[basics-more-information]] == Manual Pages The most comprehensive documentation on FreeBSD is in the form of manual pages. Nearly every program on the system comes with a short reference manual explaining the basic operation and available arguments. These manuals can be viewed using `man`: [source,shell] .... % man command .... where _command_ is the name of the command to learn about. For example, to learn more about man:ls[1], type: [source,shell] .... % man ls .... Manual pages are divided into sections which represent the type of topic. In FreeBSD, the following sections are available: . User commands. . System calls and error numbers. . Functions in the C libraries. . Device drivers. . File formats. . Games and other diversions. . Miscellaneous information. . System maintenance and operation commands. . System kernel interfaces. In some cases, the same topic may appear in more than one section of the online manual. For example, there is a `chmod` user command and a `chmod()` system call. To tell man:man[1] which section to display, specify the section number: [source,shell] .... % man 1 chmod .... This will display the manual page for the user command man:chmod[1]. References to a particular section of the online manual are traditionally placed in parenthesis in written documentation, so man:chmod[1] refers to the user command and man:chmod[2] refers to the system call. If the name of the manual page is unknown, use `man -k` to search for keywords in the manual page descriptions: [source,shell] .... % man -k mail .... This command displays a list of commands that have the keyword "mail" in their descriptions. This is equivalent to using man:apropos[1]. To read the descriptions for all of the commands in `/usr/sbin`, type: [source,shell] .... % cd /usr/sbin % man -f * | more .... or [source,shell] .... % cd /usr/sbin % whatis * |more .... [[basics-info]] === GNU Info Files FreeBSD includes several applications and utilities produced by the Free Software Foundation (FSF). In addition to manual pages, these programs may include hypertext documents called `info` files. These can be viewed using man:info[1] or, if package:editors/emacs[] is installed, the info mode of emacs. To use man:info[1], type: [source,shell] .... % info .... For a brief introduction, type `h`. For a quick command reference, type `?`. diff --git a/documentation/content/en/books/handbook/boot/_index.adoc b/documentation/content/en/books/handbook/boot/_index.adoc index abe4846b98..86cc778922 100644 --- a/documentation/content/en/books/handbook/boot/_index.adoc +++ b/documentation/content/en/books/handbook/boot/_index.adoc @@ -1,453 +1,453 @@ --- title: Chapter 15. The FreeBSD Booting Process part: Part III. System Administration prev: books/handbook/config next: books/handbook/security description: An introduction to the FreeBSD Booting Process, demonstrates how to customize the FreeBSD boot process, including everything that happens until the FreeBSD kernel has started, probed for devices, and started init tags: ["boot", "boot process", "device hints", "x86", "amd64", "MBR", "GPT", "UEFI", "bsdlabel", "boot0", "Single-User Mode", "Multi-User Mode"] showBookMenu: true weight: 19 path: "/books/handbook/boot/" --- [[boot]] = The FreeBSD Booting Process :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 15 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/boot/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[boot-synopsis]] == Synopsis The process of starting a computer and loading the operating system is referred to as "the bootstrap process", or "booting". FreeBSD's boot process provides a great deal of flexibility in customizing what happens when the system starts, including the ability to select from different operating systems installed on the same computer, different versions of the same operating system, or a different installed kernel. This chapter details the configuration options that can be set. It demonstrates how to customize the FreeBSD boot process, including everything that happens until the FreeBSD kernel has started, probed for devices, and started man:init[8]. This occurs when the text color of the boot messages changes from bright white to grey. After reading this chapter, you will recognize: * The components of the FreeBSD bootstrap system and how they interact. * The options that can be passed to the components in the FreeBSD bootstrap in order to control the boot process. * The basics of setting device hints. * How to boot into single- and multi-user mode and how to properly shut down a FreeBSD system. [NOTE] ==== This chapter only describes the boot process for FreeBSD running on x86 and amd64 systems. ==== [[boot-introduction]] == FreeBSD Boot Process Turning on a computer and starting the operating system poses an interesting dilemma. By definition, the computer does not know how to do anything until the operating system is started. This includes running programs from the disk. If the computer can not run a program from the disk without the operating system, and the operating system programs are on the disk, how is the operating system started? This problem parallels one in the book The Adventures of Baron Munchausen. A character had fallen part way down a manhole, and pulled himself out by grabbing his bootstraps and lifting. In the early days of computing, the term _bootstrap_ was applied to the mechanism used to load the operating system. It has since become shortened to "booting". On x86 hardware, the Basic Input/Output System (BIOS) is responsible for loading the operating system. The BIOS looks on the hard disk for the Master Boot Record (MBR), which must be located in a specific place on the disk. The BIOS has enough knowledge to load and run the MBR, and assumes that the MBR can then carry out the rest of the tasks involved in loading the operating system, possibly with the help of the BIOS. [NOTE] ==== FreeBSD provides for booting from both the older MBR standard, and the newer GUID Partition Table (GPT). GPT partitioning is often found on computers with the Unified Extensible Firmware Interface (UEFI). However, FreeBSD can boot from GPT partitions even on machines with only a legacy BIOS with man:gptboot[8]. Work is under way to provide direct UEFI booting. ==== The code within the MBR is typically referred to as a _boot manager_, especially when it interacts with the user. The boot manager usually has more code in the first track of the disk or within the file system. Examples of boot managers include the standard FreeBSD boot manager boot0, also called Boot Easy, and GNU GRUB, which is used by many Linux(R) distributions. [NOTE] ==== // There is extref:{faq}[a frequently asked question] about GRUB. Beyond the answer there, // Users of GRUB should refer to https://www.gnu.org/software/grub/grub-documentation.html[GNU-provided documentation]. ==== If only one operating system is installed, the MBR searches for the first bootable (active) slice on the disk, and then runs the code on that slice to load the remainder of the operating system. When multiple operating systems are present, a different boot manager can be installed to display a list of operating systems so the user can select one to boot. The remainder of the FreeBSD bootstrap system is divided into three stages. The first stage knows just enough to get the computer into a specific state and run the second stage. The second stage can do a little bit more, before running the third stage. The third stage finishes the task of loading the operating system. The work is split into three stages because the MBR puts limits on the size of the programs that can be run at stages one and two. Chaining the tasks together allows FreeBSD to provide a more flexible loader. The kernel is then started and begins to probe for devices and initialize them for use. Once the kernel boot process is finished, the kernel passes control to the user process man:init[8], which makes sure the disks are in a usable state, starts the user-level resource configuration which mounts file systems, sets up network cards to communicate on the network, and starts the processes which have been configured to run at startup. This section describes these stages in more detail and demonstrates how to interact with the FreeBSD boot process. [[boot-boot0]] === The Boot Manager The boot manager code in the MBR is sometimes referred to as _stage zero_ of the boot process. By default, FreeBSD uses the boot0 boot manager. The MBR installed by the FreeBSD installer is based on [.filename]#/boot/boot0#. The size and capability of boot0 is restricted to 446 bytes due to the slice table and `0x55AA` identifier at the end of the MBR. If boot0 and multiple operating systems are installed, a message similar to this example will be displayed at boot time: [[boot-boot0-example]] .[.filename]#boot0# Screenshot [example] ==== [source,shell] .... F1 Win F2 FreeBSD Default: F2 .... ==== Other operating systems will overwrite an existing MBR if they are installed after FreeBSD. If this happens, or to replace the existing MBR with the FreeBSD MBR, use the following command: [source,shell] .... # fdisk -B -b /boot/boot0 device .... where _device_ is the boot disk, such as [.filename]#ad0# for the first IDE disk, [.filename]#ad2# for the first IDE disk on a second IDE controller, or [.filename]#da0# for the first SCSI disk. To create a custom configuration of the MBR, refer to man:boot0cfg[8]. [[boot-boot1]] === Stage One and Stage Two Conceptually, the first and second stages are part of the same program on the same area of the disk. Due to space constraints, they have been split into two, but are always installed together. They are copied from the combined [.filename]#/boot/boot# by the FreeBSD installer or `bsdlabel`. These two stages are located outside file systems, in the first track of the boot slice, starting with the first sector. This is where boot0, or any other boot manager, expects to find a program to run which will continue the boot process. The first stage, [.filename]#boot1#, is very simple, since it can only be 512 bytes in size. It knows just enough about the FreeBSD _bsdlabel_, which stores information about the slice, to find and execute [.filename]#boot2#. Stage two, [.filename]#boot2#, is slightly more sophisticated, and understands the FreeBSD file system enough to find files. It can provide a simple interface to choose the kernel or loader to run. It runs loader, which is much more sophisticated and provides a boot configuration file. If the boot process is interrupted at stage two, the following interactive screen is displayed: [[boot-boot2-example]] .[.filename]#boot2# Screenshot [example] ==== [source,shell] .... >> FreeBSD/i386 BOOT Default: 0:ad(0,a)/boot/loader boot: .... ==== To replace the installed [.filename]#boot1# and [.filename]#boot2#, use `bsdlabel`, where _diskslice_ is the disk and slice to boot from, such as [.filename]#ad0s1# for the first slice on the first IDE disk: [source,shell] .... # bsdlabel -B diskslice .... [WARNING] ==== If just the disk name is used, such as [.filename]#ad0#, `bsdlabel` will create the disk in "dangerously dedicated mode", without slices. This is probably not the desired action, so double check the _diskslice_ before pressing kbd:[Return]. ==== [[boot-loader]] === Stage Three The loader is the final stage of the three-stage bootstrap process. It is located on the file system, usually as [.filename]#/boot/loader#. The loader is intended as an interactive method for configuration, using a built-in command set, backed up by a more powerful interpreter which has a more complex command set. During initialization, loader will probe for a console and for disks, and figure out which disk it is booting from. It will set variables accordingly, and an interpreter is started where user commands can be passed from a script or interactively. The loader will then read [.filename]#/boot/loader.rc#, which by default reads in [.filename]#/boot/defaults/loader.conf# which sets reasonable defaults for variables and reads [.filename]#/boot/loader.conf# for local changes to those variables. [.filename]#loader.rc# then acts on these variables, loading whichever modules and kernel are selected. Finally, by default, loader issues a 10 second wait for key presses, and boots the kernel if it is not interrupted. If interrupted, the user is presented with a prompt which understands the command set, where the user may adjust variables, unload all modules, load modules, and then finally boot or reboot. -crossref:boot[boot-loader-commands] lists the most commonly used loader commands. +crossref:boot[boot-loader-commands,.Loader Built-In Commands] lists the most commonly used loader commands. For a complete discussion of all available commands, refer to man:loader[8]. [[boot-loader-commands]] .Loader Built-In Commands [cols="20%,80%", frame="none", options="header"] |=== | Variable | Description |autoboot _seconds_ |Proceeds to boot the kernel if not interrupted within the time span given, in seconds. It displays a countdown, and the default time span is 10 seconds. |boot [`-options`] [`kernelname`] |Immediately proceeds to boot the kernel, with any specified options or kernel name. Providing a kernel name on the command-line is only applicable after an `unload` has been issued. Otherwise, the previously-loaded kernel will be used. If _kernelname_ is not qualified, it will be searched under _/boot/kernel_ and _/boot/modules_. |boot-conf |Goes through the same automatic configuration of modules based on specified variables, most commonly `kernel`. This only makes sense if `unload` is used first, before changing some variables. |help [`_topic_`] |Shows help messages read from [.filename]#/boot/loader.help#. If the topic given is `index`, the list of available topics is displayed. |include `_filename_` ... |Reads the specified file and interprets it line by line. An error immediately stops the `include`. |load [-t ``_type_``] `_filename_` |Loads the kernel, kernel module, or file of the type given, with the specified filename. Any arguments after _filename_ are passed to the file. If _filename_ is not qualified, it will be searched under _/boot/kernel_ and _/boot/modules_. |ls [-l] [``_path_``] |Displays a listing of files in the given path, or the root directory, if the path is not specified. If `-l` is specified, file sizes will also be shown. |lsdev [`-v`] |Lists all of the devices from which it may be possible to load modules. If `-v` is specified, more details are printed. |lsmod [`-v`] |Displays loaded modules. If `-v` is specified, more details are shown. |more `_filename_` |Displays the files specified, with a pause at each `LINES` displayed. |reboot |Immediately reboots the system. |set `_variable_`, set `_variable=value_` |Sets the specified environment variables. |unload |Removes all loaded modules. |=== Here are some practical examples of loader usage. To boot the usual kernel in single-user mode: [source,shell] .... boot -s .... To unload the usual kernel and modules and then load the previous or another, specified kernel: [source,shell] .... unload load /path/to/kernelfile .... Use the qualified [.filename]#/boot/GENERIC/kernel# to refer to the default kernel that comes with an installation, or [.filename]#/boot/kernel.old/kernel#, to refer to the previously installed kernel before a system upgrade or before configuring a custom kernel. Use the following to load the usual modules with another kernel. Note that in this case it is not necessary the qualified name: [source,shell] .... unload set kernel="mykernel" boot-conf .... To load an automated kernel configuration script: [source,shell] .... load -t userconfig_script /boot/kernel.conf .... [[boot-init]] === Last Stage Once the kernel is loaded by either loader or by boot2, which bypasses loader, it examines any boot flags and adjusts its behavior as necessary. -crossref:boot[boot-kernel] lists the commonly used boot flags. +crossref:boot[boot-kernel,.Kernel Interaction During Boot] lists the commonly used boot flags. Refer to man:boot[8] for more information on the other boot flags. [[boot-kernel]] .Kernel Interaction During Boot [cols="1,1", frame="none", options="header"] |=== | Option | Description |`-a` |During kernel initialization, ask for the device to mount as the root file system. |`-C` |Boot the root file system from a CDROM. |`-s` |Boot into single-user mode. |`-v` |Be more verbose during kernel startup. |=== Once the kernel has finished booting, it passes control to the user process man:init[8], which is located at [.filename]#/sbin/init#, or the program path specified in the `init_path` variable in `loader`. This is the last stage of the boot process. The boot sequence makes sure that the file systems available on the system are consistent. If a UFS file system is not, and `fsck` cannot fix the inconsistencies, init drops the system into single-user mode so that the system administrator can resolve the problem directly. Otherwise, the system boots into multi-user mode. [[boot-singleuser]] ==== Single-User Mode A user can specify this mode by booting with `-s` or by setting the `boot_single` variable in loader. It can also be reached by running `shutdown now` from multi-user mode. Single-user mode begins with this message: [.programlisting] .... Enter full pathname of shell or RETURN for /bin/sh: .... If the user presses kbd:[Enter], the system will enter the default Bourne shell. To specify a different shell, input the full path to the shell. Single-user mode is usually used to repair a system that will not boot due to an inconsistent file system or an error in a boot configuration file. It can also be used to reset the `root` password when it is unknown. These actions are possible as the single-user mode prompt gives full, local access to the system and its configuration files. There is no networking in this mode. While single-user mode is useful for repairing a system, it poses a security risk unless the system is in a physically secure location. By default, any user who can gain physical access to a system will have full control of that system after booting into single-user mode. If the system `console` is changed to `insecure` in [.filename]#/etc/ttys#, the system will first prompt for the `root` password before initiating single-user mode. This adds a measure of security while removing the ability to reset the `root` password when it is unknown. [[boot-insecure-console]] .Configuring an Insecure Console in [.filename]#/etc/ttys# [example] ==== [.programlisting] .... # name getty type status comments # # If console is marked "insecure", then init will ask for the root password # when going to single-user mode. console none unknown off insecure .... ==== An `insecure` console means that physical security to the console is considered to be insecure, so only someone who knows the `root` password may use single-user mode. [[boot-multiuser]] ==== Multi-User Mode If init finds the file systems to be in order, or once the user has finished their commands in single-user mode and has typed `exit` to leave single-user mode, the system enters multi-user mode, in which it starts the resource configuration of the system. The resource configuration system reads in configuration defaults from [.filename]#/etc/defaults/rc.conf# and system-specific details from [.filename]#/etc/rc.conf#. It then proceeds to mount the system file systems listed in [.filename]#/etc/fstab#. It starts up networking services, miscellaneous system daemons, then the startup scripts of locally installed packages. To learn more about the resource configuration system, refer to man:rc[8] and examine the scripts located in [.filename]#/etc/rc.d#. [[device-hints]] == Device Hints During initial system startup, the boot man:loader[8] reads man:device.hints[5]. This file stores kernel boot information known as variables, sometimes referred to as "device hints". These "device hints" are used by device drivers for device configuration. Device hints may also be specified at the Stage 3 boot loader prompt, as -demonstrated in crossref:boot[boot-loader]. +demonstrated in crossref:boot[boot-loader, Stage Three]. Variables can be added using `set`, removed with `unset`, and viewed `show`. Variables set in [.filename]#/boot/device.hints# can also be overridden. Device hints entered at the boot loader are not permanent and will not be applied on the next reboot. Once the system is booted, man:kenv[1] can be used to dump all of the variables. The syntax for [.filename]#/boot/device.hints# is one variable per line, using the hash "#" as comment markers. Lines are constructed as follows: [source,shell] .... hint.driver.unit.keyword="value" .... The syntax for the Stage 3 boot loader is: [source,shell] .... set hint.driver.unit.keyword=value .... where `driver` is the device driver name, `unit` is the device driver unit number, and `keyword` is the hint keyword. The keyword may consist of the following options: * `at`: specifies the bus which the device is attached to. * `port`: specifies the start address of the I/O to be used. * `irq`: specifies the interrupt request number to be used. * `drq`: specifies the DMA channel number. * `maddr`: specifies the physical memory address occupied by the device. * `flags`: sets various flag bits for the device. * `disabled`: if set to `1` the device is disabled. Since device drivers may accept or require more hints not listed here, viewing a driver's manual page is recommended. For more information, refer to man:device.hints[5], man:kenv[1], man:loader.conf[5], and man:loader[8]. [[boot-shutdown]] == Shutdown Sequence Upon controlled shutdown using man:shutdown[8], man:init[8] will attempt to run the script [.filename]#/etc/rc.shutdown#, and then proceed to send all processes the `TERM` signal, and subsequently the `KILL` signal to any that do not terminate in a timely manner. To power down a FreeBSD machine on architectures and systems that support power management, use `shutdown -p now` to turn the power off immediately. To reboot a FreeBSD system, use `shutdown -r now`. One must be `root` or a member of `operator` in order to run man:shutdown[8]. One can also use man:halt[8] and man:reboot[8]. Refer to their manual pages and to man:shutdown[8] for more information. Modify group membership by referring to crossref:basics[users-synopsis,“Users and Basic Account Management”]. [NOTE] ==== Power management requires man:acpi[4] to be loaded as a module or statically compiled into a custom kernel. ==== diff --git a/documentation/content/en/books/handbook/bsdinstall/_index.adoc b/documentation/content/en/books/handbook/bsdinstall/_index.adoc index 4b9f811098..f16c82569c 100644 --- a/documentation/content/en/books/handbook/bsdinstall/_index.adoc +++ b/documentation/content/en/books/handbook/bsdinstall/_index.adoc @@ -1,1271 +1,1271 @@ --- title: Chapter 2. Installing FreeBSD part: Part I. Getting Started prev: books/handbook/introduction next: books/handbook/basics description: Guide about how to install FreeBSD, the minimum hardware requirements and supported architectures, how to create the installation media, etc tags: ["bsdinstall", "installing FreeBSD", "requirements", "tutorial", "guide"] showBookMenu: true weight: 4 path: "/books/handbook/bsdinstall/" --- [[bsdinstall]] = Installing FreeBSD :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 2 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/bsdinstall/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[bsdinstall-synopsis]] == Synopsis FreeBSD supports different architectures including amd64, ARM(R), RISC-V(R), and PowerPC(R). Depending on the architecture and platform, different images can be link:https://www.freebsd.org/where/[downloaded] to install or directly run FreeBSD. The image types are: * Virtual Machine disk images, such as `qcow2`, `vmdk`, `vhd`, and raw device images. These are not installation images, but images that have FreeBSD preinstalled and ready for post-installation tasks. Virtual machine images are also commonly used in cloud environments. * SD card images, for embedded systems such as Raspberry Pi. These files must be uncompressed and written as a raw image to an SD card, from which the board will boot. * Installation images to boot from an ISO or USB device to install FreeBSD on a drive for the usual desktop, laptop, or server system. The rest of this chapter describes the third case, explaining how to install FreeBSD using the text-based installation program named bsdinstall. There may be minor differences between the installer and what is shown here, so use this chapter as a general guide rather than as a set of literal instructions. After reading this chapter, you will know: * How to obtain FreeBSD images and create FreeBSD installation media. * How to start bsdinstall. * The questions bsdinstall will ask, what they mean, and how to answer them. * How to troubleshoot a failed installation. * How to access a live version of FreeBSD before committing to an installation. [[bsdinstall-hardware]] == Minimum Hardware Requirements The hardware requirements to install FreeBSD vary by architecture and version. Hardware architectures and devices supported by a FreeBSD release are listed on the link:https://www.FreeBSD.org/releases/[FreeBSD Release Information] page. The link:https://www.FreeBSD.org/where/[FreeBSD download page] also has recommendations for choosing the correct image for different architectures. [[bsdinstall-pre]] == Pre-Installation Tasks Once it has been determined that the system meets the minimum hardware requirements for installing FreeBSD, the installation file should be downloaded and the installation media prepared. [TIP] ==== Consider using crossref:virtualization[virtualization,virtualization] if you want to use FreeBSD on a system that already has another operating system installed. ==== Before moving on to the installation, check that the system is ready by verifying the items in this checklist: [.procedure] ==== . *Back Up Important Data* + Before installing any operating system, *always* backup all important data first. Do not store the backup on the system being installed. Instead, save the data to a removable disk such as a USB drive, another system on the network, or an online backup service. Test the backup before starting the installation to make sure it contains all of the needed files. Once the installer formats the system's disk, all data stored on that disk will be lost. . *Decide Where to Install FreeBSD* + If FreeBSD will be the only operating system installed, this step can be skipped. But if FreeBSD will share the disk with another operating system, decide which disk or partition will be used for FreeBSD. + In the i386 and amd64 architectures, disks can be divided into multiple partitions using one of two partitioning schemes. A traditional _Master Boot Record_ (MBR) holds a partition table defining up to four _primary partitions_. For historical reasons, FreeBSD calls these primary partition _slices_. One of these primary partitions can be made into an _extended partition_ containing multiple _logical partitions_. The _GUID Partition Table_ (GPT) is a newer and simpler method of partitioning a disk. Common GPT implementations allow up to 128 partitions per disk, eliminating the need for logical partitions. + The FreeBSD boot loader requires either a primary or GPT partition. If all of the primary or GPT partitions are already in use, one must be freed for FreeBSD. To create a partition without deleting existing data, use a partition resizing tool to shrink an existing partition and create a new partition using the freed space. + An alternative to modifying the system's existing disk partitions is to use crossref:virtualization[virtualization,virtualization], which allows multiple operating systems to run at the same time without having to alter partitions. + A variety of free and commercial partition resizing tools are listed at link:https://en.wikipedia.org/wiki/List_of_disk_partitioning_software[List of disk partitioning software wikipedia entry]. link:https://gparted.org/livecd.php[GParted Live] is a free live CD which includes the GParted partition editor. + [WARNING] ====== When used properly, disk shrinking utilities can safely create space for creating a new partition. Since the possibility of selecting the wrong partition exists, always backup any important data and verify the integrity of the backup before modifying disk partitions. ====== + Disk partitions containing different operating systems make it possible to install multiple operating systems on one computer. . *Collect Network Information* + Some FreeBSD installation methods require a network connection in order to download the installation files. After any installation, the installer will offer to setup the system's network interfaces. + If the network has a DHCP server, it can be used to provide automatic network configuration. If DHCP is not available, the following network information for the system must be obtained from the local network administrator or Internet service provider: + [[bsdinstall-collect-network-information]] Required Network Information .. IP address .. Subnet mask .. IP address of default gateway .. Domain name of the network .. IP addresses of the network's DNS servers . *Check for FreeBSD Errata* + Although the FreeBSD Project strives to ensure that each release of FreeBSD is as stable as possible, bugs occasionally creep into the process. On very rare occasions those bugs affect the installation process. As these problems are discovered and fixed, they are noted in the FreeBSD Errata page of each version. Check the errata before installing to make sure that there are no problems that might affect the installation. + Information and errata for all the releases can be found on the link:https://www.FreeBSD.org/releases/[FreeBSD Release Information] page. ==== [[bsdinstall-installation-media]] === Prepare the Installation Media The FreeBSD installer is not an application that can be run from within another operating system. Instead, download a FreeBSD installation file, burn it to the media associated with its file type and size (CD, DVD, or USB), and boot the system to install from the inserted media. FreeBSD installation files are available at the link:https://www.FreeBSD.org/where/[FreeBSD download page]. Each installation file's name includes the release version of FreeBSD, the architecture, and the type of file. Installation files are available in several formats, compressed with man:xz[1] or uncompressed. The formats vary depending on computer architecture and media type. Installation file types: * `*-bootonly.iso*`: This is the smallest installation file as it only contains the installer. A working Internet connection is required during installation as the installer will download the files it needs to complete the FreeBSD installation. This file should be burned to optical media. * `*-disc1.iso*`: This file contains all of the files needed to install FreeBSD, its source, and the Ports Collection. This file should be burned to optical media. * `*-dvd1.iso*`: This file contains all of the files needed to install FreeBSD, its source, and the Ports Collection. It also contains a set of popular binary packages for installing a window manager and some applications so that a complete system can be installed from media without requiring a connection to the Internet. This file should be burned to optical media. * `*-memstick.img*`: This file contains all of the files needed to install FreeBSD, its source, and the Ports Collection. Write this file to a USB stick - as shown in crossref:bsdinstall[bsdinstall-usb]. + as shown in crossref:bsdinstall[bsdinstall-usb, Writing an Image File to USB]. * `*-mini-memstick.img*`: Like `*-bootonly.iso*`, does not include installation files, but downloads them as needed. A working internet connection is required during installation. It should be written to a USB stick as shown in - crossref:bsdinstall[bsdinstall-usb]. + crossref:bsdinstall[bsdinstall-usb, Writing an Image File to USB]. After downloading the image file, download at least one _checksum_ file from the same directory. There are two _checksum_ files available, named after the release number and the architecture name. For example: `CHECKSUM.SHA256-FreeBSD-13.1-RELEASE-amd64` and `CHECKSUM.SHA512-FreeBSD-13.1-RELEASE-amd64`. After downloading one of the files (or both), calculate the _checksum_ for the image file and compare it with the one shown in the _checksum_ file. Note that you need to compare the calculated _checksum_ against the correct file, as they correspond to two different algorithms: SHA256 and SHA512. FreeBSD provides man:sha256[1] and man:sha512[1] that can be used for calculating the _checksum_. Other operating systems have similar programs. Verifying the _checksum_ in FreeBSD can be done automatically using man:sha256sum[1] (and man:sha512sum[1]) by executing: [source,shell] .... % sha256sum -c CHECKSUM.SHA256-FreeBSD-13.1-RELEASE-amd64 FreeBSD-13.1-RELEASE-amd64-dvd1.iso FreeBSD-13.1-RELEASE-amd64-dvd1.iso: OK .... The checksums must match exactly. If the checksums do not match, the image file is corrupt and must be downloaded again. [[bsdinstall-usb]] ==== Writing an Image File to USB The `\*memstick.img` file is an _image_ of the complete contents of a memory stick. It _cannot_ be copied to the target device as a file. Several applications are available for writing the `*.img` to a USB stick. This section describes two of these utilities. [IMPORTANT] ==== Before proceeding, back up any important data on the USB stick. This procedure will erase the existing data on the stick. ==== [[bsdinstall-usb-dd]] [.procedure] ==== *Procedure. Using `dd` to write the image* + [WARNING] ====== This example uses `/dev/da0` as the target device where the image will be written. Be *very careful* that the correct device is used as this command will destroy the existing data on the specified target device. ====== . The command-line utility is available on BSD, Linux(R), and Mac OS(R) systems. To burn the image using `dd`, insert the USB stick and determine its device name. Then, specify the name of the downloaded installation file and the device name for the USB stick. This example burns the amd64 installation image to the first USB device on an existing FreeBSD system. + [source,shell] .... # dd if=FreeBSD-13.1-RELEASE-amd64-memstick.img of=/dev/da0 bs=1M conv=sync .... + If this command fails, verify that the USB stick is not mounted and that the device name is for the disk, not a partition. + Some operating systems might require this command to be run with man:sudo[8]. The man:dd[1] syntax varies slightly across different platforms; for example, Mac OS(R) requires a lower-case `bs=1m`. Systems like Linux(R) might buffer writes. To force all writes to complete, use man:sync[8]. ==== [.procedure] ==== *Procedure. Using Windows(R) to Write the Image* + [WARNING] ====== Be sure to give the correct drive letter as the existing data on the specified drive will be overwritten and destroyed. ====== . *Obtaining Image Writer for Windows(R)* + Image Writer for Windows(R) is a free application that can correctly write an image file to a memory stick. Download it from https://sourceforge.net/projects/win32diskimager/[win32diskimager home page] and extract it into a folder. . *Writing the Image with Image Writer* + Double-click the Win32DiskImager icon to start the program. Verify that the drive letter shown under `Device` is the drive with the memory stick. Click the folder icon and select the image to be written to the memory stick. Click btn:[Save] to accept the image file name. Verify that everything is correct, and that no folders on the memory stick are open in other windows. When everything is ready, click btn:[Write] to write the image file to the memory stick. ==== [[bsdinstall-start]] == Starting the Installation [IMPORTANT] ==== By default, the installation will not make any changes to the disk(s) before the following message: [.programlisting] .... Your changes will now be written to disk. If you have chosen to overwrite existing data, it will be PERMANENTLY ERASED. Are you sure you want to commit your changes? .... The install can be exited at any time prior to this warning. If there is a concern that something is incorrectly configured, just turn the computer off before this point and no changes will be made to the system's disks. ==== This section describes how to boot the system from the installation media which was prepared using the instructions in -crossref:bsdinstall[bsdinstall-installation-media]. +crossref:bsdinstall[bsdinstall-installation-media, Prepare the Installation Media]. When using a bootable USB stick, plug in the USB stick before turning on the computer. When booting from CD or DVD, turn on the computer and insert the media at the first opportunity. How to configure the system to boot from the inserted media depends upon the architecture. [[bsdinstall-view-probe]] === FreeBSD Boot Loader Menu Once the system boots from the installation media, a menu similar to the following will be displayed: [[bsdinstall-newboot-loader-menu]] .FreeBSD Boot Loader Menu image::bsdinstall-newboot-loader-menu.png[FreeBSD boot loader menu] By default, the menu will wait ten seconds for user input before booting into the FreeBSD installer or, if FreeBSD is already installed, before booting into FreeBSD. To pause the boot timer in order to review the selections, press kbd:[Space]. To select an option, press its highlighted number, character, or key. The following options are available. * `Boot Multi User`: This will continue the FreeBSD boot process. If the boot timer has been paused, press kbd:[1], upper- or lower-case kbd:[B], or kbd:[Enter]. * `Boot Single User`: This mode can be used to fix an existing FreeBSD installation as described in crossref:boot[boot-singleuser,“Single-User Mode”]. Press kbd:[2] or the upper- or lower-case kbd:[S] to enter this mode. * `Escape to loader prompt`: This will boot the system into a repair prompt that contains a limited number of low-level commands. This prompt is described in crossref:boot[boot-loader,“Stage Three”]. Press kbd:[3] or kbd:[Esc] to boot into this prompt. * `Reboot`: Reboots the system. * `Cons`: Allow to continue the installation by `video`, `serial`, `Dual (serial primary)` or `Dual (Video primary)` * `Kernel`: Loads a different kernel. * `Boot Options`: Opens the menu shown in, and described under, - crossref:bsdinstall[bsdinstall-boot-options-menu]. + crossref:bsdinstall[bsdinstall-boot-options-menu,.FreeBSD Boot Options Menu]. [[bsdinstall-boot-options-menu]] .FreeBSD Boot Options Menu image::bsdinstall-boot-options-menu.png[Menu showing the different boot options supported] The boot options menu is divided into two sections. The first section can be used to either return to the main boot menu or to reset any toggled options back to their defaults. The next section is used to toggle the available options to `On` or `Off` by pressing the option's highlighted number or character. The system will always boot using the settings for these options until they are modified. Several options can be toggled using this menu: * `ACPI Support`: If the system hangs during boot, try toggling this option to `Off`. This option is only present when ACPI support is available but not required. * `Safe Mode`: If the system still hangs during boot even with `ACPI Support` set to `Off`, try setting this option to `On`. * `Single User`: Toggle this option to `On` to fix an existing FreeBSD installation as described in crossref:boot[boot-singleuser,“Single-User Mode”]. Once the problem is fixed, set it back to `Off`. * `Verbose`: Toggle this option to `On` to see more detailed messages during the boot process. This can be useful when troubleshooting a piece of hardware. After making the needed selections, press kbd:[1] or kbd:[Backspace] to return to the main boot menu, then press kbd:[Enter] to continue booting into FreeBSD. A series of boot messages will appear as FreeBSD carries out its hardware device probes and loads the installation program. Once the boot is complete, the welcome menu shown in -crossref:bsdinstall[bsdinstall-choose-mode] will be displayed. +crossref:bsdinstall[bsdinstall-choose-mode,.Welcome Menu] will be displayed. [[bsdinstall-choose-mode]] .Welcome Menu image::bsdinstall-choose-mode.png[FreeBSD installation welcome menu] Press kbd:[Enter] to select the default of btn:[Install] to enter the installer. The rest of this chapter describes how to use this installer. Otherwise, use the right or left arrows or the colorized letter to select the desired menu item. The btn:[Shell] can be used to access a FreeBSD shell in order to use command line utilities to prepare the disks before installation. The btn:[Live CD] option can be used to try out FreeBSD before installing it. -The live version is described in crossref:bsdinstall[using-live-cd]. +The live version is described in crossref:bsdinstall[using-live-cd, Using the Live CD]. [TIP] ==== To review the boot messages, including the hardware device probe, press the upper- or lower-case kbd:[S] and then kbd:[Enter] to access a shell. At the shell prompt, type `more /var/run/dmesg.boot` and use the space bar to scroll through the messages. When finished, type `exit` to return to the welcome menu. ==== [[using-bsdinstall]] == Using bsdinstall This section shows the order of the bsdinstall menus and the type of information that will be asked before the system is installed. Use the arrow keys to highlight a menu option, then kbd:[Space] to select or deselect that menu item. When finished, press kbd:[Enter] to save the selection and move onto the next screen. [[bsdinstall-keymap]] === Selecting the Keymap Menu Before starting the process, bsdinstall will load the keymap files as shown in -crossref:bsdinstall[bsdinstall-keymap-loading]. +crossref:bsdinstall[bsdinstall-keymap-loading,.Keymap Loading]. [[bsdinstall-keymap-loading]] .Keymap Loading image::bsdinstall-keymap-loading.png[Keymap loading] After the keymaps have been loaded, bsdinstall displays the menu shown in -crossref:bsdinstall[bsdinstall-keymap-10]. +crossref:bsdinstall[bsdinstall-keymap-10,.Keymap Selection Menu]. Use the up and down arrows to select the keymap that most closely represents the mapping of the keyboard attached to the system. Press kbd:[Enter] to save the selection. [[bsdinstall-keymap-10]] .Keymap Selection Menu image::bsdinstall-keymap-10.png[Keymap selection menu showing all supported keyboards] [NOTE] ==== Pressing kbd:[Esc] will exit this menu and use the default keymap. If the choice of keymap is not clear, [.guimenuitem]#United States of America ISO-8859-1# is also a safe option. ==== In addition, when selecting a different keymap, the user can try the keymap and ensure it is correct before proceeding, as shown in -crossref:bsdinstall[bsdinstall-keymap-testing]. +crossref:bsdinstall[bsdinstall-keymap-testing,.Keymap Testing Menu]. [[bsdinstall-keymap-testing]] .Keymap Testing Menu image::bsdinstall-keymap-testing.png[Keymap testing menu] [[bsdinstall-hostname]] === Setting the Hostname The next bsdinstall menu is used to set the hostname for the newly installed system. [[bsdinstall-config-hostname]] .Setting the Hostname image::bsdinstall-config-hostname.png[Setting the hostname] Type in a hostname that is unique for the network. It should be a fully-qualified hostname, such as `machine3.example.com`. [[bsdinstall-components]] === Selecting Components to Install Next, bsdinstall will prompt to select optional components to install. [[bsdinstall-config-components]] .Selecting Components to Install image::bsdinstall-config-components.png[Different components that can be installed. Example: base-dbg, lib32, ports, etc.] Deciding which components to install will depend largely on the intended use of the system and the amount of disk space available. The FreeBSD kernel and userland, collectively known as the _base system_, are always installed. Depending on the architecture, some of these components may not appear: * `base-dbg` - Base tools like cat and ls, among many others, with debug symbols activated. * `kernel-dbg` - Kernel and modules with debug symbols activated. * `lib32-dbg` - Compatibility libraries for running 32-bit applications on a 64-bit version of FreeBSD with debug symbols activated. * `lib32` - Compatibility libraries for running 32-bit applications on a 64-bit version of FreeBSD. * `ports` - The FreeBSD Ports Collection is a collection of files which automates the downloading, compiling and installation of third-party software packages. crossref:ports[ports,Installing Applications: Packages and Ports] discusses how to use the Ports Collection. + [WARNING] ==== The installation program does not check for adequate disk space. Select this option only if sufficient hard disk space is available. The FreeBSD Ports Collection takes up about {ports-size} of disk space. ==== * `src` - The complete FreeBSD source code for both the kernel and the userland. Although not required for the majority of applications, it may be required to build device drivers, kernel modules, or some applications from the Ports Collection. It is also used for developing FreeBSD itself. The full source tree requires 1 GB of disk space and recompiling the entire FreeBSD system requires an additional 5 GB of space. * `tests` - FreeBSD Test Suite. [[bsdinstall-netinstall]] === Installing from the Network -The menu shown in crossref:bsdinstall[bsdinstall-netinstall-notify] only appears when installing from a `-bootonly.iso` or `-mini-memstick.img`, as this installation media does not hold copies of the installation files. +The menu shown in crossref:bsdinstall[bsdinstall-netinstall-notify,.Installing from the Network] only appears when installing from a `-bootonly.iso` or `-mini-memstick.img`, as this installation media does not hold copies of the installation files. Since the installation files must be retrieved over a network connection, this menu indicates that the network interface must be configured first. If this menu is shown in any step of the process, remember to follow the -instructions in crossref:bsdinstall[bsdinstall-config-network-dev]. +instructions in crossref:bsdinstall[bsdinstall-config-network-dev, Configuring Network Interfaces]. [[bsdinstall-netinstall-notify]] .Installing from the Network image::bsdinstall-netinstall-files.png[Indicates that certain components have not been found and will be downloaded using the network.] [[bsdinstall-partitioning]] == Allocating Disk Space The next menu is used to determine the method for allocating disk space. [[bsdinstall-zfs-partmenu]] .Partitioning Choices image::bsdinstall-zfs-partmenu.png[Shows the different partition options. Example: Manual, Shell, etc.] bsdinstall gives the user four methods for allocating disk space: * `Auto (ZFS)` partitioning creates a root-on-ZFS system with optional GELI encryption support for _boot environments_. * `Auto (UFS)` partitioning automatically sets up the disk partitions using the `UFS` file system. * `Manual` partitioning allows advanced users to create customized partitions from menu options. * `Shell` opens a shell prompt where advanced users can create customized partitions using command-line utilities like man:gpart[8], man:fdisk[8], and man:bsdlabel[8]. This section describes what to consider when laying out the disk partitions. It then demonstrates how to use the different partitioning methods. [[configtuning-initial]] === Designing the Partition Layout The default partition layout for file systems includes one file system for the entire system. When using `UFS` it may be worth considering the use of multiple file systems if you have sufficient disk space or multiple disks. When laying out file systems, remember that hard drives transfer data faster from the outer tracks to the inner. Thus, smaller and heavier-accessed file systems should be closer to the outside of the drive, while larger partitions like `/usr` should be placed toward the inner parts of the disk. It is a good idea to create partitions in an order similar to: `/`, swap, `/var`, and `/usr`. The size of the `/var` partition reflects the intended machine's usage. This partition is used to hold mailboxes, log files, and printer spools. Mailboxes and log files can grow to unexpected sizes depending on the number of users and how long log files are kept. On average, most users rarely need more than about a gigabyte of free disk space in `/var`. [NOTE] ==== Sometimes, a lot of disk space is required in `/var/tmp`. When new software is installed, the packaging tools extract a temporary copy of the packages under `/var/tmp`. Large software packages, like Firefox or LibreOffice may be tricky to install if there is not enough disk space under `/var/tmp`. ==== The `/usr` partition holds many of the files which support the system, including the FreeBSD Ports Collection and system source code. At least 2 gigabytes of space is recommended for this partition. Also, note that home directories for users are placed in `/usr/home` by default, but can be placed on another partition. By default, `/home` is a symbolic link to `/usr/home`. When selecting partition sizes, keep the space requirements in mind. Running out of space in one partition while barely using another can be a hassle. As a rule of thumb, the swap partition should be about double the size of physical memory (RAM). Systems with minimal RAM (less for larger-memory configurations) may perform better with more swap. Configuring too little swap can lead to inefficiencies in the VM page scanning code and might create issues later if more memory is added. On larger systems with multiple SCSI disks or multiple IDE disks operating on different controllers, it is recommended that swap be configured on each drive, up to four drives. The swap partitions should be approximately the same size. The kernel can handle arbitrary sizes, but internal data structures scale to 4 times the largest swap partition. Keeping the swap partitions near the same size will allow the kernel to optimally stripe swap space across disks. Large swap sizes may elicit a kernel warning message about the total configured swap. The limit is raised by increasing the amount of memory allowed for keeping track of swap allocations, as instructed by the warning message. It might be easier to recover from a runaway program before being forced to reboot. By properly partitioning a system, fragmentation introduced in the smaller write-heavy partitions will not bleed over into the mostly read partitions. Keeping the write-loaded partitions closer to the disk's edge will increase I/O performance in the partitions where it occurs the most. While I/O performance in the larger partitions may be needed, shifting them more toward the edge of the disk will not lead to a significant performance improvement over moving `/var` to the edge. [[bsdinstall-part-guided]] === Guided Partitioning Using UFS When this method is selected, a menu will display the available disk(s). If multiple disks are connected, choose the one where FreeBSD is to be installed. [[bsdinstall-part-guided-disk]] .Selecting from Multiple Disks image::bsdinstall-part-guided-disk.png[Shows the list of disks on which FreeBSD can be installed] Once the disk is selected, the next menu prompts to install to either the entire disk or to create a partition using free space. If btn:[Entire Disk] is chosen, a general partition layout filling the whole disk is automatically created. Selecting btn:[Partition] creates a partition layout from the unused space on the disk. [[bsdinstall-part-entire-part]] .Selecting Entire Disk or Partition image::bsdinstall-part-entire-part.png[Menu asking the user if he wants to use all the available space on the disk or wants to make a partition] After the btn:[Entire Disk] option is chosen, bsdinstall displays a dialog indicating that the disk will be erased. [[bsdinstall-ufs-warning]] .Confirmation image::bsdinstall-ufs-warning.png[Menu indicating the user that all data on the disk will be deleted and asking for confirmation] The next menu shows a list with the available partition scheme types. GPT is usually the most appropriate choice for amd64 computers. Older computers that are not compatible with GPT should use MBR. The other partition schemes are generally used for uncommon or older computers. -More information is available in crossref:bsdinstall[partition-schemes]. +More information is available in crossref:bsdinstall[partition-schemes,.Partitioning Schemes]. [[bsdinstall-ufs-scheme]] .Select Partition Scheme image::bsdinstall-part-manual-partscheme.png[Menu showing the user the different the different types of partition that exist and requesting one of them] After the partition layout has been created, review it to ensure it meets the needs of the installation. Selecting btn:[Revert] will reset the partitions to their original values. Pressing btn:[Auto] will recreate the automatic FreeBSD partitions. Partitions can also be manually created, modified, or deleted. When the partitioning is correct, select btn:[Finish] to continue with the installation. [[bsdinstall-part-review]] .Review Created Partitions image::bsdinstall-part-review.png[Menu showing created partitions] Once the disks are configured, the next menu provides the last chance to make changes before the selected drives are formatted. If changes need to be made, select btn:[Back] to return to the main partitioning menu. btn:[Revert & Exit] exits the installer without making any changes to the drive. Otherwise, select btn:[Commit] to start the installation process. [[bsdinstall-ufs-final-confirmation]] .Final Confirmation image::bsdinstall-final-confirmation.png[Menu indicating to the user that all changes will be written to disk and informing that if he decides to continue the existing data will be permanently deleted.] To continue with the installation process, go to -crossref:bsdinstall[bsdinstall-fetching-distribution]. +crossref:bsdinstall[bsdinstall-fetching-distribution, Fetching Distribution Files]. [[bsdinstall-part-manual]] === Manual Partitioning Selecting this method opens the partition editor: [[bsdinstall-part-manual-create]] .Manually Create Partitions image::bsdinstall-part-manual-create.png[Menu showing the Partition Editor.] Highlight the installation drive (`ada0` in this example) and select btn:[Create] to display a menu of available partition schemes: [[bsdinstall-part-manual-partscheme]] .Manually Create Partitions image::bsdinstall-part-manual-partscheme.png[Menu showing the different kind of partition schemes] GPT is usually the most appropriate choice for amd64 computers. Older computers that are not compatible with GPT should use MBR. The other partition schemes are generally used for uncommon or older computers. [[partition-schemes]] .Partitioning Schemes [cols="25h,~", frame="none", options="header"] |=== <| Abbreviation <| Description |APM |Apple Partition Map, used by PowerPC(R). |BSD |BSD label without an MBR, sometimes called _dangerously dedicated mode_ as non-BSD disk utilities may not recognize it. |GPT |link:https://en.wikipedia.org/wiki/GUID_Partition_Table[GUID Partition Table]. |MBR |link:https://en.wikipedia.org/wiki/Master_boot_record[Master Boot Record]. |=== After the partitioning scheme has been selected and created, select btn:[Create] again to create the partitions. The kbd:[Tab] key is used to give focus to the fields (after cycling through btn:[], btn:[], and btn:[]). [[bsdinstall-part-manual-addpart]] .Manually Create Partitions image::bsdinstall-part-manual-addpart.png[Menu requesting type, size, mountpoint and label for the new partition.] A standard FreeBSD GPT installation uses at least three partitions, including either UFS or ZFS: * `freebsd-boot` or `efi` - Holds the FreeBSD boot code. * `freebsd-ufs` - A FreeBSD UFS file system. * `freebsd-zfs` - A FreeBSD ZFS file system. More information about ZFS is available in crossref:zfs[zfs,The Z File System (ZFS)]. * `freebsd-swap` - FreeBSD swap space. Refer to man:gpart[8] for descriptions of the available GPT partition types. Multiple file system partitions can be created. Some people prefer a traditional layout with separate partitions for `/`, `/var`, `/tmp`, and `/usr`. [TIP] ==== Note that `/tmp` can be added later as a memory-based file system (man:tmpfs[5]) on systems with sufficient memory. ==== -See crossref:bsdinstall[bsdinstall-part-manual-splitfs] for an example. +See crossref:bsdinstall[bsdinstall-part-manual-splitfs,.Creating Traditional Split File System Partitions] for an example. The `Size` may be entered with common abbreviations: _K_ for kilobytes, _M_ for megabytes, or _G_ for gigabytes. [TIP] ==== Proper sector alignment provides the best performance, and making partition sizes even multiples of 4K bytes helps to ensure alignment on drives with either 512-byte or 4K-byte sectors. Generally, using partition sizes that are even multiples of 1M or 1G is the easiest way to make sure every partition starts at an even multiple of 4K. There is one exception: the _freebsd-boot_ partition should be no larger than 512K due to current boot code limitations. ==== A `Mountpoint` is needed if the partition will contain a file system. If only a single UFS partition will be created, the mountpoint should be `/`. The `Label` is a name by which the partition will be known. Drive names or numbers can change if the drive is connected to a different controller or port, but the partition label does not change. Referring to labels instead of drive names and partition numbers in files like `/etc/fstab` makes the system more tolerant to hardware changes. GPT labels appear in `/dev/gpt/` when a disk is attached. Other partitioning schemes have different label capabilities and their labels appear in different directories in `/dev/`. [TIP] ==== Use a unique label on every partition to avoid conflicts from identical labels. A few letters from the computer's name, use, or location can be added to the label. For instance, use `labroot` or `rootfslab` for the UFS root partition on the computer named `lab`. ==== [[bsdinstall-part-manual-splitfs]] .Creating Traditional Split File System Partitions [example] ==== For a traditional partition layout where the `/`, `/var`, `/tmp`, and `/usr` directories are separate file systems on their own partitions, create a GPT partitioning scheme, then create the partitions as shown. Partition sizes shown are typical for a 20G target disk. If more space is available on the target disk, larger swap or `/var` partitions may be useful. Labels shown here are prefixed with `ex` for "example", but readers should use other unique label values as described above. By default, FreeBSD's `gptboot` expects the first UFS partition to be the `/` partition. [.informaltable] [cols="1,1,1,1", frame="none", options="header"] |=== | Partition Type | Size | Mountpoint | Label |`freebsd-boot` |`512K` | | |`freebsd-ufs` |`2G` |`/` |`exrootfs` |`freebsd-swap` |`4G` | |`exswap` |`freebsd-ufs` |`2G` |`/var` |`exvarfs` |`freebsd-ufs` |`1G` |`/tmp` |`extmpfs` |`freebsd-ufs` |accept the default (remainder of the disk) |`/usr` |`exusrfs` |=== ==== After the custom partitions have been created, select btn:[Finish] to continue with the installation and go to -crossref:bsdinstall[bsdinstall-fetching-distribution]. +crossref:bsdinstall[bsdinstall-fetching-distribution, Fetching Distribution Files]. [[bsdinstall-part-zfs]] === Guided Partitioning Using Root-on-ZFS This partitioning mode only works with whole disks and will erase the contents of the entire disk. The main ZFS configuration menu offers a number of options to control the creation of the pool. [[bsdinstall-zfs-menu]] .ZFS Partitioning Menu image::bsdinstall-zfs-menu.png[Menu showing the different options to configure the ZFS pool] Here is a summary of the options in this menu: * `Install` - Proceed with the installation with the selected options. * `Pool Type/Disks` - Configure the `Pool Type` and the disk(s) that will constitute the pool. The automatic ZFS installer currently only supports the creation of a single top level vdev, except in stripe mode. To create more complex pools, use the instructions in - crossref:bsdinstall[bsdinstall-part-shell] to create the pool. + crossref:bsdinstall[bsdinstall-part-shell, Shell Mode Partitioning] to create the pool. * `Rescan Devices` - Repopulate the list of available disks. * `Disk Info` - This menu can be used to inspect each disk, including its partition table and various other information such as the device model number and serial number, if available. * `Pool Name` - Establish the name of the pool. The default name is _zroot_. * `Force 4K Sectors?` - Force the use of 4K sectors. By default, the installer will automatically create partitions aligned to 4K boundaries and force ZFS to use 4K sectors. This is safe even with 512 byte sector disks, and has the added benefit of ensuring that pools created on 512 byte disks will be able to have 4K sector disks added in the future, either as additional storage space or as replacements for failed disks. Press the kbd:[Enter] key to chose to activate it or not. * `Encrypt Disks?` - Encrypting the disks allows the user to encrypt the disks using GELI. More information about disk encryption is available in crossref:disks[disks-encrypting-geli,“Disk Encryption with geli”]. Press the kbd:[Enter] key to choose whether to activate it or not. * `Partition Scheme` - Choose the partition scheme. GPT is the recommended option in most cases. Press the kbd:[Enter] key to chose between the different options. * `Swap Size` - Establish the amount of swap space. * `Mirror Swap?` - Whether to mirror the swap between the disks. Be aware that enabling mirror swap will break crash dumps. Press the kbd:[Enter] key to activate it or not. * `Encrypt Swap?` - Whether to encrypt the swap. This will encrypt the swap with a temporary key each time the system boots, and discards it on reboot. Press the kbd:[Enter] key to choose to activate it or not. More information about swap encryption in crossref:disks[swap-encrypting,“Encrypting Swap”]. Select kbd:[T] to configure the `Pool Type` and the disk(s) that will constitute the pool. [[bsdinstall-zfs-vdev_type]] .ZFS Pool Type image::bsdinstall-zfs-vdev_type.png[Menu requesting the Virtual Device type. Ex: stripe, mirror, raidz1] Here is a summary of the `Pool Type` that can be selected in this menu: * `stripe` - Striping provides maximum storage of all connected devices, but no redundancy. If just one disk fails the data on the pool is lost irrevocably. * `mirror` - Mirroring stores a complete copy of all data on every disk. Mirroring provides good read performance because data is read from all disks in parallel. Write performance is slower as the data must be written to all disks in the pool. Allows all but one disk to fail. This option requires at least two disks. * `raid10` - Striped mirrors. Provides the best performance, but the least storage. This option needs at least an even number of disks and a minimum of four disks. * `raidz1` - Single Redundant RAID. Allow one disk to fail concurrently. This option needs at least three disks. * `raidz2` - Double Redundant RAID. Allows two disks to fail concurrently. This option needs at least four disks. * `raidz3` - Triple Redundant RAID. Allows three disks to fail concurrently. This option needs at least five disks. Once a `Pool Type` has been selected, a list of available disks is displayed, and the user is prompted to select one or more disks to make up the pool. The configuration is then validated to ensure that enough disks are selected. If validation fails, select btn:[] to return to the list of disks or btn:[] to change the `Pool Type`. [[bsdinstall-zfs-disk_select]] .Disk Selection image::bsdinstall-zfs-disk_select.png[Menu requesting how many disks will be added to the pool] [[bsdinstall-zfs-vdev_invalid]] .Invalid Selection image::bsdinstall-zfs-vdev_invalid.png[Menu indicating that not enough disks have been selected.] If one or more disks are missing from the list, or if disks were attached after the installer was started, select btn:[- Rescan Devices] to repopulate the list of available disks. [[bsdinstall-zfs-rescan-devices]] .Rescan Devices image::bsdinstall-zfs-rescan-devices.png[Device rescan] To avoid accidentally erasing the wrong disk, the btn:[- Disk Info] menu can be used to inspect each disk, including its partition table and various other information such as the device model number and serial number, if available. [[bsdinstall-zfs-disk_info]] .Analyzing a Disk image::bsdinstall-zfs-disk_info.png[Menu showing the information of the partitions.] Select kbd:[N] to configure the `Pool Name`. Enter the desired name, then select btn:[] to establish it or btn:[] to return to the main menu and leave the default name. [[bsdinstall-zfs-pool-name]] .Pool Name image::bsdinstall-zfs-pool-name.png[Menu requesting the name of the pool.] Select kbd:[S] to set the amount of swap. Enter the desired amount of swap, then select btn:[] to establish it or btn:[] to return to the main menu and let the default amount. [[bsdinstall-zfs-swap-amount]] .Swap Amount image::bsdinstall-zfs-swap-amount.png[Menu requesting the amount of swap memory] Once all options have been set to the desired values, select the btn:[>>> Install] option at the top of the menu. The installer then offers a last chance to cancel before the contents of the selected drives are destroyed to create the ZFS pool. [[bsdinstall-zfs-warning]] .Last Chance image::bsdinstall-zfs-warning.png[Menu indicating to the user that the data will be lost] If GELI disk encryption was enabled, the installer will prompt twice for the passphrase to be used to encrypt the disks. Initialization of the encryption then begins. [[bsdinstall-zfs-geli_password]] .Disk Encryption Password image::bsdinstall-zfs-geli_password.png[Menu requesting the password to encrypt the devices.] [[bsdinstall-zfs-init-encription]] .Initializing Encryption image::bsdinstall-zfs-init-encription.png[Menu showing that the encryption is initializing.] The installation then proceeds normally. To continue with the installation, go to -crossref:bsdinstall[bsdinstall-fetching-distribution]. +crossref:bsdinstall[bsdinstall-fetching-distribution, Fetching Distribution Files]. [[bsdinstall-part-shell]] === Shell Mode Partitioning When creating advanced installations, the bsdinstall partitioning menus may not provide the level of flexibility required. Advanced users can select the btn:[Shell] option from the partitioning menu in order to manually partition the drives, create the file system(s), populate `/tmp/bsdinstall_etc/fstab`, and mount the file systems under `/mnt`. Once this is done, type `exit` to return to bsdinstall and continue the installation. [[bsdinstall-fetching-distribution]] == Fetching Distribution Files Installation time will vary depending on the distributions chosen, installation media, and speed of the computer. A series of messages will indicate the progress. First, the installer formats the selected disk(s) and initializes the partitions. Next, in the case of a `bootonly media` or `mini memstick`, it downloads the selected components: [[bsdinstall-distfile-fetching]] .Fetching Distribution Files image::bsdinstall-distfile-fetching.png[Menu showing the download of the different components.] Next, the integrity of the distribution files is verified to ensure they have not been corrupted during download or misread from the installation media: [[bsdinstall-distfile-verify]] .Verifying Distribution Files image::bsdinstall-distfile-verifying.png[Menu showing the verification of the different components.] Finally, the verified distribution files are extracted to the disk: [[bsdinstall-distfile-extract]] .Extracting Distribution Files image::bsdinstall-distfile-extracting.png[Menu showing the extraction of the different components.] Once all requested distribution files have been extracted, bsdinstall displays the first post-installation configuration screen. The available post-configuration options are described in the next section. [[bsdinstall-post]] == Network Interfaces, Accounts, Time Zone, Services and Hardening [[bsdinstall-post-root]] === Setting the `root` Password First, the `root` password must be set. While entering the password, the characters being typed are not displayed on the screen. The password must be entered twice to prevent typing errors. [[bsdinstall-post-set-root-passwd]] .Setting the `root` Password image::bsdinstall-post-root-passwd.png[Menu showing requesting the password for the root user.] [[bsdinstall-config-network-dev]] === Configuring Network Interfaces Next, a list of the network interfaces found on the computer is shown. Select the interface to configure. [[bsdinstall-configure-net-interface]] .Choose a Network Interface image::bsdinstall-configure-network-interface.png[Menu showing the different network interfaces to configure.] If an Ethernet interface is selected, the installer will skip ahead to the menu -shown in crossref:bsdinstall[bsdinstall-configure-net-ipv4]. +shown in crossref:bsdinstall[bsdinstall-configure-net-ipv4,.Choose IPv4 Networking]. If a wireless network interface is chosen, the system will instead scan for wireless access points: [[bsdinstall-wireless-scan]] .Scanning for Wireless Access Points image::bsdinstall-configure-wireless-scan.png[Menu showing wireless network scanning.] Wireless networks are identified by a Service Set Identifier (SSID); a short, unique name given to each network. SSIDs found during the scan are listed, followed by a description of the encryption types available for that network. If the desired SSID does not appear in the list, select btn:[Rescan] to scan again. If the desired network still does not appear, check for problems with antenna connections or try moving the computer closer to the access point. Rescan after each change is made. [[bsdinstall-wireless-accesspoints]] .Choosing a Wireless Network image::bsdinstall-configure-wireless-accesspoints.png[Menu showing the different wireless networks to connect to.] Next, enter the encryption information for connecting to the selected wireless network. WPA2 encryption is strongly recommended over older encryption types such as WEP, which offer little security. If the network uses WPA2, input the password, also known as the Pre-Shared Key (PSK). For security reasons, the characters typed into the input box are displayed as asterisks. [[bsdinstall-wireless-wpa2]] .WPA2 Setup image::bsdinstall-configure-wireless-wpa2setup.png[Menu requesting the wireless network password.] Next, choose whether or not an IPv4 address should be configured on the Ethernet or wireless interface: [[bsdinstall-configure-net-ipv4]] .Choose IPv4 Networking image::bsdinstall-configure-network-interface-ipv4.png[Menu indicating if IPv4 wants to be configured for the selected interface.] There are two methods of IPv4 configuration. DHCP will automatically configure the network interface correctly and should be used if the network provides a DHCP server. Otherwise, the addressing information needs to be input manually as a static configuration. [NOTE] ==== Do not enter random network information as it will not work. If a DHCP server is not available, obtain the information listed in crossref:bsdinstall[bsdinstall-collect-network-information, Required Network Information] from the network administrator or Internet service provider. ==== If a DHCP server is available, select btn:[Yes] in the next menu to automatically configure the network interface. The installer will appear to pause for a minute or so as it finds the DHCP server and obtains the addressing information for the system. [[bsdinstall-net-ipv4-dhcp]] .Choose IPv4 DHCP Configuration image::bsdinstall-configure-network-interface-ipv4-dhcp.png[Menu indicating if DHCP wants to be configured for the selected interface.] If a DHCP server is not available, select btn:[No] and input the following addressing information in this menu: [[bsdinstall-net-ipv4-static]] .IPv4 Static Configuration image::bsdinstall-configure-network-interface-ipv4-static.png[Menu requesting data to configure IPv4 network.] * `IP Address` - The IPv4 address assigned to this computer. The address must be unique and not already in use by another device on the local network. * `Subnet Mask` - The subnet mask for the network. * `Default Router` - The IP address of the network's default gateway. The next screen will ask if the interface should be configured for IPv6. If IPv6 is available and desired, choose btn:[Yes] to select it. [[bsdinstall-net-ipv6]] .Choose IPv6 Networking image::bsdinstall-configure-network-interface-ipv6.png[Menu indicating if IPv6 wants to be configured for the selected interface.] IPv6 also has two methods of configuration. StateLess Address AutoConfiguration (SLAAC) will automatically request the correct configuration information from a local router. Refer to http://tools.ietf.org/html/rfc4862[rfc4862] for more information. Static configuration requires manual entry of network information. If an IPv6 router is available, select btn:[Yes] in the next menu to automatically configure the network interface. The installer will appear to pause for a minute or so as it finds the router and obtains the addressing information for the system. [[bsdinstall-net-ipv6-slaac]] .Choose IPv6 SLAAC Configuration image::bsdinstall-configure-network-interface-slaac.png[Menu indicating if SLAAC wants to be configured for the selected interface.] If an IPv6 router is not available, select btn:[No] and input the following addressing information in this menu: [[bsdinstall-net-ipv6-static]] .IPv6 Static Configuration image::bsdinstall-configure-network-interface-ipv6-static.png[Menu requesting data to configure IPv6 network.] * `IPv6 Address` - The IPv6 address assigned to this computer. The address must be unique and not already in use by another device on the local network. * `Default Router` - The IPv6 address of the network's default gateway. The last network configuration menu is used to configure the Domain Name System (DNS) resolver, which converts hostnames to and from network addresses. If DHCP or SLAAC was used to autoconfigure the network interface, the `Resolver Configuration` values may already be filled in. Otherwise, enter the local network's domain name in the `Search` field. `DNS #1` and `DNS #2` are the IPv4 and/or IPv6 addresses of the DNS servers. At least one DNS server is required. [[bsdinstall-net-dns-config]] .DNS Configuration image::bsdinstall-configure-network-ipv4-dns.png[Menu requesting data to configure DNS for the network.] Once the interface is configured, select a mirror site that is located in the same region of the world as the computer on which FreeBSD is being installed. Files can be retrieved more quickly when the mirror is close to the target computer, reducing installation time. [TIP] ==== Selecting `ftp://download.freebsd.org (Main Site)` will automatically route to the nearest mirror. ==== [[bsdinstall-netinstall-mirror]] .Choosing a Mirror image::bsdinstall-netinstall-mirrorselect.png[Menu requesting a network mirror.] [[bsdinstall-timezone]] === Setting the Time Zone The next series of menus are used to determine the correct local time by selecting the geographic region, country, and time zone. Setting the time zone allows the system to automatically correct for regional time changes, such as daylight savings time, and perform other time zone related functions properly. The example shown here is for a machine located in the mainland time zone of Spain, Europe. The selections will vary according to the geographical location. [[bsdinstall-timezone-region]] .Select a Region image::bsdinstall-timezone-region.png[Menu requesting the timezone region.] The appropriate region is selected using the arrow keys and then pressing kbd:[Enter]. [[bsdinstall-timezone-country]] .Select a Country image::bsdinstall-timezone-country.png[Menu requesting the timezone country.] Select the appropriate country using the arrow keys and press kbd:[Enter]. [[bsdinstall-timezone-zone]] .Select a Time Zone image::bsdinstall-timezone-zone.png[Menu requesting the timezone zone.] The appropriate time zone is selected using the arrow keys and pressing kbd:[Enter]. [[bsdinstall-timezone-confirmation]] .Confirm Time Zone image::bsdinstall-timezone-confirm.png[Menu requesting confirmation of the selected timezone.] Confirm the abbreviation for the time zone is correct. [[bsdinstall-timezone-date]] .Select Date image::bsdinstall-timezone-date.png[Menu requesting the system date.] The appropriate date is selected using the arrow keys and then pressing btn:[Set Date]. Otherwise, the date selection can be skipped by pressing btn:[Skip]. [[bsdinstall-timezone-time]] .Select Time image::bsdinstall-timezone-time.png[Menu requesting the system time.] The appropriate time is selected using the arrow keys and then pressing btn:[Set Time]. Otherwise, the time selection can be skipped by pressing btn:[Skip]. [[bsdinstall-sysconf]] === Enabling Services The next menu is used to configure which system services will be started whenever the system boots. All of these services are optional. Only start the services that are needed for the system to function. [[bsdinstall-config-serv]] .Selecting Additional Services to Enable image::bsdinstall-config-services.png[Menu showing the different services available.] Here is a summary of the services that can be enabled in this menu: * `local_unbound` - Enable the DNS local unbound. It is necessary to keep in mind that this is a configuration only meant for use as a local caching forwarding resolver. If the objective is to set up a resolver for the entire network, install package:dns/unbound[]. * `sshd` - The Secure Shell (SSH) daemon is used to remotely access a system over an encrypted connection. Only enable this service if the system should be available for remote logins. * `moused` - Enable this service if the mouse will be used from the command-line system console. * `ntpdate` - Enable automatic clock synchronization at boot time. Note that the functionality of this program is now available in the man:ntpd[8] daemon and the man:ntpdate[8] utility will soon be retired. * `ntpd` - The Network Time Protocol (NTP) daemon for automatic clock synchronization. Enable this service if you wish to synchronise your system clock with a remote time server or pool. * `powerd` - System power control utility for power control and energy saving. * `dumpdev` - Crash dumps are useful when debugging issues with the system, so users are encouraged to enable them. [[bsdinstall-hardening]] === Enabling Hardening Security Options The next menu is used to configure which security options will be enabled. All of these options are optional. But their use is encouraged. [[bsdinstall-hardening-options]] .Selecting Hardening Security Options image::bsdinstall-hardening.png[Menu shoring the different hardening security options.] Here is a summary of the options that can be enabled in this menu: * `hide_uids` - Hide processes running as other users (UID). This prevents unprivileged users from seeing running processes from other users. * `hide_gids` - Hide processes running as other groups (GID). This prevents unprivileged users from seeing running processes from other groups. * `hide_jail` - Hide processes running in jails. This prevents unprivileged users from seeing processes running inside jails. * `read_msgbuf` - Disable reading kernel message buffer for unprivileged users. Prevent unprivileged users from using man:dmesg[8] to view messages from the kernel's log buffer. * `proc_debug` - Disable process debugging facilities for unprivileged users. Disables a variety of unprivileged inter-process debugging services, including some procfs functionality, `ptrace()`, and `ktrace()`. Please note that this will also prevent debugging tools such as man:lldb[1], man:truss[1] and man:procstat[1], as well as some built-in debugging facilities in certain scripting languages like PHP. * `random_pid` - Randomize the PID of processes. * `clear_tmp` - Clean `/tmp` when the system starts up. * `disable_syslogd` - Disable opening the syslogd network socket. By default, FreeBSD runs syslogd in a secure way with `-s`. This prevents the daemon from listening for incoming UDP requests on port 514. With this option enabled, syslogd will instead run with `-ss`, which prevents syslogd from opening any port. For more information, see man:syslogd[8]. * `disable_sendmail` - Disable the sendmail mail transport agent. * `secure_console` - Make the command prompt request the `root` password when entering single-user mode. * `disable_ddtrace` - DTrace can run in a mode that affects the running kernel. Destructive actions may not be used unless explicitly enabled. Use `-w` to enable this option when using DTrace. For more information, see man:dtrace[1]. * `enable_aslr` - Enable address layout randomization. For more information about address layout randomization the link:https://en.wikipedia.org/wiki/Address_space_layout_randomization[Wikipedia article] can be consulted. [[bsdinstall-addusers]] === Add Users The next menu prompts to create at least one user account. It is recommended to log into the system using a user account rather than as `root`. When logged in as `root`, there are essentially no limits or protection on what can be done. Logging in as a normal user is safer and more secure. Select btn:[Yes] to add new users. [[bsdinstall-add-user1]] .Add User Accounts image::bsdinstall-adduser1.png[Menu requesting if a user want to be added to the system.] Follow the prompts and input the requested information for the user account. -The example shown in crossref:bsdinstall[bsdinstall-add-user2] creates the `asample` user account. +The example shown in crossref:bsdinstall[bsdinstall-add-user2,.Enter User Information] creates the `asample` user account. [[bsdinstall-add-user2]] .Enter User Information image::bsdinstall-adduser2.png[Menu requesting different information for the new user.] Here is a summary of the information to input: * `Username` - The name the user will enter to log in. A common convention is to use the first letter of the first name combined with the last name, as long as each username is unique for the system. The username is case sensitive and should not contain any spaces. * `Full name` - The user's full name. This can contain spaces and is used as a description for the user account. * `Uid` - User ID. This is typically left blank so the system automatically assigns a value. * `Login group` - The user's group. This is typically left blank to accept the default. * `Invite _user_ into other groups?` - Additional groups to which the user will be added as a member. If the user needs administrative access, type `wheel` here. * `Login class` - Typically left blank for the default. * `Shell` - Type in one of the listed values to set the interactive shell for the user. Refer to crossref:basics[shells,Shells] for more information about shells. * `Home directory` - The user's home directory. The default is usually correct. * `Home directory permissions` - Permissions on the user's home directory. The default is usually correct. * `Use password-based authentication?` - Typically `yes` so that the user is prompted to input their password at login. * `Use an empty password?` - Typically `no` as empty or blank passwords are insecure. * `Use a random password?` - Typically `no` so that the user can set their own password in the next prompt. * `Enter password` - The password for this user. Typed-in characters will not be shown on the screen. * `Enter password again` - The password must be typed again for verification. * `Lock out the account after creation?` - Typically `no` so that the user can log in. After entering all the details, a summary is shown for review. If a mistake was made, enter `no` to correct it. Once everything is correct, enter `yes` to create the new user. [[bsdinstall-add-user3]] .Exit User and Group Management image::bsdinstall-adduser3.png[Menu showing the information of the new user and requesting if everything is correct.] If there are more users to add, answer the `Add another user?` question with `yes`. Enter `no` to finish adding users and continue the installation. For more information on adding users and user management, see crossref:basics[users-synopsis,Users and Basic Account Management]. [[bsdinstall-final-conf]] === Final Configuration After everything has been installed and configured, a final chance is provided to modify settings. [[bsdinstall-final-config]] .Final Configuration image::bsdinstall-finalconfiguration.png[Menu showing different options to perform before finishing the installation. Ex: Add user, Time Zone, etc.] Use this menu to make any changes or to do any additional configuration before completing the installation. -* `Add User` - Described in crossref:bsdinstall[bsdinstall-addusers]. -* `Root Password` - Described in crossref:bsdinstall[bsdinstall-post-root]. -* `Hostname` - Described in crossref:bsdinstall[bsdinstall-hostname]. -* `Network` - Described in crossref:bsdinstall[bsdinstall-config-network-dev]. -* `Services` - Described in crossref:bsdinstall[bsdinstall-sysconf]. -* `System Hardening` - Described in crossref:bsdinstall[bsdinstall-hardening]. -* `Time Zone` - Described in crossref:bsdinstall[bsdinstall-timezone]. +* `Add User` - Described in crossref:bsdinstall[bsdinstall-addusers, Add Users]. +* `Root Password` - Described in crossref:bsdinstall[bsdinstall-post-root, Setting the `root` Password]. +* `Hostname` - Described in crossref:bsdinstall[bsdinstall-hostname, Setting the Hostname]. +* `Network` - Described in crossref:bsdinstall[bsdinstall-config-network-dev, Configuring Network Interfaces]. +* `Services` - Described in crossref:bsdinstall[bsdinstall-sysconf, Enabling Services]. +* `System Hardening` - Described in crossref:bsdinstall[bsdinstall-hardening, Enabling Hardening Security Options]. +* `Time Zone` - Described in crossref:bsdinstall[bsdinstall-timezone, Setting the Time Zone]. * `Handbook` - Download and install the FreeBSD Handbook. Once configuration is complete, select btn:[Exit]. [[bsdinstall-final-modification-shell]] .Manual Configuration image::bsdinstall-final-modification-shell.png[Menu showing that the installation has finished. And asking if you want to open a shell to make manual changes.] bsdinstall will prompt for any additional configuration that needs to be done before rebooting into the new system. Select btn:[Yes] to exit to a shell within the new system or btn:[No] to proceed to the last step of the installation. [[bsdinstall-final-main]] .Complete the Installation image::bsdinstall-mainexit.png[Menu showing that the installation has finished and asking whether to reboot the system or access the Live CD.] If further configuration or special setup is needed, select btn:[Live CD] to boot the install media into Live CD mode. If the installation is complete, select btn:[Reboot] to reboot the computer and start the new FreeBSD system. Do not forget to remove the FreeBSD install media or the computer might boot from it again. As FreeBSD boots, informational messages are displayed. After the system finishes booting, a login prompt is displayed. At the `login:` prompt, enter the username added during the installation. Avoid logging in as `root`. Refer to crossref:basics[users-superuser,The Superuser Account] for instructions on how to become the superuser when administrative access is needed. The messages that appear during boot can be reviewed by pressing kbd:[Scroll-Lock] to turn on the scroll-back buffer. The kbd:[PgUp], kbd:[PgDn], and arrow keys can be used to scroll back through the messages. When finished, press kbd:[Scroll-Lock] again to unlock the display and return to the console. To review these messages once the system has been up for some time, type `less /var/run/dmesg.boot` from a command prompt. Press kbd:[q] to return to the command line after viewing. -If sshd was enabled in crossref:bsdinstall[bsdinstall-config-serv], the first boot might be a bit slower as the system generates SSH host keys. +If sshd was enabled in crossref:bsdinstall[bsdinstall-config-serv,.Selecting Additional Services to Enable], the first boot might be a bit slower as the system generates SSH host keys. Subsequent boots will be faster. The fingerprints of the keys are then displayed as in the following example: [source,shell] .... Generating public/private rsa1 key pair. Your identification has been saved in /etc/ssh/ssh_host_key. Your public key has been saved in /etc/ssh/ssh_host_key.pub. The key fingerprint is: 10:a0:f5:af:93:ae:a3:1a:b2:bb:3c:35:d9:5a:b3:f3 root@machine3.example.com The key's randomart image is: +--[RSA1 1024]----+ | o.. | | o . . | | . o | | o | | o S | | + + o | |o . + * | |o+ ..+ . | |==o..o+E | +-----------------+ Generating public/private dsa key pair. Your identification has been saved in /etc/ssh/ssh_host_dsa_key. Your public key has been saved in /etc/ssh/ssh_host_dsa_key.pub. The key fingerprint is: 7e:1c:ce:dc:8a:3a:18:13:5b:34:b5:cf:d9:d1:47:b2 root@machine3.example.com The key's randomart image is: +--[ DSA 1024]----+ | .. . .| | o . . + | | . .. . E .| | . . o o . . | | + S = . | | + . = o | | + . * . | | . . o . | | .o. . | +-----------------+ Starting sshd. .... Refer to crossref:security[openssh,"OpenSSH"] for more information about fingerprints and SSH. FreeBSD does not install a graphical environment by default. Refer to crossref:x11[x11,The X Window System] for more information about installing and configuring a graphical window manager. Proper shutdown of a FreeBSD computer helps protect data and hardware from damage. _Do not turn off the power before the system has been properly shut down!_ If the user is a member of the `wheel` group, become the superuser by typing `su` at the command line and entering the `root` password. Then, type `shutdown -p now` and the system will shut down cleanly, and, if the hardware supports it, turn itself off. [[bsdinstall-install-trouble]] == Troubleshooting This section covers basic installation troubleshooting, such as common problems people have reported. Check the Hardware Notes listed on the link:https://www.FreeBSD.org/releases/[FreeBSD Release Information] page for the version of FreeBSD to make sure the hardware is supported. [NOTE] ==== Some installation problems can be avoided or alleviated by updating the firmware on various hardware components, most notably the motherboard. Motherboard firmware is usually referred to as the BIOS. Most motherboard and computer manufacturers have a website for upgrades and upgrade information. Manufacturers generally advise against upgrading the motherboard BIOS unless there is a good reason for doing so, like a critical update. The upgrade process _can_ go wrong, leaving the BIOS incomplete and the computer inoperative. ==== If the system hangs while probing hardware during boot or behaves strangely during the installation process, ACPI may be the culprit. FreeBSD makes extensive use of the system ACPI service on the i386 and amd64 platforms to aid in system configuration if it is detected during boot. Unfortunately, some bugs still exist in both the ACPI driver and within system motherboards and BIOS firmware. ACPI can be disabled by setting the `hint.acpi.0.disabled` hint in the third stage boot loader: [source,shell] .... set hint.acpi.0.disabled="1" .... This is reset each time the system is booted, so it is necessary to add `hint.acpi.0.disabled="1"` to the file `/boot/loader.conf`. More information about the boot loader can be found in crossref:boot[boot-synopsis,“Synopsis”]. [[using-live-cd]] == Using the Live CD The welcome menu of bsdinstall, shown in -crossref:bsdinstall[bsdinstall-choose-mode], provides a btn:[Live CD] option. +crossref:bsdinstall[bsdinstall-choose-mode,.Welcome Menu], provides a btn:[Live CD] option. This is useful for those who are still wondering whether FreeBSD is the right operating system for them and want to test some of the features before installing. The following points should be noted before using the btn:[Live CD]: * To gain access to the system, authentication is required. The username is `root` and the password is blank. * As the system runs directly from the installation media, performance will be significantly slower than that of a system installed on a hard disk. * This option only provides a command prompt and not a graphical interface. diff --git a/documentation/content/en/books/handbook/config/_index.adoc b/documentation/content/en/books/handbook/config/_index.adoc index 828734d3a4..8e7a652d63 100644 --- a/documentation/content/en/books/handbook/config/_index.adoc +++ b/documentation/content/en/books/handbook/config/_index.adoc @@ -1,1592 +1,1592 @@ --- title: Chapter 14. Configuration, Services, Logging and Power Management part: Part III. System Administration prev: books/handbook/partiii next: books/handbook/boot description: This chapter explains much of the FreeBSD configuration files, how to enable or disable a service, how to configure the logging system and the power management area. tags: ["configuration", "services", "cron", "periodic", "logging", "configuration files", "sysctl", "swap", "power management"] showBookMenu: true weight: 18 path: "/books/handbook/config/" --- [[config-tuning]] = Configuration, Services, Logging and Power Management :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 14 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/config/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[config-synopsis]] == Synopsis One of the important aspects of FreeBSD is proper system configuration. This chapter explains much of the FreeBSD configuration process, including some of the parameters which can be set to tune a FreeBSD system. Before reading this chapter, you should: * Understand UNIX(R) and FreeBSD basics (crossref:basics[basics,FreeBSD Basics]). After reading this chapter, you will know: * How to use the various configuration files in [.filename]#/etc#. * The basics of [.filename]#rc.conf# configuration and [.filename]#/usr/local/etc/rc.d# startup scripts. * How to tune FreeBSD using man:sysctl[8] variables. * How to configure the power management in FreeBSD. [[configtuning-configfiles]] == Configuration Files FreeBSD maintains a clear separation between the base system and third party applications and therefore this affects where the configuration files of these applications are located. FreeBSD base system configuration is located at the [.filename]#/etc# directory, and the [.filename]#/usr/local/etc# directory contains all the configuration files of the applications installed on the system through the ports collection and packages. The kernel state configuration is located in [.filename]#/etc/sysctl.conf#. In the section crossref:config[configtuning-sysctl], the operation of man:sysctl[8] will be explained in more detail. For more information about the FreeBSD file system structure refer to man:hier[7]. As a general rule, configuration files do not use a standard on what syntax they must follow. Although it is true that the `#` character is normally used to comment a line and that each line has a configuration variable. [NOTE] ==== Some applications like man:pkg[8] are starting to use the link:https://github.com/vstakhov/libucl[Universal Configuration Language (UCL)]. ==== === The [.filename]#/etc# directory The [.filename]#/etc# directory contains all of the FreeBSD base system configuration files that are responsible for configuring FreeBSD. [CAUTION] ==== *Extreme* caution must be taken when modifying files in the [.filename]#/etc# directory; misconfiguration could make FreeBSD unbootable or malfunction. ==== [.informaltable] [cols="1,1", frame="none"] |=== |[.filename]#/etc# |System configuration files and scripts. |[.filename]#/etc/defaults# |Default system configuration files, see man:rc[8] for more information. |[.filename]#/etc/fstab# |man:fstab[5] contains descriptive information about the various file systems. |[.filename]#/etc/mail# |Extra man:sendmail[8] configuration and other MTA configuration files. |[.filename]#/etc/mtree# |mtree configuration files, see man: mtree[8] for more information. |[.filename]#/etc/pam.d# |Configuration files for the Pluggable Authentication Modules (PAM) library. |[.filename]#/etc/periodic# |Scripts that are run daily, weekly, and monthly, via man:cron[8], see man:periodic[8] for more information. |[.filename]#/etc/rc.d# |System and daemon startup/control scripts, see man:rc[8] for more information. |[.filename]#/etc/rc.conf# |Contains descriptive information about the local host name, configuration details for any potential network interfaces and which services should be started up at system initial boot time. More information in -crossref:bsdinstall[configtuning-core-configuration] +crossref:bsdinstall[configtuning-core-configuration, Managing System-Specific Configuration] |[.filename]#/etc/security# |OpenBSM audit configuration files, see man:audit[8] for more information. |[.filename]#/etc/ppp# |ppp configuration files, see man:ppp[8] for more information. |[.filename]#/etc/ssh# |OpenSSH configuration files, see man:ssh[1] for more information. |[.filename]#/etc/ssl# |OpenSSL configuration files. |[.filename]#/etc/sysctl.conf# |Contains settings for the kernel. More information in -crossref:bsdinstall[configtuning-sysctl] +crossref:bsdinstall[configtuning-sysctl, The sysctl utility] |=== [[configtuning-sysctl]] === The sysctl utility The man:sysctl[8] utility is used to make changes to a running FreeBSD system. The man:sysctl[8] utility retrieves kernel state and allows processes with appropriate privilege to set kernel state. The state to be retrieved or set is described using a "Management Information Base" ("MIB") style name, described as a dotted set of components. .Management Information Base [.informaltable] [cols="1,1", frame="none"] |=== |sysctl |"Magic" numbers |kern |Kernel functions and features |vm |virtual memory |vfs |Filesystem |net |Network |debug |Debugging parameters |hw |Hardware |machdep |Machine dependent |user |Userland |p1003_1b |POSIX 1003.1B |=== At its core, man:sysctl[8] serves two functions: to read and to modify system settings. To view all readable variables: [source,shell] .... % sysctl -a .... The output should be similar to the following: [.programlisting] .... kern.ostype: FreeBSD ... vm.swap_enabled: 1 vm.overcommit: 0 vm.domain.0.pidctrl.kdd: 8 vm.domain.0.pidctrl.kid: 4 vm.domain.0.pidctrl.kpd: 3 ... vfs.zfs.sync_pass_rewrite: 2 vfs.zfs.sync_pass_dont_compress: 8 vfs.zfs.sync_pass_deferred_free: 2 .... To read a particular variable, specify its name: [source,shell] .... % sysctl kern.maxproc .... The output should be similar to the following: [.programlisting] .... kern.maxproc: 1044 .... The Management Information Base (MIB) is hierarchical and hence, specifying a prefix prints all the nodes hanging from it: [source,shell] .... % sysctl net .... The output should be similar to the following: [.programlisting] .... net.local.stream.recvspace: 8192 net.local.stream.sendspace: 8192 net.local.dgram.recvspace: 16384 net.local.dgram.maxdgram: 2048 net.local.seqpacket.recvspace: 8192 net.local.seqpacket.maxseqpacket: 8192 net.local.sockcount: 60 net.local.taskcount: 25 net.local.recycled: 0 net.local.deferred: 0 net.local.inflight: 0 net.inet.ip.portrange.randomtime: 1 net.inet.ip.portrange.randomcps: 9999 [...] .... To set a particular variable, use the _variable_=_value_ syntax: [source,shell] .... # sysctl kern.maxfiles=5000 .... The output should be similar to the following: [.programlisting] .... kern.maxfiles: 2088 -> 5000 .... [NOTE] ==== To keep the configuration after a reboot it is necessary to add these variables to the [.filename]#/etc/sysctl.conf# file as explained below. ==== [[configtuning-sysctlconf]] === The [.filename]#/etc/sysctl.conf# file The configuration file for man:sysctl[8], [.filename]#/etc/sysctl.conf#, looks much like [.filename]#/etc/rc.conf#. Values are set using a `variable=value` syntax. [NOTE] ==== The specified values are set after the system goes into multi-user mode. Not all variables are settable in this mode. ==== For example, to turn off logging of fatal signal exits and prevent users from seeing processes started by other users, the following tunables can be set in [.filename]#/etc/sysctl.conf#: [.programlisting] .... # Do not log fatal signal exits (e.g., sig 11) kern.logsigexit=0 # Prevent users from seeing information about processes that # are being run under another UID. security.bsd.see_other_uids=0 .... To obtain more information about what function a particular sysctl has, the following command can be executed: [source,shell] .... % sysctl -d kern.dfldsiz .... The output should be similar to the following: [.programlisting] .... kern.dfldsiz: Initial data size limit .... [[configtuning-core-configuration]] === Managing System-Specific Configuration The principal location for system configuration information is [.filename]#/etc/rc.conf#. This file contains a wide range of configuration information and it is read at system startup to configure the system. It provides the configuration information for the [.filename]#rc*# files. The entries in [.filename]#/etc/rc.conf# override the default settings in [.filename]#/etc/defaults/rc.conf#. [TIP] ==== The file [.filename]#/etc/defaults/rc.conf# containing the default settings should not be edited. Instead, all system-specific changes should be made to [.filename]#/etc/rc.conf#. ==== A number of strategies may be applied in clustered applications to separate site-wide configuration from system-specific configuration in order to reduce administration overhead. The recommended approach is to place system-specific configuration into [.filename]#/etc/rc.conf.local#. For example, these entries in [.filename]#/etc/rc.conf# apply to all systems: [.programlisting] .... sshd_enable="YES" keyrate="fast" defaultrouter="10.1.1.254" .... Whereas these entries in [.filename]#/etc/rc.conf.local# apply to this system only: [.programlisting] .... hostname="node1.example.org" ifconfig_fxp0="inet 10.1.1.1/8" .... Distribute [.filename]#/etc/rc.conf# to every system using an application such as rsync or puppet, while [.filename]#/etc/rc.conf.local# remains unique. Upgrading the system will not overwrite [.filename]#/etc/rc.conf#, so system configuration information will not be lost. [TIP] ==== Both [.filename]#/etc/rc.conf# and [.filename]#/etc/rc.conf.local# are parsed by man:sh[1]. This allows system operators to create complex configuration scenarios. Refer to man:rc.conf[5] for further information on this topic. ==== [[configtuning-rcd]] == Managing Services in FreeBSD FreeBSD uses the man:rc[8] system of startup scripts during system initialization and for managing services. The scripts listed in [.filename]#/etc/rc.d# provide basic services which can be controlled with the `start`, `stop`, and `restart` options to man:service[8]. A basic script may look similar to the following: [.programlisting] .... #!/bin/sh # # PROVIDE: utility # REQUIRE: DAEMON # KEYWORD: shutdown . /etc/rc.subr name=utility rcvar=utility_enable command="/usr/local/sbin/utility" load_rc_config $name # # DO NOT CHANGE THESE DEFAULT VALUES HERE # SET THEM IN THE /etc/rc.conf FILE # utility_enable=${utility_enable-"NO"} pidfile=${utility_pidfile-"/var/run/utility.pid"} run_rc_command "$1" .... Refer to extref:{rc-scripting}[this article] for instructions on how to create custom man:rc[8] scripts. [[configtuning-starting-services]] === Starting Services Many users install third party software on FreeBSD from the Ports Collection and require the installed services to be started upon system initialization. Services, such as package:security/openssh-portable[] or package:www/nginx[] are just two of the many software packages which may be started during system initialization. This section explains the procedures available for starting services. Since the man:rc[8] system is primarily intended to start and stop services at system startup and shutdown time, the `start`, `stop` and `restart` options will only perform their action if the appropriate [.filename]#/etc/rc.conf# variable is set. So the first step to start a service, like for example package:www/nginx[] is to add it to [.filename]#/etc/rc.conf# by executing the following command: [source,shell] .... # sysrc nginx_enable="YES" .... Then nginx can be started executing the following command: [source,shell] .... # service nginx start .... [TIP] ==== To `start`, `stop` or `restart` a service regardless of the settings in [.filename]#/etc/rc.conf#, these commands should be prefixed with "one". For instance, to start package:www/nginx[] regardless of the current [.filename]#/etc/rc.conf# setting, execute the following command: [source,shell] .... # service nginx onestart .... ==== It is also possible to put a service automatically into a jail, see the corresponding crossref:jails[service-jails,Service Jails] explanation. [[configtuning-status-services]] === Status of a Service To determine if a service is running, use the `status` subcommand. For example, to verify that package:www/nginx[] is running: [source,shell] .... # service nginx status .... The output should be similar to the following: [.programlisting] .... nginx is running as pid 27871. .... [[configtuning-reload-services]] === Reload a Service In some cases, it is also possible to `reload` a service. This attempts to send a signal to an individual service, forcing the service to reload its configuration files. In most cases, this means sending the service a `SIGHUP` signal. *Not all services support this feature.* The man:rc[8] system is used for network services and it also contributes to most of the system initialization. For instance, when the [.filename]#/etc/rc.d/bgfsck# script is executed, it prints out the following message: [source,shell] .... Starting background file system checks in 60 seconds. .... This script is used for background file system checks, which occur only during system initialization. Many system services depend on other services to function properly. For example, man:yp[8] and other RPC-based services may fail to start until after the man:rpcbind[8] service has started. Additional information can be found in man:rc[8] and man:rc.subr[8]. === Using Services to Start Services Other services can be started using man:inetd[8]. Working with man:inetd[8] and its configuration is described in depth in crossref:network-servers[network-inetd,“The inetd Super-Server”]. In some cases, it may make more sense to use man:cron[8] to start system services. This approach has a number of advantages as man:cron[8] runs these processes as the owner of the man:crontab[5]. This allows regular users to start and maintain their own applications. The `@reboot` feature of man:cron[8], may be used in place of the time specification. This causes the job to run when man:cron[8] is started, normally during system initialization. [[cron-periodic]] == Cron and Periodic Scheduling tasks to run at a certain day or time is a very common task on FreeBSD. The tool in charge of performing this task is man:cron[8]. In addition to tasks that can be scheduled by the user via man:cron[8], FreeBSD performs routine background tasks managed by man:periodic[8]. [[configtuning-cron]] === Cron The man:cron[8] utility runs in the background and regularly checks [.filename]#/etc/crontab# for tasks to execute and searches [.filename]#/var/cron/tabs# for custom crontab files. These files are used to schedule tasks which cron runs at the specified times. Each entry in a crontab defines a task to run and is known as a _cron job_. Two different types of configuration files are used: the system crontab, which should not be modified, and user crontabs, which can be created and edited as needed. The format used by these files is documented in man:crontab[5]. The format of the system crontab, [.filename]#/etc/crontab# includes a `who` column which does not exist in user crontabs. In the system crontab, cron runs the command as the user specified in this column. In a user crontab, all commands run as the user who created the crontab. User crontabs allow individual users to schedule their own tasks. The `root` user can also have a user [.filename]#crontab# which can be used to schedule tasks that do not exist in the system [.filename]#crontab#. Here is a sample entry from the system crontab, [.filename]#/etc/crontab#: [.programlisting] .... # /etc/crontab - root's crontab for FreeBSD # # <.> # SHELL=/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin <.> # #minute hour mday month wday who command <.> # # Save some entropy so that /dev/random can re-seed on boot. */11 * * * * operator /usr/libexec/save-entropy <.> # # Rotate log files every hour, if necessary. 0 * * * * root newsyslog # # Perform daily/weekly/monthly maintenance. 1 3 * * * root periodic daily 15 4 * * 6 root periodic weekly 30 5 1 * * root periodic monthly # # Adjust the time zone if the CMOS clock keeps local time, as opposed to # UTC time. See adjkerntz(8) for details. 1,31 0-5 * * * root adjkerntz -a .... <.> Lines that begin with the `+#+` character are comments. A comment can be placed in the file as a reminder of what and why a desired action is performed. Comments cannot be on the same line as a command or else they will be interpreted as part of the command; they must be on a new line. Blank lines are ignored. <.> The equals (`=`) character is used to define any environment settings. In this example, it is used to define the `SHELL` and `PATH`. If the `SHELL` is omitted, cron will use the default Bourne shell. If the `PATH` is omitted, the full path must be given to the command or script to run. <.> This line defines the seven fields used in a system crontab: `minute`, `hour`, `mday`, `month`, `wday`, `who`, and `command`. The `minute` field is the time in minutes when the specified command will be run, the `hour` is the hour when the specified command will be run, the `mday` is the day of the month, `month` is the month, and `wday` is the day of the week. These fields must be numeric values, representing the twenty-four hour clock, or a `*`, representing all values for that field. The `who` field only exists in the system crontab and specifies which user the command should be run as. The last field is the command to be executed. <.> This entry defines the values for this cron job. The `\*/11`, followed by several more `*` characters, specifies that `/usr/libexec/save-entropy` is invoked by `operator` every eleven minutes of every hour, of every day and day of the week, of every month. Commands can include any number of switches. However, commands which extend to multiple lines need to be broken with the backslash "\" continuation character. [[configtuning-installcrontab]] === Creating a User Crontab To create a user crontab, invoke `crontab` in editor mode: [source,shell] .... % crontab -e .... This will open the user's crontab using the default text editor. The first time a user runs this command, it will open an empty file. Once a user creates a crontab, this command will open that file for editing. It is useful to add these lines to the top of the crontab file in order to set the environment variables and to remember the meanings of the fields in the crontab: [.programlisting] .... SHELL=/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin # Order of crontab fields # minute hour mday month wday command .... Then add a line for each command or script to run, specifying the time to run the command. This example runs the specified custom Bourne shell script every day at two in the afternoon. Since the path to the script is not specified in `PATH`, the full path to the script is given: [.programlisting] .... 0 14 * * * /home/user/bin/mycustomscript.sh .... [TIP] ==== Before using a custom script, make sure it is executable and test it with the limited set of environment variables set by cron. To replicate the environment that would be used to run the above cron entry, use: [.programlisting] .... env -i SHELL=/bin/sh PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin HOME=/home/user LOGNAME=user /home/user/bin/mycustomscript.sh .... The environment set by cron is discussed in man:crontab[5]. Checking that scripts operate correctly in a cron environment is especially important if they include any commands that delete files using wildcards. ==== When finished editing the crontab, save the file. It will automatically be installed, and cron will read the crontab and run its cron jobs at their specified times. To list the cron jobs in a crontab, use this command: [source,shell] .... % crontab -l .... The output should be similar to the following: [.programlisting] .... 0 14 * * * /home/user/bin/mycustomscript.sh .... To remove all of the cron jobs in a user crontab: [source,shell] .... % crontab -r .... The output should be similar to the following: [.programlisting] .... remove crontab for user? y .... [[configtuning-periodic]] === Periodic FreeBSD provides a set of system management scripts to check status of various subsystems, perform security-related checks, rotate log files, etc. These scripts are run on a periodic basis: daily. weekly, or monthly. The management of these tasks is performed by man:periodic[8] and its configuration resides in man:periodic.conf[5]. The periodic tasks are initiated by entries in the system crontab, shown above. Scripts executed by man:periodic[8] are located in [.filename]#/etc/periodic/# for base utilities and in [.filename]#/usr/local/etc/periodic/# for third-party software. They are organized in 4 subdirectories, daily, weekly, monthly and security. [[enable-disable-periodic]] === Enable or Disable Periodic Tasks FreeBSD has some scripts enabled by default to run periodically. To enable or disable a task, the first step is to edit [.filename]#/etc/periodic.conf# executing the following command: [source,shell] .... # ee /etc/periodic.conf .... And then to enable, for example, `daily_status_zfs_enable` put the following content in the file: [.programlisting] .... daily_status_zfs_enable="YES" .... To disable a task that is active by default, all that needs to be done is to change `YES` to `NO`. [[configuring-output-periodic-tasks]] === Configuring the Output of Periodic Tasks In [.filename]#/etc/periodic.conf# the variables `daily_output`, `weekly_output` and `monthly_output` specifies where to send the results of the script execution. By default the output of the periodic scripts are emailed to root, and therefore it is best to read root's mail or alias root to a mailbox that is monitored. To send the results to another email or to other emails, add the email addresses separated by spaces to [.filename]#/etc/periodic.conf#: [.programlisting] .... daily_output="email1@example.com email2@example.com" weekly_output="email1@example.com email2@example.com" monthly_output="email1@example.com email2@example.com" .... To log periodic output instead of receiving it as email, add the following lines to [.filename]#/etc/periodic.conf#. man:newsyslog[8] will rotate these files at the appropriate times: [.programlisting] .... daily_output=/var/log/daily.log weekly_output=/var/log/weekly.log monthly_output=/var/log/monthly.log .... [[configtuning-syslog]] == Configuring System Logging Generating and reading system logs is an important aspect of system administration. The information in system logs can be used to detect hardware and software issues as well as application and system configuration errors. This information also plays an important role in security auditing and incident response. Most system daemons and applications will generate log entries. FreeBSD provides a system logger, man:syslogd[8], to manage logging. By default, syslogd is enabled and started when the system boots. This section describes how to configure the FreeBSD system logger for both local and remote logging and how to perform log rotation and log management. === Configuring Local Logging The configuration file, [.filename]#/etc/syslog.conf#, controls what syslogd does with log entries as they are received. There are several parameters to control the handling of incoming events. The _facility_ describes which subsystem generated the message, such as the kernel or a daemon, and the _level_ describes the severity of the event that occurred. This makes it possible to configure if and where a log message is logged, depending on the facility and level. It is also possible to take action depending on the application that sent the message, and in the case of remote logging, the hostname of the machine generating the logging event. This configuration file contains one line per action, where the syntax for each line is a selector field followed by an action field. The syntax of the selector field is _facility.level_ which will match log messages from _facility_ at level _level_ or higher. It is also possible to add an optional comparison flag before the level to specify more precisely what is logged. Multiple selector fields can be used for the same action, and are separated with a semicolon (`;`). Using `*` will match everything. The action field denotes where to send the log message, such as to a file or remote log host. As an example, here is the default [.filename]#/etc/syslog.conf# from FreeBSD: [.programlisting] .... # Spaces ARE valid field separators in this file. However, # other *nix-like systems still insist on using tabs as field # separators. If you are sharing this file between systems, you # may want to use only tabs as field separators here. # Consult the syslog.conf(5) manpage. *.err;kern.warning;auth.notice;mail.crit /dev/console <.> *.notice;authpriv.none;kern.debug;lpr.info;mail.crit;news.err /var/log/messages security.* /var/log/security auth.info;authpriv.info /var/log/auth.log mail.info /var/log/maillog <.> cron.* /var/log/cron !-devd *.=debug /var/log/debug.log <.> *.emerg * daemon.info /var/log/daemon.log # uncomment this to log all writes to /dev/console to /var/log/console.log # touch /var/log/console.log and chmod it to mode 600 before it will work #console.info /var/log/console.log # uncomment this to enable logging of all log messages to /var/log/all.log # touch /var/log/all.log and chmod it to mode 600 before it will work #*.* /var/log/all.log # uncomment this to enable logging to a remote loghost named loghost #*.* @loghost # uncomment these if you're running inn # news.crit /var/log/news/news.crit # news.err /var/log/news/news.err # news.notice /var/log/news/news.notice # Uncomment this if you wish to see messages produced by devd # !devd # *.>=notice /var/log/devd.log <.> !* include /etc/syslog.d include /usr/local/etc/syslog.d .... <.> Matches all messages with a level of `err` or higher, as well as `kern.warning`, `auth.notice` and `mail.crit`, and sends these log messages to the console ([.filename]#/dev/console#). <.> Matches all messages from the `mail` facility at level `info` or above and logs the messages to [.filename]#/var/log/maillog#. <.> Uses a comparison flag (`=`) to only match messages at level `debug` and logs them to [.filename]#/var/log/debug.log#. <.> Is an example usage of a program specification. This makes the rules following it only valid for the specified program. In this case, only the messages generated by man:devd[8] are logged to [.filename]#/var/log/devd.log#. For more information about [.filename]#/etc/syslog.conf#, its syntax, and more advanced usage examples, see man:syslog.conf[5]. [[logging-facilities]] === Logging Facilities A facility describes the part of the system generating the message. Facilities are a way of separating the different messages so that it is easier for the user to consult the logs. .syslog facilities [options="header", cols="1,1"] |=== | Name | Description | auth | The authorization system: man:login[1], man:su[1], man:getty[8], etc. | authpriv | The same as auth, but logged to a file readable only by root. | console | Messages written to [.filename]#/dev/console# by the kernel console output driver. | cron | Messages written by the man:cron[8] daemon. | daemon | System daemons, such as man:routed[8], that are not provided for explicitly by other facilities. | ftp | The file transfer protocol daemons: man:ftpd[8], man:tftpd[8]. | kern | Messages generated by the kernel. These cannot be generated by any user processes. | lpr | The line printer spooling system: man:lpr[1], man:lpc[8], man:lpd[8], etc. | mail | The mail system. | mark | This facility adds a record every 20 minutes. | news | The network news system. | ntp | The network time protocol system. | security | Security subsystems, such as man:ipfw[4]. | syslog | Messages generated internally by syslogd(8). | user | Messages generated by random user processes. *This is the default facility identifier if none is specified*. | uucp | The Unix-to-Unix Copy system. An ancient protocol. Really weird to see messages from this facility. | local0 through local7 | Reserved for local use. |=== [[logging-levels]] === Logging Levels The level describes the severity of the message, and is a keyword from the following ordered list (higher to lower): .syslog levels [options="header", cols="1,1"] |=== | Name | Description | emerg | A panic condition. This is normally broadcast to all users. | alert | A condition that should be corrected immediately, such as a corrupted system database. | crit | Critical conditions, e.g., hard device errors. | err | Errors. | warning | Warning messages. | notice | Conditions that are not error conditions, but should possibly be handled specially. | info | Informational messages. | debug | Messages that contain information normally of use only when debugging a program. | none | This special level disables a particular facility. |=== [[read-log-messages]] === Read Log Messages By default FreeBSD log files use the format link:https://datatracker.ietf.org/doc/html/rfc3164[rfc3164], also known as The BSD syslog Protocol. Learn more about other formats and how to use them at man:syslog[8]. Typically the logs have the following syntax: [.programlisting] .... date time hostname program[pid]: the message .... The output of the [.filename]#/var/log/cron# file will be used as an example: [.programlisting] .... [...] Jul 16 12:40:00 FreeBSD /usr/sbin/cron[81519]: (root) CMD (/usr/libexec/atrun) Jul 16 12:44:00 FreeBSD /usr/sbin/cron[83072]: (operator) CMD (/usr/libexec/save-entropy) [...] .... Verbose logging, so the facility and the level on each message will be added, can be enabled in man:syslog[8] by running the following command: [source,shell] .... # sysrc syslogd_flags="-vv" .... Once the function is activated, the facility and the level will be displayed in the log as shown in the following example: [.programlisting] .... [...] Jul 16 17:40:00 FreeBSD /usr/sbin/cron[1016]: (root) CMD (/usr/libexec/atrun) Jul 16 17:44:00 FreeBSD /usr/sbin/cron[1030]: (operator) CMD (/usr/libexec/save-entropy) [...] .... === Log Management and Rotation Log files can grow quickly, taking up disk space and making it more difficult to locate useful information. In FreeBSD, man:newsyslog[8] is used to manage log files and attempt to mitigate this. This built-in program periodically rotates and compresses log files, and optionally creates missing log files and signals programs when log files are moved. [NOTE] ==== Since newsyslog is run from man:cron[8], it cannot rotate files more often than it is scheduled to run from man:cron[8]. In the default configuration, it runs every hour. ==== Here is the default configuration in FreeBSD, more information in man:newsyslog.conf[5]: [.programlisting] .... # configuration file for newsyslog # # Entries which do not specify the '/pid_file' field will cause the # syslogd process to be signalled when that log file is rotated. This # action is only appropriate for log files which are written to by the # syslogd process (ie, files listed in /etc/syslog.conf). If there # is no process which needs to be signalled when a given log file is # rotated, then the entry for that file should include the 'N' flag. # # Note: some sites will want to select more restrictive protections than the # defaults. In particular, it may be desirable to switch many of the 644 # entries to 640 or 600. For example, some sites will consider the # contents of maillog, messages, and lpd-errs to be confidential. In the # future, these defaults may change to more conservative ones. # # logfilename [owner:group] mode count size when flags [/pid_file] [sig_num] /var/log/all.log 600 7 * @T00 J /var/log/auth.log 600 7 1000 @0101T JC /var/log/console.log 600 5 1000 * J /var/log/cron 600 3 1000 * JC /var/log/daily.log 640 7 * @T00 JN /var/log/debug.log 600 7 1000 * JC /var/log/init.log 644 3 1000 * J /var/log/kerberos.log 600 7 1000 * J /var/log/maillog 640 7 * @T00 JC /var/log/messages 644 5 1000 @0101T JC /var/log/monthly.log 640 12 * $M1D0 JN /var/log/devd.log 644 3 1000 * JC /var/log/security 600 10 1000 * JC /var/log/utx.log 644 3 * @01T05 B /var/log/weekly.log 640 5 * $W6D0 JN /var/log/daemon.log 644 5 1000 @0101T JC /etc/newsyslog.conf.d/[!.]*.conf /usr/local/etc/newsyslog.conf.d/[!.]*.conf .... . `logfilename` - Name of the system log file to be archived. . `[owner:group]` - This optional field specifies the owner and group for the archive file. . `mode` - Specify the file mode of the log file and archives. Valid mode bits are 0666. (That is, read and write permissions for the rotated log may be specified for the owner, group, and others.) . `count` - Specify the maximum number of archive files which may exist. . `size` - When the size of the log file reaches size in kilobytes, the log file will be trimmed as described above. If this field contains an asterisk ('*'), the log file will not be trimmed based on size. . `when` - Consist of an interval, a specific time, or both. Supported options in man:newsyslog.conf[5]. . `flags` - Indicates the flags that newsyslog accepts, supported options in man:newsyslog.conf[5]. . `[/pid_file]` - This optional field specifies the file name containing a daemon's process ID or to find a group process ID. . `[sig_num]` - This optional field specifies the signal that will be sent to the daemon process. [NOTE] ==== The last two fields are optional and specify the name of the Process ID (PID) file of a process and a signal number to send to that process when the file is rotated. ==== [[network-syslogd]] === Configuring Remote Logging Monitoring the log files of multiple hosts can become unwieldy as the number of systems increases. Configuring centralized logging can reduce some of the administrative burden of log file administration. In FreeBSD, centralized log file aggregation, merging, and rotation can be configured using syslogd and newsyslog. This section demonstrates an example configuration, where host `A`, named `logserv.example.com`, will collect logging information for the local network. Host `B`, named `logclient.example.com`, will be configured to pass logging information to the logging server. ==== Log Server Configuration A log server is a system that has been configured to accept logging information from other hosts. Before configuring a log server, check the following: * If there is a firewall between the logging server and any logging clients, ensure that the firewall ruleset allows UDP port 514 for both the clients and the server. * The logging server and all client machines must have forward and reverse entries in the local DNS. If the network does not have a DNS server, create entries in each system's [.filename]#/etc/hosts#. Proper name resolution is required so that log entries are not rejected by the logging server. On the log server, edit [.filename]#/etc/syslog.conf# to specify the name of the client to receive log entries from, the logging facility to be used, and the name of the log to store the host's log entries. This example adds the hostname of `B`, logs all facilities, and stores the log entries in [.filename]#/var/log/logclient.log#. .Sample Log Server Configuration [example] ==== [.programlisting] .... +logclient.example.com *.* /var/log/logclient.log .... ==== When adding multiple log clients, add a similar two-line entry for each client. More information about the available facilities may be found in man:syslog.conf[5]. Next, execute the following commands: [source,shell] .... # sysrc syslogd_enable="YES" # sysrc syslogd_flags="-a logclient.example.com -v -v" .... The first entry starts syslogd at system boot. The second entry allows log entries from the specified client. The `-v -v` increases the verbosity of logged messages. This is useful for tweaking facilities as administrators are able to see what type of messages are being logged under each facility. Multiple `-a` options may be specified to allow logging from multiple clients. IP addresses and whole netblocks may also be specified. Refer to man:syslogd[8] for a full list of possible options. Finally, create the log file: [source,shell] .... # touch /var/log/logclient.log .... At this point, syslogd should be restarted and verified: [source,shell] .... # service syslogd restart # pgrep syslog .... If a PID is returned, the server restarted successfully, and client configuration can begin. If the server did not restart, consult [.filename]#/var/log/messages# for the error. ==== Log Client Configuration A logging client sends log entries to a logging server on the network. The client also keeps a local copy of its own logs. Once a logging server has been configured, execute the following commands on the logging client: [source,shell] .... # sysrc syslogd_enable="YES" # sysrc syslogd_flags="-s -v -v" .... The first entry enables syslogd on boot up. The second entry prevents logs from being accepted by this client from other hosts (`-s`) and increases the verbosity of logged messages. Next, define the logging server in the client's [.filename]#/etc/syslog.conf#. In this example, all logged facilities are sent to a remote system, denoted by the `@` symbol, with the specified hostname: [.programlisting] .... *.* @logserv.example.com .... After saving the edit, restart syslogd for the changes to take effect: [source,shell] .... # service syslogd restart .... To test that log messages are being sent across the network, use man:logger[1] on the client to send a message to syslogd: [source,shell] .... # logger "Test message from logclient" .... This message should now exist both in [.filename]#/var/log/messages# on the client and [.filename]#/var/log/logclient.log# on the log server. ==== Debugging Log Servers If no messages are being received on the log server, the cause is most likely a network connectivity issue, a hostname resolution issue, or a typo in a configuration file. To isolate the cause, ensure that both the logging server and the logging client are able to `ping` each other using the hostname specified in their [.filename]#/etc/rc.conf#. If this fails, check the network cabling, the firewall ruleset, and the hostname entries in the DNS server or [.filename]#/etc/hosts# on both the logging server and clients. Repeat until the `ping` is successful from both hosts. If the `ping` succeeds on both hosts but log messages are still not being received, temporarily increase logging verbosity to narrow down the configuration issue. In the following example, [.filename]#/var/log/logclient.log# on the logging server is empty and [.filename]#/var/log/messages# on the logging client does not indicate a reason for the failure. To increase debugging output, edit the `syslogd_flags` entry on the logging server and issue a restart: [source,shell] .... sysrc syslogd_flags="-d -a logclient.example.com -v -v" .... [source,shell] .... # service syslogd restart .... Debugging data similar to the following will flash on the console immediately after the restart: [.programlisting] .... logmsg: pri 56, flags 4, from logserv.example.com, msg syslogd: restart syslogd: restarted logmsg: pri 6, flags 4, from logserv.example.com, msg syslogd: kernel boot file is /boot/kernel/kernel Logging to FILE /var/log/messages syslogd: kernel boot file is /boot/kernel/kernel cvthname(192.168.1.10) validate: dgram from IP 192.168.1.10, port 514, name logclient.example.com; rejected in rule 0 due to name mismatch. .... In this example, the log messages are being rejected due to a typo which results in a hostname mismatch. The client's hostname should be `logclient`, not `logclien`. Fix the typo, issue a restart, and verify the results: [source,shell] .... # service syslogd restart .... The output should be similar to the following: [.programlisting] .... logmsg: pri 56, flags 4, from logserv.example.com, msg syslogd: restart syslogd: restarted logmsg: pri 6, flags 4, from logserv.example.com, msg syslogd: kernel boot file is /boot/kernel/kernel syslogd: kernel boot file is /boot/kernel/kernel logmsg: pri 166, flags 17, from logserv.example.com, msg Dec 10 20:55:02 logserv.example.com syslogd: exiting on signal 2 cvthname(192.168.1.10) validate: dgram from IP 192.168.1.10, port 514, name logclient.example.com; accepted in rule 0. logmsg: pri 15, flags 0, from logclient.example.com, msg Dec 11 02:01:28 trhodes: Test message 2 Logging to FILE /var/log/logclient.log Logging to FILE /var/log/messages .... At this point, the messages are being properly received and placed in the correct file. ==== Security Considerations As with any network service, security requirements should be considered before implementing a logging server. Log files may contain sensitive data about services enabled on the local host, user accounts, and configuration data. Network data sent from the client to the server will not be encrypted or password protected. If a need for encryption exists, consider using package:security/stunnel[], which will transmit the logging data over an encrypted tunnel. Local security is also an issue. Log files are not encrypted during use or after log rotation. Local users may access log files to gain additional insight into system configuration. Setting proper permissions on log files is critical. The built-in log rotator, newsyslog, supports setting permissions on newly created and rotated log files. Setting log files to mode `600` should prevent unwanted access by local users. Refer to man:newsyslog.conf[5] for additional information. [[acpi-overview]] == Power and Resource Management It is important to utilize hardware resources in an efficient manner. Power and resource management allows the operating system to monitor system limits and to possibly run some actions triggered by events related to those limits. [[acpi-config]] === ACPI configuration On FreeBSD the management of these resources is managed by the man:acpi[4] kernel device. [NOTE] ==== In FreeBSD the man:acpi[4] driver is loaded by default at system boot. This driver *cannot be unloaded after boot* because the system bus uses it for various hardware interactions. ==== In addition to man:acpi[4], FreeBSD has several dedicated kernel modules for various ACPI vendor subsystems. These modules will add some extra functionality like fan speed, keyboard backlit or screen brightness. The list can be obtained by running the following command: [source,shell] .... % ls /boot/kernel | grep acpi .... The output should be similar to the following: [.programlisting] .... acpi_asus.ko acpi_asus_wmi.ko acpi_dock.ko acpi_fujitsu.ko acpi_hp.ko acpi_ibm.ko acpi_panasonic.ko acpi_sony.ko acpi_toshiba.ko acpi_video.ko acpi_wmi.ko sdhci_acpi.ko uacpi.ko .... In the event that, for example, an IBM/Lenovo laptop is used, it will be necessary to load the module man:acpi_ibm[4] by executing the following command: [source,shell] .... # kldload acpi_ibm .... And add this line to [.filename]#/boot/loader.conf# to load it at boot: [.programlisting] .... acpi_ibm_load="YES" .... An alternative to the man:acpi_video[4] module is the man:backlight[9] driver. It provides a generic way for handling a panel backlight. The default GENERIC kernel includes this driver. The man:backlight[8] utility can be used to query and adjust the brightness of the panel backlight. In this example the brightness is decreased by 10%: [source,shell] .... % backlight decr 10 .... [[cpu-power-management]] === CPU Power Management CPU is the most consuming part of the system. Knowing how to improve CPU efficiency is a fundamental part of our system in order to save energy. In order to make proper use of the machine's resources in a correct way, FreeBSD supports technologies such as Intel Turbo Boost, AMD Turbo Core, Intel Speed Shift among others through the use of man:powerd[8] and man:cpufreq[4]. The first step will be to obtain the CPU information by executing the following command: [source,shell] .... % sysctl dev.cpu.0 <.> .... <.> In this case the `0` digit represents the first core of the CPU. The output should be similar to the following: [.programlisting] .... dev.cpu.0.cx_method: C1/mwait/hwc C2/mwait/hwc C3/mwait/hwc/bma dev.cpu.0.cx_usage_counters: 3507294 0 0 dev.cpu.0.cx_usage: 100.00% 0.00% 0.00% last 3804us dev.cpu.0.cx_lowest: C3 <1> dev.cpu.0.cx_supported: C1/1/1 C2/2/1 C3/3/57 <2> dev.cpu.0.freq_levels: 2267/35000 2266/35000 1600/15000 800/12000 <3> dev.cpu.0.freq: 1600 <4> dev.cpu.0.temperature: 40.0C <5> dev.cpu.0.coretemp.throttle_log: 0 dev.cpu.0.coretemp.tjmax: 105.0C dev.cpu.0.coretemp.resolution: 1 dev.cpu.0.coretemp.delta: 65 dev.cpu.0.%parent: acpi0 dev.cpu.0.%pnpinfo: _HID=none _UID=0 _CID=none dev.cpu.0.%location: handle=\_PR_.CPU0 dev.cpu.0.%driver: cpu dev.cpu.0.%desc: ACPI CPU .... <1> Lowest Cx state to use for idling the CPU. <2> CPU supported Cx states. <3> Currently available levels for the CPU (frequency/power usage). <4> Current active CPU frequency in MHz. <5> Current temperature of the CPU. [NOTE] ==== If the temperature information is not displayed, load the man:coretemp[4] module. In case of using an AMD CPU, load the man:amdtemp[4] module. ==== Once the CPU information is available the easiest way to configure power saving is to let man:powerd[8] take over. Enable man:powerd[8] service in [.filename]#/etc/rc.conf# to start at system boot: [source,shell] .... # sysrc powerd_enable=YES .... It will also be necessary to indicate certain parameters to man:powerd[8] to tell it how to manage the state of the CPU executing the following command: [source,shell] .... # sysrc powerd_flags="-a hiadaptive -i 25 -r 85 -N" .... . `-a`: Selects the mode to use while on AC power. . `hiadaptive`: Operation mode. More info at man:powerd[8]. . `-i`: Specifies the CPU load percent level when adaptive mode should begin to degrade performance to save power. . `-r`: Specifies the CPU load percent level where adaptive mode should consider the CPU running and increase performance. . `-N`: Treat "nice" time as idle for the purpose of load calculation; i.e., do not increase the CPU frequency if the CPU is only busy with "nice" processes. And then enable the service executing the following command: [source,shell] .... # service powerd start .... [[cpufreq]] === CPU Frequency Control FreeBSD includes a generic man:cpufreq[4] driver to allow the administrator, or software such as man:powerd[8] and package:sysutils/powerdxx[], to manage the frequency of the CPU to achieve the desired balance between performance and economy. A lower setting will save power while reducing the heat generated by the CPU. A higher setting will increase performance at the cost of using additional power and generating more heat. [[est]] === Intel(R) Enhanced Speed Step(TM) The Intel(R) Enhanced Speed Step(TM) driver, man:est[4], replaces the generic man:cpufreq[4] driver for CPUs that provide this feature. The CPU frequency can be statically adjusted using man:sysctl[8], or with the `/etc/rc.d/power_profile` startup script. Additional software, such as man:powerd[8] or package:sysutils/powerdxx[], can be used to automatically adjust the CPU frequency based on processor utilization. Each supported frequency, along with its expected power consumption, can be listed by examining the man:sysctl[3] tree: [source,shell] .... # sysctl dev.cpufreq.0.freq_driver dev.cpu.0.freq_levels dev.cpu.0.freq .... The output should be similar to the following: [.programlisting] .... dev.cpufreq.0.freq_driver: est0 dev.cpu.0.freq_levels: 3001/53000 3000/53000 2900/50301 2700/46082 2600/43525 2400/39557 2300/37137 2100/33398 2000/31112 1800/27610 1700/25455 1500/22171 1400/20144 1200/17084 1100/15181 900/12329 800/10550 dev.cpu.0.freq: 800 .... A frequency 1 MHz higher than the maximum frequency of the CPU indicates the Intel(R) Turbo Boost(TM) feature. [[hwpstate_intel]] === Intel Speed Shift(TM) Users running newer Intel(R) CPUs may find some differences in dynamic frequency control when upgrading to FreeBSD 13. A new driver for the Intel(R) Speed Shift(TM) feature set, available on certain SKUs, exposes the ability for the hardware to dynamically vary the core frequencies, including on a per core basis. FreeBSD 13 comes with the man:hwpstate_intel[4] driver to automatically enable Speed Shift(TM) control on equipped CPUs, replacing the older Enhanced Speed Step(TM) man:est[4] driver. The man:sysctl[8] `dev.cpufreq.%d.freq_driver` will indicate if the system is using Speed Shift. To determine which frequency control driver is being used, examining the `dev.cpufreq.0.freq_driver` oid. [source,shell] .... # sysctl dev.cpufreq.0.freq_driver .... The output should be similar to the following: [.programlisting] .... dev.cpufreq.0.freq_driver: hwpstate_intel0 .... This indicates that the new man:hwpstate_intel[4] driver is in use. On such systems, the oid `dev.cpu.%d.freq_levels` will show only the maximum CPU frequency, and will indicate a power consumption level of `-1`. The current CPU frequency can be determined by examining the `dev.cpu.%d.freq` oid. [source,shell] .... # sysctl dev.cpu.0.freq_levels dev.cpu.0.freq .... The output should be similar to the following: [.programlisting] .... dev.cpu.0.freq_levels: 3696/-1 dev.cpu.0.freq: 898 .... For more information, including on how to balance performance and energy use, and on how to disable this driver, refer to the man page man:hwpstate_intel[4]. [NOTE] ==== Users accustomed to using man:powerd[8] or package:sysutils/powerdxx[] will find these utilities have been superseded by the man:hwpstate_intel[4] driver and no longer work as expected. ==== [[graphics-card-power-management]] === Graphics Card Power Management Graphics cards have become a fundamental part of computing in recent years. Some graphics cards may have excessive power consumption. FreeBSD allows certain configurations to improve power consumption. In case of using a Intel(R) graphics card with the package:graphics/drm-kmod[] driver these options can be added to [.filename]#/boot/loader.conf#: [.programlisting] .... compat.linuxkpi.fastboot=1 <.> compat.linuxkpi.enable_dc=2 <.> compat.linuxkpi.enable_fbc=1 <.> .... <.> Try to skip unnecessary mode sets at boot time. <.> Enable power-saving display C-states. <.> Enable frame buffer compression for power savings === Suspend/Resume The suspend/resume function allows the machine to be kept in a state in which there is no a big energy consumption and allows the system to be resumed without having to lose the state of the running programs. [NOTE] ==== In order for the suspend/resume functionality to work correctly the graphics drivers must be loaded on the system. In non-KMS-supported graphics cards man:sc[4] must be used not to break the suspend/resume functionality. More information about which driver to use and how to configure it can be found at the crossref:x11[x11, The X Window System chapter]. ==== man:acpi[4] supports the next list of sleep states: .Supported Sleep States [options="header", cols="1,1"] |=== |S1 |Quick suspend to RAM. The CPU enters a lower power state, but most peripherals are left running. |S2 |Lower power state than S1, but with the same basic characteristics. Not supported by many systems. |S3 (Sleep mode) |Suspend to RAM. Most devices are powered off, and the system stops running except for memory refresh. |S4 (Hibernation) |Suspend to disk. All devices are powered off, and the system stops running. When resuming, the system starts as if from a cold power on. *Not yet supported by FreeBSD*. |S5 |System shuts down cleanly and powers off. |=== [[configure-suspend-resume]] ==== Configuring Suspend/Resume The first step will be to know which type of sleep states supports the hardware we are using executing the following command: [source,shell] .... % sysctl hw.acpi.supported_sleep_state .... The output should be similar to the following: [.programlisting] .... hw.acpi.supported_sleep_state: S3 S4 S5 .... [WARNING] ==== As stated above FreeBSD does *not* yet support the `S4` state. ==== man:acpiconf[8] can be used to check if the `S3` state works correctly by running the following command, if it succeeds, the screen should go black and the machine will turn off: [source,shell] .... # acpiconf -s 3 .... In the vast majority of cases the Suspend/Resume functionality wants to be used on a laptop. FreeBSD can be configured to enter the `S3` state when closing the lid by adding the following line to the [.filename]#/etc/sysctl.conf# file. [.programlisting] .... hw.acpi.lid_switch_state=S3 .... [[troubleshooting-suspend-resume]] ==== Troubleshooting in Suspend/Resume A lot of effort has been made to make the Suspend and Resume functions work properly and in the best way on FreeBSD. But currently the Suspend and Resume functions only work properly on some specific laptops. Some checks can be done in case it doesn't work properly. In some cases it is enough to turn off the bluetooth. In others it is enough loading the correct driver for the graphics card, etc. In case it doesn't work correctly, some tips can be found on the FreeBSD Wiki in the section link:https://wiki.freebsd.org/SuspendResume[Suspend/Resume]. [[adding-swap-space]] == Adding Swap Space Sometimes a FreeBSD system requires more swap space. This section describes two methods to increase swap space: adding swap to an existing partition or new hard drive, and creating a swap file on an existing file system. For information on how to encrypt swap space, which options exist, and why it should be done, refer to crossref:disks[swap-encrypting,“Encrypting Swap”]. [[new-drive-swap]] === Swap on a New Hard Drive or Existing Partition Adding a new drive for swap gives better performance than using a partition on an existing drive. Setting up partitions and drives is explained in crossref:disks[disks-adding,"Adding Disks"] while crossref:bsdinstall[configtuning-initial,"Designing the Partition Layout"] discusses partition layouts and swap partition size considerations. [WARNING] ==== It is possible to use any partition not currently mounted, even if it already contains data. Using `swapon` on a partition that contains data will overwrite and destroy that data. Make sure that the partition to be added as swap is really the intended partition before running `swapon`. ==== man:swapon[8] can be used to add a swap partition to the system executing the following command: [source,shell] .... # swapon /dev/ada1p2 .... To automatically add this swap partition on boot, add an entry to [.filename]#/etc/fstab#: [.programlisting] .... /dev/ada1p2 none swap sw 0 0 .... See man:fstab[5] for an explanation of the entries in [.filename]#/etc/fstab#. [[create-swapfile]] === Creating a Swap File [[swapfile-10-and-later]] These examples create a 512M swap file called [.filename]#/usr/swap0#. [WARNING] ==== Swap files on ZFS file systems are strongly discouraged, as swapping can lead to system hangs. ==== The first step is to create the swap file: [source,shell] .... # dd if=/dev/zero of=/usr/swap0 bs=1m count=512 .... The second step is to put the proper permissions on the new file: [source,shell] .... # chmod 0600 /usr/swap0 .... The third step is to inform the system about the swap file by adding a line to [.filename]#/etc/fstab#: [.programlisting] .... md none swap sw,file=/usr/swap0,late 0 0 .... Swap space will be added on system startup. To add swap space immediately, use man:swapon[8]: [source,shell] .... # swapon -aL .... diff --git a/documentation/content/en/books/handbook/cutting-edge/_index.adoc b/documentation/content/en/books/handbook/cutting-edge/_index.adoc index e2e5152f74..47a1df32ed 100644 --- a/documentation/content/en/books/handbook/cutting-edge/_index.adoc +++ b/documentation/content/en/books/handbook/cutting-edge/_index.adoc @@ -1,1180 +1,1180 @@ --- title: Chapter 26. Updating and Upgrading FreeBSD part: Part III. System Administration prev: books/handbook/l10n next: books/handbook/dtrace description: Information about how to keep a FreeBSD system up-to-date with freebsd-update or Git, how to rebuild and reinstall the entire base system, etc tags: ["updating", "upgrading", "documentation", "FreeBSD-STABLE", "FreeBSD-CURRENT", "Security Patches"] showBookMenu: true weight: 30 path: "/books/handbook/cutting-edge/" --- [[updating-upgrading]] = Updating and Upgrading FreeBSD :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 26 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/cutting-edge/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[updating-upgrading-synopsis]] == Synopsis FreeBSD is under constant development between releases. Some people prefer to use the officially released versions, while others prefer to keep in sync with the latest developments. However, even official releases are often updated with security and other critical fixes. Regardless of the version used, FreeBSD provides all the necessary tools to keep the system updated, and allows for easy upgrades between versions. This chapter describes how to track the development system and the basic tools for keeping a FreeBSD system up-to-date. After reading this chapter, you will know: * How to keep a FreeBSD system up-to-date with freebsd-update or Git. * How to compare the state of an installed system against a known pristine copy. * How to keep the installed documentation up-to-date with Git or documentation ports. * The difference between the two development branches: FreeBSD-STABLE and FreeBSD-CURRENT. * How to rebuild and reinstall the entire base system. Before reading this chapter, you should: * Properly set up the network connection (crossref:advanced-networking[advanced-networking,Advanced Networking]). * Know how to install additional third-party software (crossref:ports[ports,Installing Applications: Packages and Ports]). [NOTE] ==== Throughout this chapter, `git` is used to obtain and update FreeBSD sources. Optionally, the package:devel/git[] port or package may be used. ==== [[updating-upgrading-freebsdupdate]] == FreeBSD Update Applying security patches in a timely manner and upgrading to a newer release of an operating system are important aspects of ongoing system administration. FreeBSD includes a utility called `freebsd-update` which can be used to perform both these tasks. This utility supports binary security and errata updates to FreeBSD, without the need to manually compile and install the patch or a new kernel. Binary updates are available for all architectures and releases currently supported by the security team. The list of supported releases and their estimated end-of-life dates are listed at https://www.FreeBSD.org/security/[https://www.FreeBSD.org/security/]. This utility also supports operating system upgrades to minor point releases as well as upgrades to another release branch. Before upgrading to a new release, review its release announcement as it contains important information pertinent to the release. Release announcements are available from https://www.FreeBSD.org/releases/[https://www.FreeBSD.org/releases/]. [NOTE] ==== If a man:crontab[5] utilizing the features of man:freebsd-update[8] exists, it must be disabled before upgrading the operating system. ==== This section describes the configuration file used by `freebsd-update`, demonstrates how to apply a security patch and how to upgrade to a minor or major operating system release, and discusses some of the considerations when upgrading the operating system. [[freebsdupdate-config-file]] === The Configuration File The default configuration file for `freebsd-update` works as-is. Some users may wish to tweak the default configuration in [.filename]#/etc/freebsd-update.conf#, allowing better control of the process. The comments in this file explain the available options, but the following may require a bit more explanation: [.programlisting] .... # Components of the base system which should be kept updated. Components world kernel .... This parameter controls which parts of FreeBSD will be kept up-to-date. The default is to update the entire base system and the kernel. Individual components can instead be specified, such as `src/base` or `src/sys`. However, the best option is to leave this at the default as changing it to include specific items requires every needed item to be listed. Over time, this could have disastrous consequences as source code and binaries may become out of sync. [.programlisting] .... # Paths which start with anything matching an entry in an IgnorePaths # statement will be ignored. IgnorePaths /boot/kernel/linker.hints .... To leave specified directories, such as [.filename]#/bin# or [.filename]#/sbin#, untouched during the update process, add their paths to this statement. This option may be used to prevent `freebsd-update` from overwriting local modifications. [.programlisting] .... # Paths which start with anything matching an entry in an UpdateIfUnmodified # statement will only be updated if the contents of the file have not been # modified by the user (unless changes are merged; see below). UpdateIfUnmodified /etc/ /var/ /root/ /.cshrc /.profile .... This option will only update unmodified configuration files in the specified directories. Any changes made by the user will prevent the automatic updating of these files. There is another option, `KeepModifiedMetadata`, which will instruct `freebsd-update` to save the changes during the merge. [.programlisting] .... # When upgrading to a new FreeBSD release, files which match MergeChanges # will have any local changes merged into the version from the new release. MergeChanges /etc/ /var/named/etc/ /boot/device.hints .... List of directories with configuration files that `freebsd-update` should attempt to merge. The file merge process is a series of man:diff[1] patches. Merges are either accepted, open an editor, or cause `freebsd-update` to abort. When in doubt, backup [.filename]#/etc# and just accept the merges. [.programlisting] .... # Directory in which to store downloaded updates and temporary # files used by FreeBSD Update. # WorkDir /var/db/freebsd-update .... This directory is where all patches and temporary files are placed. In cases where the user is doing a version upgrade, this location should have at least a gigabyte of disk space available. [.programlisting] .... # When upgrading between releases, should the list of Components be # read strictly (StrictComponents yes) or merely as a list of components # which *might* be installed of which FreeBSD Update should figure out # which actually are installed and upgrade those (StrictComponents no)? # StrictComponents no .... When this option is set to `yes`, `freebsd-update` will assume that the `Components` list is complete and will not attempt to make changes outside of the list. Effectively, `freebsd-update` will attempt to update every file which belongs to the `Components` list. Refer to man:freebsd-update.conf[5] for more details. [[freebsdupdate-security-patches]] === Applying Security Patches The process of applying FreeBSD security patches has been simplified, allowing an administrator to keep a system fully patched using `freebsd-update`. More information about FreeBSD security advisories can be found in crossref:security[security-advisories,"FreeBSD Security Advisories"]. FreeBSD security patches may be downloaded and installed using the following commands. The first command will determine if any outstanding patches are available, and if so, will list the files that will be modified if the patches are applied. The second command will apply the patches. [source,shell] .... # freebsd-update fetch # freebsd-update install .... If the update applies any kernel patches, the system will need a reboot in order to boot into the patched kernel. If the patch was applied to any running binaries, the affected applications should be restarted so that the patched version of the binary is used. [NOTE] ==== Usually, the user needs to be prepared to reboot the system. To know if the system requires a reboot due to a kernel update, execute the commands `freebsd-version -k` and `uname -r`. Reboot the system if the outputs differ. ==== The system can be configured to automatically check for updates once every day by adding this entry to [.filename]#/etc/crontab#: [.programlisting] .... @daily root freebsd-update cron .... If patches exist, they will automatically be downloaded but will not be applied. The `root` user will be sent an email so that the patches may be reviewed and manually installed with `freebsd-update install`. If anything goes wrong, `freebsd-update` has the ability to roll back the last set of changes with the following command: [source,shell] .... # freebsd-update rollback Uninstalling updates... done. .... Again, the system should be restarted if the kernel or any kernel modules were modified and any affected binaries should be restarted. Only the [.filename]#GENERIC# kernel can be automatically updated by `freebsd-update`. If a custom kernel is installed, it will have to be rebuilt and reinstalled after `freebsd-update` finishes installing the updates. The default kernel name is _GENERIC_. The man:uname[1] command may be used to verify its installation. [NOTE] ==== Always keep a copy of the [.filename]#GENERIC# kernel in [.filename]#/boot/GENERIC#. It will be helpful in diagnosing a variety of problems and in performing version upgrades. -Refer to crossref:cutting-edge[freebsd-update-custom-kernel-9x] for instructions on how to get a copy of the [.filename]#GENERIC# kernel. +Refer to crossref:cutting-edge[freebsd-update-custom-kernel-9x, Custom Kernels with FreeBSD 9.X and Later] for instructions on how to get a copy of the [.filename]#GENERIC# kernel. ==== Unless the default configuration in [.filename]#/etc/freebsd-update.conf# has been changed, `freebsd-update` will install the updated kernel sources along with the rest of the updates. Rebuilding and reinstalling a new custom kernel can then be performed in the usual way. The updates distributed by `freebsd-update` do not always involve the kernel. It is not necessary to rebuild a custom kernel if the kernel sources have not been modified by `freebsd-update install`. However, `freebsd-update` will always update [.filename]#/usr/src/sys/conf/newvers.sh#. The current patch level, as indicated by the `-p` number reported by `uname -r`, is obtained from this file. Rebuilding a custom kernel, even if nothing else changed, allows `uname` to accurately report the current patch level of the system. This is particularly helpful when maintaining multiple systems, as it allows for a quick assessment of the updates installed in each one. [[freebsdupdate-upgrade]] === Performing Minor and Major Version Upgrades Upgrades from one minor version of FreeBSD to another are called _minor version_ upgrades. An example: - FreeBSD 13.1 to 13.2. _Major version_ upgrades increase the major version number. An example: - FreeBSD 13.2 to 14.0. Both types of upgrade can be performed by providing `freebsd-update` with a release version target. [WARNING] ==== After each new `RELEASE`, FreeBSD package build servers will, for a limited period, *not* use the newer version of the operating system. This provides continuity for the many users who do not upgrade immediately after a release announcement. For example: * packages for users of 13.1 and 13.2 will be built on a server running 13.1, until 13.1 reaches end of life -- and, critically: * a kernel module that is built on 13.1 might *not* be suitable for 13.2. So, with any minor or major OS upgrade, if your package requirements include any kernel module: * *be prepared to build the module from source*. ==== [NOTE] ==== If the system is running a custom kernel, make sure that a copy of the [.filename]#GENERIC# kernel exists in [.filename]#/boot/GENERIC# before starting the upgrade. -Refer to crossref:cutting-edge[freebsd-update-custom-kernel-9x] for instructions on how to get a copy of the [.filename]#GENERIC# kernel. +Refer to crossref:cutting-edge[freebsd-update-custom-kernel-9x, Custom Kernels with FreeBSD 9.X and Later] for instructions on how to get a copy of the [.filename]#GENERIC# kernel. ==== Before upgrading to a new version, ensure the existing FreeBSD installation is up to date with respect to security and errata patches: [source,shell] .... # freebsd-update fetch # freebsd-update install .... The following command, when run on a FreeBSD 13.1 system, will upgrade it to FreeBSD 13.2: [source,shell] .... # freebsd-update -r 13.2-RELEASE upgrade .... After the command has been received, `freebsd-update` will evaluate the configuration file and current system in an attempt to gather the information necessary to perform the upgrade. A screen listing will display which components have and have not been detected. For example: [source,shell] .... Looking up update.FreeBSD.org mirrors... 1 mirrors found. Fetching metadata signature for 13.1-RELEASE from update1.FreeBSD.org... done. Fetching metadata index... done. Inspecting system... done. The following components of FreeBSD seem to be installed: kernel/smp src/base src/bin src/contrib src/crypto src/etc src/games src/gnu src/include src/krb5 src/lib src/libexec src/release src/rescue src/sbin src/secure src/share src/sys src/tools src/ubin src/usbin world/base world/info world/lib32 world/manpages The following components of FreeBSD do not seem to be installed: kernel/generic world/catpages world/dict world/doc world/games world/proflibs Does this look reasonable (y/n)? y .... At this point, `freebsd-update` will attempt to download all files required for the upgrade. In some cases, the user may be prompted with questions regarding what to install or how to proceed. When using a custom kernel, the above step will produce a warning similar to the following: [source,shell] .... WARNING: This system is running a "MYKERNEL" kernel, which is not a kernel configuration distributed as part of FreeBSD 13.1-RELEASE. This kernel will not be updated: you MUST update the kernel manually before running "/usr/sbin/freebsd-update install" .... This warning may be safely ignored at this point. The updated [.filename]#GENERIC# kernel will be used as an intermediate step in the upgrade process. Once all the patches have been downloaded to the local system, they will be applied. This process may take a while, depending on the speed and workload of the machine. Configuration files will then be merged. The merging process requires some user intervention as a file may be merged or an editor may appear on screen for a manual merge. The results of every successful merge will be shown to the user as the process continues. A failed or ignored merge will cause the process to abort. Users may wish to make a backup of [.filename]#/etc# and manually merge important files, such as [.filename]#master.passwd# or [.filename]#group# at a later time. [NOTE] ==== The system is not being altered yet as all patching and merging is happening in another directory. Once all patches have been applied successfully, all configuration files have been merged and it seems the process will go smoothly, the changes can be committed to disk by the user using the following command: [source,shell] .... # freebsd-update install .... ==== The kernel and kernel modules will be patched first. If the system is running with a custom kernel, use man:nextboot[8] to set the kernel for the next boot to the updated [.filename]#/boot/GENERIC#: [source,shell] .... # nextboot -k GENERIC .... [WARNING] ==== Before rebooting with the [.filename]#GENERIC# kernel, make sure it contains all the drivers required for the system to boot properly and connect to the network, if the machine being updated is accessed remotely. In particular, if the running custom kernel contains built-in functionality usually provided by kernel modules, make sure to temporarily load these modules into the [.filename]#GENERIC# kernel using the [.filename]#/boot/loader.conf# facility. It is recommended to disable non-essential services as well as any disk and network mounts until the upgrade process is complete. ==== The machine should now be restarted with the updated kernel: [source,shell] .... # shutdown -r now .... Once the system has come back online, restart `freebsd-update` using the following command. Since the state of the process has been saved, `freebsd-update` will not start from the beginning, but will instead move on to the next phase and remove all old shared libraries and object files. [source,shell] .... # freebsd-update install .... [NOTE] ==== Depending upon whether any library version numbers were bumped, there may only be two install phases instead of three. ==== The upgrade is now complete. If this was a major version upgrade, reinstall all ports and packages as -described in crossref:cutting-edge[freebsdupdate-portsrebuild]. +described in crossref:cutting-edge[freebsdupdate-portsrebuild, Upgrading Packages After a Major Version Upgrade]. [[freebsd-update-custom-kernel-9x]] ==== Custom Kernels with FreeBSD 9.X and Later Before using `freebsd-update`, ensure that a copy of the [.filename]#GENERIC# kernel exists in [.filename]#/boot/GENERIC#. If a custom kernel has only been built once, the kernel in [.filename]#/boot/kernel.old# is the `GENERIC` kernel. Simply rename this directory to [.filename]#/boot/GENERIC#. If a custom kernel has been built more than once or if it is unknown how many times the custom kernel has been built, obtain a copy of the `GENERIC` kernel that matches the current version of the operating system. If physical access to the system is available, a copy of the `GENERIC` kernel can be installed from the installation media: [source,shell] .... # mount /cdrom # cd /cdrom/usr/freebsd-dist # tar -C/ -xvf kernel.txz boot/kernel/kernel .... Alternately, the `GENERIC` kernel may be rebuilt and installed from source: [source,shell] .... # cd /usr/src # make kernel __MAKE_CONF=/dev/null SRCCONF=/dev/null .... For this kernel to be identified as the `GENERIC` kernel by `freebsd-update`, the [.filename]#GENERIC# configuration file must not have been modified in any way. It is also suggested that the kernel is built without any other special options. Rebooting into the [.filename]#GENERIC# kernel is not required as `freebsd-update` only needs [.filename]#/boot/GENERIC# to exist. [[freebsdupdate-portsrebuild]] ==== Upgrading Packages After a Major Version Upgrade Generally, installed applications will continue to work without problems after minor version upgrades. Major versions use different Application Binary Interfaces (ABIs), which will break most third-party applications. After a major version upgrade, all installed packages and ports need to be upgraded. Packages can be upgraded using `pkg upgrade`. To upgrade installed ports, use a utility such as package:ports-mgmt/portmaster[]. A forced upgrade of all installed packages will replace the packages with fresh versions from the repository even if the version number has not increased. This is required because of the ABI version change when upgrading between major versions of FreeBSD. The forced upgrade can be accomplished by performing: [source,shell] .... # pkg-static upgrade -f .... A rebuild of all installed applications can be accomplished with this command: [source,shell] .... # portmaster -af .... This command will display the configuration screens for each application that has configurable options and wait for the user to interact with those screens. To prevent this behavior, and use only the default options, include `-G` in the above command. Once the software upgrades are complete, finish the upgrade process with a final call to `freebsd-update` in order to tie up all the loose ends in the upgrade process: [source,shell] .... # freebsd-update install .... If the [.filename]#GENERIC# kernel was temporarily used, this is the time to build and install a new custom kernel using the instructions in crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]. Reboot the machine into the new FreeBSD version. The upgrade process is now complete. [[freebsdupdate-system-comparison]] === System State Comparison The state of the installed FreeBSD version against a known good copy can be tested using `freebsd-update IDS`. This command evaluates the current version of system utilities, libraries, and configuration files and can be used as a built-in Intrusion Detection System (IDS). [WARNING] ==== This command is not a replacement for a real IDS such as package:security/snort[]. As `freebsd-update` stores data on disk, the possibility of tampering is evident. While this possibility may be reduced using `kern.securelevel` and by storing the `freebsd-update` data on a read-only file system when not in use, a better solution would be to compare the system against a secure disk, such as a DVD or securely stored external USB disk device. An alternative method for providing IDS functionality using a built-in utility is described in crossref:security[security-ids,"Binary Verification"] ==== To begin the comparison, specify the output file to save the results to: [source,shell] .... # freebsd-update IDS >> outfile.ids .... The system will now be inspected and a lengthy listing of files, along with the SHA256 hash values for both the known value in the release and the current installation, will be sent to the specified output file. The entries in the listing are extremely long, but the output format may be easily parsed. For instance, to obtain a list of all files which differ from those in the release, issue the following command: [source,shell] .... # cat outfile.ids | awk '{ print $1 }' | more /etc/master.passwd /etc/motd /etc/passwd /etc/pf.conf .... This sample output has been truncated as many more files exist. Some files have natural modifications. For example, [.filename]#/etc/passwd# will be modified if users have been added to the system. Kernel modules may differ as `freebsd-update` may have updated them. To exclude specific files or directories, add them to the `IDSIgnorePaths` option in [.filename]#/etc/freebsd-update.conf#. [[updating-bootcode]] == Updating Bootcode The following manuals describe the upgrade process of bootcode and boot loaders: man:gpart[8], man:gptboot[8], man:gptzfsboot[8], and man:loader.efi[8]. [[updating-upgrading-documentation]] == Updating the Documentation Set Documentation is an integral part of the FreeBSD operating system. While an up-to-date version of the FreeBSD documentation is always available on the FreeBSD web site (link:https://docs.FreeBSD.org[Documentation Portal]), it can be handy to have an up-to-date, local copy of the FreeBSD website, handbooks, FAQ, and articles. This section describes how to use either source or the FreeBSD Ports Collection to keep a local copy of the FreeBSD documentation up-to-date. For information on editing and submitting corrections to the documentation, refer to the FreeBSD Documentation Project Primer for New Contributors (extref:{fdp-primer}[FreeBSD Documentation Project Primer for New Contributors]). [[updating-installed-documentation]] === Updating Documentation from Source Rebuilding the FreeBSD documentation from source requires a collection of tools which are not part of the FreeBSD base system. The required tools can be installed following extref:{fdp-primer}[these steps, overview-quick-start] from the FreeBSD Documentation Project Primer. Once installed, use `git` to fetch a clean copy of the documentation source: [source,shell] .... # git clone https://git.FreeBSD.org/doc.git /usr/doc .... The initial download of the documentation sources may take a while. Let it run until it completes. Future updates of the documentation sources may be fetched by running: [source,shell] .... # git pull .... Once an up-to-date snapshot of the documentation sources has been fetched to [.filename]#/usr/doc#, everything is ready for an update of the installed documentation. A full update may be performed by typing: [source,shell] .... # cd /usr/doc # make .... [[current-stable]] == Tracking a Development Branch FreeBSD has two development branches: FreeBSD-CURRENT and FreeBSD-STABLE. This section provides an explanation of each branch and its intended audience, as well as how to keep a system up-to-date with each respective branch. [[current]] === Using FreeBSD-CURRENT FreeBSD-CURRENT is the "bleeding edge" of FreeBSD development and FreeBSD-CURRENT users are expected to have a high degree of technical skill. Less technical users who wish to track a development branch should track FreeBSD-STABLE instead. FreeBSD-CURRENT is the very latest source code for FreeBSD and includes works in progress, experimental changes, and transitional mechanisms that might or might not be present in the next official release. While many FreeBSD developers compile the FreeBSD-CURRENT source code daily, there are short periods of time when the source may not be buildable. These problems are resolved as quickly as possible, but whether or not FreeBSD-CURRENT brings disaster or new functionality can be a matter of when the source code was synced. FreeBSD-CURRENT is made available for three primary interest groups: . Members of the FreeBSD community who are actively working on some part of the source tree. . Members of the FreeBSD community who are active testers. They are willing to spend time solving problems, making topical suggestions on changes and the general direction of FreeBSD, and submitting patches. . Users who wish to keep an eye on things, use the current source for reference purposes, or make the occasional comment or code contribution. FreeBSD-CURRENT should _not_ be considered a fast-track to getting new features before the next release as pre-release features are not yet fully tested and most likely contain bugs. It is not a quick way of getting bug fixes as any given commit is just as likely to introduce new bugs as to fix existing ones. FreeBSD-CURRENT is not in any way "officially supported". To track FreeBSD-CURRENT: . Join the {freebsd-current} and the {dev-commits-src-main} lists. This is _essential_ in order to see the comments that people are making about the current state of the system and to receive important bulletins about the current state of FreeBSD-CURRENT. + The {dev-commits-src-main} list records the commit log entry for each change as it is made, along with any pertinent information on possible side effects. + To join these lists, go to {mailing-lists}, click on the list to subscribe to, and follow the instructions. In order to track changes to the whole source tree, not just the changes to FreeBSD-CURRENT, subscribe to the {dev-commits-src-all}. . Synchronize with the FreeBSD-CURRENT sources. Typically, `git` is used to check out the -CURRENT code from the `main` branch of the FreeBSD Git repository (see crossref:mirrors[git,“Using Git”] for details). . Due to the size of the repository, some users choose to only synchronize the sections of source that interest them or which they are contributing patches to. However, users that plan to compile the operating system from source must download _all_ of FreeBSD-CURRENT, not just selected portions. + Before compiling FreeBSD-CURRENT, read [.filename]#/usr/src/Makefile# very -carefully and follow the instructions in crossref:cutting-edge[makeworld]. +carefully and follow the instructions in crossref:cutting-edge[makeworld, Updating FreeBSD from Source]. Read the {freebsd-current} and [.filename]#/usr/src/UPDATING# to stay up-to-date on other bootstrapping procedures that sometimes become necessary on the road to the next release. . Be active! FreeBSD-CURRENT users are encouraged to submit their suggestions for enhancements or bug fixes. Suggestions with accompanying code are always welcome. [[stable]] === Using FreeBSD-STABLE FreeBSD-STABLE is the development branch from which major releases are made. Changes go into this branch at a slower pace and with the general assumption that they have first been tested in FreeBSD-CURRENT. This is _still_ a development branch and, at any given time, the sources for FreeBSD-STABLE may or may not be suitable for general use. It is simply another engineering development track, not a resource for end-users. Users who do not have the resources to perform testing should instead run the most recent release of FreeBSD. Those interested in tracking or contributing to the FreeBSD development process, especially as it relates to the next release of FreeBSD, should consider following FreeBSD-STABLE. While the FreeBSD-STABLE branch should compile and run at all times, this cannot be guaranteed. Since more people run FreeBSD-STABLE than FreeBSD-CURRENT, it is inevitable that bugs and corner cases will sometimes be found in FreeBSD-STABLE that were not apparent in FreeBSD-CURRENT. For this reason, one should not blindly track FreeBSD-STABLE. It is particularly important _not_ to update any production servers to FreeBSD-STABLE without thoroughly testing the code in a development or testing environment. To track FreeBSD-STABLE: . Join the {freebsd-stable} in order to stay informed of build dependencies that may appear in FreeBSD-STABLE or any other issues requiring special attention. Developers will also make announcements in this mailing list when they are contemplating some controversial fix or update, giving the users a chance to respond if they have any issues to raise concerning the proposed change. + Join the relevant git list for the branch being tracked. For example, users tracking the {betarel-current-major}-STABLE branch should join the {dev-commits-src-branches}. This list records the commit log entry for each change as it is made, along with any pertinent information on possible side effects. + To join these lists, go to {mailing-lists}, click on the list to subscribe to, and follow the instructions. In order to track changes for the whole source tree, subscribe to {dev-commits-src-all}. . To install a new FreeBSD-STABLE system, install the most recent FreeBSD-STABLE release from the crossref:mirrors[mirrors,FreeBSD mirror sites] or use a monthly snapshot built from FreeBSD-STABLE. Refer to link:https://www.FreeBSD.org/snapshots/[www.freebsd.org/snapshots] for more information about snapshots. + To compile or upgrade an existing FreeBSD system to FreeBSD-STABLE, use `git` to check out the source for the desired branch. Branch names, such as `stable/13`, are listed at link:https://www.FreeBSD.org/releng/[www.freebsd.org/releng]. . Before compiling or upgrading to FreeBSD-STABLE , read [.filename]#/usr/src/Makefile# carefully and follow the instructions in - crossref:cutting-edge[makeworld]. Read the {freebsd-stable} and [.filename]#/usr/src/UPDATING# to keep up-to-date on other bootstrapping procedures that sometimes become necessary on the road to the next release. + crossref:cutting-edge[makeworld, Updating FreeBSD from Source]. Read the {freebsd-stable} and [.filename]#/usr/src/UPDATING# to keep up-to-date on other bootstrapping procedures that sometimes become necessary on the road to the next release. [[translate-n-number]] === The N-number When tracking down bugs it is important to know which versions of the source code have been used to create the system exhibiting an issue. FreeBSD provides version information compiled into the kernel. man:uname[1] retrieves this information, for example: [source,shell] .... % uname -v FreeBSD 14.0-CURRENT #112 main-n247514-031260d64c18: Tue Jun 22 20:43:19 MDT 2021 fred@machine:/usr/home/fred/obj/usr/home/fred/git/head/amd64.amd64/sys/FRED .... The final field gives information regarding the kernel name, the person that built it, and the location that it was compiled in. Looking at the 4th field, it is made up of several parts: [source,shell] .... main-n247514-031260d64c18 main <.> n247514 <.> 031260d64c18 <.> <.> .... <.> Git branch name. Note: comparisons of n-numbers are only valid on branches published by the project (`main`, `stable/XX` and `releng/XX`). Local branches will have n-numbers that will overlap commits of their parent branch. <.> The n-number is a linear count of commits back to the start of the Git repository starting with the Git hash included in the line. <.> Git hash of the checked out tree <.> Sometimes a suffix of `-dirty` is present when the kernel was built in a tree with uncommitted changes. It is absent in this example because the FRED kernel was built from a pristine checkout. The `git rev-list` command is used to find the n-number corresponding to a Git hash. For example: [source,shell] .... % git rev-list --first-parent --count 031260d64c18 <.> 247514 <.> .... <.> git hash to translate (the hash from the above example is reused) <.> The n-number. Usually this number is not all that important. However, when bug fixes are committed, this number makes it easy to quickly determine whether the fix is present in the currently running system. Developers will often refer to the hash of the commit (or provide a URL which has that hash), but not the n-number since the hash is the easily visible identifier for a change while the n-number is not. Security advisories and errata notices will also note an n-number, which can be directly compared against your system. When you need to use shallow Git clones, you cannot compare n-numbers reliably as the `git rev-list` command counts all the revisions in the repository which a shallow clone omits. [[makeworld]] == Updating FreeBSD from Source Updating FreeBSD by compiling from source offers several advantages over binary updates. Code can be built with options to take advantage of specific hardware. Parts of the base system can be built with non-default settings, or left out entirely where they are not needed or desired. The build process takes longer to update a system than just installing binary updates, but allows complete customization to produce a tailored version of FreeBSD. [[updating-src-quick-start]] === Quick Start This is a quick reference for the typical steps used to update FreeBSD by building from source. Later sections describe the process in more detail. [WARNING] ==== When switching from man:mergemaster[8] to man:etcupdate[8], the first run might merge changes incorrectly generating spurious conflicts. To prevent this, perform the following steps *before* updating sources and building the new world: [source,shell] .... # etcupdate extract <.> # etcupdate diff <.> .... <.> Bootstrap the database of stock [.filename]#/etc# files; for more information see man:etcupdate[8]. <.> Check the diff after bootstrapping. Trim any local changes that are no longer needed to reduce the chance of conflicts in future updates. ==== [.procedure] ==== * Update and Build + [source,shell] .... # git pull -C /usr/src <.> check /usr/src/UPDATING <.> # cd /usr/src <.> # make -j4 buildworld <.> # make -j4 kernel <.> # shutdown -r now <.> # etcupdate -p <.> # cd /usr/src <.> # make installworld <.> # etcupdate -B <.> # shutdown -r now <.> .... <.> Get the latest version of the source. See -crossref:cutting-edge[updating-src-obtaining-src] for more information on obtaining and updating source. +crossref:cutting-edge[updating-src-obtaining-src, Updating the Source] for more information on obtaining and updating source. <.> Check [.filename]#/usr/src/UPDATING# for any manual steps required before or after building from source. <.> Go to the source directory. <.> Compile the world, everything except the kernel. <.> Compile and install the kernel. This is equivalent to `make buildkernel installkernel`. <.> Reboot the system to the new kernel. <.> Update and merge configuration files in [.filename]#/etc/# required before installworld. <.> Go to the source directory. <.> Install the world. <.> Update and merge configuration files in [.filename]#/etc/#. <.> Restart the system to use the newly-built world and kernel. ==== [[updating-src-preparing]] === Preparing for a Source Update Read [.filename]#/usr/src/UPDATING#. Any manual steps that must be performed before or after an update are described in this file. [[updating-src-obtaining-src]] === Updating the Source FreeBSD source code is located in [.filename]#/usr/src/#. The preferred method of updating this source is through the Git version control system. Verify that the source code is under version control: [source,shell] .... # cd /usr/src # git remote --v origin https://git.freebsd.org/src.git (fetch) origin https://git.freebsd.org/src.git (push) .... This indicates that [.filename]#/usr/src/# is under version control and can be updated with man:git[1]: [[synching]] [source,shell] .... # git pull -C /usr/src .... The update process can take some time if the directory has not been updated recently. After it finishes, the source code is up to date and the build process described in the next section can begin. [NOTE] ==== Obtaining the source: If the output says `fatal: not a git repository`, the files there are missing or were installed with a different method. A new checkout of the source is required. ==== [[updating-src-obtaining-src-repopath]] .FreeBSD Versions and Repository Branches [cols="10%,10%,80%", options="header"] |=== | uname ‑r Output | Repository Path | Description |`_X.Y_-RELEASE` |`releng/_X.Y_` |The Release version plus only critical security and bug fix patches. This branch is recommended for most users. |`_X.Y_-STABLE` |`stable/_X_` | The Release version plus all additional development on that branch. _STABLE_ refers to the Applications Binary Interface (ABI) not changing, so software compiled for earlier versions still runs. For example, software compiled to run on FreeBSD 10.1 will still run on FreeBSD 10-STABLE compiled later. STABLE branches occasionally have bugs or incompatibilities which might affect users, although these are typically fixed quickly. |`_X_-CURRENT` |`main` |The latest unreleased development version of FreeBSD. The CURRENT branch can have major bugs or incompatibilities and is recommended only for advanced users. |=== Determine which version of FreeBSD is being used with man:uname[1]: [source,shell] .... # uname -r 13.2-RELEASE .... -Based on crossref:cutting-edge[updating-src-obtaining-src-repopath], the source used to update `13.2-RELEASE` has a repository path of `releng/13.2`. +Based on crossref:cutting-edge[updating-src-obtaining-src-repopath,.FreeBSD Versions and Repository Branches], the source used to update `13.2-RELEASE` has a repository path of `releng/13.2`. That path is used when checking out the source: [source,shell] .... # mv /usr/src /usr/src.bak <.> # git clone --branch releng/13.2 https://git.FreeBSD.org/src.git /usr/src <.> .... <.> Move the old directory out of the way. If there are no local modifications in this directory, it can be deleted. -<.> The path from crossref:cutting-edge[updating-src-obtaining-src-repopath] is added to the repository URL. The third parameter is the destination directory for the source code on the local system. +<.> The path from crossref:cutting-edge[updating-src-obtaining-src-repopath,.FreeBSD Versions and Repository Branches] is added to the repository URL. The third parameter is the destination directory for the source code on the local system. [[updating-src-building]] === Building from Source The _world_, or all of the operating system except the kernel, is compiled. This is done first to provide up-to-date tools to build the kernel. Then the kernel itself is built: [source,shell] .... # cd /usr/src # make buildworld # make buildkernel .... The compiled code is written to [.filename]#/usr/obj#. These are the basic steps. Additional options to control the build are described below. [[updating-src-building-clean-build]] ==== Performing a Clean Build Some versions of the FreeBSD build system leave previously-compiled code in the temporary object directory, [.filename]#/usr/obj#. This can speed up later builds by avoiding recompiling code that has not changed. To force a clean rebuild of everything, use `cleanworld` before starting a build: [source,shell] .... # make cleanworld .... [[updating-src-building-jobs]] ==== Setting the Number of Jobs Increasing the number of build jobs on multi-core processors can improve build speed. Determine the number of cores with `sysctl hw.ncpu`. Processors vary, as do the build systems used with different versions of FreeBSD, so testing is the only sure method to tell how a different number of jobs affects the build speed. For a starting point, consider values between half and double the number of cores. The number of jobs is specified with `-j`. [[updating-src-building-jobs-example]] .Increasing the Number of Build Jobs [example] ==== Building the world and kernel with four jobs: [source,shell] .... # make -j4 buildworld buildkernel .... ==== [[updating-src-building-only-kernel]] ==== Building Only the Kernel A `buildworld` must be completed if the source code has changed. After that, a `buildkernel` to build a kernel can be run at any time. To build just the kernel: [source,shell] .... # cd /usr/src # make buildkernel .... [[updating-src-building-custom-kernel]] ==== Building a Custom Kernel The standard FreeBSD kernel is based on a _kernel config file_ called [.filename]#GENERIC#. The [.filename]#GENERIC# kernel includes the most commonly-needed device drivers and options. Sometimes it is useful or necessary to build a custom kernel, adding or removing device drivers or options to fit a specific need. For example, someone developing a small embedded computer with severely limited RAM could remove unneeded device drivers or options to make the kernel slightly smaller. Kernel config files are located in [.filename]#/usr/src/sys/arch/conf/#, where _arch_ is the output from `uname -m`. On most computers, that is `amd64`, giving a config file directory of [.filename]#/usr/src/sys/amd64/conf/#. [TIP] ==== [.filename]#/usr/src# can be deleted or recreated, so it is preferable to keep custom kernel config files in a separate directory, like [.filename]#/root#. Link the kernel config file into the [.filename]#conf# directory. If that directory is deleted or overwritten, the kernel config can be re-linked into the new one. ==== A custom config file can be created by copying the [.filename]#GENERIC# config file. In this example, the new custom kernel is for a storage server, so is named [.filename]#STORAGESERVER#: [source,shell] .... # cp /usr/src/sys/amd64/conf/GENERIC /root/STORAGESERVER # cd /usr/src/sys/amd64/conf # ln -s /root/STORAGESERVER . .... [.filename]#/root/STORAGESERVER# is then edited, adding or removing devices or options as shown in man:config[5]. The custom kernel is built by setting `KERNCONF` to the kernel config file on the command line: [source,shell] .... # make buildkernel KERNCONF=STORAGESERVER .... [[updating-src-installing]] === Installing the Compiled Code After the `buildworld` and `buildkernel` steps have been completed, the new kernel and world are installed: [source,shell] .... # cd /usr/src # make installkernel # shutdown -r now # cd /usr/src # make installworld # shutdown -r now .... If a custom kernel was built, `KERNCONF` must also be set to use the new custom kernel: [source,shell] .... # cd /usr/src # make installkernel KERNCONF=STORAGESERVER # shutdown -r now # cd /usr/src # make installworld # shutdown -r now .... [[updating-src-completing]] === Completing the Update A few final tasks complete the update. Any modified configuration files are merged with the new versions, outdated libraries are located and removed, then the system is restarted. [[updating-src-completing-merge-etcupdate]] ==== Merging Configuration Files with man:etcupdate[8] man:etcupdate[8] is a tool for managing updates to files that are not updated as part of an installworld such as files located in [.filename]#/etc/#. It manages updates by doing a three-way merge of changes made to these files against the local versions. man:etcupdate[8] is designed to minimize the amount of user intervention. [NOTE] ==== In general, man:etcupdate[8] does not need any specific arguments for its job. There is however a handy in between command for sanity checking what will be done the first time man:etcupdate[8] is used: [source,shell] .... # etcupdate diff .... This command allows the user to audit configuration changes. ==== If man:etcupdate[8] is not able to merge a file automatically, the merge conflicts can be resolved with manual interaction by issuing: [source,shell] .... # etcupdate resolve .... [WARNING] ==== When switching from man:mergemaster[8] to man:etcupdate[8], the first run might merge changes incorrectly generating spurious conflicts. To prevent this, perform the following steps *before* updating sources and building the new world: [source,shell] .... # etcupdate extract <.> # etcupdate diff <.> .... <.> Bootstrap the database of stock [.filename]#/etc# files; for more information see man:etcupdate[8]. <.> Check the diff after bootstrapping. Trim any local changes that are no longer needed to reduce the chance of conflicts in future updates. ==== [[updating-src-completing-check-old]] ==== Checking for Outdated Files and Libraries Some obsolete files or directories can remain after an update. These files can be located: [source,shell] .... # make check-old .... and deleted: [source,shell] .... # make delete-old .... Some obsolete libraries can also remain. These can be detected with: [source,shell] .... # make check-old-libs .... and deleted with [source,shell] .... # make delete-old-libs .... Programs which were still using those old libraries will stop working when the library has been deleted. These programs must be rebuilt or replaced after deleting the old libraries. [TIP] ==== When all the old files or directories are known to be safe to delete, pressing kbd:[y] and kbd:[Enter] to delete each file can be avoided by setting `BATCH_DELETE_OLD_FILES` in the command. For example: [source,shell] .... # make BATCH_DELETE_OLD_FILES=yes delete-old-libs .... ==== [[updating-src-completing-restart]] ==== Restarting After the Update The last step after updating is to restart the computer so all the changes take effect: [source,shell] .... # shutdown -r now .... [[small-lan]] == Tracking for Multiple Machines When multiple machines need to track the same source tree, it is a waste of disk space, network bandwidth, and CPU cycles to have each system download the sources and rebuild everything. The solution is to have one machine do most of the work, while the rest of the machines mount that work via NFS. This section outlines a method of doing so. For more information about using NFS, refer to crossref:network-servers[network-nfs,"Network File System (NFS)"]. First, identify a set of machines which will run the same set of binaries, known as a _build set_. Each machine can have a custom kernel, but will run the same userland binaries. From that set, choose a machine to be the _build machine_ that the world and kernel are built on. Ideally, this is a fast machine that has sufficient spare CPU to run `make buildworld` and `make buildkernel`. Select a machine to be the _test machine_, which will test software updates before they are put into production. This _must_ be a machine that can afford to be down for an extended period of time. It can be the build machine, but need not be. All the machines in this build set need to mount [.filename]#/usr/obj# and [.filename]#/usr/src# from the build machine via NFS. For multiple build sets, [.filename]#/usr/src# should be on one build machine, and NFS mounted on the rest. Ensure that [.filename]#/etc/make.conf# and [.filename]#/etc/src.conf# on all the machines in the build set agree with the build machine. That means that the build machine must build all the parts of the base system that any machine in the build set is going to install. Also, each build machine should have its kernel name set with `KERNCONF` in [.filename]#/etc/make.conf#, and the build machine should list them all in its `KERNCONF`, listing its own kernel first. The build machine must have the kernel configuration files for each machine in its [.filename]#/usr/src/sys/arch/conf#. On the build machine, build the kernel and world as described in -crossref:cutting-edge[makeworld], +crossref:cutting-edge[makeworld, Updating FreeBSD from Source], but do not install anything on the build machine. Instead, install the built kernel on the test machine. On the test machine, mount [.filename]#/usr/src# and [.filename]#/usr/obj# via NFS. Then, run `shutdown now` to go to single-user mode in order to install the new kernel and world and run `etcupdate` as usual. When done, reboot to return to normal multi-user operations. After verifying that everything on the test machine is working properly, use the same procedure to install the new software on each of the other machines in the build set. The same methodology can be used for the ports tree. The first step is to share [.filename]#/usr/ports# via NFS to all the machines in the build set. To configure [.filename]#/etc/make.conf# to share distfiles, set `DISTDIR` to a common shared directory that is writable by whichever user `root` is mapped to by the NFS mount. Each machine should set `WRKDIRPREFIX` to a local build directory, if ports are to be built locally. Alternately, if the build system is to build and distribute packages to the machines in the build set, set `PACKAGES` on the build system to a directory similar to `DISTDIR`. [[building-on-non-freebsd-hosts]] == Building on non-FreeBSD Hosts Historically, building FreeBSD required a FreeBSD host. Nowadays, the FreeBSD can be build on Linux distributions and macOS. To build FreeBSD on non-FreeBSD hosts, the recommendation is to use the `tools/build/make.py` script. This script acts as a wrapper around `bmake`, which is the make implementation used by FreeBSD. It ensures that the necessary tooling, including the actual FreeBSD's man:make[1], is bootstrapped and that the build environment is properly configured. In particular, it sets the external toolchain variables, such as `XCC`, `XLD`, and others. Additionally, the script can pass any additional command arguments, such as `-j 4` for parallel builds or specific make targets, to `bmake`. [NOTE] ==== A recent version of `bmake` can be used instead of the `tools/build/make.py` script as well. In that case, however, required environment variables need to be set manually (the easiest way to obtain a list of them is by running `tools/build/make.py --debug`). ==== Otherwise, the list of prerequisites for building FreeBSD is rather short. In fact, it boils down to installing a couple of dependencies. On macOS, the only dependency LLVM. The necessary dependencies can be installed with package manager (e.g., link:https://brew.sh/[Homebrew]): [source,shell] .... brew install llvm .... On a Linux distributions, install link:https://clang.llvm.org/[Clang] version 10.0 or newer and the headers for libarchive and libbz2 (often packaged as libarchive-dev and libbz2-dev). Once the dependencies are installed, the host should be able to build FreeBSD. For example, the following `tools/build/make.py` invocation builds the world: [source,shell] .... MAKEOBJDIRPREFIX=/tmp/obj tools/build/make.py -j 8 TARGET=arm64 TARGET_ARCH=aarch64 buildworld .... It builds the world for target `aarch64:arm64` on 8 CPUs and uses [.filename]#/tmp/obj# for object files. Note that the variables `MAKEOBJDIRPREFIX`, `TARGET`, and `TARGET_ARCH` are mandatory when building on non-FreeBSD hosts. Also, make sure to create the object directory pointed to by the `MAKEOBJDIRPREFIX` environment variable. Refer to man:arch[7] and man:build[7] for more details. diff --git a/documentation/content/en/books/handbook/disks/_index.adoc b/documentation/content/en/books/handbook/disks/_index.adoc index e18dee2852..49c7b2acc3 100644 --- a/documentation/content/en/books/handbook/disks/_index.adoc +++ b/documentation/content/en/books/handbook/disks/_index.adoc @@ -1,2572 +1,2572 @@ --- title: Chapter 20. Storage part: Part III. System Administration prev: books/handbook/audit next: books/handbook/geom description: This chapter covers the use of disks and storage media in FreeBSD. This includes SCSI and IDE disks, CD and DVD media, memory-backed disks, and USB storage devices. tags: ["storage", "disks", "gpart", "mount", "quotas", "encrypt", "GPT", "cdrecord", "NTFS", "quotas", "swap", "HAST", "CD", "DVD", "resizing", "growing"] showBookMenu: true weight: 24 path: "/books/handbook/disks/" --- [[disks]] = Storage :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 20 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/disks/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[disks-synopsis]] == Synopsis This chapter covers the use of disks and storage media in FreeBSD. This includes SCSI and IDE disks, CD and DVD media, memory-backed disks, and USB storage devices. After reading this chapter, you will know: * How to add additional hard disks to a FreeBSD system. * How to grow the size of a disk's partition on FreeBSD. * How to configure FreeBSD to use USB storage devices. * How to use CD and DVD media on a FreeBSD system. * How to use the backup programs available under FreeBSD. * How to set up memory disks. * What file system snapshots are and how to use them efficiently. * How to use quotas to limit disk space usage. * How to encrypt disks and swap to secure them against attackers. * How to configure a highly available storage network. Before reading this chapter, you should: * Know how to crossref:kernelconfig[kernelconfig,configure and install a new FreeBSD kernel]. [[disks-adding]] == Adding Disks This section describes how to add a new SATA disk to a machine that currently only has a single drive. First, turn off the computer and install the drive in the computer following the instructions of the computer, controller, and drive manufacturers. Reboot the system and become `root`. Inspect [.filename]#/var/run/dmesg.boot# to ensure the new disk was found. In this example, the newly added SATA drive will appear as [.filename]#ada1#. For this example, a single large partition will be created on the new disk. The http://en.wikipedia.org/wiki/GUID_Partition_Table[GPT] partitioning scheme will be used in preference to the older and less versatile MBR scheme. [NOTE] ==== If the disk to be added is not blank, old partition information can be removed with `gpart delete`. See man:gpart[8] for details. ==== The partition scheme is created, and then a single partition is added. To improve performance on newer disks with larger hardware block sizes, the partition is aligned to one megabyte boundaries: [source,shell] .... # gpart create -s GPT ada1 # gpart add -t freebsd-ufs -a 1M ada1 .... Depending on use, several smaller partitions may be desired. See man:gpart[8] for options to create partitions smaller than a whole disk. The disk partition information can be viewed with `gpart show`: [source,shell] .... % gpart show ada1 => 34 1465146988 ada1 GPT (699G) 34 2014 - free - (1.0M) 2048 1465143296 1 freebsd-ufs (699G) 1465145344 1678 - free - (839K) .... A file system is created in the new partition on the new disk: [source,shell] .... # newfs -U /dev/ada1p1 .... An empty directory is created as a _mountpoint_, a location for mounting the new disk in the original disk's file system: [source,shell] .... # mkdir /newdisk .... Finally, an entry is added to [.filename]#/etc/fstab# so the new disk will be mounted automatically at startup: [.programlisting] .... /dev/ada1p1 /newdisk ufs rw 2 2 .... The new disk can be mounted manually, without restarting the system: [source,shell] .... # mount /newdisk .... [[disks-growing]] == Resizing and Growing Disks A disk's capacity can increase without any changes to the data already present. This happens commonly with virtual machines, when the virtual disk turns out to be too small and is enlarged. Sometimes a disk image is written to a USB memory stick, but does not use the full capacity. Here we describe how to resize or _grow_ disk contents to take advantage of increased capacity. Determine the device name of the disk to be resized by inspecting [.filename]#/var/run/dmesg.boot#. In this example, there is only one SATA disk in the system, so the drive will appear as [.filename]#ada0#. List the partitions on the disk to see the current configuration: [source,shell] .... # gpart show ada0 => 34 83886013 ada0 GPT (48G) [CORRUPT] 34 128 1 freebsd-boot (64k) 162 79691648 2 freebsd-ufs (38G) 79691810 4194236 3 freebsd-swap (2G) 83886046 1 - free - (512B) .... [NOTE] ==== If the disk was formatted with the http://en.wikipedia.org/wiki/GUID_Partition_Table[GPT] partitioning scheme, it may show as "corrupted" because the GPT backup partition table is no longer at the end of the drive. Fix the backup partition table with `gpart`: [source,shell] .... # gpart recover ada0 ada0 recovered .... ==== Now the additional space on the disk is available for use by a new partition, or an existing partition can be expanded: [source,shell] .... # gpart show ada0 => 34 102399933 ada0 GPT (48G) 34 128 1 freebsd-boot (64k) 162 79691648 2 freebsd-ufs (38G) 79691810 4194236 3 freebsd-swap (2G) 83886046 18513921 - free - (8.8G) .... Partitions can only be resized into contiguous free space. Here, the last partition on the disk is the swap partition, but the second partition is the one that needs to be resized. Swap partitions only contain temporary data, so it can safely be unmounted, deleted, and then recreate the third partition after resizing the second partition. Disable the swap partition: [source,shell] .... # swapoff /dev/ada0p3 .... Delete the third partition, specified by the `-i` flag, from the disk _ada0_. [source,shell] .... # gpart delete -i 3 ada0 ada0p3 deleted # gpart show ada0 => 34 102399933 ada0 GPT (48G) 34 128 1 freebsd-boot (64k) 162 79691648 2 freebsd-ufs (38G) 79691810 22708157 - free - (10G) .... [WARNING] ==== There is risk of data loss when modifying the partition table of a mounted file system. It is best to perform the following steps on an unmounted file system while running from a live CD-ROM or USB device. However, if absolutely necessary, a mounted file system can be resized after disabling GEOM safety features: [source,shell] .... # sysctl kern.geom.debugflags=16 .... ==== Resize the partition, leaving room to recreate a swap partition of the desired size. The partition to resize is specified with `-i`, and the new desired size with `-s`. Optionally, alignment of the partition is controlled with `-a`. This only modifies the size of the partition. The file system in the partition will be expanded in a separate step. [source,shell] .... # gpart resize -i 2 -s 47G -a 4k ada0 ada0p2 resized # gpart show ada0 => 34 102399933 ada0 GPT (48G) 34 128 1 freebsd-boot (64k) 162 98566144 2 freebsd-ufs (47G) 98566306 3833661 - free - (1.8G) .... Recreate the swap partition and activate it. If no size is specified with `-s`, all remaining space is used: [source,shell] .... # gpart add -t freebsd-swap -a 4k ada0 ada0p3 added # gpart show ada0 => 34 102399933 ada0 GPT (48G) 34 128 1 freebsd-boot (64k) 162 98566144 2 freebsd-ufs (47G) 98566306 3833661 3 freebsd-swap (1.8G) # swapon /dev/ada0p3 .... Grow the UFS file system to use the new capacity of the resized partition: [source,shell] .... # growfs /dev/ada0p2 Device is mounted read-write; resizing will result in temporary write suspension for /. It's strongly recommended to make a backup before growing the file system. OK to grow file system on /dev/ada0p2, mounted on /, from 38GB to 47GB? [Yes/No] Yes super-block backups (for fsck -b #) at: 80781312, 82063552, 83345792, 84628032, 85910272, 87192512, 88474752, 89756992, 91039232, 92321472, 93603712, 94885952, 96168192, 97450432 .... If the file system is ZFS, the resize is triggered by running the `online` subcommand with `-e`: [source,shell] .... # zpool online -e zroot /dev/ada0p2 .... Both the partition and the file system on it have now been resized to use the newly-available disk space. [[usb-disks]] == USB Storage Devices Many external storage solutions, such as hard drives, USB thumbdrives, and CD and DVD burners, use the Universal Serial Bus (USB). FreeBSD provides support for USB 1.x, 2.0, and 3.0 devices. [NOTE] ==== USB 3.0 support is not compatible with some hardware, including Haswell (Lynx point) chipsets. If FreeBSD boots with a `failed with error 19` message, disable xHCI/USB3 in the system BIOS. ==== Support for USB storage devices is built into the [.filename]#GENERIC# kernel. For a custom kernel, be sure that the following lines are present in the kernel configuration file: [.programlisting] .... device scbus # SCSI bus (required for ATA/SCSI) device da # Direct Access (disks) device pass # Passthrough device (direct ATA/SCSI access) device uhci # provides USB 1.x support device ohci # provides USB 1.x support device ehci # provides USB 2.0 support device xhci # provides USB 3.0 support device usb # USB Bus (required) device umass # Disks/Mass storage - Requires scbus and da device cd # needed for CD and DVD burners .... FreeBSD uses the man:umass[4] driver which uses the SCSI subsystem to access USB storage devices. Since any USB device will be seen as a SCSI device by the system, if the USB device is a CD or DVD burner, do _not_ include `device atapicam` in a custom kernel configuration file. The rest of this section demonstrates how to verify that a USB storage device is recognized by FreeBSD and how to configure the device so that it can be used. === Device Configuration To test the USB configuration, plug in the USB device. Use `dmesg` to confirm that the drive appears in the system message buffer. It should look something like this: [source,shell] .... umass0: on usbus0 umass0: SCSI over Bulk-Only; quirks = 0x0100 umass0:4:0:-1: Attached to scbus4 da0 at umass-sim0 bus 0 scbus4 target 0 lun 0 da0: Fixed Direct Access SCSI-4 device da0: Serial Number WD-WXE508CAN263 da0: 40.000MB/s transfers da0: 152627MB (312581808 512 byte sectors: 255H 63S/T 19457C) da0: quirks=0x2 .... The brand, device node ([.filename]#da0#), speed, and size will differ according to the device. Since the USB device is seen as a SCSI one, `camcontrol` can be used to list the USB storage devices attached to the system: [source,shell] .... # camcontrol devlist at scbus4 target 0 lun 0 (pass3,da0) .... Alternately, `usbconfig` can be used to list the device. Refer to man:usbconfig[8] for more information about this command. [source,shell] .... # usbconfig ugen0.3: at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (2mA) .... -If the device has not been formatted, refer to crossref:disks[disks-adding] for instructions on how to format and create partitions on the USB drive. +If the device has not been formatted, refer to crossref:disks[disks-adding, Adding Disks] for instructions on how to format and create partitions on the USB drive. If the drive comes with a file system, it can be mounted by `root` using the instructions in crossref:basics[mount-unmount,“Mounting and Unmounting File Systems”]. [WARNING] ==== Allowing untrusted users to mount arbitrary media, by enabling `vfs.usermount` as described below, should not be considered safe from a security point of view. Most file systems were not built to safeguard against malicious devices. ==== To make the device mountable as a normal user, one solution is to make all users of the device a member of the `operator` group using man:pw[8]. Next, ensure that `operator` is able to read and write the device by adding these lines to [.filename]#/etc/devfs.rules#: [.programlisting] .... [localrules=5] add path 'da*' mode 0660 group operator .... [NOTE] ==== If internal SCSI disks are also installed in the system, change the second line as follows: [.programlisting] .... add path 'da[3-9]*' mode 0660 group operator .... This will exclude the first three SCSI disks ([.filename]#da0# to [.filename]#da2#) from belonging to the `operator` group. Replace _3_ with the number of internal SCSI disks. Refer to man:devfs.rules[5] for more information about this file. ==== Next, enable the ruleset in [.filename]#/etc/rc.conf#: [.programlisting] .... devfs_system_ruleset="localrules" .... Then, instruct the system to allow regular users to mount file systems by adding the following line to [.filename]#/etc/sysctl.conf#: [.programlisting] .... vfs.usermount=1 .... Since this only takes effect after the next reboot, use `sysctl` to set this variable now: [source,shell] .... # sysctl vfs.usermount=1 vfs.usermount: 0 -> 1 .... The final step is to create a directory where the file system is to be mounted. This directory needs to be owned by the user that is to mount the file system. One way to do that is for `root` to create a subdirectory owned by that user as [.filename]#/mnt/username#. In the following example, replace _username_ with the login name of the user and _usergroup_ with the user's primary group: [source,shell] .... # mkdir /mnt/username # chown username:usergroup /mnt/username .... Suppose a USB thumbdrive is plugged in, and a device [.filename]#/dev/da0s1# appears. If the device is formatted with a FAT file system, the user can mount it using: [source,shell] .... % mount -t msdosfs -o -m=644,-M=755 /dev/da0s1 /mnt/username .... Before the device can be unplugged, it _must_ be unmounted first: [source,shell] .... % umount /mnt/username .... After device removal, the system message buffer will show messages similar to the following: [source,shell] .... umass0: at uhub3, port 2, addr 3 (disconnected) da0 at umass-sim0 bus 0 scbus4 target 0 lun 0 da0: s/n WD-WXE508CAN263 detached (da0:umass-sim0:0:0:0): Periph destroyed .... === Automounting Removable Media USB devices can be automatically mounted by uncommenting this line in [.filename]#/etc/auto_master#: [source,shell] .... /media -media -nosuid .... Then add these lines to [.filename]#/etc/devd.conf#: [source,shell] .... notify 100 { match "system" "GEOM"; match "subsystem" "DEV"; action "/usr/sbin/automount -c"; }; .... Reload the configuration if man:autofs[5] and man:devd[8] are already running: [source,shell] .... # service automount restart # service devd restart .... man:autofs[5] can be set to start at boot by adding this line to [.filename]#/etc/rc.conf#: [.programlisting] .... autofs_enable="YES" .... man:autofs[5] requires man:devd[8] to be enabled, as it is by default. Start the services immediately with: [source,shell] .... # service automount start # service automountd start # service autounmountd start # service devd start .... Each file system that can be automatically mounted appears as a directory in [.filename]#/media/#. The directory is named after the file system label. If the label is missing, the directory is named after the device node. The file system is transparently mounted on the first access, and unmounted after a period of inactivity. Automounted drives can also be unmounted manually: [source,shell] .... # automount -fu .... This mechanism is typically used for memory cards and USB memory sticks. It can be used with any block device, including optical drives or iSCSILUNs. [[creating-cds]] == Creating and Using CD Media Compact Disc (CD) media provide a number of features that differentiate them from conventional disks. They are designed so that they can be read continuously without delays to move the head between tracks. While CD media do have tracks, these refer to a section of data to be read continuously, and not a physical property of the disk. The ISO 9660 file system was designed to deal with these differences. The FreeBSD Ports Collection provides several utilities for burning and duplicating audio and data CDs. This chapter demonstrates the use of several command line utilities. For CD burning software with a graphical utility, consider installing the package:sysutils/xcdroast[] or package:sysutils/k3b[] packages or ports. [[atapicam]] === Supported Devices The [.filename]#GENERIC# kernel provides support for SCSI, USB, and ATAPICD readers and burners. If a custom kernel is used, the options that need to be present in the kernel configuration file vary by the type of device. For a SCSI burner, make sure these options are present: [.programlisting] .... device scbus # SCSI bus (required for ATA/SCSI) device da # Direct Access (disks) device pass # Passthrough device (direct ATA/SCSI access) device cd # needed for CD and DVD burners .... For a USB burner, make sure these options are present: [.programlisting] .... device scbus # SCSI bus (required for ATA/SCSI) device da # Direct Access (disks) device pass # Passthrough device (direct ATA/SCSI access) device cd # needed for CD and DVD burners device uhci # provides USB 1.x support device ohci # provides USB 1.x support device ehci # provides USB 2.0 support device xhci # provides USB 3.0 support device usb # USB Bus (required) device umass # Disks/Mass storage - Requires scbus and da .... For an ATAPI burner, make sure these options are present: [.programlisting] .... device ata # Legacy ATA/SATA controllers device scbus # SCSI bus (required for ATA/SCSI) device pass # Passthrough device (direct ATA/SCSI access) device cd # needed for CD and DVD burners .... [NOTE] ==== On FreeBSD versions prior to 10.x, this line is also needed in the kernel configuration file if the burner is an ATAPI device: [.programlisting] .... device atapicam .... Alternately, this driver can be loaded at boot time by adding the following line to [.filename]#/boot/loader.conf#: [.programlisting] .... atapicam_load="YES" .... This will require a reboot of the system as this driver can only be loaded at boot time. ==== To verify that FreeBSD recognizes the device, run `dmesg` and look for an entry for the device. On systems prior to 10.x, the device name in the first line of the output will be [.filename]#acd0# instead of [.filename]#cd0#. [source,shell] .... % dmesg | grep cd cd0 at ahcich1 bus 0 scbus1 target 0 lun 0 cd0: Removable CD-ROM SCSI-0 device cd0: Serial Number M3OD3S34152 cd0: 150.000MB/s transfers (SATA 1.x, UDMA6, ATAPI 12bytes, PIO 8192bytes) cd0: Attempt to query device size failed: NOT READY, Medium not present - tray closed .... [[cdrecord]] === Burning a CD In FreeBSD, `cdrecord` can be used to burn CDs. This command is installed with the package:sysutils/cdrtools[] package or port. While `cdrecord` has many options, basic usage is simple. Specify the name of the ISO file to burn and, if the system has multiple burner devices, specify the name of the device to use: [source,shell] .... # cdrecord dev=device imagefile.iso .... To determine the device name of the burner, use `-scanbus` which might produce results like this: [source,shell] .... # cdrecord -scanbus ProDVD-ProBD-Clone 3.00 (amd64-unknown-freebsd10.0) Copyright (C) 1995-2010 Jörg Schilling Using libscg version 'schily-0.9' scsibus0: 0,0,0 0) 'SEAGATE ' 'ST39236LW ' '0004' Disk 0,1,0 1) 'SEAGATE ' 'ST39173W ' '5958' Disk 0,2,0 2) * 0,3,0 3) 'iomega ' 'jaz 1GB ' 'J.86' Removable Disk 0,4,0 4) 'NEC ' 'CD-ROM DRIVE:466' '1.26' Removable CD-ROM 0,5,0 5) * 0,6,0 6) * 0,7,0 7) * scsibus1: 1,0,0 100) * 1,1,0 101) * 1,2,0 102) * 1,3,0 103) * 1,4,0 104) * 1,5,0 105) 'YAMAHA ' 'CRW4260 ' '1.0q' Removable CD-ROM 1,6,0 106) 'ARTEC ' 'AM12S ' '1.06' Scanner 1,7,0 107) * .... Locate the entry for the CD burner and use the three numbers separated by commas as the value for `dev`. In this case, the Yamaha burner device is `1,5,0`, so the appropriate input to specify that device is `dev=1,5,0`. Refer to the manual page for `cdrecord` for other ways to specify this value and for information on writing audio tracks and controlling the write speed. Alternately, run the following command to get the device address of the burner: [source,shell] .... # camcontrol devlist at scbus1 target 0 lun 0 (cd0,pass0) .... Use the numeric values for `scbus`, `target`, and `lun`. For this example, `1,0,0` is the device name to use. [[mkisofs]] === Writing Data to an ISO File System In order to produce a data CD, the data files that are going to make up the tracks on the CD must be prepared before they can be burned to the CD. In FreeBSD, package:sysutils/cdrtools[] installs `mkisofs`, which can be used to produce an ISO 9660 file system that is an image of a directory tree within a UNIX(R) file system. The simplest usage is to specify the name of the ISO file to create and the path to the files to place into the ISO 9660 file system: [source,shell] .... # mkisofs -o imagefile.iso /path/to/tree .... This command maps the file names in the specified path to names that fit the limitations of the standard ISO 9660 file system, and will exclude files that do not meet the standard for ISO file systems. A number of options are available to overcome the restrictions imposed by the standard. In particular, `-R` enables the Rock Ridge extensions common to UNIX(R) systems and `-J` enables Joliet extensions used by Microsoft(R) systems. For CDs that are going to be used only on FreeBSD systems, `-U` can be used to disable all filename restrictions. When used with `-R`, it produces a file system image that is identical to the specified FreeBSD tree, even if it violates the ISO 9660 standard. The last option of general use is `-b`. This is used to specify the location of a boot image for use in producing an "El Torito" bootable CD. This option takes an argument which is the path to a boot image from the top of the tree being written to the CD. By default, `mkisofs` creates an ISO image in "floppy disk emulation" mode, and thus expects the boot image to be exactly 1200, 1440 or 2880 KB in size. Some boot loaders, like the one used by the FreeBSD distribution media, do not use emulation mode. In this case, `-no-emul-boot` should be used. So, if [.filename]#/tmp/myboot# holds a bootable FreeBSD system with the boot image in [.filename]#/tmp/myboot/boot/cdboot#, this command would produce [.filename]#/tmp/bootable.iso#: [source,shell] .... # mkisofs -R -no-emul-boot -b boot/cdboot -o /tmp/bootable.iso /tmp/myboot .... The resulting ISO image can be mounted as a memory disk with: [source,shell] .... # mdconfig -a -t vnode -f /tmp/bootable.iso -u 0 # mount -t cd9660 /dev/md0 /mnt .... One can then verify that [.filename]#/mnt# and [.filename]#/tmp/myboot# are identical. There are many other options available for `mkisofs` to fine-tune its behavior. Refer to man:mkisofs[8] for details. [NOTE] ==== It is possible to copy a data CD to an image file that is functionally equivalent to the image file created with `mkisofs`. To do so, use [.filename]#dd# with the device name as the input file and the name of the ISO to create as the output file: [source,shell] .... # dd if=/dev/cd0 of=file.iso bs=2048 .... -The resulting image file can be burned to CD as described in crossref:disks[cdrecord]. +The resulting image file can be burned to CD as described in crossref:disks[cdrecord, Burning a CD]. ==== [[mounting-cd]] === Using Data CDs Once an ISO has been burned to a CD, it can be mounted by specifying the file system type, the name of the device containing the CD, and an existing mount point: [source,shell] .... # mount -t cd9660 /dev/cd0 /mnt .... Since `mount` assumes that a file system is of type `ufs`, an `Incorrect super block` error will occur if `-t cd9660` is not included when mounting a data CD. While any data CD can be mounted this way, disks with certain ISO 9660 extensions might behave oddly. For example, Joliet disks store all filenames in two-byte Unicode characters. If some non-English characters show up as question marks, specify the local charset with `-C`. For more information, refer to man:mount_cd9660[8]. [NOTE] ==== In order to do this character conversion with the help of `-C`, the kernel requires the [.filename]#cd9660_iconv.ko# module to be loaded. This can be done either by adding this line to [.filename]#loader.conf#: [.programlisting] .... cd9660_iconv_load="YES" .... and then rebooting the machine, or by directly loading the module with `kldload`. ==== Occasionally, `Device not configured` will be displayed when trying to mount a data CD. This usually means that the CD drive has not detected a disk in the tray, or that the drive is not visible on the bus. It can take a couple of seconds for a CD drive to detect media, so be patient. Sometimes, a SCSICD drive may be missed because it did not have enough time to answer the bus reset. To resolve this, a custom kernel can be created which increases the default SCSI delay. Add the following option to the custom kernel configuration file and rebuild the kernel using the instructions in crossref:kernelconfig[kernelconfig-building,“Building and Installing a Custom Kernel”]: [.programlisting] .... options SCSI_DELAY=15000 .... This tells the SCSI bus to pause 15 seconds during boot, to give the CD drive every possible chance to answer the bus reset. [NOTE] ==== It is possible to burn a file directly to CD, without creating an ISO 9660 file system. This is known as burning a raw data CD and some people do this for backup purposes. This type of disk can not be mounted as a normal data CD. In order to retrieve the data burned to such a CD, the data must be read from the raw device node. For example, this command will extract a compressed tar file located on the second CD device into the current working directory: [source,shell] .... # tar xzvf /dev/cd1 .... In order to mount a data CD, the data must be written using `mkisofs`. ==== [[duplicating-audiocds]] === Duplicating Audio CDs To duplicate an audio CD, extract the audio data from the CD to a series of files, then write these files to a blank CD. crossref:disks[using-cdrecord] describes how to duplicate and burn an audio CD. If the FreeBSD version is less than 10.0 and the device is ATAPI, the `atapicam` -module must be first loaded using the instructions in crossref:disks[atapicam]. +module must be first loaded using the instructions in crossref:disks[atapicam, Supported Devices]. [[using-cdrecord]] [.procedure] .Procedure: Duplicating an Audio CD . The package:sysutils/cdrtools[] package or port installs `cdda2wav`. This command can be used to extract all of the audio tracks, with each track written to a separate WAV file in the current working directory: + [source,shell] .... % cdda2wav -vall -B -Owav .... + A device name does not need to be specified if there is only one CD device on the system. Refer to the `cdda2wav` manual page for instructions on how to specify a device and to learn more about the other options available for this command. . Use `cdrecord` to write the [.filename]#.wav# files: + [source,shell] .... % cdrecord -v dev=2,0 -dao -useinfo *.wav .... + -Make sure that _2,0_ is set appropriately, as described in crossref:disks[cdrecord]. +Make sure that _2,0_ is set appropriately, as described in crossref:disks[cdrecord, Burning a CD]. [[creating-dvds]] == Creating and Using DVD Media Compared to the CD, the DVD is the next generation of optical media storage technology. The DVD can hold more data than any CD and is the standard for video publishing. Five physical recordable formats can be defined for a recordable DVD: * DVD-R: This was the first DVD recordable format available. The DVD-R standard is defined by the http://www.dvdforum.org/forum.shtml[DVD Forum]. This format is write once. * DVD-RW: This is the rewritable version of the DVD-R standard. A DVD-RW can be rewritten about 1000 times. * DVD-RAM: This is a rewritable format which can be seen as a removable hard drive. However, this media is not compatible with most DVD-ROM drives and DVD-Video players as only a few DVD writers support the DVD-RAM format. Refer - to crossref:disks[creating-dvd-ram] for more information on DVD-RAM use. + to crossref:disks[creating-dvd-ram, Using a DVD-RAM] for more information on DVD-RAM use. * DVD+RW: This is a rewritable format defined by the https://en.wikipedia.org/wiki/DVD%2BRW_Alliance[DVD+RW Alliance]. A DVD+RW can be rewritten about 1000 times. * DVD+R: This format is the write once variation of the DVD+RW format. A single layer recordable DVD can hold up to 4,700,000,000 bytes which is actually 4.38 GB or 4485 MB as 1 kilobyte is 1024 bytes. [NOTE] ==== A distinction must be made between the physical media and the application. For example, a DVD-Video is a specific file layout that can be written on any recordable DVD physical media such as DVD-R, DVD+R, or DVD-RW. Before choosing the type of media, ensure that both the burner and the DVD-Video player are compatible with the media under consideration. ==== === Configuration To perform DVD recording, use man:growisofs[1]. This command is part of the package:sysutils/dvd+rw-tools[] utilities which support all DVD media types. These tools use the SCSI subsystem to access the devices, therefore crossref:disks[atapicam,ATAPI/CAM support] must be loaded or statically compiled into the kernel. This support is not needed if the burner uses the USB interface. -Refer to crossref:disks[usb-disks] for more details on USB device configuration. +Refer to crossref:disks[usb-disks, USB Storage Devices] for more details on USB device configuration. DMA access must also be enabled for ATAPI devices, by adding the following line to [.filename]#/boot/loader.conf#: [.programlisting] .... hw.ata.atapi_dma="1" .... Before attempting to use dvd+rw-tools, consult the http://fy.chalmers.se/~appro/linux/DVD+RW/hcn.html[Hardware Compatibility Notes]. [NOTE] ==== For a graphical user interface, consider using package:sysutils/k3b[] which provides a user friendly interface to man:growisofs[1] and many other burning tools. ==== === Burning Data DVDs Since man:growisofs[1] is a front-end to crossref:disks[mkisofs,mkisofs], it will invoke man:mkisofs[8] to create the file system layout and perform the write on the DVD. This means that an image of the data does not need to be created before the burning process. To burn to a DVD+R or a DVD-R the data in [.filename]#/path/to/data#, use the following command: [source,shell] .... # growisofs -dvd-compat -Z /dev/cd0 -J -R /path/to/data .... In this example, `-J -R` is passed to man:mkisofs[8] to create an ISO 9660 file system with Joliet and Rock Ridge extensions. Refer to man:mkisofs[8] for more details. For the initial session recording, `-Z` is used for both single and multiple sessions. Replace _/dev/cd0_, with the name of the DVD device. Using `-dvd-compat` indicates that the disk will be closed and that the recording will be unappendable. This should also provide better media compatibility with DVD-ROM drives. To burn a pre-mastered image, such as _imagefile.iso_, use: [source,shell] .... # growisofs -dvd-compat -Z /dev/cd0=imagefile.iso .... The write speed should be detected and automatically set according to the media and the drive being used. To force the write speed, use `-speed=`. Refer to man:growisofs[1] for example usage. [NOTE] ==== In order to support working files larger than 4.38GB, an UDF/ISO-9660 hybrid file system must be created by passing `-udf -iso-level 3` to man:mkisofs[8] and all related programs, such as man:growisofs[1]. This is required only when creating an ISO image file or when writing files directly to a disk. Since a disk created this way must be mounted as an UDF file system with man:mount_udf[8], it will be usable only on an UDF aware operating system. Otherwise it will look as if it contains corrupted files. To create this type of ISO file: [source,shell] .... % mkisofs -R -J -udf -iso-level 3 -o imagefile.iso /path/to/data .... To burn files directly to a disk: [source,shell] .... # growisofs -dvd-compat -udf -iso-level 3 -Z /dev/cd0 -J -R /path/to/data .... When an ISO image already contains large files, no additional options are required for man:growisofs[1] to burn that image on a disk. Be sure to use an up-to-date version of package:sysutils/cdrtools[], which contains man:mkisofs[8], as an older version may not contain large files support. If the latest version does not work, install package:sysutils/cdrtools-devel[] and read its man:mkisofs[8]. ==== === Burning a DVD-Video A DVD-Video is a specific file layout based on the ISO 9660 and micro-UDF (M-UDF) specifications. Since DVD-Video presents a specific data structure hierarchy, a particular program such as package:multimedia/dvdauthor[] is needed to author the DVD. If an image of the DVD-Video file system already exists, it can be burned in the same way as any other image. If `dvdauthor` was used to make the DVD and the result is in [.filename]#/path/to/video#, the following command should be used to burn the DVD-Video: [source,shell] .... # growisofs -Z /dev/cd0 -dvd-video /path/to/video .... `-dvd-video` is passed to man:mkisofs[8] to instruct it to create a DVD-Video file system layout. This option implies the `-dvd-compat` man:growisofs[1] option. === Using a DVD+RW Unlike CD-RW, a virgin DVD+RW needs to be formatted before first use. It is _recommended_ to let man:growisofs[1] take care of this automatically whenever appropriate. However, it is possible to use `dvd+rw-format` to format the DVD+RW: [source,shell] .... # dvd+rw-format /dev/cd0 .... Only perform this operation once and keep in mind that only virgin DVD+RW medias need to be formatted. Once formatted, the DVD+RW can be burned as usual. To burn a totally new file system and not just append some data onto a DVD+RW, the media does not need to be blanked first. Instead, write over the previous recording like this: [source,shell] .... # growisofs -Z /dev/cd0 -J -R /path/to/newdata .... The DVD+RW format supports appending data to a previous recording. This operation consists of merging a new session to the existing one as it is not considered to be multi-session writing. man:growisofs[1] will _grow_ the ISO 9660 file system present on the media. For example, to append data to a DVD+RW, use the following: [source,shell] .... # growisofs -M /dev/cd0 -J -R /path/to/nextdata .... The same man:mkisofs[8] options used to burn the initial session should be used during next writes. [NOTE] ==== Use `-dvd-compat` for better media compatibility with DVD-ROM drives. When using DVD+RW, this option will not prevent the addition of data. ==== To blank the media, use: [source,shell] .... # growisofs -Z /dev/cd0=/dev/zero .... === Using a DVD-RW A DVD-RW accepts two disc formats: incremental sequential and restricted overwrite. By default, DVD-RW discs are in sequential format. A virgin DVD-RW can be directly written without being formatted. However, a non-virgin DVD-RW in sequential format needs to be blanked before writing a new initial session. To blank a DVD-RW in sequential mode: [source,shell] .... # dvd+rw-format -blank=full /dev/cd0 .... [NOTE] ==== A full blanking using `-blank=full` will take about one hour on a 1x media. A fast blanking can be performed using `-blank`, if the DVD-RW will be recorded in Disk-At-Once (DAO) mode. To burn the DVD-RW in DAO mode, use the command: [source,shell] .... # growisofs -use-the-force-luke=dao -Z /dev/cd0=imagefile.iso .... Since man:growisofs[1] automatically attempts to detect fast blanked media and engage DAO write, `-use-the-force-luke=dao` should not be required. One should instead use restricted overwrite mode with any DVD-RW as this format is more flexible than the default of incremental sequential. ==== To write data on a sequential DVD-RW, use the same instructions as for the other DVD formats: [source,shell] .... # growisofs -Z /dev/cd0 -J -R /path/to/data .... To append some data to a previous recording, use `-M` with man:growisofs[1]. However, if data is appended on a DVD-RW in incremental sequential mode, a new session will be created on the disc and the result will be a multi-session disc. A DVD-RW in restricted overwrite format does not need to be blanked before a new initial session. Instead, overwrite the disc with `-Z`. It is also possible to grow an existing ISO 9660 file system written on the disc with `-M`. The result will be a one-session DVD. To put a DVD-RW in restricted overwrite format, the following command must be used: [source,shell] .... # dvd+rw-format /dev/cd0 .... To change back to sequential format, use: [source,shell] .... # dvd+rw-format -blank=full /dev/cd0 .... === Multi-Session Few DVD-ROM drives support multi-session DVDs and most of the time only read the first session. DVD+R, DVD-R and DVD-RW in sequential format can accept multiple sessions. The notion of multiple sessions does not exist for the DVD+RW and the DVD-RW restricted overwrite formats. Using the following command after an initial non-closed session on a DVD+R, DVD-R, or DVD-RW in sequential format, will add a new session to the disc: [source,shell] .... # growisofs -M /dev/cd0 -J -R /path/to/nextdata .... Using this command with a DVD+RW or a DVD-RW in restricted overwrite mode will append data while merging the new session to the existing one. The result will be a single-session disc. Use this method to add data after an initial write on these types of media. [NOTE] ==== Since some space on the media is used between each session to mark the end and start of sessions, one should add sessions with a large amount of data to optimize media space. The number of sessions is limited to 154 for a DVD+R, about 2000 for a DVD-R, and 127 for a DVD+R Double Layer. ==== === For More Information To obtain more information about a DVD, use `dvd+rw-mediainfo _/dev/cd0_` while the disc in the specified drive. More information about dvd+rw-tools can be found in man:growisofs[1], on the http://fy.chalmers.se/~appro/linux/DVD+RW/[dvd+rw-tools web site], and in the http://lists.debian.org/cdwrite/[cdwrite mailing list] archives. [NOTE] ==== When creating a problem report related to the use of dvd+rw-tools, always include the output of `dvd+rw-mediainfo`. ==== [[creating-dvd-ram]] === Using a DVD-RAM DVD-RAM writers can use either a SCSI or ATAPI interface. For ATAPI devices, DMA access has to be enabled by adding the following line to [.filename]#/boot/loader.conf#: [.programlisting] .... hw.ata.atapi_dma="1" .... A DVD-RAM can be seen as a removable hard drive. Like any other hard drive, the DVD-RAM must be formatted before it can be used. In this example, the whole disk space will be formatted with a standard UFS2 file system: [source,shell] .... # dd if=/dev/zero of=/dev/acd0 bs=2k count=1 # bsdlabel -Bw acd0 # newfs /dev/acd0 .... The DVD device, [.filename]#acd0#, must be changed according to the configuration. Once the DVD-RAM has been formatted, it can be mounted as a normal hard drive: [source,shell] .... # mount /dev/acd0 /mnt .... Once mounted, the DVD-RAM will be both readable and writeable. [[floppies]] == Creating and Using Floppy Disks This section explains how to format a 3.5 inch floppy disk in FreeBSD. [.procedure] ==== *Procedure: Steps to Format a Floppy* A floppy disk needs to be low-level formatted before it can be used. This is usually done by the vendor, but formatting is a good way to check media integrity. To low-level format the floppy disk on FreeBSD, use man:fdformat[1]. When using this utility, make note of any error messages, as these can help determine if the disk is good or bad. . To format the floppy, insert a new 3.5 inch floppy disk into the first floppy drive and issue: + [source,shell] .... # /usr/sbin/fdformat -f 1440 /dev/fd0 .... + . After low-level formatting the disk, create a disk label as it is needed by the system to determine the size of the disk and its geometry. The supported geometry values are listed in [.filename]#/etc/disktab#. + To write the disk label, use man:bsdlabel[8]: + [source,shell] .... # /sbin/bsdlabel -B -w /dev/fd0 fd1440 .... + . The floppy is now ready to be high-level formatted with a file system. The floppy's file system can be either UFS or FAT, where FAT is generally a better choice for floppies. + To format the floppy with FAT, issue: + [source,shell] .... # /sbin/newfs_msdos /dev/fd0 .... ==== The disk is now ready for use. To use the floppy, mount it with man:mount_msdosfs[8]. One can also install and use package:emulators/mtools[] from the Ports Collection. [[using-ntfs]] == Using NTFS Disks This section explains how to mount NTFS disks in FreeBSD. NTFS (New Technology File System) is a proprietary journaling file system developed by Microsoft(R). It has been the default file system in Microsoft Windows(R) for many years. FreeBSD can mount NTFS volumes using a FUSE file system. These file systems are implemented as user space programs which interact with the man:fusefs[5] kernel module via a well defined interface. [.procedure] ==== *Procedure: Steps to Mount a NTFS Disk* . Before using a FUSE file system we need to load the man:fusefs[5] kernel module: + [source,shell] .... # kldload fusefs .... + Use man:sysrc[8] to load the module at startup: + [source,shell] .... # sysrc kld_list+=fusefs .... . Install the actual NTFS file system from packages as in the example (see crossref:ports[pkgng-intro,Using pkg for Binary Package Management]) or from ports (see crossref:ports[ports-using,Using the Ports Collection]): + [source,shell] .... # pkg install fusefs-ntfs .... . Last we need to create a directory where the file system will be mounted: + [source,shell] .... # mkdir /mnt/usb .... . Suppose a USB disk is plugged in. The disk partition information can be viewed with man:gpart[8]: + [source,shell] .... # gpart show da0 => 63 1953525105 da0 MBR (932G) 63 1953525105 1 ntfs (932G) .... . We can mount the disk using the following command: + [source,shell] .... # ntfs-3g /dev/da0s1 /mnt/usb/ .... The disk is now ready to use. + . Additionally, an entry can be added to /etc/fstab: + [.programlisting] .... /dev/da0s1 /mnt/usb ntfs mountprog=/usr/local/bin/ntfs-3g,noauto,rw 0 0 .... + Now the disk can be now mounted with: + [source,shell] .... # mount /mnt/usb .... . The disk can be unmounted with: + [source,shell] .... # umount /mnt/usb/ .... ==== [[backup-basics]] == Backup Basics Implementing a backup plan is essential in order to have the ability to recover from disk failure, accidental file deletion, random file corruption, or complete machine destruction, including destruction of on-site backups. The backup type and schedule will vary, depending upon the importance of the data, the granularity needed for file restores, and the amount of acceptable downtime. Some possible backup techniques include: * Archives of the whole system, backed up onto permanent, off-site media. This provides protection against all of the problems listed above, but is slow and inconvenient to restore from, especially for non-privileged users. * File system snapshots, which are useful for restoring deleted files or previous versions of files. * Copies of whole file systems or disks which are synchronized with another system on the network using a scheduled package:net/rsync[]. * Hardware or software RAID, which minimizes or avoids downtime when a disk fails. Typically, a mix of backup techniques is used. For example, one could create a schedule to automate a weekly, full system backup that is stored off-site and to supplement this backup with hourly ZFS snapshots. In addition, one could make a manual backup of individual directories or files before making file edits or deletions. This section describes some of the utilities which can be used to create and manage backups on a FreeBSD system. === File System Backups The traditional UNIX(R) programs for backing up a file system are man:dump[8], which creates the backup, and man:restore[8], which restores the backup. These utilities work at the disk block level, below the abstractions of the files, links, and directories that are created by file systems. Unlike other backup software, `dump` backs up an entire file system and is unable to backup only part of a file system or a directory tree that spans multiple file systems. Instead of writing files and directories, `dump` writes the raw data blocks that comprise files and directories. [NOTE] ==== If `dump` is used on the root directory, it will not back up [.filename]#/home#, [.filename]#/usr#, or many other directories since these are typically mount points for other file systems or symbolic links into those file systems. ==== When used to restore data, `restore` stores temporary files in [.filename]#/tmp/# by default. When using a recovery disk with a small [.filename]#/tmp#, set `TMPDIR` to a directory with more free space for the restore to succeed. When using `dump`, be aware that some quirks remain from its early days in Version 6 of AT&T UNIX(R),circa 1975. The default parameters assume a backup to a 9-track tape, rather than to another type of media or to the high-density tapes available today. These defaults must be overridden on the command line. It is possible to backup a file system across the network to another system or a tape drive attached to another computer. While the man:rdump[8] and man:rrestore[8] utilities can be used for this purpose, they are not considered to be secure. Instead, one can use `dump` and `restore` more securely over an SSH connection. This example creates a full, compressed backup of [.filename]#/usr# and sends the backup file to the specified host over an SSH connection. .Using `dump` over ssh [example] ==== [source,shell] .... # /sbin/dump -0uan -f - /usr | gzip -2 | ssh -c blowfish \ targetuser@targetmachine.example.com dd of=/mybigfiles/dump-usr-l0.gz .... ==== This example sets `RSH` in order to write the backup to a tape drive on a remote system over an SSH connection: .Using `dump` over ssh with `RSH` Set [example] ==== [source,shell] .... # env RSH=/usr/bin/ssh /sbin/dump -0uan -f targetuser@targetmachine.example.com:/dev/sa0 /usr .... ==== [TIP] ==== Systems using the crossref:zfs[,Z file system (ZFS)] can make use of man:zfs[8] for creating snapshots, as well as crossref:zfs[zfs-zfs-send,sending and receiving] them to/from remote systems. ==== === Directory Backups Several built-in utilities are available for backing up and restoring specified files and directories as needed. A good choice for making a backup of all of the files in a directory is man:tar[1]. This utility dates back to Version 6 of AT&T UNIX(R) and by default assumes a recursive backup to a local tape device. Switches can be used to instead specify the name of a backup file. This example creates a compressed backup of the current directory and saves it to [.filename]#/tmp/mybackup.tgz#. When creating a backup file, make sure that the backup is not saved to the same directory that is being backed up. .Backing Up the Current Directory with `tar` [example] ==== [source,shell] .... # tar czvf /tmp/mybackup.tgz . .... ==== To restore the entire backup, `cd` into the directory to restore into and specify the name of the backup. Note that this will overwrite any newer versions of files in the restore directory. When in doubt, restore to a temporary directory or specify the name of the file within the backup to restore. .Restoring Up the Current Directory with `tar` [example] ==== [source,shell] .... # tar xzvf /tmp/mybackup.tgz .... ==== There are dozens of available switches which are described in man:tar[1]. This utility also supports the use of exclude patterns to specify which files should not be included when backing up the specified directory or restoring files from a backup. To create a backup using a specified list of files and directories, man:cpio[1] is a good choice. Unlike `tar`, `cpio` does not know how to walk the directory tree and it must be provided the list of files to backup. For example, a list of files can be created using `ls` or `find`. This example creates a recursive listing of the current directory which is then piped to `cpio` in order to create an output backup file named [.filename]#/tmp/mybackup.cpio#. .Using `ls` and `cpio` to Make a Recursive Backup of the Current Directory [example] ==== [source,shell] .... # ls -R | cpio -ovF /tmp/mybackup.cpio .... ==== A backup utility which tries to bridge the features provided by `tar` and `cpio` is man:pax[1]. Over the years, the various versions of `tar` and `cpio` became slightly incompatible. POSIX(R) created `pax` which attempts to read and write many of the various `cpio` and `tar` formats, plus new formats of its own. The `pax` equivalent to the previous examples would be: .Backing Up the Current Directory with `pax` [example] ==== [source,shell] .... # pax -wf /tmp/mybackup.pax . .... ==== [[backups-tapebackups]] === Using Data Tapes for Backups While tape technology has continued to evolve, modern backup systems tend to combine off-site backups with local removable media. FreeBSD supports any tape drive that uses SCSI, such as LTO or DAT. There is limited support for SATA and USB tape drives. For SCSI tape devices, FreeBSD uses the man:sa[4] driver and the [.filename]#/dev/sa0#, [.filename]#/dev/nsa0#, and [.filename]#/dev/esa0# devices. The physical device name is [.filename]#/dev/sa0#. When [.filename]#/dev/nsa0# is used, the backup application will not rewind the tape after writing a file, which allows writing more than one file to a tape. Using [.filename]#/dev/esa0# ejects the tape after the device is closed. In FreeBSD, `mt` is used to control operations of the tape drive, such as seeking through files on a tape or writing tape control marks to the tape. For example, the first three files on a tape can be preserved by skipping past them before writing a new file: [source,shell] .... # mt -f /dev/nsa0 fsf 3 .... This utility supports many operations. Refer to man:mt[1] for details. To write a single file to tape using `tar`, specify the name of the tape device and the file to backup: [source,shell] .... # tar cvf /dev/sa0 file .... To recover files from a `tar` archive on tape into the current directory: [source,shell] .... # tar xvf /dev/sa0 .... To backup a UFS file system, use `dump`. This examples backs up [.filename]#/usr# without rewinding the tape when finished: [source,shell] .... # dump -0aL -b64 -f /dev/nsa0 /usr .... To interactively restore files from a `dump` file on tape into the current directory: [source,shell] .... # restore -i -f /dev/nsa0 .... [[backups-programs-amanda]] === Third-Party Backup Utilities The FreeBSD Ports Collection provides many third-party utilities which can be used to schedule the creation of backups, simplify tape backup, and make backups easier and more convenient. Many of these applications are client/server based and can be used to automate the backups of a single system or all of the computers in a network. Popular utilities include: * Amanda (package:misc/amanda-server[] and package:misc/amanda-client[]), * Bacula (package:sysutils/bacula13-server[] and package:sysutils/bacula13-client[]), * Bareos (package:sysutils/bareos-server[] and package:sysutils/bareos-client[]), * package:net/rsync[], * package:sysutils/duply[], and * package:sysutils/duplicity[]. === Emergency Recovery In addition to regular backups, it is recommended to perform the following steps as part of an emergency preparedness plan. Create a print copy of the output of the following commands: * `gpart show` * `more /etc/fstab` * `pkg prime-list` * `dmesg` Store this printout and a copy of the installation media in a secure location. Should an emergency restore be needed, boot into the installation media and select `Live CD` to access a rescue shell. This rescue mode can be used to view the current state of the system, and if needed, to reformat disks and restore data from backups. Next, test the rescue shell and the backups. Make notes of the procedure. Store these notes with the media, the printouts, and the backups. These notes may prevent the inadvertent destruction of the backups while under the stress of performing an emergency recovery. For an added measure of security, store the latest backup at a remote location which is physically separated from the computers and disk drives by a significant distance. [[disks-virtual]] == Memory Disks In addition to physical disks, FreeBSD also supports the creation and use of memory disks. One possible use for a memory disk is to access the contents of an ISO file system without the overhead of first burning it to a CD or DVD, then mounting the CD/DVD media. In FreeBSD, the man:md[4] driver is used to provide support for memory disks. The [.filename]#GENERIC# kernel includes this driver. When using a custom kernel configuration file, ensure it includes this line: [.programlisting] .... device md .... [[disks-mdconfig]] === Attaching and Detaching Existing Images To mount an existing file system image, use `mdconfig` to specify the name of the ISO file and a free unit number. Then, refer to that unit number to mount it on an existing mount point. Once mounted, the files in the ISO will appear in the mount point. This example attaches _diskimage.iso_ to the memory device [.filename]#/dev/md0# then mounts that memory device on [.filename]#/mnt#: [source,shell] .... # mdconfig -f diskimage.iso -u 0 # mount -t cd9660 /dev/md0 /mnt .... Notice that `-t cd9660` was used to mount an ISO format. If a unit number is not specified with `-u`, `mdconfig` will automatically allocate an unused memory device and output the name of the allocated unit, such as [.filename]#md4#. Refer to man:mdconfig[8] for more details about this command and its options. When a memory disk is no longer in use, its resources should be released back to the system. First, unmount the file system, then use `mdconfig` to detach the disk from the system and release its resources. To continue this example: [source,shell] .... # umount /mnt # mdconfig -d -u 0 .... To determine if any memory disks are still attached to the system, type `mdconfig -l`. [[disks-md-freebsd5]] === Creating a File- or Memory-Backed Memory Disk FreeBSD also supports memory disks where the storage to use is allocated from either a hard disk or an area of memory. The first method is commonly referred to as a file-backed file system and the second method as a memory-backed file system. Both types can be created using `mdconfig`. To create a new memory-backed file system, specify a type of `swap` and the size of the memory disk to create. Then, format the memory disk with a file system and mount as usual. This example creates a 5M memory disk on unit `1`. That memory disk is then formatted with the UFS file system before it is mounted: [source,shell] .... # mdconfig -a -t swap -s 5m -u 1 # newfs -U md1 /dev/md1: 5.0MB (10240 sectors) block size 16384, fragment size 2048 using 4 cylinder groups of 1.27MB, 81 blks, 192 inodes. with soft updates super-block backups (for fsck -b #) at: 160, 2752, 5344, 7936 # mount /dev/md1 /mnt # df /mnt Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/md1 4718 4 4338 0% /mnt .... To create a new file-backed memory disk, first allocate an area of disk to use. This example creates an empty 5MB file named [.filename]#newimage#: [source,shell] .... # dd if=/dev/zero of=newimage bs=1k count=5k 5120+0 records in 5120+0 records out .... Next, attach that file to a memory disk, label the memory disk and format it with the UFS file system, mount the memory disk, and verify the size of the file-backed disk: [source,shell] .... # mdconfig -f newimage -u 0 # bsdlabel -w md0 auto # newfs -U md0a /dev/md0a: 5.0MB (10224 sectors) block size 16384, fragment size 2048 using 4 cylinder groups of 1.25MB, 80 blks, 192 inodes. super-block backups (for fsck -b #) at: 160, 2720, 5280, 7840 # mount /dev/md0a /mnt # df /mnt Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/md0a 4710 4 4330 0% /mnt .... It takes several commands to create a file- or memory-backed file system using `mdconfig`. FreeBSD also comes with `mdmfs` which automatically configures a memory disk, formats it with the UFS file system, and mounts it. For example, after creating _newimage_ with `dd`, this one command is equivalent to running the `bsdlabel`, `newfs`, and `mount` commands shown above: [source,shell] .... # mdmfs -F newimage -s 5m md0 /mnt .... To instead create a new memory-based memory disk with `mdmfs`, use this one command: [source,shell] .... # mdmfs -s 5m md1 /mnt .... If the unit number is not specified, `mdmfs` will automatically select an unused memory device. For more details about `mdmfs`, refer to man:mdmfs[8]. [[snapshots]] == File System Snapshots FreeBSD offers a feature in conjunction with crossref:config[soft-updates,Soft Updates]: file system snapshots. UFS snapshots allow a user to create images of specified file systems, and treat them as a file. If you are using the crossref:zfs[,Z file system (ZFS)], refer to crossref:zfs[zfs-zfs-snapshot,"Managing Snapshots"] on how to use snapshots. Snapshot files must be created in the file system that the action is performed on, and a user may create no more than 20 snapshots per file system. Active snapshots are recorded in the superblock so they are persistent across unmount and remount operations along with system reboots. When a snapshot is no longer required, it can be removed using man:rm[1]. While snapshots may be removed in any order, all the used space may not be acquired because another snapshot will possibly claim some of the released blocks. The un-alterable `snapshot` file flag is set by man:mksnap_ffs[8] after initial creation of a snapshot file. man:unlink[1] makes an exception for snapshot files since it allows them to be removed. Snapshots are created using man:mount[8]. To place a snapshot of [.filename]#/var# in the file [.filename]#/var/snapshot/snap#, use the following command: [source,shell] .... # mount -u -o snapshot /var/snapshot/snap /var .... Alternatively, use man:mksnap_ffs[8] to create the snapshot: [source,shell] .... # mksnap_ffs /var /var/snapshot/snap .... One can find snapshot files on a file system, such as [.filename]#/var#, using man:find[1]: [source,shell] .... # find /var -flags snapshot .... Once a snapshot has been created, it has several uses: * Some administrators will use a snapshot file for backup purposes, because the snapshot can be transferred to CDs or tape. * The file system integrity checker, man:fsck[8], may be run on the snapshot. Assuming that the file system was clean when it was mounted, this should always provide a clean and unchanging result. * Running man:dump[8] on the snapshot will produce a dump file that is consistent with the file system and the timestamp of the snapshot. man:dump[8] can also take a snapshot, create a dump image, and then remove the snapshot in one command by using `-L`. * The snapshot can be mounted as a frozen image of the file system. To man:mount[8] the snapshot [.filename]#/var/snapshot/snap# run: + [source,shell] .... # mdconfig -a -t vnode -o readonly -f /var/snapshot/snap -u 4 # mount -r /dev/md4 /mnt .... The frozen [.filename]#/var# is now available through [.filename]#/mnt#. Everything will initially be in the same state it was during the snapshot creation time. The only exception is that any earlier snapshots will appear as zero length files. To unmount the snapshot, use: [source,shell] .... # umount /mnt # mdconfig -d -u 4 .... For more information about `softupdates` and file system snapshots, including technical papers, visit Marshall Kirk McKusick's website at http://www.mckusick.com/[http://www.mckusick.com/]. [[quotas]] == Disk Quotas Disk quotas can be used to limit the amount of disk space or the number of files a user or members of a group may allocate on a per-file system basis. This prevents one user or group of users from consuming all of the available disk space. This section describes how to configure disk quotas for the UFS file system. To configure quotas on the ZFS file system, refer to crossref:zfs[zfs-zfs-quota,"Dataset, User, and Group Quotas"] === Enabling Disk Quotas To determine if the FreeBSD kernel provides support for disk quotas: [source,shell] .... % sysctl kern.features.ufs_quota kern.features.ufs_quota: 1 .... In this example, the `1` indicates quota support. If the value is instead `0`, add the following line to a custom kernel configuration file and rebuild the kernel using the instructions in crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]: [.programlisting] .... options QUOTA .... Next, enable disk quotas in [.filename]#/etc/rc.conf#: [.programlisting] .... quota_enable="YES" .... Normally on bootup, the quota integrity of each file system is checked by man:quotacheck[8]. This program insures that the data in the quota database properly reflects the data on the file system. This is a time consuming process that will significantly affect the time the system takes to boot. To skip this step, add this variable to [.filename]#/etc/rc.conf#: [.programlisting] .... check_quotas="NO" .... Finally, edit [.filename]#/etc/fstab# to enable disk quotas on a per-file system basis. To enable per-user quotas on a file system, add `userquota` to the options field in the [.filename]#/etc/fstab# entry for the file system to enable quotas on. For example: [.programlisting] .... /dev/da1s2g /home ufs rw,userquota 1 2 .... To enable group quotas, use `groupquota` instead. To enable both user and group quotas, separate the options with a comma: [.programlisting] .... /dev/da1s2g /home ufs rw,userquota,groupquota 1 2 .... By default, quota files are stored in the root directory of the file system as [.filename]#quota.user# and [.filename]#quota.group#. Refer to man:fstab[5] for more information. Specifying an alternate location for the quota files is not recommended. Once the configuration is complete, reboot the system and [.filename]#/etc/rc# will automatically run the appropriate commands to create the initial quota files for all of the quotas enabled in [.filename]#/etc/fstab#. In the normal course of operations, there should be no need to manually run man:quotacheck[8], man:quotaon[8], or man:quotaoff[8]. However, one should read these manual pages to be familiar with their operation. === Setting Quota Limits To verify that quotas are enabled, run: [source,shell] .... # quota -v .... There should be a one line summary of disk usage and current quota limits for each file system that quotas are enabled on. The system is now ready to be assigned quota limits with `edquota`. Several options are available to enforce limits on the amount of disk space a user or group may allocate, and how many files they may create. Allocations can be limited based on disk space (block quotas), number of files (inode quotas), or a combination of both. Each limit is further broken down into two categories: hard and soft limits. A hard limit may not be exceeded. Once a user reaches a hard limit, no further allocations can be made on that file system by that user. For example, if the user has a hard limit of 500 kbytes on a file system and is currently using 490 kbytes, the user can only allocate an additional 10 kbytes. Attempting to allocate an additional 11 kbytes will fail. Soft limits can be exceeded for a limited amount of time, known as the grace period, which is one week by default. If a user stays over their limit longer than the grace period, the soft limit turns into a hard limit and no further allocations are allowed. When the user drops back below the soft limit, the grace period is reset. In the following example, the quota for the `test` account is being edited. When `edquota` is invoked, the editor specified by `EDITOR` is opened in order to edit the quota limits. The default editor is set to vi. [source,shell] .... # edquota -u test Quotas for user test: /usr: kbytes in use: 65, limits (soft = 50, hard = 75) inodes in use: 7, limits (soft = 50, hard = 60) /usr/var: kbytes in use: 0, limits (soft = 50, hard = 75) inodes in use: 0, limits (soft = 50, hard = 60) .... There are normally two lines for each file system that has quotas enabled. One line represents the block limits and the other represents the inode limits. Change the value to modify the quota limit. For example, to raise the block limit on [.filename]#/usr# to a soft limit of `500` and a hard limit of `600`, change the values in that line as follows: [.programlisting] .... /usr: kbytes in use: 65, limits (soft = 500, hard = 600) .... The new quota limits take effect upon exiting the editor. Sometimes it is desirable to set quota limits on a range of users. This can be done by first assigning the desired quota limit to a user. Then, use `-p` to duplicate that quota to a specified range of user IDs (UIDs). The following command will duplicate those quota limits for UIDs `10,000` through `19,999`: [source,shell] .... # edquota -p test 10000-19999 .... For more information, refer to man:edquota[8]. === Checking Quota Limits and Disk Usage To check individual user or group quotas and disk usage, use man:quota[1]. A user may only examine their own quota and the quota of a group they are a member of. Only the superuser may view all user and group quotas. To get a summary of all quotas and disk usage for file systems with quotas enabled, use man:repquota[8]. Normally, file systems that the user is not using any disk space on will not show in the output of `quota`, even if the user has a quota limit assigned for that file system. Use `-v` to display those file systems. The following is sample output from `quota -v` for a user that has quota limits on two file systems. [.programlisting] .... Disk quotas for user test (uid 1002): Filesystem usage quota limit grace files quota limit grace /usr 65* 50 75 5days 7 50 60 /usr/var 0 50 75 0 50 60 .... In this example, the user is currently 15 kbytes over the soft limit of 50 kbytes on [.filename]#/usr# and has 5 days of grace period left. The asterisk `*` indicates that the user is currently over the quota limit. === Quotas over NFS Quotas are enforced by the quota subsystem on the NFS server. The man:rpc.rquotad[8] daemon makes quota information available to `quota` on NFS clients, allowing users on those machines to see their quota statistics. On the NFS server, enable `rpc.rquotad` by removing the `+#+` from this line in [.filename]*/etc/inetd.conf*: [.programlisting] .... rquotad/1 dgram rpc/udp wait root /usr/libexec/rpc.rquotad rpc.rquotad .... Then, restart `inetd`: [source,shell] .... # service inetd restart .... [[disks-encrypting]] == Encrypting Disk Partitions FreeBSD offers excellent online protections against unauthorized data access. File permissions and crossref:mac[mac,Mandatory Access Control] (MAC) help prevent unauthorized users from accessing data while the operating system is active and the computer is powered up. However, the permissions enforced by the operating system are irrelevant if an attacker has physical access to a computer and can move the computer's hard drive to another system to copy and analyze the data. Regardless of how an attacker may have come into possession of a hard drive or powered-down computer, the GEOM-based cryptographic subsystems built into FreeBSD are able to protect the data on the computer's file systems against even highly-motivated attackers with significant resources. Unlike encryption methods that encrypt individual files, the built-in `gbde` and `geli` utilities can be used to transparently encrypt entire file systems. No cleartext ever touches the hard drive's platter. This chapter demonstrates how to create an encrypted file system on FreeBSD. It first demonstrates the process using `gbde` and then demonstrates the same example using `geli`. === Disk Encryption with gbde The objective of the man:gbde[4] facility is to provide a formidable challenge for an attacker to gain access to the contents of a _cold_ storage device. However, if the computer is compromised while up and running and the storage device is actively attached, or the attacker has access to a valid passphrase, it offers no protection to the contents of the storage device. Thus, it is important to provide physical security while the system is running and to protect the passphrase used by the encryption mechanism. This facility provides several barriers to protect the data stored in each disk sector. It encrypts the contents of a disk sector using 128-bit AES in CBC mode. Each sector on the disk is encrypted with a different AES key. For more information on the cryptographic design, including how the sector keys are derived from the user-supplied passphrase, refer to man:gbde[4]. FreeBSD provides a kernel module for gbde which can be loaded with this command: [source,shell] .... # kldload geom_bde .... If using a custom kernel configuration file, ensure it contains this line: `options GEOM_BDE` The following example demonstrates adding a new hard drive to a system that will hold a single encrypted partition that will be mounted as [.filename]#/private#. [.procedure] .Procedure: Encrypting a Partition with gbde . Add the New Hard Drive + -Install the new drive to the system as explained in crossref:disks[disks-adding]. +Install the new drive to the system as explained in crossref:disks[disks-adding, Adding Disks]. For the purposes of this example, a new hard drive partition has been added as [.filename]#/dev/ad4s1c# and [.filename]#/dev/ad0s1*# represents the existing standard FreeBSD partitions. + [source,shell] .... # ls /dev/ad* /dev/ad0 /dev/ad0s1b /dev/ad0s1e /dev/ad4s1 /dev/ad0s1 /dev/ad0s1c /dev/ad0s1f /dev/ad4s1c /dev/ad0s1a /dev/ad0s1d /dev/ad4 .... . Create a Directory to Hold `gbde` Lock Files + [source,shell] .... # mkdir /etc/gbde .... + The gbde lock file contains information that gbde requires to access encrypted partitions. Without access to the lock file, gbde will not be able to decrypt the data contained in the encrypted partition without significant manual intervention which is not supported by the software. Each encrypted partition uses a separate lock file. . Initialize the `gbde` Partition + A gbde partition must be initialized before it can be used. This initialization needs to be performed only once. This command will open the default editor, in order to set various configuration options in a template. For use with the UFS file system, set the sector_size to 2048: + [source,shell] .... # gbde init /dev/ad4s1c -i -L /etc/gbde/ad4s1c.lock # # Sector size is the smallest unit of data which can be read or written. # Making it too small decreases performance and decreases available space. # Making it too large may prevent filesystems from working. 512 is the # minimum and always safe. For UFS, use the fragment size # sector_size = 2048 [...] .... + Once the edit is saved, the user will be asked twice to type the passphrase used to secure the data. The passphrase must be the same both times. The ability of gbde to protect data depends entirely on the quality of the passphrase. For tips on how to select a secure passphrase that is easy to remember, see http://world.std.com/\~reinhold/diceware.html[http://world.std.com/~reinhold/diceware.htm]. + This initialization creates a lock file for the gbde partition. In this example, it is stored as [.filename]#/etc/gbde/ad4s1c.lock#. Lock files must end in ".lock" in order to be correctly detected by the [.filename]#/etc/rc.d/gbde# start up script. + [CAUTION] ==== Lock files _must_ be backed up together with the contents of any encrypted partitions. Without the lock file, the legitimate owner will be unable to access the data on the encrypted partition. ==== . Attach the Encrypted Partition to the Kernel + [source,shell] .... # gbde attach /dev/ad4s1c -l /etc/gbde/ad4s1c.lock .... + This command will prompt to input the passphrase that was selected during the initialization of the encrypted partition. The new encrypted device will appear in [.filename]#/dev# as [.filename]#/dev/device_name.bde#: + [source,shell] .... # ls /dev/ad* /dev/ad0 /dev/ad0s1b /dev/ad0s1e /dev/ad4s1 /dev/ad0s1 /dev/ad0s1c /dev/ad0s1f /dev/ad4s1c /dev/ad0s1a /dev/ad0s1d /dev/ad4 /dev/ad4s1c.bde .... . Create a File System on the Encrypted Device + Once the encrypted device has been attached to the kernel, a file system can be created on the device. This example creates a UFS file system with soft updates enabled. Be sure to specify the partition which has a [.filename]#*.bde# extension: + [source,shell] .... # newfs -U /dev/ad4s1c.bde .... . Mount the Encrypted Partition + Create a mount point and mount the encrypted file system: + [source,shell] .... # mkdir /private # mount /dev/ad4s1c.bde /private .... . Verify That the Encrypted File System is Available + The encrypted file system should now be visible and available for use: + [source,shell] .... % df -H Filesystem Size Used Avail Capacity Mounted on /dev/ad0s1a 1037M 72M 883M 8% / /devfs 1.0K 1.0K 0B 100% /dev /dev/ad0s1f 8.1G 55K 7.5G 0% /home /dev/ad0s1e 1037M 1.1M 953M 0% /tmp /dev/ad0s1d 6.1G 1.9G 3.7G 35% /usr /dev/ad4s1c.bde 150G 4.1K 138G 0% /private .... After each boot, any encrypted file systems must be manually re-attached to the kernel, checked for errors, and mounted, before the file systems can be used. To configure these steps, add the following lines to [.filename]#/etc/rc.conf#: [.programlisting] .... gbde_autoattach_all="YES" gbde_devices="ad4s1c" gbde_lockdir="/etc/gbde" .... This requires that the passphrase be entered at the console at boot time. After typing the correct passphrase, the encrypted partition will be mounted automatically. Additional gbde boot options are available and listed in man:rc.conf[5]. [NOTE] ==== sysinstall is incompatible with gbde-encrypted devices. All [.filename]#*.bde# devices must be detached from the kernel before starting sysinstall or it will crash during its initial probing for devices. To detach the encrypted device used in the example, use the following command: [source,shell] .... # gbde detach /dev/ad4s1c .... ==== [[disks-encrypting-geli]] === Disk Encryption with `geli` An alternative cryptographic GEOM class is available using `geli`. This control utility adds some features and uses a different scheme for doing cryptographic work. It provides the following features: * Utilizes the man:crypto[9] framework and automatically uses cryptographic hardware when it is available. * Supports multiple cryptographic algorithms such as AES-XTS, AES-CBC, and Camellia-CBCAES. * Allows the root partition to be encrypted. The passphrase used to access the encrypted root partition will be requested during system boot. * Allows the use of two independent keys. * It is fast as it performs simple sector-to-sector encryption. * Allows backup and restore of master keys. If a user destroys their keys, it is still possible to get access to the data by restoring keys from the backup. * Allows a disk to attach with a random, one-time key which is useful for swap partitions and temporary file systems. More features and usage examples can be found in man:geli[8]. The following example describes how to generate a key file which will be used as part of the master key for the encrypted provider mounted under [.filename]#/private#. The key file will provide some random data used to encrypt the master key. The master key will also be protected by a passphrase. The provider's sector size will be 4kB. The example describes how to attach to the `geli` provider, create a file system on it, mount it, work with it, and finally, how to detach it. [.procedure] .Procedure: Encrypting a Partition with `geli` . Load `geli` Support + Support for `geli` is available as a loadable kernel module. To configure the system to automatically load the module at boot time, add the following line to [.filename]#/boot/loader.conf#: + [.programlisting] .... geom_eli_load="YES" .... + To load the kernel module now: + [source,shell] .... # kldload geom_eli .... + For a custom kernel, ensure the kernel configuration file contains these lines: + [.programlisting] .... options GEOM_ELI device crypto .... . Generate the Master Key + The following commands generate a master key that all data will be encrypted with. This key can never be changed. Rather than using it directly, it is encrypted with one or more user keys. The user keys are made up of an optional combination of random bytes from a file, [.filename]#/root/da2.key#, and/or a passphrase. In this case, the data source for the key file is [.filename]#/dev/random#. This command also configures the sector size of the provider ([.filename]#/dev/da2.eli#) as 4kB, for better performance: + [source,shell] .... # dd if=/dev/random of=/root/da2.key bs=64 count=1 # geli init -K /root/da2.key -s 4096 /dev/da2 Enter new passphrase: Reenter new passphrase: .... + It is not mandatory to use both a passphrase and a key file as either method of securing the master key can be used in isolation. + If the key file is given as "-", standard input will be used. For example, this command generates three key files: + [source,shell] .... # cat keyfile1 keyfile2 keyfile3 | geli init -K - /dev/da2 .... . Attach the Provider with the Generated Key + To attach the provider, specify the key file, the name of the disk, and the passphrase: + [source,shell] .... # geli attach -k /root/da2.key /dev/da2 Enter passphrase: .... + This creates a new device with an [.filename]#.eli# extension: + [source,shell] .... # ls /dev/da2* /dev/da2 /dev/da2.eli .... . Create the New File System + Next, format the device with the UFS file system and mount it on an existing mount point: + [source,shell] .... # dd if=/dev/random of=/dev/da2.eli bs=1m # newfs /dev/da2.eli # mount /dev/da2.eli /private .... + The encrypted file system should now be available for use: + [source,shell] .... # df -H Filesystem Size Used Avail Capacity Mounted on /dev/ad0s1a 248M 89M 139M 38% / /devfs 1.0K 1.0K 0B 100% /dev /dev/ad0s1f 7.7G 2.3G 4.9G 32% /usr /dev/ad0s1d 989M 1.5M 909M 0% /tmp /dev/ad0s1e 3.9G 1.3G 2.3G 35% /var /dev/da2.eli 150G 4.1K 138G 0% /private .... Once the work on the encrypted partition is done, and the [.filename]#/private# partition is no longer needed, it is prudent to put the device into cold storage by unmounting and detaching the `geli` encrypted partition from the kernel: [source,shell] .... # umount /private # geli detach da2.eli .... An [.filename]#rc.d# script is provided to simplify the mounting of `geli`-encrypted devices at boot time. For this example, add these lines to [.filename]#/etc/rc.conf#: [.programlisting] .... geli_devices="da2" geli_da2_flags="-k /root/da2.key" .... This configures [.filename]#/dev/da2# as a `geli` provider with a master key of [.filename]#/root/da2.key#. The system will automatically detach the provider from the kernel before the system shuts down. During the startup process, the script will prompt for the passphrase before attaching the provider. Other kernel messages might be shown before and after the password prompt. If the boot process seems to stall, look carefully for the password prompt among the other messages. Once the correct passphrase is entered, the provider is attached. The file system is then mounted, typically by an entry in [.filename]#/etc/fstab#. Refer to crossref:basics[mount-unmount,“Mounting and Unmounting File Systems”] for instructions on how to configure a file system to mount at boot time. [[swap-encrypting]] == Encrypting Swap Like the encryption of disk partitions, encryption of swap space is used to protect sensitive information. Consider an application that deals with passwords. As long as these passwords stay in physical memory, they are not written to disk and will be cleared after a reboot. However, if FreeBSD starts swapping out memory pages to free space, the passwords may be written to the disk unencrypted. Encrypting swap space can be a solution for this scenario. This section demonstrates how to configure an encrypted swap partition using man:gbde[8] or man:geli[8] encryption. It assumes that [.filename]#/dev/ada0s1b# is the swap partition. === Configuring Encrypted Swap Swap partitions are not encrypted by default and should be cleared of any sensitive data before continuing. To overwrite the current swap partition with random garbage, execute the following command: [source,shell] .... # dd if=/dev/random of=/dev/ada0s1b bs=1m .... To encrypt the swap partition using man:gbde[8], add the `.bde` suffix to the swap line in [.filename]#/etc/fstab#: [.programlisting] .... # Device Mountpoint FStype Options Dump Pass# /dev/ada0s1b.bde none swap sw 0 0 .... To instead encrypt the swap partition using man:geli[8], use the `.eli` suffix: [.programlisting] .... # Device Mountpoint FStype Options Dump Pass# /dev/ada0s1b.eli none swap sw 0 0 .... By default, man:geli[8] uses the AES algorithm with a key length of 128 bits. Normally the default settings will suffice. If desired, these defaults can be altered in the options field in [.filename]#/etc/fstab#. The possible flags are: aalgo:: Data integrity verification algorithm used to ensure that the encrypted data has not been tampered with. See man:geli[8] for a list of supported algorithms. ealgo:: Encryption algorithm used to protect the data. See man:geli[8] for a list of supported algorithms. keylen:: The length of the key used for the encryption algorithm. See man:geli[8] for the key lengths that are supported by each encryption algorithm. sectorsize:: The size of the blocks data is broken into before it is encrypted. Larger sector sizes increase performance at the cost of higher storage overhead. The recommended size is 4096 bytes. This example configures an encrypted swap partition using the AES-XTS algorithm with a key length of 128 bits and a sectorsize of 4 kilobytes: [.programlisting] .... # Device Mountpoint FStype Options Dump Pass# /dev/ada0s1b.eli none swap sw,ealgo=AES-XTS,keylen=128,sectorsize=4096 0 0 .... === Encrypted Swap Verification Once the system has rebooted, proper operation of the encrypted swap can be verified using `swapinfo`. If man:gbde[8] is being used: [source,shell] .... % swapinfo Device 1K-blocks Used Avail Capacity /dev/ada0s1b.bde 542720 0 542720 0 .... If man:geli[8] is being used: [source,shell] .... % swapinfo Device 1K-blocks Used Avail Capacity /dev/ada0s1b.eli 542720 0 542720 0 .... [[disks-hast]] == Highly Available Storage (HAST) High availability is one of the main requirements in serious business applications and highly-available storage is a key component in such environments. In FreeBSD, the Highly Available STorage (HAST) framework allows transparent storage of the same data across several physically separated machines connected by a TCP/IP network. HAST can be understood as a network-based RAID1 (mirror), and is similar to the DRBD(R) storage system used in the GNU/Linux(R) platform. In combination with other high-availability features of FreeBSD like CARP, HAST makes it possible to build a highly-available storage cluster that is resistant to hardware failures. The following are the main features of HAST: * Can be used to mask I/O errors on local hard drives. * File system agnostic as it works with any file system supported by FreeBSD. * Efficient and quick resynchronization as only the blocks that were modified during the downtime of a node are synchronized. * Can be used in an already deployed environment to add additional redundancy. * Together with CARP, Heartbeat, or other tools, it can be used to build a robust and durable storage system. After reading this section, you will know: * What HAST is, how it works, and which features it provides. * How to set up and use HAST on FreeBSD. * How to integrate CARP and man:devd[8] to build a robust storage system. Before reading this section, you should: * Understand UNIX(R) and FreeBSD basics (crossref:basics[basics,FreeBSD Basics]). * Know how to configure network interfaces and other core FreeBSD subsystems (crossref:config[config-tuning,Configuration and Tuning]). * Have a good understanding of FreeBSD networking (crossref:partiv[network-communication,"Network Communication"]). The HAST project was sponsored by The FreeBSD Foundation with support from http://www.omc.net/[http://www.omc.net/] and http://www.transip.nl/[http://www.transip.nl/]. === HAST Operation HAST provides synchronous block-level replication between two physical machines: the _primary_ node and the _secondary_ node. These two machines together are referred to as a cluster. Since HAST works in a primary-secondary configuration, it allows only one of the cluster nodes to be active at any given time. The primary node, also called _active_, is the one which will handle all the I/O requests to HAST-managed devices. The secondary node is automatically synchronized from the primary node. The physical components of the HAST system are the local disk on primary node, and the disk on the remote, secondary node. HAST operates synchronously on a block level, making it transparent to file systems and applications. HAST provides regular GEOM providers in [.filename]#/dev/hast/# for use by other tools or applications. There is no difference between using HAST-provided devices and raw disks or partitions. Each write, delete, or flush operation is sent to both the local disk and to the remote disk over TCP/IP. Each read operation is served from the local disk, unless the local disk is not up-to-date or an I/O error occurs. In such cases, the read operation is sent to the secondary node. HAST tries to provide fast failure recovery. For this reason, it is important to reduce synchronization time after a node's outage. To provide fast synchronization, HAST manages an on-disk bitmap of dirty extents and only synchronizes those during a regular synchronization, with an exception of the initial sync. There are many ways to handle synchronization. HAST implements several replication modes to handle different synchronization methods: * _memsync_: This mode reports a write operation as completed when the local write operation is finished and when the remote node acknowledges data arrival, but before actually storing the data. The data on the remote node will be stored directly after sending the acknowledgement. This mode is intended to reduce latency, but still provides good reliability. This mode is the default. * _fullsync_: This mode reports a write operation as completed when both the local write and the remote write complete. This is the safest and the slowest replication mode. * _async_: This mode reports a write operation as completed when the local write completes. This is the fastest and the most dangerous replication mode. It should only be used when replicating to a distant node where latency is too high for other modes. === HAST Configuration The HAST framework consists of several components: * The man:hastd[8] daemon which provides data synchronization. When this daemon is started, it will automatically load `geom_gate.ko`. * The userland management utility, man:hastctl[8]. * The man:hast.conf[5] configuration file. This file must exist before starting hastd. Users who prefer to statically build `GEOM_GATE` support into the kernel should add this line to the custom kernel configuration file, then rebuild the kernel using the instructions in crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]: [.programlisting] .... options GEOM_GATE .... The following example describes how to configure two nodes in primary-secondary operation using HAST to replicate the data between the two. The nodes will be called `hasta`, with an IP address of `172.16.0.1`, and `hastb`, with an IP address of `172.16.0.2`. Both nodes will have a dedicated hard drive [.filename]#/dev/ad6# of the same size for HAST operation. The HAST pool, sometimes referred to as a resource or the GEOM provider in [.filename]#/dev/hast/#, will be called `test`. Configuration of HAST is done using [.filename]#/etc/hast.conf#. This file should be identical on both nodes. The simplest configuration is: [.programlisting] .... resource test { on hasta { local /dev/ad6 remote 172.16.0.2 } on hastb { local /dev/ad6 remote 172.16.0.1 } } .... For more advanced configuration, refer to man:hast.conf[5]. [TIP] ==== It is also possible to use host names in the `remote` statements if the hosts are resolvable and defined either in [.filename]#/etc/hosts# or in the local DNS. ==== Once the configuration exists on both nodes, the HAST pool can be created. Run these commands on both nodes to place the initial metadata onto the local disk and to start man:hastd[8]: [source,shell] .... # hastctl create test # service hastd onestart .... [NOTE] ==== It is _not_ possible to use GEOM providers with an existing file system or to convert an existing storage to a HAST-managed pool. This procedure needs to store some metadata on the provider and there will not be enough required space available on an existing provider. ==== A HAST node's `primary` or `secondary` role is selected by an administrator, or software like Heartbeat, using man:hastctl[8]. On the primary node, `hasta`, issue this command: [source,shell] .... # hastctl role primary test .... Run this command on the secondary node, `hastb`: [source,shell] .... # hastctl role secondary test .... Verify the result by running `hastctl` on each node: [source,shell] .... # hastctl status test .... Check the `status` line in the output. If it says `degraded`, something is wrong with the configuration file. It should say `complete` on each node, meaning that the synchronization between the nodes has started. The synchronization completes when `hastctl status` reports 0 bytes of `dirty` extents. The next step is to create a file system on the GEOM provider and mount it. This must be done on the `primary` node. Creating the file system can take a few minutes, depending on the size of the hard drive. This example creates a UFS file system on [.filename]#/dev/hast/test#: [source,shell] .... # newfs -U /dev/hast/test # mkdir /hast/test # mount /dev/hast/test /hast/test .... Once the HAST framework is configured properly, the final step is to make sure that HAST is started automatically during system boot. Add this line to [.filename]#/etc/rc.conf#: [.programlisting] .... hastd_enable="YES" .... ==== Failover Configuration The goal of this example is to build a robust storage system which is resistant to the failure of any given node. If the primary node fails, the secondary node is there to take over seamlessly, check and mount the file system, and continue to work without missing a single bit of data. To accomplish this task, the Common Address Redundancy Protocol (CARP) is used to provide for automatic failover at the IP layer. CARP allows multiple hosts on the same network segment to share an IP address. Set up CARP on both nodes of the cluster according to the documentation available in crossref:advanced-networking[carp,“Common Address Redundancy Protocol (CARP)”]. In this example, each node will have its own management IP address and a shared IP address of _172.16.0.254_. The primary HAST node of the cluster must be the primary CARP node. The HAST pool created in the previous section is now ready to be exported to the other hosts on the network. This can be accomplished by exporting it through NFS or Samba, using the shared IP address _172.16.0.254_. The only problem which remains unresolved is an automatic failover should the primary node fail. In the event of CARP interfaces going up or down, the FreeBSD operating system generates a man:devd[8] event, making it possible to watch for state changes on the CARP interfaces. A state change on the CARP interface is an indication that one of the nodes failed or came back online. These state change events make it possible to run a script which will automatically handle the HAST failover. To catch state changes on the CARP interfaces, add this configuration to [.filename]#/etc/devd.conf# on each node, while replacing `` with the virtual host id and `` with the associated interface name: [.programlisting] .... notify 30 { match "system" "CARP"; match "subsystem" "@"; match "type" "MASTER"; action "/usr/local/sbin/carp-hast-switch primary"; }; notify 30 { match "system" "CARP"; match "subsystem" "@"; match "type" "BACKUP"; action "/usr/local/sbin/carp-hast-switch secondary"; }; .... Restart man:devd[8] on both nodes to put the new configuration into effect: [source,shell] .... # service devd restart .... When the specified interface state changes by going up or down , the system generates a notification, allowing the man:devd[8] subsystem to run the specified automatic failover script, [.filename]#/usr/local/sbin/carp-hast-switch#. For further clarification about this configuration, refer to man:devd.conf[5]. Here is an example of an automated failover script: [.programlisting] .... #!/bin/sh # Original script by Freddie Cash # Modified by Michael W. Lucas # and Viktor Petersson # The names of the HAST resources, as listed in /etc/hast.conf resources="test" # delay in mounting HAST resource after becoming primary # make your best guess delay=3 # logging log="local0.debug" name="carp-hast" # end of user configurable stuff case "$1" in primary) logger -p $log -t $name "Switching to primary provider for ${resources}." sleep ${delay} # Wait for any "hastd secondary" processes to stop for disk in ${resources}; do while $( pgrep -lf "hastd: ${disk} \(secondary\)" > /dev/null 2>&1 ); do sleep 1 done # Switch role for each disk hastctl role primary ${disk} if [ $? -ne 0 ]; then logger -p $log -t $name "Unable to change role to primary for resource ${disk}." exit 1 fi done # Wait for the /dev/hast/* devices to appear for disk in ${resources}; do for I in $( jot 60 ); do [ -c "/dev/hast/${disk}" ] && break sleep 0.5 done if [ ! -c "/dev/hast/${disk}" ]; then logger -p $log -t $name "GEOM provider /dev/hast/${disk} did not appear." exit 1 fi done logger -p $log -t $name "Role for HAST resources ${resources} switched to primary." logger -p $log -t $name "Mounting disks." for disk in ${resources}; do mkdir -p /hast/${disk} fsck -p -y -t ufs /dev/hast/${disk} mount /dev/hast/${disk} /hast/${disk} done ;; secondary) logger -p $log -t $name "Switching to secondary provider for ${resources}." # Switch roles for the HAST resources for disk in ${resources}; do if ! mount | grep -q "^/dev/hast/${disk} on " then else umount -f /hast/${disk} fi sleep $delay hastctl role secondary ${disk} 2>&1 if [ $? -ne 0 ]; then logger -p $log -t $name "Unable to switch role to secondary for resource ${disk}." exit 1 fi logger -p $log -t $name "Role switched to secondary for resource ${disk}." done ;; esac .... In a nutshell, the script takes these actions when a node becomes primary: * Promotes the HAST pool to primary on the other node. * Checks the file system under the HAST pool. * Mounts the pool. When a node becomes secondary: * Unmounts the HAST pool. * Degrades the HAST pool to secondary. [CAUTION] ==== This is just an example script which serves as a proof of concept. It does not handle all the possible scenarios and can be extended or altered in any way, for example, to start or stop required services. ==== [TIP] ==== For this example, a standard UFS file system was used. To reduce the time needed for recovery, a journal-enabled UFS or ZFS file system can be used instead. ==== Instead of using the highly available storage locally, it can also be shared to other computers on a network via crossref:network-servers[network-nfs,NFS], crossref:network-servers[network-iscsi,iSCSI], man:sshfs[1], or programs in ports (i.e. package:net/samba419[]). More detailed information with additional examples can be found at http://wiki.FreeBSD.org/HAST[http://wiki.FreeBSD.org/HAST]. === Troubleshooting HAST should generally work without issues. However, as with any other software product, there may be times when it does not work as supposed. The sources of the problems may be different, but the rule of thumb is to ensure that the time is synchronized between the nodes of the cluster. When troubleshooting HAST, the debugging level of man:hastd[8] should be increased by starting `hastd` with `-d`. This argument may be specified multiple times to further increase the debugging level. Consider also using `-F`, which starts `hastd` in the foreground. [[disks-hast-sb]] ==== Recovering from the Split-brain Condition _Split-brain_ occurs when the nodes of the cluster are unable to communicate with each other, and both are configured as primary. This is a dangerous condition because it allows both nodes to make incompatible changes to the data. This problem must be corrected manually by the system administrator. The administrator must either decide which node has more important changes, or perform the merge manually. Then, let HAST perform full synchronization of the node which has the broken data. To do this, issue these commands on the node which needs to be resynchronized: [source,shell] .... # hastctl role init test # hastctl create test # hastctl role secondary test .... diff --git a/documentation/content/en/books/handbook/firewalls/_index.adoc b/documentation/content/en/books/handbook/firewalls/_index.adoc index 60e9846bc5..9d4afc7f34 100644 --- a/documentation/content/en/books/handbook/firewalls/_index.adoc +++ b/documentation/content/en/books/handbook/firewalls/_index.adoc @@ -1,2691 +1,2691 @@ --- title: Chapter 33. Firewalls part: IV. Network Communication prev: books/handbook/network-servers next: books/handbook/advanced-networking description: "FreeBSD has three firewalls built into the base system: PF, IPFW, and IPFILTER. This chapter covers how to define packet filtering rules, the differences between the firewalls built into FreeBSD and how to use them" tags: ["firewall", "pf", "ipfw", "ipfilter", "blacklistd", "filtering"] showBookMenu: true weight: 38 path: "/books/handbook/firewalls/" --- [[firewalls]] = Firewalls :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 33 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/firewalls/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[firewalls-intro]] == Synopsis Firewalls make it possible to filter the incoming and outgoing traffic that flows through a system. A firewall can use one or more sets of "rules" to inspect network packets as they come in or go out of network connections and either allows the traffic through or blocks it. The rules of a firewall can inspect one or more characteristics of the packets such as the protocol type, source or destination host address, and source or destination port. Firewalls can enhance the security of a host or a network. They can be used to do one or more of the following: * Protect and insulate the applications, services, and machines of an internal network from unwanted traffic from the public Internet. * Limit or disable access from hosts of the internal network to services of the public Internet. * Support network address translation (NAT), which allows an internal network to use private IP addresses and share a single connection to the public Internet using either a single IP address or a shared pool of automatically assigned public addresses. FreeBSD has three firewalls built into the base system: PF, IPFW, and IPFILTER, also known as IPF. FreeBSD also provides two traffic shapers for controlling bandwidth usage: man:altq[4] and man:dummynet[4]. ALTQ has traditionally been closely tied with PF and dummynet with IPFW. Each firewall uses rules to control the access of packets to and from a FreeBSD system, although they go about it in different ways and each has a different rule syntax. FreeBSD provides multiple firewalls in order to meet the different requirements and preferences for a wide variety of users. Each user should evaluate which firewall best meets their needs. After reading this chapter, you will know: * How to define packet filtering rules. * The differences between the firewalls built into FreeBSD. * How to use and configure the PF firewall. * How to use and configure the IPFW firewall. * How to use and configure the IPFILTER firewall. Before reading this chapter, you should: * Understand basic FreeBSD and Internet concepts. [NOTE] ==== Since all firewalls are based on inspecting the values of selected packet control fields, the creator of the firewall ruleset must have an understanding of how TCP/IP works, what the different values in the packet control fields are, and how these values are used in a normal session conversation. For a good introduction, refer to http://www.ipprimer.com[Daryl's TCP/IP Primer]. ==== [[firewalls-concepts]] == Firewall Concepts A ruleset contains a group of rules which pass or block packets based on the values contained in the packet. The bi-directional exchange of packets between hosts comprises a session conversation. The firewall ruleset processes both the packets arriving from the public Internet, as well as the packets produced by the system as a response to them. Each TCP/IP service is predefined by its protocol and listening port. Packets destined for a specific service originate from the source address using an unprivileged port and target the specific service port on the destination address. All the above parameters can be used as selection criteria to create rules which will pass or block services. To lookup unknown port numbers, refer to [.filename]#/etc/services#. Alternatively, visit http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers[http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers] and do a port number lookup to find the purpose of a particular port number. Check out this link for http://web.archive.org/web/20150803024617/http://www.sans.org/security-resources/idfaq/oddports.php[port numbers used by Trojans]. FTP has two modes: active mode and passive mode. The difference is in how the data channel is acquired. Passive mode is more secure as the data channel is acquired by the ordinal ftp session requester. For a good explanation of FTP and the different modes, see http://www.slacksite.com/other/ftp.html[http://www.slacksite.com/other/ftp.html]. A firewall ruleset can be either "exclusive" or "inclusive". An exclusive firewall allows all traffic through except for the traffic matching the ruleset. An inclusive firewall does the reverse as it only allows traffic matching the rules through and blocks everything else. An inclusive firewall offers better control of the outgoing traffic, making it a better choice for systems that offer services to the public Internet. It also controls the type of traffic originating from the public Internet that can gain access to a private network. All traffic that does not match the rules is blocked and logged. Inclusive firewalls are generally safer than exclusive firewalls because they significantly reduce the risk of allowing unwanted traffic. [NOTE] ==== Unless noted otherwise, all configuration and example rulesets in this chapter create inclusive firewall rulesets. ==== Security can be tightened further using a "stateful firewall". This type of firewall keeps track of open connections and only allows traffic which either matches an existing connection or opens a new, allowed connection. Stateful filtering treats traffic as a bi-directional exchange of packets comprising a session. When state is specified on a matching rule the firewall dynamically generates internal rules for each anticipated packet being exchanged during the session. It has sufficient matching capabilities to determine if a packet is valid for a session. Any packets that do not properly fit the session template are automatically rejected. When the session completes, it is removed from the dynamic state table. Stateful filtering allows one to focus on blocking/passing new sessions. If the new session is passed, all its subsequent packets are allowed automatically and any impostor packets are automatically rejected. If a new session is blocked, none of its subsequent packets are allowed. Stateful filtering provides advanced matching abilities capable of defending against the flood of different attack methods employed by attackers. NAT stands for _Network Address Translation_. NAT function enables the private LAN behind the firewall to share a single ISP-assigned IP address, even if that address is dynamically assigned. NAT allows each computer in the LAN to have Internet access, without having to pay the ISP for multiple Internet accounts or IP addresses. NAT will automatically translate the private LAN IP address for each system on the LAN to the single public IP address as packets exit the firewall bound for the public Internet. It also performs the reverse translation for returning packets. According to RFC 1918, the following IP address ranges are reserved for private networks which will never be routed directly to the public Internet, and therefore are available for use with NAT: * `10.0.0.0/8`. * `172.16.0.0/12`. * `192.168.0.0/16`. [WARNING] ==== When working with the firewall rules, be _very careful_. Some configurations _can lock the administrator out_ of the server. To be on the safe side, consider performing the initial firewall configuration from the local console rather than doing it remotely over ssh. ==== [[firewalls-pf]] == PF Since FreeBSD 5.3, a ported version of OpenBSD's PF firewall has been included as an integrated part of the base system. PF is a complete, full-featured firewall that has optional support for ALTQ (Alternate Queuing), which provides Quality of Service (QoS). The OpenBSD Project maintains the definitive reference for PF in the http://www.openbsd.org/faq/pf/[PF FAQ]. Peter Hansteen maintains a thorough PF tutorial at http://home.nuug.no/\~peter/pf/[http://home.nuug.no/~peter/pf/]. [WARNING] ==== When reading the http://www.openbsd.org/faq/pf/[PF FAQ], keep in mind that FreeBSD's version of PF has diverged substantially from the upstream OpenBSD version over the years. Not all features work the same way on FreeBSD as they do in OpenBSD and vice versa. ==== The {freebsd-pf} is a good place to ask questions about configuring and running the PF firewall. Check the mailing list archives before asking a question as it may have already been answered. This section of the Handbook focuses on PF as it pertains to FreeBSD. It demonstrates how to enable PF and ALTQ. It also provides several examples for creating rulesets on a FreeBSD system. === Enabling PF To use PF, its kernel module must be first loaded. This section describes the entries that can be added to [.filename]#/etc/rc.conf# to enable PF. Start by adding `pf_enable=yes` to [.filename]#/etc/rc.conf#: [source,shell] .... # sysrc pf_enable=yes .... Additional options, described in man:pfctl[8], can be passed to PF when it is started. Add or change this entry in [.filename]#/etc/rc.conf# and specify any required flags between the two quotes (`""`): [.programlisting] .... pf_flags="" # additional flags for pfctl startup .... PF will not start if it cannot find its ruleset configuration file. By default, FreeBSD does not ship with a ruleset and there is no [.filename]#/etc/pf.conf#. Example rulesets can be found in [.filename]#/usr/share/examples/pf/#. If a custom ruleset has been saved somewhere else, add a line to [.filename]#/etc/rc.conf# which specifies the full path to the file: [.programlisting] .... pf_rules="/path/to/pf.conf" .... Logging support for PF is provided by man:pflog[4]. To enable logging support, add `pflog_enable=yes` to [.filename]#/etc/rc.conf#: [source,shell] .... # sysrc pflog_enable=yes .... The following lines can also be added to change the default location of the log file or to specify any additional flags to pass to man:pflog[4] when it is started: [.programlisting] .... pflog_logfile="/var/log/pflog" # where pflogd should store the logfile pflog_flags="" # additional flags for pflogd startup .... Finally, if there is a LAN behind the firewall and packets need to be forwarded for the computers on the LAN, or NAT is required, enable the following option: [.programlisting] .... gateway_enable="YES" # Enable as LAN gateway .... After saving the needed edits, PF can be started with logging support by typing: [source,shell] .... # service pf start # service pflog start .... By default, PF reads its configuration rules from [.filename]#/etc/pf.conf# and modifies, drops, or passes packets according to the rules or definitions specified in this file. The FreeBSD installation includes several sample files located in [.filename]#/usr/share/examples/pf/#. Refer to the http://www.openbsd.org/faq/pf/[PF FAQ] for complete coverage of PF rulesets. To control PF, use `pfctl`. -crossref:firewalls[pfctl] summarizes some useful options to this command. +crossref:firewalls[pfctl,.Useful `pfctl` Options] summarizes some useful options to this command. Refer to man:pfctl[8] for a description of all available options: [[pfctl]] .Useful `pfctl` Options [cols="1,1", frame="none", options="header"] |=== | Command | Purpose |`pfctl -e` |Enable PF. |`pfctl -d` |Disable PF. |`pfctl -F all -f /etc/pf.conf` |Flush all NAT, filter, state, and table rules and reload [.filename]#/etc/pf.conf#. |`pfctl -s [ rules \| nat \| states ]` |Report on the filter rules, NAT rules, or state table. |`pfctl -vnf /etc/pf.conf` |Check [.filename]#/etc/pf.conf# for errors, but do not load ruleset. |=== [TIP] ==== package:security/sudo[] is useful for running commands like `pfctl` that require elevated privileges. It can be installed from the Ports Collection. ==== To keep an eye on the traffic that passes through the PF firewall, consider installing the package:sysutils/pftop[] package or port. Once installed, pftop can be run to view a running snapshot of traffic in a format which is similar to man:top[1]. [[pf-tutorial]] === PF Rulesets This section demonstrates how to create a customized ruleset. It starts with the simplest of rulesets and builds upon its concepts using several examples to demonstrate real-world usage of PF's many features. The simplest possible ruleset is for a single machine that does not run any services and which needs access to one network, which may be the Internet. To create this minimal ruleset, edit [.filename]#/etc/pf.conf# so it looks like this: [.programlisting] .... block in all pass out all keep state .... The first rule denies all incoming traffic by default. The second rule allows connections created by this system to pass out, while retaining state information on those connections. This state information allows return traffic for those connections to pass back and should only be used on machines that can be trusted. The ruleset can be loaded with: [source,shell] .... # pfctl -e ; pfctl -f /etc/pf.conf .... In addition to keeping state, PF provides _lists_ and _macros_ which can be defined for use when creating rules. Macros can include lists and need to be defined before use. As an example, insert these lines at the very top of the ruleset: [.programlisting] .... tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }" udp_services = "{ domain }" .... PF understands port names as well as port numbers, as long as the names are listed in [.filename]#/etc/services#. This example creates two macros. The first is a list of seven TCP port names and the second is one UDP port name. Once defined, macros can be used in rules. In this example, all traffic is blocked except for the connections initiated by this system for the seven specified TCP services and the one specified UDP service: [.programlisting] .... tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }" udp_services = "{ domain }" block all pass out proto tcp to any port $tcp_services keep state pass proto udp to any port $udp_services keep state .... Even though UDP is considered to be a stateless protocol, PF is able to track some state information. For example, when a UDP request is passed which asks a name server about a domain name, PF will watch for the response to pass it back. Whenever an edit is made to a ruleset, the new rules must be loaded so they can be used: [source,shell] .... # pfctl -f /etc/pf.conf .... If there are no syntax errors, `pfctl` will not output any messages during the rule load. Rules can also be tested before attempting to load them: [source,shell] .... # pfctl -nf /etc/pf.conf .... Including `-n` causes the rules to be interpreted only, but not loaded. This provides an opportunity to correct any errors. At all times, the last valid ruleset loaded will be enforced until either PF is disabled or a new ruleset is loaded. [TIP] ==== Adding `-v` to a `pfctl` ruleset verify or load will display the fully parsed rules exactly the way they will be loaded. This is extremely useful when debugging rules. ==== [[pftut-gateway]] ==== A Simple Gateway with NAT This section demonstrates how to configure a FreeBSD system running PF to act as a gateway for at least one other machine. The gateway needs at least two network interfaces, each connected to a separate network. In this example, [.filename]#xl0# is connected to the Internet and [.filename]#xl1# is connected to the internal network. First, enable the gateway to let the machine forward the network traffic it receives on one interface to another interface. This sysctl setting will forward IPv4 packets: [source,shell] .... # sysctl net.inet.ip.forwarding=1 .... To forward IPv6 traffic, use: [source,shell] .... # sysctl net.inet6.ip6.forwarding=1 .... To enable these settings at system boot, use man:sysrc[8] to add them to [.filename]#/etc/rc.conf#: [source,shell] .... # sysrc gateway_enable=yes # sysrc ipv6_gateway_enable=yes .... Verify with `ifconfig` that both of the interfaces are up and running. Next, create the PF rules to allow the gateway to pass traffic. While the following rule allows stateful traffic from hosts of the internal network to pass to the gateway, the `to` keyword does not guarantee passage all the way from source to destination: [.programlisting] .... pass in on xl1 from xl1:network to xl0:network port $ports keep state .... That rule only lets the traffic pass in to the gateway on the internal interface. To let the packets go further, a matching rule is needed: [.programlisting] .... pass out on xl0 from xl1:network to xl0:network port $ports keep state .... While these two rules will work, rules this specific are rarely needed. For a busy network admin, a readable ruleset is a safer ruleset. The remainder of this section demonstrates how to keep the rules as simple as possible for readability. For example, those two rules could be replaced with one rule: [.programlisting] .... pass from xl1:network to any port $ports keep state .... The `interface:network` notation can be replaced with a macro to make the ruleset even more readable. For example, a `$localnet` macro could be defined as the network directly attached to the internal interface (`$xl1:network`). Alternatively, the definition of `$localnet` could be changed to an _IP address/netmask_ notation to denote a network, such as `192.168.100.1/24` for a subnet of private addresses. If required, `$localnet` could even be defined as a list of networks. Whatever the specific needs, a sensible `$localnet` definition could be used in a typical pass rule as follows: [.programlisting] .... pass from $localnet to any port $ports keep state .... The following sample ruleset allows all traffic initiated by machines on the internal network. It first defines two macros to represent the external and internal 3COM interfaces of the gateway. [NOTE] ==== For dialup users, the external interface will use [.filename]#tun0#. For an ADSL connection, specifically those using PPP over Ethernet (PPPoE), the correct external interface is [.filename]#tun0#, not the physical Ethernet interface. ==== [.programlisting] .... ext_if = "xl0" # macro for external interface - use tun0 for PPPoE int_if = "xl1" # macro for internal interface localnet = $int_if:network # ext_if IP address could be dynamic, hence ($ext_if) nat on $ext_if from $localnet to any -> ($ext_if) block all pass from { lo0, $localnet } to any keep state .... This ruleset introduces the `nat` rule which is used to handle the network address translation from the non-routable addresses inside the internal network to the IP address assigned to the external interface. The parentheses surrounding the last part of the nat rule `($ext_if)` is included when the IP address of the external interface is dynamically assigned. It ensures that network traffic runs without serious interruptions even if the external IP address changes. Note that this ruleset probably allows more traffic to pass out of the network than is needed. One reasonable setup could create this macro: [.programlisting] .... client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http, \ https, cvspserver, 2628, 5999, 8000, 8080 }" .... to use in the main pass rule: [.programlisting] .... pass inet proto tcp from $localnet to any port $client_out \ flags S/SA keep state .... A few other pass rules may be needed. This one enables SSH on the external interface: [.programlisting] .... pass in inet proto tcp to $ext_if port ssh .... This macro definition and rule allows DNS and NTP for internal clients: [.programlisting] .... udp_services = "{ domain, ntp }" pass quick inet proto { tcp, udp } to any port $udp_services keep state .... Note the `quick` keyword in this rule. Since the ruleset consists of several rules, it is important to understand the relationships between the rules in a ruleset. Rules are evaluated from top to bottom, in the sequence they are written. For each packet or connection evaluated by PF, _the last matching rule_ in the ruleset is the one which is applied. However, when a packet matches a rule which contains the `quick` keyword, the rule processing stops and the packet is treated according to that rule. This is very useful when an exception to the general rules is needed. [[pftut-ftp]] ==== Creating an FTP Proxy Configuring working FTP rules can be problematic due to the nature of the FTP protocol. FTP pre-dates firewalls by several decades and is insecure in its design. The most common points against using FTP include: * Passwords are transferred in the clear. * The protocol demands the use of at least two TCP connections (control and data) on separate ports. * When a session is established, data is communicated using randomly selected ports. All of these points present security challenges, even before considering any potential security weaknesses in client or server software. More secure alternatives for file transfer exist, such as man:sftp[1] or man:scp[1], which both feature authentication and data transfer over encrypted connections. For those situations when FTP is required, PF provides redirection of FTP traffic to a small proxy program called man:ftp-proxy[8], which is included in the base system of FreeBSD. The role of the proxy is to dynamically insert and delete rules in the ruleset, using a set of anchors, to correctly handle FTP traffic. To enable the FTP proxy, add this line to [.filename]#/etc/rc.conf#: [.programlisting] .... ftpproxy_enable="YES" .... Then start the proxy by running: [source,bash] .... # service ftp-proxy start .... For a basic configuration, three elements need to be added to [.filename]#/etc/pf.conf#. First, the anchors which the proxy will use to insert the rules it generates for the FTP sessions: [.programlisting] .... nat-anchor "ftp-proxy/*" rdr-anchor "ftp-proxy/*" .... Second, a pass rule is needed to allow FTP traffic in to the proxy. Third, redirection and NAT rules need to be defined before the filtering rules. Insert this `rdr` rule immediately after the `nat` rule: [.programlisting] .... rdr pass on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021 .... Finally, allow the redirected traffic to pass: [.programlisting] .... pass out proto tcp from $proxy to any port ftp .... where `$proxy` expands to the address the proxy daemon is bound to. Save [.filename]#/etc/pf.conf#, load the new rules, and verify from a client that FTP connections are working: [source,shell] .... # pfctl -f /etc/pf.conf .... This example covers a basic setup where the clients in the local network need to contact FTP servers elsewhere. This basic configuration should work well with most combinations of FTP clients and servers. As shown in man:ftp-proxy[8], the proxy's behavior can be changed in various ways by adding options to the `ftpproxy_flags=` line. Some clients or servers may have specific quirks that must be compensated for in the configuration, or there may be a need to integrate the proxy in specific ways such as assigning FTP traffic to a specific queue. For ways to run an FTP server protected by PF and man:ftp-proxy[8], configure a separate `ftp-proxy` in reverse mode, using `-R`, on a separate port with its own redirecting pass rule. [[pftut-icmp]] ==== Managing ICMP Many of the tools used for debugging or troubleshooting a TCP/IP network rely on the Internet Control Message Protocol (ICMP), which was designed specifically with debugging in mind. The ICMP protocol sends and receives _control messages_ between hosts and gateways, mainly to provide feedback to a sender about any unusual or difficult conditions enroute to the target host. Routers use ICMP to negotiate packet sizes and other transmission parameters in a process often referred to as _path MTU discovery_. From a firewall perspective, some ICMP control messages are vulnerable to known attack vectors. Also, letting all diagnostic traffic pass unconditionally makes debugging easier, but it also makes it easier for others to extract information about the network. For these reasons, the following rule may not be optimal: [.programlisting] .... pass inet proto icmp from any to any .... One solution is to let all ICMP traffic from the local network through while stopping all probes from outside the network: [.programlisting] .... pass inet proto icmp from $localnet to any keep state pass inet proto icmp from any to $ext_if keep state .... Additional options are available which demonstrate some of PF's flexibility. For example, rather than allowing all ICMP messages, one can specify the messages used by man:ping[8] and man:traceroute[8]. Start by defining a macro for that type of message: [.programlisting] .... icmp_types = "echoreq" .... and a rule which uses the macro: [.programlisting] .... pass inet proto icmp all icmp-type $icmp_types keep state .... If other types of ICMP packets are needed, expand `icmp_types` to a list of those packet types. Type `more /usr/src/sbin/pfctl/pfctl_parser.c` to see the list of ICMP message types supported by PF. Refer to http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml[http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml] for an explanation of each message type. Since Unix `traceroute` uses UDP by default, another rule is needed to allow Unix `traceroute`: [.programlisting] .... # allow out the default range for traceroute(8): pass out on $ext_if inet proto udp from any to any port 33433 >< 33626 keep state .... Since `TRACERT.EXE` on Microsoft Windows systems uses ICMP echo request messages, only the first rule is needed to allow network traces from those systems. Unix `traceroute` can be instructed to use other protocols as well, and will use ICMP echo request messages if `-I` is used. Check the man:traceroute[8] man page for details. [[pftut-pathmtudisc]] ===== Path MTU Discovery Internet protocols are designed to be device independent, and one consequence of device independence is that the optimal packet size for a given connection cannot always be predicted reliably. The main constraint on packet size is the _Maximum Transmission Unit_ (MTU) which sets the upper limit on the packet size for an interface. Type `ifconfig` to view the MTUs for a system's network interfaces. TCP/IP uses a process known as path MTU discovery to determine the right packet size for a connection. This process sends packets of varying sizes with the "Do not fragment" flag set, expecting an ICMP return packet of "type 3, code 4" when the upper limit has been reached. Type 3 means "destination unreachable", and code 4 is short for "fragmentation needed, but the do-not-fragment flag is set". To allow path MTU discovery in order to support connections to other MTUs, add the `destination unreachable` type to the `icmp_types` macro: [.programlisting] .... icmp_types = "{ echoreq, unreach }" .... Since the pass rule already uses that macro, it does not need to be modified to support the new ICMP type: [.programlisting] .... pass inet proto icmp all icmp-type $icmp_types keep state .... PF allows filtering on all variations of ICMP types and codes. The list of possible types and codes are documented in man:icmp[4] and man:icmp6[4]. [[pftut-tables]] ==== Using Tables Some types of data are relevant to filtering and redirection at a given time, but their definition is too long to be included in the ruleset file. PF supports the use of tables, which are defined lists that can be manipulated without needing to reload the entire ruleset, and which can provide fast lookups. Table names are always enclosed within `< >`, like this: [.programlisting] .... table { 192.168.2.0/24, !192.168.2.5 } .... In this example, the `192.168.2.0/24` network is part of the table, except for the address `192.168.2.5`, which is excluded using the `!` operator. It is also possible to load tables from files where each item is on a separate line, as seen in this example [.filename]#/etc/clients#: [.programlisting] .... 192.168.2.0/24 !192.168.2.5 .... To refer to the file, define the table like this: [.programlisting] .... table persist file "/etc/clients" .... Once the table is defined, it can be referenced by a rule: [.programlisting] .... pass inet proto tcp from to any port $client_out flags S/SA keep state .... A table's contents can be manipulated live, using `pfctl`. This example adds another network to the table: [source,shell] .... # pfctl -t clients -T add 192.168.1.0/16 .... Note that any changes made this way will take affect now, making them ideal for testing, but will not survive a power failure or reboot. To make the changes permanent, modify the definition of the table in the ruleset or edit the file that the table refers to. One can maintain the on-disk copy of the table using a man:cron[8] job which dumps the table's contents to disk at regular intervals, using a command such as `pfctl -t clients -T show >/etc/clients`. Alternatively, [.filename]#/etc/clients# can be updated with the in-memory table contents: [source,shell] .... # pfctl -t clients -T replace -f /etc/clients .... [[pftut-overload]] ==== Using Overload Tables to Protect SSH Those who run SSH on an external interface have probably seen something like this in the authentication logs: [.programlisting] .... Sep 26 03:12:34 skapet sshd[25771]: Failed password for root from 200.72.41.31 port 40992 ssh2 Sep 26 03:12:34 skapet sshd[5279]: Failed password for root from 200.72.41.31 port 40992 ssh2 Sep 26 03:12:35 skapet sshd[5279]: Received disconnect from 200.72.41.31: 11: Bye Bye Sep 26 03:12:44 skapet sshd[29635]: Invalid user admin from 200.72.41.31 Sep 26 03:12:44 skapet sshd[24703]: input_userauth_request: invalid user admin Sep 26 03:12:44 skapet sshd[24703]: Failed password for invalid user admin from 200.72.41.31 port 41484 ssh2 .... This is indicative of a brute force attack where somebody or some program is trying to discover the user name and password which will let them into the system. If external SSH access is needed for legitimate users, changing the default port used by SSH can offer some protection. However, PF provides a more elegant solution. Pass rules can contain limits on what connecting hosts can do and violators can be banished to a table of addresses which are denied some or all access. It is even possible to drop all existing connections from machines which overreach the limits. To configure this, create this table in the tables section of the ruleset: [.programlisting] .... table persist .... Then, somewhere early in the ruleset, add rules to block brute access while allowing legitimate access: [.programlisting] .... block quick from pass inet proto tcp from any to $localnet port $tcp_services \ flags S/SA keep state \ (max-src-conn 100, max-src-conn-rate 15/5, \ overload flush global) .... The part in parentheses defines the limits and the numbers should be changed to meet local requirements. It can be read as follows: `max-src-conn` is the number of simultaneous connections allowed from one host. `max-src-conn-rate` is the rate of new connections allowed from any single host (_15_) per number of seconds (_5_). `overload ` means that any host which exceeds these limits gets its address added to the `bruteforce` table. The ruleset blocks all traffic from addresses in the `bruteforce` table. Finally, `flush global` says that when a host reaches the limit, that all (`global`) of that host's connections will be terminated (`flush`). [NOTE] ==== These rules will _not_ block slow bruteforcers, as described in http://home.nuug.no/\~peter/hailmary2013/[http://home.nuug.no/~peter/hailmary2013/]. ==== This example ruleset is intended mainly as an illustration. For example, if a generous number of connections in general are wanted, but the desire is to be more restrictive when it comes to ssh, supplement the rule above with something like the one below, early on in the rule set: [.programlisting] .... pass quick proto { tcp, udp } from any to any port ssh \ flags S/SA keep state \ (max-src-conn 15, max-src-conn-rate 5/3, \ overload flush global) .... [NOTE] ==== *It May Not be Necessary to Block All Overloaders:* + It is worth noting that the overload mechanism is a general technique which does not apply exclusively to SSH, and it is not always optimal to entirely block all traffic from offenders. For example, an overload rule could be used to protect a mail service or a web service, and the overload table could be used in a rule to assign offenders to a queue with a minimal bandwidth allocation or to redirect to a specific web page. ==== Over time, tables will be filled by overload rules and their size will grow incrementally, taking up more memory. Sometimes an IP address that is blocked is a dynamically assigned one, which has since been assigned to a host who has a legitimate reason to communicate with hosts in the local network. For situations like these, pfctl provides the ability to expire table entries. For example, this command will remove `` table entries which have not been referenced for `86400` seconds: [source,shell] .... # pfctl -t bruteforce -T expire 86400 .... Similar functionality is provided by package:security/expiretable[], which removes table entries which have not been accessed for a specified period of time. Once installed, expiretable can be run to remove `` table entries older than a specified age. This example removes all entries older than 24 hours: [.programlisting] .... /usr/local/sbin/expiretable -v -d -t 24h bruteforce .... [[pftut-spamd]] ==== Protecting Against SPAM Not to be confused with the spamd daemon which comes bundled with spamassassin, package:mail/spamd[] can be configured with PF to provide an outer defense against SPAM. This spamd hooks into the PF configuration using a set of redirections. Spammers tend to send a large number of messages, and SPAM is mainly sent from a few spammer friendly networks and a large number of hijacked machines, both of which are reported to _blocklists_ fairly quickly. When an SMTP connection from an address in a blocklist is received, spamd presents its banner and immediately switches to a mode where it answers SMTP traffic one byte at a time. This technique, which is intended to waste as much time as possible on the spammer's end, is called _tarpitting_. The specific implementation which uses one byte SMTP replies is often referred to as _stuttering_. This example demonstrates the basic procedure for setting up spamd with automatically updated blocklists. Refer to the man pages which are installed with package:mail/spamd[] for more information. [.procedure] **** .Procedure: Configuring spamd . Install the package:mail/spamd[] package or port. To use spamd's greylisting features, man:fdescfs[5] must be mounted at [.filename]#/dev/fd#. Add the following line to [.filename]#/etc/fstab#: + [.programlisting] .... fdescfs /dev/fd fdescfs rw 0 0 .... + Then, mount the filesystem: + [.programlisting] .... # mount fdescfs .... . Next, edit the PF ruleset to include: + [.programlisting] .... table persist table persist rdr pass on $ext_if inet proto tcp from to \ { $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025 rdr pass on $ext_if inet proto tcp from ! to \ { $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025 .... + The two tables `` and `` are essential. SMTP traffic from an address listed in `` but not in `` is redirected to the spamd daemon listening at port 8025. . The next step is to configure spamd in [.filename]#/usr/local/etc/spamd.conf# and to add some [.filename]#rc.conf# parameters. + The installation of package:mail/spamd[] includes a sample configuration file ([.filename]#/usr/local/etc/spamd.conf.sample#) and a man page for [.filename]#spamd.conf#. Refer to these for additional configuration options beyond those shown in this example. + One of the first lines in the configuration file that does not begin with a `+#+` comment sign contains the block which defines the `all` list, which specifies the lists to use: + [.programlisting] .... all:\ :traplist:allowlist: .... + This entry adds the desired blocklists, separated by colons (`:`). To use an allowlist to subtract addresses from a blocklist, add the name of the allowlist _immediately_ after the name of that blocklist. For example: `:blocklist:allowlist:`. + This is followed by the specified blocklist's definition: + [.programlisting] .... traplist:\ :black:\ :msg="SPAM. Your address %A has sent spam within the last 24 hours":\ :method=http:\ :file=www.openbsd.org/spamd/traplist.gz .... + where the first line is the name of the blocklist and the second line specifies the list type. The `msg` field contains the message to display to blocklisted senders during the SMTP dialogue. The `method` field specifies how spamd-setup fetches the list data; supported methods are `http`, `ftp`, from a `file` in a mounted file system, and via `exec` of an external program. Finally, the `file` field specifies the name of the file spamd expects to receive. + The definition of the specified allowlist is similar, but omits the `msg` field since a message is not needed: + [.programlisting] .... allowlist:\ :white:\ :method=file:\ :file=/var/mail/allowlist.txt .... + [TIP] ==== *Choose Data Sources with Care:* + Using all the blocklists in the sample [.filename]#spamd.conf# will block large blocks of the Internet. Administrators need to edit the file to create an optimal configuration which uses applicable data sources and, when necessary, uses custom lists. ==== + Next, add this entry to [.filename]#/etc/rc.conf#. Additional flags are described in the man page specified by the comment: + [.programlisting] .... spamd_flags="-v" # use "" and see spamd-setup(8) for flags .... + When finished, reload the ruleset, start spamd by typing `service obspamd start`, and complete the configuration using `spamd-setup`. Finally, create a man:cron[8] job which calls `spamd-setup` to update the tables at reasonable intervals. **** On a typical gateway in front of a mail server, hosts will soon start getting trapped within a few seconds to several minutes. PF also supports _greylisting_, which temporarily rejects messages from unknown hosts with _45n_ codes. Messages from greylisted hosts which try again within a reasonable time are let through. Traffic from senders which are set up to behave within the limits set by RFC 1123 and RFC 2821 are immediately let through. More information about greylisting as a technique can be found at the http://www.greylisting.org/[greylisting.org] web site. The most amazing thing about greylisting, apart from its simplicity, is that it still works. Spammers and malware writers have been very slow to adapt to bypass this technique. The basic procedure for configuring greylisting is as follows: [.procedure] .Procedure: Configuring Greylisting . Make sure that man:fdescfs[5] is mounted as described in Step 1 of the previous Procedure. . To run spamd in greylisting mode, add this line to [.filename]#/etc/rc.conf#: + [.programlisting] .... spamd_grey="YES" # use spamd greylisting if YES .... + Refer to the spamd man page for descriptions of additional related parameters. . To complete the greylisting setup: + [.programlisting] .... # service obspamd restart # service obspamlogd start .... Behind the scenes, the spamdb database tool and the spamlogd whitelist updater perform essential functions for the greylisting feature. spamdb is the administrator's main interface to managing the block, grey, and allow lists via the contents of the [.filename]#/var/db/spamdb# database. [[pftut-hygiene]] ==== Network Hygiene This section describes how `block-policy`, `scrub`, and `antispoof` can be used to make the ruleset behave sanely. The `block-policy` is an option which can be set in the `options` part of the ruleset, which precedes the redirection and filtering rules. This option determines which feedback, if any, PF sends to hosts that are blocked by a rule. The option has two possible values: `drop` drops blocked packets with no feedback, and `return` returns a status code such as `Connection refused`. If not set, the default policy is `drop`. To change the `block-policy`, specify the desired value: [.programlisting] .... set block-policy return .... In PF, `scrub` is a keyword which enables network packet normalization. This process reassembles fragmented packets and drops TCP packets that have invalid flag combinations. Enabling `scrub` provides a measure of protection against certain kinds of attacks based on incorrect handling of packet fragments. A number of options are available, but the simplest form is suitable for most configurations: [.programlisting] .... scrub in all .... Some services, such as NFS, require specific fragment handling options. Refer to https://home.nuug.no/\~peter/pf/en/scrub.html[https://home.nuug.no/~peter/pf/en/scrub.html] for more information. This example reassembles fragments, clears the "do not fragment" bit, and sets the maximum segment size to 1440 bytes: [.programlisting] .... scrub in all fragment reassemble no-df max-mss 1440 .... The `antispoof` mechanism protects against activity from spoofed or forged IP addresses, mainly by blocking packets appearing on interfaces and in directions which are logically not possible. These rules weed out spoofed traffic coming in from the rest of the world as well as any spoofed packets which originate in the local network: [.programlisting] .... antispoof for $ext_if antispoof for $int_if .... [[pftut-unrouteables]] ==== Handling Non-Routable Addresses Even with a properly configured gateway to handle network address translation, one may have to compensate for other people's misconfigurations. A common misconfiguration is to let traffic with non-routable addresses out to the Internet. Since traffic from non-routeable addresses can play a part in several DoS attack techniques, consider explicitly blocking traffic from non-routeable addresses from entering the network through the external interface. In this example, a macro containing non-routable addresses is defined, then used in blocking rules. Traffic to and from these addresses is quietly dropped on the gateway's external interface. [.programlisting] .... martians = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, \ 10.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24, \ 0.0.0.0/8, 240.0.0.0/4 }" block drop in quick on $ext_if from $martians to any block drop out quick on $ext_if from any to $martians .... === Enabling ALTQ On FreeBSD, ALTQ can be used with PF to provide Quality of Service (QOS). Once ALTQ is enabled, queues can be defined in the ruleset which determine the processing priority of outbound packets. Before enabling ALTQ, refer to man:altq[4] to determine if the drivers for the network cards installed on the system support it. ALTQ is not available as a loadable kernel module. If the system's interfaces support ALTQ, create a custom kernel using the instructions in crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]. The following kernel options are available. The first is needed to enable ALTQ. At least one of the other options is necessary to specify the queueing scheduler algorithm: [.programlisting] .... options ALTQ options ALTQ_CBQ # Class Based Queuing (CBQ) options ALTQ_RED # Random Early Detection (RED) options ALTQ_RIO # RED In/Out options ALTQ_HFSC # Hierarchical Packet Scheduler (HFSC) options ALTQ_PRIQ # Priority Queuing (PRIQ) .... The following scheduler algorithms are available: CBQ:: Class Based Queuing (CBQ) is used to divide a connection's bandwidth into different classes or queues to prioritize traffic based on filter rules. RED:: Random Early Detection (RED) is used to avoid network congestion by measuring the length of the queue and comparing it to the minimum and maximum thresholds for the queue. When the queue is over the maximum, all new packets are randomly dropped. RIO:: In Random Early Detection In and Out (RIO) mode, RED maintains multiple average queue lengths and multiple threshold values, one for each QOS level. HFSC:: Hierarchical Fair Service Curve Packet Scheduler (HFSC) is described in http://www-2.cs.cmu.edu/\~hzhang/HFSC/main.html[http://www-2.cs.cmu.edu/~hzhang/HFSC/main.html]. PRIQ:: Priority Queuing (PRIQ) always passes traffic that is in a higher queue first. More information about the scheduling algorithms and example rulesets are available at the https://web.archive.org/web/20151109213426/http://www.openbsd.org/faq/pf/queueing.html[OpenBSD's web archive]. [[firewalls-ipfw]] == IPFW IPFW is a stateful firewall written for FreeBSD which supports both IPv4 and IPv6. It is comprised of several components: the kernel firewall filter rule processor and its integrated packet accounting facility, the logging facility, NAT, the man:dummynet[4] traffic shaper, a forward facility, a bridge facility, and an ipstealth facility. FreeBSD provides a sample ruleset in [.filename]#/etc/rc.firewall# which defines several firewall types for common scenarios to assist novice users in generating an appropriate ruleset. IPFW provides a powerful syntax which advanced users can use to craft customized rulesets that meet the security requirements of a given environment. This section describes how to enable IPFW, provides an overview of its rule syntax, and demonstrates several rulesets for common configuration scenarios. [[firewalls-ipfw-enable]] === Enabling IPFW IPFW is included in the basic FreeBSD install as a kernel loadable module, meaning that a custom kernel is not needed in order to enable IPFW. For those users who wish to statically compile IPFW support into a custom -kernel, see crossref:firewalls[firewalls-ipfw-kernelconfig]. +kernel, see crossref:firewalls[firewalls-ipfw-kernelconfig, IPFW Kernel Options]. To configure the system to enable IPFW at boot time, add `firewall_enable="YES"` to [.filename]#/etc/rc.conf#: [source,shell] .... # sysrc firewall_enable="YES" .... To use one of the default firewall types provided by FreeBSD, add another line which specifies the type: [source,shell] .... # sysrc firewall_type="open" .... The available types are: * `open`: passes all traffic. * `client`: protects only this machine. * `simple`: protects the whole network. * `closed`: entirely disables IP traffic except for the loopback interface. * `workstation`: protects only this machine using stateful rules. * `UNKNOWN`: disables the loading of firewall rules. * [.filename]#filename#: full path of the file containing the firewall ruleset. If `firewall_type` is set to either `client` or `simple`, modify the default rules found in [.filename]#/etc/rc.firewall# to fit the configuration of the system. Note that the `filename` type is used to load a custom ruleset. An alternate way to load a custom ruleset is to set the `firewall_script` variable to the absolute path of an _executable script_ that includes IPFW commands. The examples used in this section assume that the `firewall_script` is set to [.filename]#/etc/ipfw.rules#: [source,shell] .... # sysrc firewall_script="/etc/ipfw.rules" .... To enable logging through man:syslogd[8], include this line: [source,shell] .... # sysrc firewall_logging="YES" .... [WARNING] ==== Only firewall rules with the `log` option will be logged. The default rules do not include this option and it must be manually added. Therefore it is advisable that the default ruleset is edited for logging. In addition, log rotation may be desired if the logs are stored in a separate file. ==== There is no [.filename]#/etc/rc.conf# variable to set logging limits. To limit the number of times a rule is logged per connection attempt, specify the number using this line in [.filename]#/etc/sysctl.conf#: [source,shell] .... # echo "net.inet.ip.fw.verbose_limit=5" >> /etc/sysctl.conf .... To enable logging through a dedicated interface named `ipfw0`, add this line to [.filename]#/etc/rc.conf# instead: [source,shell] .... # sysrc firewall_logif="YES" .... Then use tcpdump to see what is being logged: [source,shell] .... # tcpdump -t -n -i ipfw0 .... [TIP] ==== There is no overhead due to logging unless tcpdump is attached. ==== After saving the needed edits, start the firewall. To enable logging limits now, also set the `sysctl` value specified above: [source,shell] .... # service ipfw start # sysctl net.inet.ip.fw.verbose_limit=5 .... [[firewalls-ipfw-rules]] === IPFW Rule Syntax When a packet enters the IPFW firewall, it is compared against the first rule in the ruleset and progresses one rule at a time, moving from top to bottom in sequence. When the packet matches the selection parameters of a rule, the rule's action is executed and the search of the ruleset terminates for that packet. This is referred to as "first match wins". If the packet does not match any of the rules, it gets caught by the mandatory IPFW default rule number 65535, which denies all packets and silently discards them. However, if the packet matches a rule that contains the `count`, `skipto`, or `tee` keywords, the search continues. Refer to man:ipfw[8] for details on how these keywords affect rule processing. When creating an IPFW rule, keywords must be written in the following order. Some keywords are mandatory while other keywords are optional. The words shown in uppercase represent a variable and the words shown in lowercase must precede the variable that follows it. The `+#+` symbol is used to mark the start of a comment and may appear at the end of a rule or on its own line. Blank lines are ignored. `_CMD RULE_NUMBER set SET_NUMBER ACTION log LOG_AMOUNT PROTO from SRC SRC_PORT to DST DST_PORT OPTIONS_` This section provides an overview of these keywords and their options. It is not an exhaustive list of every possible option. Refer to man:ipfw[8] for a complete description of the rule syntax that can be used when creating IPFW rules. CMD:: Every rule must start with `ipfw add`. RULE_NUMBER:: Each rule is associated with a number from `1` to `65534`. The number is used to indicate the order of rule processing. Multiple rules can have the same number, in which case they are applied according to the order in which they have been added. SET_NUMBER:: Each rule is associated with a set number from `0` to `31`. Sets can be individually disabled or enabled, making it possible to quickly add or delete a set of rules. If a SET_NUMBER is not specified, the rule will be added to set `0`. ACTION:: A rule can be associated with one of the following actions. The specified action will be executed when the packet matches the selection criterion of the rule. + `allow | accept | pass | permit`: these keywords are equivalent and allow packets that match the rule. + `check-state`: checks the packet against the dynamic state table. If a match is found, execute the action associated with the rule which generated this dynamic rule, otherwise move to the next rule. A `check-state` rule does not have selection criterion. If no `check-state` rule is present in the ruleset, the dynamic rules table is checked at the first `keep-state` or `limit` rule. + `count`: updates counters for all packets that match the rule. The search continues with the next rule. + `deny | drop`: either word silently discards packets that match this rule. + Additional actions are available. Refer to man:ipfw[8] for details. LOG_AMOUNT:: When a packet matches a rule with the `log` keyword, a message will be logged to man:syslogd[8] with a facility name of `SECURITY`. Logging only occurs if the number of packets logged for that particular rule does not exceed a specified LOG_AMOUNT. If no LOG_AMOUNT is specified, the limit is taken from the value of `net.inet.ip.fw.verbose_limit`. A value of zero removes the logging limit. Once the limit is reached, logging can be re-enabled by clearing the logging counter or the packet counter for that rule, using `ipfw resetlog`. + [NOTE] ==== Logging is done after all other packet matching conditions have been met, and before performing the final action on the packet. The administrator decides which rules to enable logging on. ==== PROTO:: This optional value can be used to specify any protocol name or number found in [.filename]#/etc/protocols#. SRC:: The `from` keyword must be followed by the source address or a keyword that represents the source address. An address can be represented by `any`, `me` (any address configured on an interface on this system), `me6`, (any IPv6 address configured on an interface on this system), or `table` followed by the number of a lookup table which contains a list of addresses. When specifying an IP address, it can be optionally followed by its CIDR mask or subnet mask. For example, `1.2.3.4/25` or `1.2.3.4:255.255.255.128`. SRC_PORT:: An optional source port can be specified using the port number or name from [.filename]#/etc/services#. DST:: The `to` keyword must be followed by the destination address or a keyword that represents the destination address. The same keywords and addresses described in the SRC section can be used to describe the destination. DST_PORT:: An optional destination port can be specified using the port number or name from [.filename]#/etc/services#. OPTIONS:: Several keywords can follow the source and destination. As the name suggests, OPTIONS are optional. Commonly used options include `in` or `out`, which specify the direction of packet flow, `icmptypes` followed by the type of ICMP message, and `keep-state`. + When a `keep-state` rule is matched, the firewall will create a dynamic rule which matches bidirectional traffic between the source and destination addresses and ports using the same protocol. + The dynamic rules facility is vulnerable to resource depletion from a SYN-flood attack which would open a huge number of dynamic rules. To counter this type of attack with IPFW, use `limit`. This option limits the number of simultaneous sessions by checking the open dynamic rules, counting the number of times this rule and IP address combination occurred. If this count is greater than the value specified by `limit`, the packet is discarded. + Dozens of OPTIONS are available. Refer to man:ipfw[8] for a description of each available option. === Example Ruleset This section demonstrates how to create an example stateful firewall ruleset script named [.filename]#/etc/ipfw.rules#. In this example, all connection rules use `in` or `out` to clarify the direction. They also use `via` _interface-name_ to specify the interface the packet is traveling over. [NOTE] ==== When first creating or testing a firewall ruleset, consider temporarily setting this tunable: [.programlisting] .... net.inet.ip.fw.default_to_accept="1" .... This sets the default policy of man:ipfw[8] to be more permissive than the default `deny ip from any to any`, making it slightly more difficult to get locked out of the system right after a reboot. ==== The firewall script begins by indicating that it is a Bourne shell script and flushes any existing rules. It then creates the `cmd` variable so that `ipfw add` does not have to be typed at the beginning of every rule. It also defines the `pif` variable which represents the name of the interface that is attached to the Internet. [.programlisting] .... #!/bin/sh # Flush out the list before we begin. ipfw -q -f flush # Set rules command prefix cmd="ipfw -q add" pif="dc0" # interface name of NIC attached to Internet .... The first two rules allow all traffic on the trusted internal interface and on the loopback interface: [.programlisting] .... # Change xl0 to LAN NIC interface name $cmd 00005 allow all from any to any via xl0 # No restrictions on Loopback Interface $cmd 00010 allow all from any to any via lo0 .... The next rule allows the packet through if it matches an existing entry in the dynamic rules table: [.programlisting] .... $cmd 00101 check-state .... The next set of rules defines which stateful connections internal systems can create to hosts on the Internet: [.programlisting] .... # Allow access to public DNS # Replace x.x.x.x with the IP address of a public DNS server # and repeat for each DNS server in /etc/resolv.conf $cmd 00110 allow tcp from any to x.x.x.x 53 out via $pif setup keep-state $cmd 00111 allow udp from any to x.x.x.x 53 out via $pif keep-state # Allow access to ISP's DHCP server for cable/DSL configurations. # Use the first rule and check log for IP address. # Then, uncomment the second rule, input the IP address, and delete the first rule $cmd 00120 allow log udp from any to any 67 out via $pif keep-state #$cmd 00120 allow udp from any to x.x.x.x 67 out via $pif keep-state # Allow outbound HTTP and HTTPS connections $cmd 00200 allow tcp from any to any 80 out via $pif setup keep-state $cmd 00220 allow tcp from any to any 443 out via $pif setup keep-state # Allow outbound email connections $cmd 00230 allow tcp from any to any 25 out via $pif setup keep-state $cmd 00231 allow tcp from any to any 110 out via $pif setup keep-state # Allow outbound ping $cmd 00250 allow icmp from any to any out via $pif keep-state # Allow outbound NTP $cmd 00260 allow udp from any to any 123 out via $pif keep-state # Allow outbound SSH $cmd 00280 allow tcp from any to any 22 out via $pif setup keep-state # deny and log all other outbound connections $cmd 00299 deny log all from any to any out via $pif .... The next set of rules controls connections from Internet hosts to the internal network. It starts by denying packets typically associated with attacks and then explicitly allows specific types of connections. All the authorized services that originate from the Internet use `limit` to prevent flooding. [.programlisting] .... # Deny all inbound traffic from non-routable reserved address spaces $cmd 00300 deny all from 192.168.0.0/16 to any in via $pif #RFC 1918 private IP $cmd 00301 deny all from 172.16.0.0/12 to any in via $pif #RFC 1918 private IP $cmd 00302 deny all from 10.0.0.0/8 to any in via $pif #RFC 1918 private IP $cmd 00303 deny all from 127.0.0.0/8 to any in via $pif #loopback $cmd 00304 deny all from 0.0.0.0/8 to any in via $pif #loopback $cmd 00305 deny all from 169.254.0.0/16 to any in via $pif #DHCP auto-config $cmd 00306 deny all from 192.0.2.0/24 to any in via $pif #reserved for docs $cmd 00307 deny all from 204.152.64.0/23 to any in via $pif #Sun cluster interconnect $cmd 00308 deny all from 224.0.0.0/3 to any in via $pif #Class D & E multicast # Deny public pings $cmd 00310 deny icmp from any to any in via $pif # Deny ident $cmd 00315 deny tcp from any to any 113 in via $pif # Deny all Netbios services. $cmd 00320 deny tcp from any to any 137 in via $pif $cmd 00321 deny tcp from any to any 138 in via $pif $cmd 00322 deny tcp from any to any 139 in via $pif $cmd 00323 deny tcp from any to any 81 in via $pif # Deny fragments $cmd 00330 deny all from any to any frag in via $pif # Deny ACK packets that did not match the dynamic rule table $cmd 00332 deny tcp from any to any established in via $pif # Allow traffic from ISP's DHCP server. # Replace x.x.x.x with the same IP address used in rule 00120. #$cmd 00360 allow udp from any to x.x.x.x 67 in via $pif keep-state # Allow HTTP connections to internal web server $cmd 00400 allow tcp from any to me 80 in via $pif setup limit src-addr 2 # Allow inbound SSH connections $cmd 00410 allow tcp from any to me 22 in via $pif setup limit src-addr 2 # Reject and log all other incoming connections $cmd 00499 deny log all from any to any in via $pif .... The last rule logs all packets that do not match any of the rules in the ruleset: [.programlisting] .... # Everything else is denied and logged $cmd 00999 deny log all from any to any .... [[in-kernel-nat]] === In-kernel NAT FreeBSD's IPFW firewall has two implementations of NAT: the userland implementation man:natd[8], and the more recent in-kernel NAT implementation. Both work in conjunction with IPFW to provide network address translation. This can be used to provide an Internet Connection Sharing solution so that several internal computers can connect to the Internet using a single public IP address. To do this, the FreeBSD machine connected to the Internet must act as a gateway. This system must have two NICs, where one is connected to the Internet and the other is connected to the internal LAN. Each machine connected to the LAN should be assigned an IP address in the private network space, as defined by https://www.ietf.org/rfc/rfc1918.txt[RFC 1918]. Some additional configuration is needed in order to enable the in-kernel NAT facility of IPFW. To enable in-kernel NAT support at boot time, the following must be set in [.filename]#/etc/rc.conf#: [.programlisting] .... gateway_enable="YES" firewall_enable="YES" firewall_nat_enable="YES" .... [NOTE] ==== When `firewall_nat_enable` is set but `firewall_enable` is not, it will have no effect and do nothing. This is because the in-kernel NAT implementation is only compatible with IPFW. ==== When the ruleset contains stateful rules, the positioning of the NAT rule is critical and the `skipto` action is used. The `skipto` action requires a rule number so that it knows which rule to jump to. The example below builds upon the firewall ruleset shown in the previous section. It adds some additional entries and modifies some existing rules in order to configure the firewall for in-kernel NAT. It starts by adding some additional variables which represent the rule number to skip to, the `keep-state` option, and a list of TCP ports which will be used to reduce the number of rules. [.programlisting] .... #!/bin/sh ipfw -q -f flush cmd="ipfw -q add" skip="skipto 1000" pif=dc0 ks="keep-state" good_tcpo="22,25,37,53,80,443,110" .... With in-kernel NAT it is necessary to disable TCP segmentation offloading (TSO) due to the architecture of man:libalias[3], a library implemented as a kernel module to provide the in-kernel NAT facility of IPFW. TSO can be disabled on a per network interface basis using man:ifconfig[8] or on a system wide basis using man:sysctl[8]. To disable TSO system wide, the following must be set it [.filename]#/etc/sysctl.conf#: [.programlisting] .... net.inet.tcp.tso="0" .... A NAT instance will also be configured. It is possible to have multiple NAT instances each with their own configuration. For this example only one NAT instance is needed, NAT instance number 1. The configuration can take a few options such as: `if` which indicates the public interface, `same_ports` which takes care that aliased ports and local port numbers are mapped the same, `unreg_only` will result in only unregistered (private) address spaces to be processed by the NAT instance, and `reset` which will help to keep a functioning NAT instance even when the public IP address of the IPFW machine changes. For all possible options that can be passed to a single NAT instance configuration consult man:ipfw[8]. When configuring a stateful NATing firewall, it is necessary to allow translated packets to be reinjected in the firewall for further processing. This can be achieved by disabling `one_pass` behavior at the start of the firewall script. [.programlisting] .... ipfw disable one_pass ipfw -q nat 1 config if $pif same_ports unreg_only reset .... The inbound NAT rule is inserted _after_ the two rules which allow all traffic on the trusted and loopback interfaces and after the reassemble rule but _before_ the `check-state` rule. It is important that the rule number selected for this NAT rule, in this example `100`, is higher than the first three rules and lower than the `check-state` rule. Furthermore, because of the behavior of in-kernel NAT it is advised to place a reassemble rule just before the first NAT rule and after the rules that allow traffic on trusted interface. Normally, IP fragmentation should not happen, but when dealing with IPSEC/ESP/GRE tunneling traffic it might and the reassembling of fragments is necessary before handing the complete packet over to the in-kernel NAT facility. [NOTE] ==== The reassemble rule was not needed with userland man:natd[8] because the internal workings of the IPFW `divert` action already takes care of reassembling packets before delivery to the socket as also stated in man:ipfw[8]. The NAT instance and rule number used in this example does not match with the default NAT instance and rule number created by [.filename]#rc.firewall#. [.filename]#rc.firewall# is a script that sets up the default firewall rules present in FreeBSD. ==== [.programlisting] .... $cmd 005 allow all from any to any via xl0 # exclude LAN traffic $cmd 010 allow all from any to any via lo0 # exclude loopback traffic $cmd 099 reass all from any to any in # reassemble inbound packets $cmd 100 nat 1 ip from any to any in via $pif # NAT any inbound packets # Allow the packet through if it has an existing entry in the dynamic rules table $cmd 101 check-state .... The outbound rules are modified to replace the `allow` action with the `$skip` variable, indicating that rule processing will continue at rule `1000`. The seven `tcp` rules have been replaced by rule `125` as the `$good_tcpo` variable contains the seven allowed outbound ports. [NOTE] ==== Remember that IPFW's performance is largely determined by the number of rules present in the ruleset. ==== [.programlisting] .... # Authorized outbound packets $cmd 120 $skip udp from any to x.x.x.x 53 out via $pif $ks $cmd 121 $skip udp from any to x.x.x.x 67 out via $pif $ks $cmd 125 $skip tcp from any to any $good_tcpo out via $pif setup $ks $cmd 130 $skip icmp from any to any out via $pif $ks .... The inbound rules remain the same, except for the very last rule which removes the `via $pif` in order to catch both inbound and outbound rules. The NAT rule must follow this last outbound rule, must have a higher number than that last rule, and the rule number must be referenced by the `skipto` action. In this ruleset, rule number `1000` handles passing all packets to our configured instance for NAT processing. The next rule allows any packet which has undergone NAT processing to pass. [.programlisting] .... $cmd 999 deny log all from any to any $cmd 1000 nat 1 ip from any to any out via $pif # skipto location for outbound stateful rules $cmd 1001 allow ip from any to any .... In this example, rules `100`, `101`, `125`, `1000`, and `1001` control the address translation of the outbound and inbound packets so that the entries in the dynamic state table always register the private LANIP address. Consider an internal web browser which initializes a new outbound HTTP session over port 80. When the first outbound packet enters the firewall, it does not match rule `100` because it is headed out rather than in. It passes rule `101` because this is the first packet and it has not been posted to the dynamic state table yet. The packet finally matches rule `125` as it is outbound on an allowed port and has a source IP address from the internal LAN. On matching this rule, two actions take place. First, the `keep-state` action adds an entry to the dynamic state table and the specified action, `skipto rule 1000`, is executed. Next, the packet undergoes NAT and is sent out to the Internet. This packet makes its way to the destination web server, where a response packet is generated and sent back. This new packet enters the top of the ruleset. It matches rule `100` and has its destination IP address mapped back to the original internal address. It then is processed by the `check-state` rule, is found in the table as an existing session, and is released to the LAN. On the inbound side, the ruleset has to deny bad packets and allow only authorized services. A packet which matches an inbound rule is posted to the dynamic state table and the packet is released to the LAN. The packet generated as a response is recognized by the `check-state` rule as belonging to an existing session. It is then sent to rule `1000` to undergo NAT before being released to the outbound interface. [NOTE] ==== Transitioning from userland man:natd[8] to in-kernel NAT might appear seamless at first but there is small catch. When using the GENERIC kernel, IPFW will load the [.filename]#libalias.ko# kernel module, when `firewall_nat_enable` is enabled in [.filename]#/etc/rc.conf#. The [.filename]#libalias.ko# kernel module only provides basic NAT functionality, whereas the userland implementation man:natd[8] has all NAT functionality available in its userland library without any extra configuration. All functionality refers to the following kernel modules that can additionally be loaded when needed besides the standard [.filename]#libalias.ko# kernel module: [.filename]#alias_ftp.ko#, [.filename]#alias_bbt.ko#, [.filename]#skinny.ko#, [.filename]#irc.ko#, [.filename]#alias_pptp.ko# and [.filename]#alias_smedia.ko# using the `kld_list` directive in [.filename]#/etc/rc.conf#. If a custom kernel is used, the full functionality of the userland library can be compiled in, in the kernel, using the `options LIBALIAS`. ==== ==== Port Redirection The drawback with NAT in general is that the LAN clients are not accessible from the Internet. Clients on the LAN can make outgoing connections to the world but cannot receive incoming ones. This presents a problem if trying to run Internet services on one of the LAN client machines. A simple way around this is to redirect selected Internet ports on the NAT providing machine to a LAN client. For example, an IRC server runs on client `A` and a web server runs on client `B`. For this to work properly, connections received on ports 6667 (IRC) and 80 (HTTP) must be redirected to the respective machines. With in-kernel NAT all configuration is done in the NAT instance configuration. For a full list of options that an in-kernel NAT instance can use, consult man:ipfw[8]. The IPFW syntax follows the syntax of natd. The syntax for `redirect_port` is as follows: [.programlisting] .... redirect_port proto targetIP:targetPORT[-targetPORT] [aliasIP:]aliasPORT[-aliasPORT] [remoteIP[:remotePORT[-remotePORT]]] .... To configure the above example setup, the arguments should be: [.programlisting] .... redirect_port tcp 192.168.0.2:6667 6667 redirect_port tcp 192.168.0.3:80 80 .... After adding these arguments to the configuration of NAT instance 1 in the above ruleset, the TCP ports will be port forwarded to the LAN client machines running the IRC and HTTP services. [.programlisting] .... ipfw -q nat 1 config if $pif same_ports unreg_only reset \ redirect_port tcp 192.168.0.2:6667 6667 \ redirect_port tcp 192.168.0.3:80 80 .... Port ranges over individual ports can be indicated with `redirect_port`. For example, _tcp 192.168.0.2:2000-3000 2000-3000_ would redirect all connections received on ports 2000 to 3000 to ports 2000 to 3000 on client `A`. ==== Address Redirection Address redirection is useful if more than one IP address is available. Each LAN client can be assigned its own external IP address by man:ipfw[8], which will then rewrite outgoing packets from the LAN clients with the proper external IP address and redirects all traffic incoming on that particular IP address back to the specific LAN client. This is also known as static NAT. For example, if IP addresses `128.1.1.1`, `128.1.1.2`, and `128.1.1.3` are available, `128.1.1.1` can be used as the man:ipfw[8] machine's external IP address, while `128.1.1.2` and `128.1.1.3` are forwarded back to LAN clients `A` and `B`. The `redirect_addr` syntax is as below, where `localIP` is the internal IP address of the LAN client, and `publicIP` the external IP address corresponding to the LAN client. [.programlisting] .... redirect_addr localIP publicIP .... In the example, the arguments would read: [.programlisting] .... redirect_addr 192.168.0.2 128.1.1.2 redirect_addr 192.168.0.3 128.1.1.3 .... Like `redirect_port`, these arguments are placed in a NAT instance configuration. With address redirection, there is no need for port redirection, as all data received on a particular IP address is redirected. The external IP addresses on the man:ipfw[8] machine must be active and aliased to the external interface. Refer to man:rc.conf[5] for details. ==== Userspace NAT Let us start with a statement: the userspace NAT implementation: man:natd[8], has more overhead than in-kernel NAT. For man:natd[8] to translate packets, the packets have to be copied from the kernel to userspace and back which brings in extra overhead that is not present with in-kernel NAT. To enable the userspace NAT daemon man:natd[8] at boot time, the following is a minimum configuration in [.filename]#/etc/rc.conf#. Where `natd_interface` is set to the name of the NIC attached to the Internet. The man:rc[8] script of man:natd[8] will automatically check if a dynamic IP address is used and configure itself to handle that. [.programlisting] .... gateway_enable="YES" natd_enable="YES" natd_interface="rl0" .... In general, the above ruleset as explained for in-kernel NAT can also be used together with man:natd[8]. The exceptions are the configuration of the in-kernel NAT instance `(ipfw -q nat 1 config ...)` which is not needed together with reassemble rule 99 because its functionality is included in the `divert` action. Rule number 100 and 1000 will have to change sligthly as shown below. [.programlisting] .... $cmd 100 divert natd ip from any to any in via $pif $cmd 1000 divert natd ip from any to any out via $pif .... To configure port or address redirection, a similar syntax as with in-kernel NAT is used. Although, now, instead of specifying the configuration in our ruleset script like with in-kernel NAT, configuration of man:natd[8] is best done in a configuration file. To do this, an extra flag must be passed via [.filename]#/etc/rc.conf# which specifies the path of the configuration file. [.programlisting] .... natd_flags="-f /etc/natd.conf" .... [NOTE] ==== The specified file must contain a list of configuration options, one per line. For more information about the configuration file and possible variables, consult man:natd[8]. Below are two example entries, one per line: [.programlisting] .... redirect_port tcp 192.168.0.2:6667 6667 redirect_addr 192.168.0.3 128.1.1.3 .... ==== [[firewalls-ipfw-cmd]] === The IPFW Command `ipfw` can be used to make manual, single rule additions or deletions to the active firewall while it is running. The problem with using this method is that all the changes are lost when the system reboots. It is recommended to instead write all the rules in a file and to use that file to load the rules at boot time and to replace the currently running firewall rules whenever that file changes. `ipfw` is a useful way to display the running firewall rules to the console screen. The IPFW accounting facility dynamically creates a counter for each rule that counts each packet that matches the rule. During the process of testing a rule, listing the rule with its counter is one way to determine if the rule is functioning as expected. To list all the running rules in sequence: [source,shell] .... # ipfw list .... To list all the running rules with a time stamp of when the last time the rule was matched: [source,shell] .... # ipfw -t list .... The next example lists accounting information and the packet count for matched rules along with the rules themselves. The first column is the rule number, followed by the number of matched packets and bytes, followed by the rule itself. [source,shell] .... # ipfw -a list .... To list dynamic rules in addition to static rules: [source,shell] .... # ipfw -d list .... To also show the expired dynamic rules: [source,shell] .... # ipfw -d -e list .... To zero the counters: [source,shell] .... # ipfw zero .... To zero the counters for just the rule with number _NUM_: [source,shell] .... # ipfw zero NUM .... ==== Logging Firewall Messages Even with the logging facility enabled, IPFW will not generate any rule logging on its own. The firewall administrator decides which rules in the ruleset will be logged, and adds the `log` keyword to those rules. Normally only deny rules are logged. It is customary to duplicate the "ipfw default deny everything" rule with the `log` keyword included as the last rule in the ruleset. This way, it is possible to see all the packets that did not match any of the rules in the ruleset. Logging is a two edged sword. If one is not careful, an over abundance of log data or a DoS attack can fill the disk with log files. Log messages are not only written to syslogd, but also are displayed on the root console screen and soon become annoying. The `IPFIREWALL_VERBOSE_LIMIT=5` kernel option limits the number of consecutive messages sent to man:syslogd[8], concerning the packet matching of a given rule. When this option is enabled in the kernel, the number of consecutive messages concerning a particular rule is capped at the number specified. There is nothing to be gained from 200 identical log messages. With this option set to five, five consecutive messages concerning a particular rule would be logged to syslogd and the remainder identical consecutive messages would be counted and posted to syslogd with a phrase like the following: [.programlisting] .... last message repeated 45 times .... All logged packets messages are written by default to [.filename]#/var/log/security#, which is defined in [.filename]#/etc/syslog.conf#. [[firewalls-ipfw-rules-script]] ==== Building a Rule Script Most experienced IPFW users create a file containing the rules and code them in a manner compatible with running them as a script. The major benefit of doing this is the firewall rules can be refreshed in mass without the need of rebooting the system to activate them. This method is convenient in testing new rules as the procedure can be executed as many times as needed. Being a script, symbolic substitution can be used for frequently used values to be substituted into multiple rules. This example script is compatible with the syntax used by the man:sh[1], man:csh[1], and man:tcsh[1] shells. Symbolic substitution fields are prefixed with a dollar sign ($). Symbolic fields do not have the $ prefix. The value to populate the symbolic field must be enclosed in double quotes (""). Start the rules file like this: [.programlisting] .... ############### start of example ipfw rules script ############# # ipfw -q -f flush # Delete all rules # Set defaults oif="tun0" # out interface odns="192.0.2.11" # ISP's DNS server IP address cmd="ipfw -q add " # build rule prefix ks="keep-state" # just too lazy to key this each time $cmd 00500 check-state $cmd 00502 deny all from any to any frag $cmd 00501 deny tcp from any to any established $cmd 00600 allow tcp from any to any 80 out via $oif setup $ks $cmd 00610 allow tcp from any to $odns 53 out via $oif setup $ks $cmd 00611 allow udp from any to $odns 53 out via $oif $ks ################### End of example ipfw rules script ############ .... The rules are not important as the focus of this example is how the symbolic substitution fields are populated. If the above example was in [.filename]#/etc/ipfw.rules#, the rules could be reloaded by the following command: [source,shell] .... # sh /etc/ipfw.rules .... [.filename]#/etc/ipfw.rules# can be located anywhere and the file can have any name. The same thing could be accomplished by running these commands by hand: [source,shell] .... # ipfw -q -f flush # ipfw -q add check-state # ipfw -q add deny all from any to any frag # ipfw -q add deny tcp from any to any established # ipfw -q add allow tcp from any to any 80 out via tun0 setup keep-state # ipfw -q add allow tcp from any to 192.0.2.11 53 out via tun0 setup keep-state # ipfw -q add 00611 allow udp from any to 192.0.2.11 53 out via tun0 keep-state .... [[firewalls-ipfw-kernelconfig]] === IPFW Kernel Options In order to statically compile IPFW support into a custom kernel, refer to the instructions in crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]. The following options are available for the custom kernel configuration file: [.programlisting] .... options IPFIREWALL # enables IPFW options IPFIREWALL_VERBOSE # enables logging for rules with log keyword to syslogd(8) options IPFIREWALL_VERBOSE_LIMIT=5 # limits number of logged packets per-entry options IPFIREWALL_DEFAULT_TO_ACCEPT # sets default policy to pass what is not explicitly denied options IPFIREWALL_NAT # enables basic in-kernel NAT support options LIBALIAS # enables full in-kernel NAT support options IPFIREWALL_NAT64 # enables in-kernel NAT64 support options IPFIREWALL_NPTV6 # enables in-kernel IPv6 NPT support options IPFIREWALL_PMOD # enables protocols modification module support options IPDIVERT # enables NAT through natd(8) .... [NOTE] ==== IPFW can be loaded as a kernel module: options above are built by default as modules or can be set at runtime using tunables. ==== [[firewalls-ipf]] == IPFILTER (IPF) IPFILTER, also known as IPF, is a cross-platform, open source firewall which has been ported to several operating systems, including FreeBSD, NetBSD, OpenBSD, and Solaris(TM). IPFILTER is a kernel-side firewall and NAT mechanism that can be controlled and monitored by userland programs. Firewall rules can be set or deleted using ipf, NAT rules can be set or deleted using ipnat, run-time statistics for the kernel parts of IPFILTER can be printed using ipfstat, and ipmon can be used to log IPFILTER actions to the system log files. IPF was originally written using a rule processing logic of "the last matching rule wins" and only used stateless rules. Since then, IPF has been enhanced to include the `quick` and `keep state` options. The IPF FAQ is at http://www.phildev.net/ipf/index.html[http://www.phildev.net/ipf/index.html]. A searchable archive of the IPFilter mailing list is available at http://marc.info/?l=ipfilter[http://marc.info/?l=ipfilter]. This section of the Handbook focuses on IPF as it pertains to FreeBSD. It provides examples of rules that contain the `quick` and `keep state` options. === Enabling IPF IPF is included in the basic FreeBSD install as a kernel loadable module, meaning that a custom kernel is not needed in order to enable IPF. For users who prefer to statically compile IPF support into a custom kernel, refer to the instructions in crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]. The following kernel options are available: [.programlisting] .... options IPFILTER options IPFILTER_LOG options IPFILTER_LOOKUP options IPFILTER_DEFAULT_BLOCK .... where `options IPFILTER` enables support for IPFILTER, `options IPFILTER_LOG` enables IPF logging using the [.filename]#ipl# packet logging pseudo-device for every rule that has the `log` keyword, `IPFILTER_LOOKUP` enables IP pools in order to speed up IP lookups, and `options IPFILTER_DEFAULT_BLOCK` changes the default behavior so that any packet not matching a firewall `pass` rule gets blocked. To configure the system to enable IPF at boot time, add the following entries to [.filename]#/etc/rc.conf#. These entries will also enable logging and `default pass all`. To change the default policy to `block all` without compiling a custom kernel, remember to add a `block all` rule at the end of the ruleset. [.programlisting] .... ipfilter_enable="YES" # Start ipf firewall ipfilter_rules="/etc/ipf.rules" # loads rules definition text file ipv6_ipfilter_rules="/etc/ipf6.rules" # loads rules definition text file for IPv6 ipmon_enable="YES" # Start IP monitor log ipmon_flags="-Ds" # D = start as daemon # s = log to syslog # v = log tcp window, ack, seq # n = map IP & port to names .... If NAT functionality is needed, also add these lines: [.programlisting] .... gateway_enable="YES" # Enable as LAN gateway ipnat_enable="YES" # Start ipnat function ipnat_rules="/etc/ipnat.rules" # rules definition file for ipnat .... Then, to start IPF now: [.programlisting] .... # service ipfilter start .... To load the firewall rules, specify the name of the ruleset file using `ipf`. The following command can be used to replace the currently running firewall rules: [source,shell] .... # ipf -Fa -f /etc/ipf.rules .... where `-Fa` flushes all the internal rules tables and `-f` specifies the file containing the rules to load. This provides the ability to make changes to a custom ruleset and update the running firewall with a fresh copy of the rules without having to reboot the system. This method is convenient for testing new rules as the procedure can be executed as many times as needed. Refer to man:ipf[8] for details on the other flags available with this command. === IPF Rule Syntax This section describes the IPF rule syntax used to create stateful rules. When creating rules, keep in mind that unless the `quick` keyword appears in a rule, every rule is read in order, with the _last matching rule_ being the one that is applied. This means that even if the first rule to match a packet is a `pass`, if there is a later matching rule that is a `block`, the packet will be dropped. Sample rulesets can be found in [.filename]#/usr/share/examples/ipfilter#. When creating rules, a `+#+` character is used to mark the start of a comment and may appear at the end of a rule, to explain that rule's function, or on its own line. Any blank lines are ignored. The keywords which are used in rules must be written in a specific order, from left to right. Some keywords are mandatory while others are optional. Some keywords have sub-options which may be keywords themselves and also include more sub-options. The keyword order is as follows, where the words shown in uppercase represent a variable and the words shown in lowercase must precede the variable that follows it: `_ACTION DIRECTION OPTIONS proto PROTO_TYPE from SRC_ADDR SRC_PORT to DST_ADDR DST_PORT TCP_FLAG|ICMP_TYPE keep state STATE_` This section describes each of these keywords and their options. It is not an exhaustive list of every possible option. Refer to man:ipf[5] for a complete description of the rule syntax that can be used when creating IPF rules and examples for using each keyword. ACTION:: The action keyword indicates what to do with the packet if it matches that rule. Every rule _must_ have an action. The following actions are recognized: + `block`: drops the packet. + `pass`: allows the packet. + `log`: generates a log record. + `count`: counts the number of packets and bytes which can provide an indication of how often a rule is used. + `auth`: queues the packet for further processing by another program. + `call`: provides access to functions built into IPF that allow more complex actions. + `decapsulate`: removes any headers in order to process the contents of the packet. DIRECTION:: Next, each rule must explicitly state the direction of traffic using one of these keywords: + `in`: the rule is applied against an inbound packet. + `out`: the rule is applied against an outbound packet. + `all`: the rule applies to either direction. + If the system has multiple interfaces, the interface can be specified along with the direction. An example would be `in on fxp0`. OPTIONS:: Options are optional. However, if multiple options are specified, they must be used in the order shown here. + `log`: when performing the specified ACTION, the contents of the packet's headers will be written to the man:ipl[4] packet log pseudo-device. + `quick`: if a packet matches this rule, the ACTION specified by the rule occurs and no further processing of any following rules will occur for this packet. + `on`: must be followed by the interface name as displayed by man:ifconfig[8]. The rule will only match if the packet is going through the specified interface in the specified direction. + When using the `log` keyword, the following qualifiers may be used in this order: + `body`: indicates that the first 128 bytes of the packet contents will be logged after the headers. + `first`: if the `log` keyword is being used in conjunction with a `keep state` option, this option is recommended so that only the triggering packet is logged and not every packet which matches the stateful connection. + Additional options are available to specify error return messages. Refer to man:ipf[5] for more details. PROTO_TYPE:: The protocol type is optional. However, it is mandatory if the rule needs to specify a SRC_PORT or a DST_PORT as it defines the type of protocol. When specifying the type of protocol, use the `proto` keyword followed by either a protocol number or name from [.filename]#/etc/protocols#. Example protocol names include `tcp`, `udp`, or `icmp`. If PROTO_TYPE is specified but no SRC_PORT or DST_PORT is specified, all port numbers for that protocol will match that rule. SRC_ADDR:: The `from` keyword is mandatory and is followed by a keyword which represents the source of the packet. The source can be a hostname, an IP address followed by the CIDR mask, an address pool, or the keyword `all`. Refer to man:ipf[5] for examples. + There is no way to match ranges of IP addresses which do not express themselves easily using the dotted numeric form / mask-length notation. The package:net-mgmt/ipcalc[] package or port may be used to ease the calculation of the CIDR mask. Additional information is available at the utility's web page: http://jodies.de/ipcalc[http://jodies.de/ipcalc]. SRC_PORT:: The port number of the source is optional. However, if it is used, it requires PROTO_TYPE to be first defined in the rule. The port number must also be preceded by the `proto` keyword. + A number of different comparison operators are supported: `=` (equal to), `!=` (not equal to), `<` (less than), `>` (greater than), `<=` (less than or equal to), and `>=` (greater than or equal to). + To specify port ranges, place the two port numbers between `<>` (less than and greater than ), `><` (greater than and less than ), or `:` (greater than or equal to and less than or equal to). DST_ADDR:: The `to` keyword is mandatory and is followed by a keyword which represents the destination of the packet. Similar to SRC_ADDR, it can be a hostname, an IP address followed by the CIDR mask, an address pool, or the keyword `all`. DST_PORT:: Similar to SRC_PORT, the port number of the destination is optional. However, if it is used, it requires PROTO_TYPE to be first defined in the rule. The port number must also be preceded by the `proto` keyword. TCP_FLAG|ICMP_TYPE:: If `tcp` is specified as the PROTO_TYPE, flags can be specified as letters, where each letter represents one of the possible TCP flags used to determine the state of a connection. Possible values are: `S` (SYN), `A` (ACK), `P` (PSH), `F` (FIN), `U` (URG), `R` (RST), `C` (CWN), and `E` (ECN). + If `icmp` is specified as the PROTO_TYPE, the ICMP type to match can be specified. Refer to man:ipf[5] for the allowable types. STATE:: If a `pass` rule contains `keep state`, IPF will add an entry to its dynamic state table and allow subsequent packets that match the connection. IPF can track state for TCP, UDP, and ICMP sessions. Any packet that IPF can be certain is part of an active session, even if it is a different protocol, will be allowed. + In IPF, packets destined to go out through the interface connected to the public Internet are first checked against the dynamic state table. If the packet matches the next expected packet comprising an active session conversation, it exits the firewall and the state of the session conversation flow is updated in the dynamic state table. Packets that do not belong to an already active session are checked against the outbound ruleset. Packets coming in from the interface connected to the public Internet are first checked against the dynamic state table. If the packet matches the next expected packet comprising an active session, it exits the firewall and the state of the session conversation flow is updated in the dynamic state table. Packets that do not belong to an already active session are checked against the inbound ruleset. + Several keywords can be added after `keep state`. If used, these keywords set various options that control stateful filtering, such as setting connection limits or connection age. Refer to man:ipf[5] for the list of available options and their descriptions. === Example Ruleset This section demonstrates how to create an example ruleset which only allows services matching `pass` rules and blocks all others. FreeBSD uses the loopback interface ([.filename]#lo0#) and the IP address `127.0.0.1` for internal communication. The firewall ruleset must contain rules to allow free movement of these internally used packets: [.programlisting] .... # no restrictions on loopback interface pass in quick on lo0 all pass out quick on lo0 all .... The public interface connected to the Internet is used to authorize and control access of all outbound and inbound connections. If one or more interfaces are cabled to private networks, those internal interfaces may require rules to allow packets originating from the LAN to flow between the internal networks or to the interface attached to the Internet. The ruleset should be organized into three major sections: any trusted internal interfaces, outbound connections through the public interface, and inbound connections through the public interface. These two rules allow all traffic to pass through a trusted LAN interface named [.filename]#xl0#: [.programlisting] .... # no restrictions on inside LAN interface for private network pass out quick on xl0 all pass in quick on xl0 all .... The rules for the public interface's outbound and inbound sections should have the most frequently matched rules placed before less commonly matched rules, with the last rule in the section blocking and logging all packets for that interface and direction. This set of rules defines the outbound section of the public interface named [.filename]#dc0#. These rules keep state and identify the specific services that internal systems are authorized for public Internet access. All the rules use `quick` and specify the appropriate port numbers and, where applicable, destination addresses. [.programlisting] .... # interface facing Internet (outbound) # Matches session start requests originating from or behind the # firewall, destined for the Internet. # Allow outbound access to public DNS servers. # Replace x.x.x.x with address listed in /etc/resolv.conf. # Repeat for each DNS server. pass out quick on dc0 proto tcp from any to x.x.x.x port = 53 flags S keep state pass out quick on dc0 proto udp from any to x.x.x.x port = 53 keep state # Allow access to ISP's specified DHCP server for cable or DSL networks. # Use the first rule, then check log for the IP address of DHCP server. # Then, uncomment the second rule, replace z.z.z.z with the IP address, # and comment out the first rule pass out log quick on dc0 proto udp from any to any port = 67 keep state #pass out quick on dc0 proto udp from any to z.z.z.z port = 67 keep state # Allow HTTP and HTTPS pass out quick on dc0 proto tcp from any to any port = 80 flags S keep state pass out quick on dc0 proto tcp from any to any port = 443 flags S keep state # Allow email pass out quick on dc0 proto tcp from any to any port = 110 flags S keep state pass out quick on dc0 proto tcp from any to any port = 25 flags S keep state # Allow NTP pass out quick on dc0 proto tcp from any to any port = 37 flags S keep state # Allow FTP pass out quick on dc0 proto tcp from any to any port = 21 flags S keep state # Allow SSH pass out quick on dc0 proto tcp from any to any port = 22 flags S keep state # Allow ping pass out quick on dc0 proto icmp from any to any icmp-type 8 keep state # Block and log everything else block out log first quick on dc0 all .... This example of the rules in the inbound section of the public interface blocks all undesirable packets first. This reduces the number of packets that are logged by the last rule. [.programlisting] .... # interface facing Internet (inbound) # Block all inbound traffic from non-routable or reserved address spaces block in quick on dc0 from 192.168.0.0/16 to any #RFC 1918 private IP block in quick on dc0 from 172.16.0.0/12 to any #RFC 1918 private IP block in quick on dc0 from 10.0.0.0/8 to any #RFC 1918 private IP block in quick on dc0 from 127.0.0.0/8 to any #loopback block in quick on dc0 from 0.0.0.0/8 to any #loopback block in quick on dc0 from 169.254.0.0/16 to any #DHCP auto-config block in quick on dc0 from 192.0.2.0/24 to any #reserved for docs block in quick on dc0 from 204.152.64.0/23 to any #Sun cluster interconnect block in quick on dc0 from 224.0.0.0/3 to any #Class D & E multicast # Block fragments and too short tcp packets block in quick on dc0 all with frags block in quick on dc0 proto tcp all with short # block source routed packets block in quick on dc0 all with opt lsrr block in quick on dc0 all with opt ssrr # Block OS fingerprint attempts and log first occurrence block in log first quick on dc0 proto tcp from any to any flags FUP # Block anything with special options block in quick on dc0 all with ipopts # Block public pings and ident block in quick on dc0 proto icmp all icmp-type 8 block in quick on dc0 proto tcp from any to any port = 113 # Block incoming Netbios services block in log first quick on dc0 proto tcp/udp from any to any port = 137 block in log first quick on dc0 proto tcp/udp from any to any port = 138 block in log first quick on dc0 proto tcp/udp from any to any port = 139 block in log first quick on dc0 proto tcp/udp from any to any port = 81 .... Any time there are logged messages on a rule with the `log first` option, run `ipfstat -hio` to evaluate how many times the rule has been matched. A large number of matches may indicate that the system is under attack. The rest of the rules in the inbound section define which connections are allowed to be initiated from the Internet. The last rule denies all connections which were not explicitly allowed by previous rules in this section. [.programlisting] .... # Allow traffic in from ISP's DHCP server. Replace z.z.z.z with # the same IP address used in the outbound section. pass in quick on dc0 proto udp from z.z.z.z to any port = 68 keep state # Allow public connections to specified internal web server pass in quick on dc0 proto tcp from any to x.x.x.x port = 80 flags S keep state # Block and log only first occurrence of all remaining traffic. block in log first quick on dc0 all .... === Configuring NAT To enable NAT, add these statements to [.filename]#/etc/rc.conf# and specify the name of the file containing the NAT rules: [.programlisting] .... gateway_enable="YES" ipnat_enable="YES" ipnat_rules="/etc/ipnat.rules" .... NAT rules are flexible and can accomplish many different things to fit the needs of both commercial and home users. The rule syntax presented here has been simplified to demonstrate common usage. For a complete rule syntax description, refer to man:ipnat[5]. The basic syntax for a NAT rule is as follows, where `map` starts the rule and _IF_ should be replaced with the name of the external interface: [.programlisting] .... map IF LAN_IP_RANGE -> PUBLIC_ADDRESS .... The _LAN_IP_RANGE_ is the range of IP addresses used by internal clients. Usually, it is a private address range such as `192.168.1.0/24`. The _PUBLIC_ADDRESS_ can either be the static external IP address or the keyword `0/32` which represents the IP address assigned to _IF_. In IPF, when a packet arrives at the firewall from the LAN with a public destination, it first passes through the outbound rules of the firewall ruleset. Then, the packet is passed to the NAT ruleset which is read from the top down, where the first matching rule wins. IPF tests each NAT rule against the packet's interface name and source IP address. When a packet's interface name matches a NAT rule, the packet's source IP address in the private LAN is checked to see if it falls within the IP address range specified in _LAN_IP_RANGE_. On a match, the packet has its source IP address rewritten with the public IP address specified by _PUBLIC_ADDRESS_. IPF posts an entry in its internal NAT table so that when the packet returns from the Internet, it can be mapped back to its original private IP address before being passed to the firewall rules for further processing. For networks that have large numbers of internal systems or multiple subnets, the process of funneling every private IP address into a single public IP address becomes a resource problem. Two methods are available to relieve this issue. The first method is to assign a range of ports to use as source ports. By adding the `portmap` keyword, NAT can be directed to only use source ports in the specified range: [.programlisting] .... map dc0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:60000 .... Alternately, use the `auto` keyword which tells NAT to determine the ports that are available for use: [.programlisting] .... map dc0 192.168.1.0/24 -> 0/32 portmap tcp/udp auto .... The second method is to use a pool of public addresses. This is useful when there are too many LAN addresses to fit into a single public address and a block of public IP addresses is available. These public addresses can be used as a pool from which NAT selects an IP address as a packet's address is mapped on its way out. The range of public IP addresses can be specified using a netmask or CIDR notation. These two rules are equivalent: [.programlisting] .... map dc0 192.168.1.0/24 -> 204.134.75.0/255.255.255.0 map dc0 192.168.1.0/24 -> 204.134.75.0/24 .... A common practice is to have a publicly accessible web server or mail server segregated to an internal network segment. The traffic from these servers still has to undergo NAT, but port redirection is needed to direct inbound traffic to the correct server. For example, to map a web server using the internal address `10.0.10.25` to its public IP address of `20.20.20.5`, use this rule: [.programlisting] .... rdr dc0 20.20.20.5/32 port 80 -> 10.0.10.25 port 80 .... If it is the only web server, this rule would also work as it redirects all external HTTP requests to `10.0.10.25`: [.programlisting] .... rdr dc0 0.0.0.0/0 port 80 -> 10.0.10.25 port 80 .... IPF has a built in FTP proxy which can be used with NAT. It monitors all outbound traffic for active or passive FTP connection requests and dynamically creates temporary filter rules containing the port number used by the FTP data channel. This eliminates the need to open large ranges of high order ports for FTP connections. In this example, the first rule calls the proxy for outbound FTP traffic from the internal LAN. The second rule passes the FTP traffic from the firewall to the Internet, and the third rule handles all non-FTP traffic from the internal LAN: [.programlisting] .... map dc0 10.0.10.0/29 -> 0/32 proxy port 21 ftp/tcp map dc0 0.0.0.0/0 -> 0/32 proxy port 21 ftp/tcp map dc0 10.0.10.0/29 -> 0/32 .... The FTP `map` rules go before the NAT rule so that when a packet matches an FTP rule, the FTP proxy creates temporary filter rules to let the FTP session packets pass and undergo NAT. All LAN packets that are not FTP will not match the FTP rules but will undergo NAT if they match the third rule. Without the FTP proxy, the following firewall rules would instead be needed. Note that without the proxy, all ports above `1024` need to be allowed: [.programlisting] .... # Allow out LAN PC client FTP to public Internet # Active and passive modes pass out quick on rl0 proto tcp from any to any port = 21 flags S keep state # Allow out passive mode data channel high order port numbers pass out quick on rl0 proto tcp from any to any port > 1024 flags S keep state # Active mode let data channel in from FTP server pass in quick on rl0 proto tcp from any to any port = 20 flags S keep state .... Whenever the file containing the NAT rules is edited, run `ipnat` with `-CF` to delete the current NAT rules and flush the contents of the dynamic translation table. Include `-f` and specify the name of the NAT ruleset to load: [source,shell] .... # ipnat -CF -f /etc/ipnat.rules .... To display the NAT statistics: [source,shell] .... # ipnat -s .... To list the NAT table's current mappings: [source,shell] .... # ipnat -l .... To turn verbose mode on and display information relating to rule processing and active rules and table entries: [source,shell] .... # ipnat -v .... === Viewing IPF Statistics IPF includes man:ipfstat[8] which can be used to retrieve and display statistics which are gathered as packets match rules as they go through the firewall. Statistics are accumulated since the firewall was last started or since the last time they were reset to zero using `ipf -Z`. The default `ipfstat` output looks like this: [source,shell] .... input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0 output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0 input packets logged: blocked 99286 passed 0 output packets logged: blocked 0 passed 0 packets logged: input 0 output 0 log failures: input 3898 output 0 fragment state(in): kept 0 lost 0 fragment state(out): kept 0 lost 0 packet state(in): kept 169364 lost 0 packet state(out): kept 431395 lost 0 ICMP replies: 0 TCP RSTs sent: 0 Result cache hits(in): 1215208 (out): 1098963 IN Pullups succeeded: 2 failed: 0 OUT Pullups succeeded: 0 failed: 0 Fastroute successes: 0 failures: 0 TCP cksum fails(in): 0 (out): 0 Packet log flags set: (0) .... Several options are available. When supplied with either `-i` for inbound or `-o` for outbound, the command will retrieve and display the appropriate list of filter rules currently installed and in use by the kernel. To also see the rule numbers, include `-n`. For example, `ipfstat -on` displays the outbound rules table with rule numbers: [source,shell] .... @1 pass out on xl0 from any to any @2 block out on dc0 from any to any @3 pass out quick on dc0 proto tcp/udp from any to any keep state .... Include `-h` to prefix each rule with a count of how many times the rule was matched. For example, `ipfstat -oh` displays the outbound internal rules table, prefixing each rule with its usage count: [source,shell] .... 2451423 pass out on xl0 from any to any 354727 block out on dc0 from any to any 430918 pass out quick on dc0 proto tcp/udp from any to any keep state .... To display the state table in a format similar to man:top[1], use `ipfstat -t`. When the firewall is under attack, this option provides the ability to identify and see the attacking packets. The optional sub-flags give the ability to select the destination or source IP, port, or protocol to be monitored in real time. Refer to man:ipfstat[8] for details. === IPF Logging IPF provides `ipmon`, which can be used to write the firewall's logging information in a human readable format. It requires that `options IPFILTER_LOG` be first added to a custom kernel using the instructions in crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]. This command is typically run in daemon mode in order to provide a continuous system log file so that logging of past events may be reviewed. Since FreeBSD has a built in man:syslogd[8] facility to automatically rotate system logs, the default [.filename]#rc.conf# `ipmon_flags` statement uses `-Ds`: [.programlisting] .... ipmon_flags="-Ds" # D = start as daemon # s = log to syslog # v = log tcp window, ack, seq # n = map IP & port to names .... Logging provides the ability to review, after the fact, information such as which packets were dropped, what addresses they came from, and where they were going. This information is useful in tracking down attackers. Once the logging facility is enabled in [.filename]#rc.conf# and started with `service ipmon start`, IPF will only log the rules which contain the `log` keyword. The firewall administrator decides which rules in the ruleset should be logged and normally only deny rules are logged. It is customary to include the `log` keyword in the last rule in the ruleset. This makes it possible to see all the packets that did not match any of the rules in the ruleset. By default, `ipmon -Ds` mode uses `local0` as the logging facility. The following logging levels can be used to further segregate the logged data: [source,shell] .... LOG_INFO - packets logged using the "log" keyword as the action rather than pass or block. LOG_NOTICE - packets logged which are also passed LOG_WARNING - packets logged which are also blocked LOG_ERR - packets which have been logged and which can be considered short due to an incomplete header .... In order to setup IPF to log all data to [.filename]#/var/log/ipfilter.log#, first create the empty file: [source,shell] .... # touch /var/log/ipfilter.log .... Then, to write all logged messages to the specified file, add the following statement to [.filename]#/etc/syslog.conf#: [.programlisting] .... local0.* /var/log/ipfilter.log .... To activate the changes and instruct man:syslogd[8] to read the modified [.filename]#/etc/syslog.conf#, run `service syslogd reload`. Do not forget to edit [.filename]#/etc/newsyslog.conf# to rotate the new log file. Messages generated by `ipmon` consist of data fields separated by white space. Fields common to all messages are: . The date of packet receipt. . The time of packet receipt. This is in the form HH:MM:SS.F, for hours, minutes, seconds, and fractions of a second. . The name of the interface that processed the packet. . The group and rule number of the rule in the format `@0:17`. . The action: `p` for passed, `b` for blocked, `S` for a short packet, `n` did not match any rules, and `L` for a log rule. . The addresses written as three fields: the source address and port separated by a comma, the -> symbol, and the destination address and port. For example: `209.53.17.22,80 -> 198.73.220.17,1722`. . `PR` followed by the protocol name or number: for example, `PR tcp`. . `len` followed by the header length and total length of the packet: for example, `len 20 40`. If the packet is a TCP packet, there will be an additional field starting with a hyphen followed by letters corresponding to any flags that were set. Refer to man:ipf[5] for a list of letters and their flags. If the packet is an ICMP packet, there will be two fields at the end: the first always being "icmp" and the next being the ICMP message and sub-message type, separated by a slash. For example: `icmp 3/3` for a port unreachable message. [[firewalls-blacklistd]] == Blacklistd Blacklistd is a daemon listening to sockets awaiting to receive notifications from other daemons about connection attempts that failed or were successful. It is most widely used in blocking too many connection attempts on open ports. A prime example is SSH running on the internet getting a lot of requests from bots or scripts trying to guess passwords and gain access. Using blacklistd, the daemon can notify the firewall to create a filter rule to block excessive connection attempts from a single source after a number of tries. Blacklistd was first developed on NetBSD and appeared there in version 7. FreeBSD 11 imported blacklistd from NetBSD. This chapter describes how to set up blacklistd, configure it, and provides examples on how to use it. Readers should be familiar with basic firewall concepts like rules. For details, refer to the firewall chapter. PF is used in the examples, but other firewalls available on FreeBSD should be able to work with blacklistd, too. === Enabling Blacklistd The main configuration for blacklistd is stored in man:blacklistd.conf[5]. Various command line options are also available to change blacklistd's run-time behavior. Persistent configuration across reboots should be stored in [.filename]#/etc/blacklistd.conf#. To enable the daemon during system boot, add a `blacklistd_enable` line to [.filename]#/etc/rc.conf# like this: [source,shell] .... # sysrc blacklistd_enable=yes .... To start the service manually, run this command: [source,shell] .... # service blacklistd start .... === Creating a Blacklistd Ruleset Rules for blacklistd are configured in man:blacklistd.conf[5] with one entry per line. Each rule contains a tuple separated by spaces or tabs. Rules either belong to a `local` or a `remote`, which applies to the machine where blacklistd is running or an outside source, respectively. ==== Local Rules An example blacklistd.conf entry for a local rule looks like this: [.programlisting] .... [local] ssh stream * * * 3 24h .... All rules that follow the `[local]` section are treated as local rules (which is the default), applying to the local machine. When a `[remote]` section is encountered, all rules that follow it are handled as remote machine rules. Seven fields separated by either tabs or spaces define a rule. The first four fields identify the traffic that should be blocklisted. The three fields that follow define backlistd's behavior. Wildcards are denoted as asterisks (`*`), matching anything in this field. The first field defines the location. In local rules, these are the network ports. The syntax for the location field is as follows: [.programlisting] .... [address|interface][/mask][:port] .... Addresses can be specified as IPv4 in numeric format or IPv6 in square brackets. An interface name like `_em0_` can also be used. The socket type is defined by the second field. TCP sockets are of type `stream`, whereas UDP is denoted as `dgram`. The example above uses TCP, since SSH is using that protocol. A protocol can be used in the third field of a blacklistd rule. The following protocols can be used: `tcp`, `udp`, `tcp6`, `udp6`, or numeric. A wildcard, like in the example, is typically used to match all protocols unless there is a reason to distinguish traffic by a certain protocol. In the fourth field, the effective user or owner of the daemon process that is reporting the event is defined. The username or UID can be used here, as well as a wildcard (see example rule above). The packet filter rule name is declared by the fifth field, which starts the behavior part of the rule. By default, blacklistd puts all blocks under a pf anchor called `blacklistd` in [.filename]#pf.conf# like this: [.programlisting] .... anchor "blacklistd/*" in on $ext_if block in pass out .... For separate blocklists, an anchor name can be used in this field. In other cases, the wildcard will suffice. When a name starts with a hyphen (`-`) it means that an anchor with the default rule name prepended should be used. A modified example from the above using the hyphen would look like this: [.programlisting] .... ssh stream * * -ssh 3 24h .... With such a rule, any new blocklist rules are added to an anchor called `blacklistd-ssh`. To block whole subnets for a single rule violation, a `/` in the rule name can be used. This causes the remaining portion of the name to be interpreted as the mask to be applied to the address specified in the rule. For example, this rule would block every address adjoining `/24`. [.programlisting] .... 22 stream tcp * */24 3 24h .... [NOTE] ==== It is important to specify the proper protocol here. IPv4 and IPv6 treat /24 differently, that is the reason why `*` cannot be used in the third field for this rule. ==== This rule defines that if any one host in that network is misbehaving, everything else on that network will be blocked, too. The sixth field, called `nfail`, sets the number of login failures required to blocklist the remote IP in question. When a wildcard is used at this position, it means that blocks will never happen. In the example rule above, a limit of three is defined meaning that after three attempts to log into SSH on one connection, the IP is blocked. The last field in a blacklistd rule definition specifies how long a host is blocklisted. The default unit is seconds, but suffixes like `m`, `h`, and `d` can also be specified for minutes, hours, and days, respectively. The example rule in its entirety means that after three times authenticating to SSH will result in a new PF block rule for that host. Rule matches are performed by first checking local rules one after another, from most specific to least specific. When a match occurs, the `remote` rules are applied and the name, `nfail`, and disable fields are changed by the `remote` rule that matched. ==== Remote Rules Remote rules are used to specify how blacklistd changes its behavior depending on the remote host currently being evaluated. Each field in a remote rule is the same as in a local rule. The only difference is in the way blacklistd is using them. To explain it, this example rule is used: [.programlisting] .... [remote] 203.0.113.128/25 * * * =/25 = 48h .... The address field can be an IP address (either v4 or v6), a port or both. This allows setting special rules for a specific remote address range like in this example. The fields for socket type, protocol and owner are identically interpreted as in the local rule. The name fields is different though: the equal sign (`=`) in a remote rule tells blacklistd to use the value from the matching local rule. It means that the firewall rule entry is taken and the `/25` prefix (a netmask of `255.255.255.128`) is added. When a connection from that address range is blocklisted, the entire subnet is affected. A PF anchor name can also be used here, in which case blacklistd will add rules for this address block to the anchor of that name. The default table is used when a wildcard is specified. A custom number of failures in the `nfail` column can be defined for an address. This is useful for exceptions to a specific rule, to maybe allow someone a less strict application of rules or a bit more leniency in login tries. Blocking is disabled when an asterisk is used in this sixth field. Remote rules allow a stricter enforcement of limits on attempts to log in compared to attempts coming from a local network like an office. === Blacklistd Client Configuration There are a few software packages in FreeBSD that can utilize blacklistd's functionality. The two most prominent ones are man:ftpd[8] and man:sshd[8] to block excessive connection attempts. To activate blacklistd in the SSH daemon, add the following line to [.filename]#/etc/ssh/sshd_config#: [.programlisting] .... UseBlacklist yes .... Restart sshd afterwards to make these changes take effect. Blacklisting for man:ftpd[8] is enabled using `-B`, either in [.filename]#/etc/inetd.conf# or as a flag in [.filename]#/etc/rc.conf# like this: [.programlisting] .... ftpd_flags="-B" .... That is all that is needed to make these programs talk to blacklistd. === Blacklistd Management Blacklistd provides the user with a management utility called man:blacklistctl[8]. It displays blocked addresses and networks that are blocklisted by the rules defined in man:blacklistd.conf[5]. To see the list of currently blocked hosts, use `dump` combined with `-b` like this. [source,shell] .... # blacklistctl dump -b address/ma:port id nfail last access 213.0.123.128/25:22 OK 6/3 2019/06/08 14:30:19 .... This example shows that there were 6 out of three permitted attempts on port 22 coming from the address range `213.0.123.128/25`. There are more attempts listed than are allowed because SSH allows a client to try multiple logins on a single TCP connection. A connection that is currently going on is not stopped by blacklistd. The last connection attempt is listed in the `last access` column of the output. To see the remaining time that this host will be on the blocklist, add `-r` to the previous command. [source,shell] .... # blacklistctl dump -br address/ma:port id nfail remaining time 213.0.123.128/25:22 OK 6/3 36s .... In this example, there are 36s seconds left until this host will not be blocked any more. === Removing Hosts from the Block List Sometimes it is necessary to remove a host from the block list before the remaining time expires. Unfortunately, there is no functionality in blacklistd to do that. However, it is possible to remove the address from the PF table using pfctl. For each blocked port, there is a child anchor inside the blacklistd anchor defined in [.filename]#/etc/pf.conf#. For example, if there is a child anchor for blocking port 22 it is called `blacklistd/22`. There is a table inside that child anchor that contains the blocked addresses. This table is called port followed by the port number. In this example, it would be called `port22`. With that information at hand, it is now possible to use man:pfctl[8] to display all addresses listed like this: [source,shell] .... # pfctl -a blacklistd/22 -t port22 -T show ... 213.0.123.128/25 ... .... After identifying the address to be unblocked from the list, the following command removes it from the list: [source,shell] .... # pfctl -a blacklistd/22 -t port22 -T delete 213.0.123.128/25 .... The address is now removed from PF, but will still show up in the blacklistctl list, since it does not know about any changes made in PF. The entry in blacklistd's database will eventually expire and be removed from its output. The entry will be added again if the host is matching one of the block rules in blacklistd again. diff --git a/documentation/content/en/books/handbook/geom/_index.adoc b/documentation/content/en/books/handbook/geom/_index.adoc index 7d6a0b528c..f26ed8a874 100644 --- a/documentation/content/en/books/handbook/geom/_index.adoc +++ b/documentation/content/en/books/handbook/geom/_index.adoc @@ -1,1305 +1,1305 @@ --- title: "Chapter 21. GEOM: Modular Disk Transformation Framework" part: Part III. System Administration prev: books/handbook/disks next: books/handbook/zfs description: In FreeBSD, the GEOM framework permits access and control to classes, such as Master Boot Records and BSD labels, through the use of providers, or the disk devices in /dev. tags: ["GEOM", "RAID", "RAID0", "RAID1", "RAID3", "Striping", "bsdlabel", "newfs", "labelling", "UFS", "journaling"] showBookMenu: true weight: 25 path: "/books/handbook/geom/" --- [[geom]] = GEOM: Modular Disk Transformation Framework :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 21 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/geom/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[geom-synopsis]] == Synopsis In FreeBSD, the GEOM framework permits access and control to classes, such as Master Boot Records and BSD labels, through the use of providers, or the disk devices in [.filename]#/dev#. By supporting various software RAID configurations, GEOM transparently provides access to the operating system and operating system utilities. This chapter covers the use of disks under the GEOM framework in FreeBSD. This includes the major RAID control utilities which use the framework for configuration. This chapter is not a definitive guide to RAID configurations and only GEOM-supported RAID classifications are discussed. After reading this chapter, you will know: * What type of RAID support is available through GEOM. * How to use the base utilities to configure, maintain, and manipulate the various RAID levels. * How to mirror, stripe, encrypt, and remotely connect disk devices through GEOM. * How to troubleshoot disks attached to the GEOM framework. Before reading this chapter, you should: * Understand how FreeBSD treats disk devices (crossref:disks[disks,Storage]). * Know how to configure and install a new kernel (crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]). [[geom-striping]] == RAID0 - Striping Striping combines several disk drives into a single volume. Striping can be performed through the use of hardware RAID controllers. The GEOM disk subsystem provides software support for disk striping, also known as RAID0, without the need for a RAID disk controller. In RAID0, data is split into blocks that are written across all the drives in the array. As seen in the following illustration, instead of having to wait on the system to write 256k to one disk, RAID0 can simultaneously write 64k to each of the four disks in the array, offering superior I/O performance. This performance can be enhanced further by using multiple disk controllers. image::striping.png[Disk Striping Illustration] Each disk in a RAID0 stripe must be of the same size, since I/O requests are interleaved to read or write to multiple disks in parallel. [NOTE] ==== RAID0 does _not_ provide any redundancy. This means that if one disk in the array fails, all of the data on the disks is lost. If the data is important, implement a backup strategy that regularly saves backups to a remote system or device. ==== The process for creating a software, GEOM-based RAID0 on a FreeBSD system using commodity disks is as follows. Once the stripe is created, refer to man:gstripe[8] for more information on how to control an existing stripe. [.procedure] **** *Procedure: Creating a Stripe of Unformatted ATA Disks* . Load the [.filename]#geom_stripe.ko# module: + [source,shell] .... # kldload geom_stripe .... . Ensure that a suitable mount point exists. If this volume will become a root partition, then temporarily use another mount point such as [.filename]#/mnt#. . Determine the device names for the disks which will be striped, and create the new stripe device. For example, to stripe two unused and unpartitioned ATA disks with device names of [.filename]#/dev/ad2# and [.filename]#/dev/ad3#: + [source,shell] .... # gstripe label -v st0 /dev/ad2 /dev/ad3 Metadata value stored on /dev/ad2. Metadata value stored on /dev/ad3. Done. .... . Write a standard label, also known as a partition table, on the new volume and install the default bootstrap code: + [source,shell] .... # bsdlabel -wB /dev/stripe/st0 .... . This process should create two other devices in [.filename]#/dev/stripe# in addition to [.filename]#st0#. Those include [.filename]#st0a# and [.filename]#st0c#. At this point, a UFS file system can be created on [.filename]#st0a# using `newfs`: + [source,shell] .... # newfs -U /dev/stripe/st0a .... + Many numbers will glide across the screen, and after a few seconds, the process will be complete. The volume has been created and is ready to be mounted. . To manually mount the created disk stripe: + [source,shell] .... # mount /dev/stripe/st0a /mnt .... . To mount this striped file system automatically during the boot process, place the volume information in [.filename]#/etc/fstab#. In this example, a permanent mount point, named [.filename]#stripe#, is created: + [source,shell] .... # mkdir /stripe # echo "/dev/stripe/st0a /stripe ufs rw 2 2" \ >> /etc/fstab .... . The [.filename]#geom_stripe.ko# module must also be automatically loaded during system initialization, by adding a line to [.filename]#/boot/loader.conf#: + [source,shell] .... # echo 'geom_stripe_load="YES"' >> /boot/loader.conf .... **** [[geom-mirror]] == RAID1 - Mirroring RAID1, or _mirroring_, is the technique of writing the same data to more than one disk drive. Mirrors are usually used to guard against data loss due to drive failure. Each drive in a mirror contains an identical copy of the data. When an individual drive fails, the mirror continues to work, providing data from the drives that are still functioning. The computer keeps running, and the administrator has time to replace the failed drive without user interruption. Two common situations are illustrated in these examples. The first creates a mirror out of two new drives and uses it as a replacement for an existing single drive. The second example creates a mirror on a single new drive, copies the old drive's data to it, then inserts the old drive into the mirror. While this procedure is slightly more complicated, it only requires one new drive. Traditionally, the two drives in a mirror are identical in model and capacity, but man:gmirror[8] does not require that. Mirrors created with dissimilar drives will have a capacity equal to that of the smallest drive in the mirror. Extra space on larger drives will be unused. Drives inserted into the mirror later must have at least as much capacity as the smallest drive already in the mirror. [WARNING] ==== The mirroring procedures shown here are non-destructive, but as with any major disk operation, make a full backup first. ==== [WARNING] ==== While man:dump[8] is used in these procedures to copy file systems, it does not work on file systems with soft updates journaling. See man:tunefs[8] for information on detecting and disabling soft updates journaling. ==== [[geom-mirror-metadata]] === Metadata Issues Many disk systems store metadata at the end of each disk. Old metadata should be erased before reusing the disk for a mirror. Most problems are caused by two particular types of leftover metadata: GPT partition tables and old metadata from a previous mirror. GPT metadata can be erased with man:gpart[8]. This example erases both primary and backup GPT partition tables from disk [.filename]#ada8#: [source,shell] .... # gpart destroy -F ada8 .... A disk can be removed from an active mirror and the metadata erased in one step using man:gmirror[8]. Here, the example disk [.filename]#ada8# is removed from the active mirror [.filename]#gm4#: [source,shell] .... # gmirror remove gm4 ada8 .... If the mirror is not running, but old mirror metadata is still on the disk, use `gmirror clear` to remove it: [source,shell] .... # gmirror clear ada8 .... man:gmirror[8] stores one block of metadata at the end of the disk. As GPT partition schemes also store metadata at the end of the disk, mirroring entire GPT disks with man:gmirror[8] is not recommended. MBR partitioning is used here because it only stores a partition table at the start of the disk and does not conflict with the mirror metadata. [[geom-mirror-two-new-disks]] === Creating a Mirror with Two New Disks In this example, FreeBSD has already been installed on a single disk, [.filename]#ada0#. Two new disks, [.filename]#ada1# and [.filename]#ada2#, have been connected to the system. A new mirror will be created on these two disks and used to replace the old single disk. The [.filename]#geom_mirror.ko# kernel module must either be built into the kernel or loaded at boot- or run-time. Manually load the kernel module now: [source,shell] .... # gmirror load .... Create the mirror with the two new drives: [source,shell] .... # gmirror label -v gm0 /dev/ada1 /dev/ada2 .... [.filename]#gm0# is a user-chosen device name assigned to the new mirror. After the mirror has been started, this device name appears in [.filename]#/dev/mirror/#. MBR and bsdlabel partition tables can now be created on the mirror with man:gpart[8]. This example uses a traditional file system layout, with partitions for [.filename]#/#, swap, [.filename]#/var#, [.filename]#/tmp#, and [.filename]#/usr#. A single [.filename]#/# and a swap partition will also work. Partitions on the mirror do not have to be the same size as those on the existing disk, but they must be large enough to hold all the data already present on [.filename]#ada0#. [source,shell] .... # gpart create -s MBR mirror/gm0 # gpart add -t freebsd -a 4k mirror/gm0 # gpart show mirror/gm0 => 63 156301423 mirror/gm0 MBR (74G) 63 63 - free - (31k) 126 156301299 1 freebsd (74G) 156301425 61 - free - (30k) .... [source,shell] .... # gpart create -s BSD mirror/gm0s1 # gpart add -t freebsd-ufs -a 4k -s 2g mirror/gm0s1 # gpart add -t freebsd-swap -a 4k -s 4g mirror/gm0s1 # gpart add -t freebsd-ufs -a 4k -s 2g mirror/gm0s1 # gpart add -t freebsd-ufs -a 4k -s 1g mirror/gm0s1 # gpart add -t freebsd-ufs -a 4k mirror/gm0s1 # gpart show mirror/gm0s1 => 0 156301299 mirror/gm0s1 BSD (74G) 0 2 - free - (1.0k) 2 4194304 1 freebsd-ufs (2.0G) 4194306 8388608 2 freebsd-swap (4.0G) 12582914 4194304 4 freebsd-ufs (2.0G) 16777218 2097152 5 freebsd-ufs (1.0G) 18874370 137426928 6 freebsd-ufs (65G) 156301298 1 - free - (512B) .... Make the mirror bootable by installing bootcode in the MBR and bsdlabel and setting the active slice: [source,shell] .... # gpart bootcode -b /boot/mbr mirror/gm0 # gpart set -a active -i 1 mirror/gm0 # gpart bootcode -b /boot/boot mirror/gm0s1 .... Format the file systems on the new mirror, enabling soft-updates. [source,shell] .... # newfs -U /dev/mirror/gm0s1a # newfs -U /dev/mirror/gm0s1d # newfs -U /dev/mirror/gm0s1e # newfs -U /dev/mirror/gm0s1f .... File systems from the original [.filename]#ada0# disk can now be copied onto the mirror with man:dump[8] and man:restore[8]. [source,shell] .... # mount /dev/mirror/gm0s1a /mnt # dump -C16 -b64 -0aL -f - / | (cd /mnt && restore -rf -) # mount /dev/mirror/gm0s1d /mnt/var # mount /dev/mirror/gm0s1e /mnt/tmp # mount /dev/mirror/gm0s1f /mnt/usr # dump -C16 -b64 -0aL -f - /var | (cd /mnt/var && restore -rf -) # dump -C16 -b64 -0aL -f - /tmp | (cd /mnt/tmp && restore -rf -) # dump -C16 -b64 -0aL -f - /usr | (cd /mnt/usr && restore -rf -) .... Edit [.filename]#/mnt/etc/fstab# to point to the new mirror file systems: [.programlisting] .... # Device Mountpoint FStype Options Dump Pass# /dev/mirror/gm0s1a / ufs rw 1 1 /dev/mirror/gm0s1b none swap sw 0 0 /dev/mirror/gm0s1d /var ufs rw 2 2 /dev/mirror/gm0s1e /tmp ufs rw 2 2 /dev/mirror/gm0s1f /usr ufs rw 2 2 .... If the [.filename]#geom_mirror.ko# kernel module has not been built into the kernel, [.filename]#/mnt/boot/loader.conf# is edited to load the module at boot: [.programlisting] .... geom_mirror_load="YES" .... Reboot the system to test the new mirror and verify that all data has been copied. The BIOS will see the mirror as two individual drives rather than a mirror. Since the drives are identical, it does not matter which is selected to boot. -See crossref:geom[gmirror-troubleshooting] if there are problems booting. +See crossref:geom[gmirror-troubleshooting, Troubleshooting] if there are problems booting. Powering down and disconnecting the original [.filename]#ada0# disk will allow it to be kept as an offline backup. In use, the mirror will behave just like the original single drive. [[geom-mirror-existing-drive]] === Creating a Mirror with an Existing Drive In this example, FreeBSD has already been installed on a single disk, [.filename]#ada0#. A new disk, [.filename]#ada1#, has been connected to the system. A one-disk mirror will be created on the new disk, the existing system copied onto it, and then the old disk will be inserted into the mirror. This slightly complex procedure is required because `gmirror` needs to put a 512-byte block of metadata at the end of each disk, and the existing [.filename]#ada0# has usually had all of its space already allocated. Load the [.filename]#geom_mirror.ko# kernel module: [source,shell] .... # gmirror load .... Check the media size of the original disk with `diskinfo`: [source,shell] .... # diskinfo -v ada0 | head -n3 /dev/ada0 512 # sectorsize 1000204821504 # mediasize in bytes (931G) .... Create a mirror on the new disk. To make certain that the mirror capacity is not any larger than the original [.filename]#ada0# drive, man:gnop[8] is used to create a fake drive of the same size. This drive does not store any data, but is used only to limit the size of the mirror. When man:gmirror[8] creates the mirror, it will restrict the capacity to the size of [.filename]#gzero.nop#, even if the new [.filename]#ada1# drive has more space. Note that the _1000204821504_ in the second line is equal to [.filename]#ada0#'s media size as shown by `diskinfo` above. [source,shell] .... # geom zero load # gnop create -s 1000204821504 gzero # gmirror label -v gm0 gzero.nop ada1 # gmirror forget gm0 .... Since [.filename]#gzero.nop# does not store any data, the mirror does not see it as connected. The mirror is told to "forget" unconnected components, removing references to [.filename]#gzero.nop#. The result is a mirror device containing only a single disk, [.filename]#ada1#. After creating [.filename]#gm0#, view the partition table on [.filename]#ada0#. This output is from a 1 TB drive. If there is some unallocated space at the end of the drive, the contents may be copied directly from [.filename]#ada0# to the new mirror. However, if the output shows that all of the space on the disk is allocated, as in the following listing, there is no space available for the 512-byte mirror metadata at the end of the disk. [source,shell] .... # gpart show ada0 => 63 1953525105 ada0 MBR (931G) 63 1953525105 1 freebsd [active] (931G) .... In this case, the partition table must be edited to reduce the capacity by one sector on [.filename]#mirror/gm0#. The procedure will be explained later. In either case, partition tables on the primary disk should be first copied using `gpart backup` and `gpart restore`. [source,shell] .... # gpart backup ada0 > table.ada0 # gpart backup ada0s1 > table.ada0s1 .... These commands create two files, [.filename]#table.ada0# and [.filename]#table.ada0s1#. This example is from a 1 TB drive: [source,shell] .... # cat table.ada0 MBR 4 1 freebsd 63 1953525105 [active] .... [source,shell] .... # cat table.ada0s1 BSD 8 1 freebsd-ufs 0 4194304 2 freebsd-swap 4194304 33554432 4 freebsd-ufs 37748736 50331648 5 freebsd-ufs 88080384 41943040 6 freebsd-ufs 130023424 838860800 7 freebsd-ufs 968884224 984640881 .... If no free space is shown at the end of the disk, the size of both the slice and the last partition must be reduced by one sector. Edit the two files, reducing the size of both the slice and last partition by one. These are the last numbers in each listing. [source,shell] .... # cat table.ada0 MBR 4 1 freebsd 63 1953525104 [active] .... [source,shell] .... # cat table.ada0s1 BSD 8 1 freebsd-ufs 0 4194304 2 freebsd-swap 4194304 33554432 4 freebsd-ufs 37748736 50331648 5 freebsd-ufs 88080384 41943040 6 freebsd-ufs 130023424 838860800 7 freebsd-ufs 968884224 984640880 .... If at least one sector was unallocated at the end of the disk, these two files can be used without modification. Now restore the partition table into [.filename]#mirror/gm0#: [source,shell] .... # gpart restore mirror/gm0 < table.ada0 # gpart restore mirror/gm0s1 < table.ada0s1 .... Check the partition table with `gpart show`. This example has [.filename]#gm0s1a# for [.filename]#/#, [.filename]#gm0s1d# for [.filename]#/var#, [.filename]#gm0s1e# for [.filename]#/usr#, [.filename]#gm0s1f# for [.filename]#/data1#, and [.filename]#gm0s1g# for [.filename]#/data2#. [source,shell] .... # gpart show mirror/gm0 => 63 1953525104 mirror/gm0 MBR (931G) 63 1953525042 1 freebsd [active] (931G) 1953525105 62 - free - (31k) # gpart show mirror/gm0s1 => 0 1953525042 mirror/gm0s1 BSD (931G) 0 2097152 1 freebsd-ufs (1.0G) 2097152 16777216 2 freebsd-swap (8.0G) 18874368 41943040 4 freebsd-ufs (20G) 60817408 20971520 5 freebsd-ufs (10G) 81788928 629145600 6 freebsd-ufs (300G) 710934528 1242590514 7 freebsd-ufs (592G) 1953525042 63 - free - (31k) .... Both the slice and the last partition must have at least one free block at the end of the disk. Create file systems on these new partitions. The number of partitions will vary to match the original disk, [.filename]#ada0#. [source,shell] .... # newfs -U /dev/mirror/gm0s1a # newfs -U /dev/mirror/gm0s1d # newfs -U /dev/mirror/gm0s1e # newfs -U /dev/mirror/gm0s1f # newfs -U /dev/mirror/gm0s1g .... Make the mirror bootable by installing bootcode in the MBR and bsdlabel and setting the active slice: [source,shell] .... # gpart bootcode -b /boot/mbr mirror/gm0 # gpart set -a active -i 1 mirror/gm0 # gpart bootcode -b /boot/boot mirror/gm0s1 .... Adjust [.filename]#/etc/fstab# to use the new partitions on the mirror. Back up this file first by copying it to [.filename]#/etc/fstab.orig#. [source,shell] .... # cp /etc/fstab /etc/fstab.orig .... Edit [.filename]#/etc/fstab#, replacing [.filename]#/dev/ada0# with [.filename]#mirror/gm0#. [.programlisting] .... # Device Mountpoint FStype Options Dump Pass# /dev/mirror/gm0s1a / ufs rw 1 1 /dev/mirror/gm0s1b none swap sw 0 0 /dev/mirror/gm0s1d /var ufs rw 2 2 /dev/mirror/gm0s1e /usr ufs rw 2 2 /dev/mirror/gm0s1f /data1 ufs rw 2 2 /dev/mirror/gm0s1g /data2 ufs rw 2 2 .... If the [.filename]#geom_mirror.ko# kernel module has not been built into the kernel, edit [.filename]#/boot/loader.conf# to load it at boot: [.programlisting] .... geom_mirror_load="YES" .... File systems from the original disk can now be copied onto the mirror with man:dump[8] and man:restore[8]. Each file system dumped with `dump -L` will create a snapshot first, which can take some time. [source,shell] .... # mount /dev/mirror/gm0s1a /mnt # dump -C16 -b64 -0aL -f - / | (cd /mnt && restore -rf -) # mount /dev/mirror/gm0s1d /mnt/var # mount /dev/mirror/gm0s1e /mnt/usr # mount /dev/mirror/gm0s1f /mnt/data1 # mount /dev/mirror/gm0s1g /mnt/data2 # dump -C16 -b64 -0aL -f - /usr | (cd /mnt/usr && restore -rf -) # dump -C16 -b64 -0aL -f - /var | (cd /mnt/var && restore -rf -) # dump -C16 -b64 -0aL -f - /data1 | (cd /mnt/data1 && restore -rf -) # dump -C16 -b64 -0aL -f - /data2 | (cd /mnt/data2 && restore -rf -) .... Restart the system, booting from [.filename]#ada1#. If everything is working, the system will boot from [.filename]#mirror/gm0#, which now contains the same data as [.filename]#ada0# had previously. -See crossref:geom[gmirror-troubleshooting] if there are problems booting. +See crossref:geom[gmirror-troubleshooting, Troubleshooting] if there are problems booting. At this point, the mirror still consists of only the single [.filename]#ada1# disk. After booting from [.filename]#mirror/gm0# successfully, the final step is inserting [.filename]#ada0# into the mirror. [IMPORTANT] ==== When [.filename]#ada0# is inserted into the mirror, its former contents will be overwritten by data from the mirror. Make certain that [.filename]#mirror/gm0# has the same contents as [.filename]#ada0# before adding [.filename]#ada0# to the mirror. If the contents previously copied by man:dump[8] and man:restore[8] are not identical to what was on [.filename]#ada0#, revert [.filename]#/etc/fstab# to mount the file systems on [.filename]#ada0#, reboot, and start the whole procedure again. ==== [source,shell] .... # gmirror insert gm0 ada0 GEOM_MIRROR: Device gm0: rebuilding provider ada0 .... Synchronization between the two disks will start immediately. Use `gmirror status` to view the progress. [source,shell] .... # gmirror status Name Status Components mirror/gm0 DEGRADED ada1 (ACTIVE) ada0 (SYNCHRONIZING, 64%) .... After a while, synchronization will finish. [source,shell] .... GEOM_MIRROR: Device gm0: rebuilding provider ada0 finished. # gmirror status Name Status Components mirror/gm0 COMPLETE ada1 (ACTIVE) ada0 (ACTIVE) .... [.filename]#mirror/gm0# now consists of the two disks [.filename]#ada0# and [.filename]#ada1#, and the contents are automatically synchronized with each other. In use, [.filename]#mirror/gm0# will behave just like the original single drive. [[gmirror-troubleshooting]] === Troubleshooting If the system no longer boots, BIOS settings may have to be changed to boot from one of the new mirrored drives. Either mirror drive can be used for booting, as they contain identical data. If the boot stops with this message, something is wrong with the mirror device: [source,shell] .... Mounting from ufs:/dev/mirror/gm0s1a failed with error 19. Loader variables: vfs.root.mountfrom=ufs:/dev/mirror/gm0s1a vfs.root.mountfrom.options=rw Manual root filesystem specification: : [options] Mount using filesystem and with the specified (optional) option list. e.g. ufs:/dev/da0s1a zfs:tank cd9660:/dev/acd0 ro (which is equivalent to: mount -t cd9660 -o ro /dev/acd0 /) ? List valid disk boot devices . Yield 1 second (for background tasks) Abort manual input mountroot> .... Forgetting to load the [.filename]#geom_mirror.ko# module in [.filename]#/boot/loader.conf# can cause this problem. To fix it, boot from a FreeBSD installation media and choose `Shell` at the first prompt. Then load the mirror module and mount the mirror device: [source,shell] .... # gmirror load # mount /dev/mirror/gm0s1a /mnt .... Edit [.filename]#/mnt/boot/loader.conf#, adding a line to load the mirror module: [.programlisting] .... geom_mirror_load="YES" .... Save the file and reboot. Other problems that cause `error 19` require more effort to fix. Although the system should boot from [.filename]#ada0#, another prompt to select a shell will appear if [.filename]#/etc/fstab# is incorrect. Enter `ufs:/dev/ada0s1a` at the boot loader prompt and press kbd:[Enter]. Undo the edits in [.filename]#/etc/fstab# then mount the file systems from the original disk ([.filename]#ada0#) instead of the mirror. Reboot the system and try the procedure again. [source,shell] .... Enter full pathname of shell or RETURN for /bin/sh: # cp /etc/fstab.orig /etc/fstab # reboot .... === Recovering from Disk Failure The benefit of disk mirroring is that an individual disk can fail without causing the mirror to lose any data. In the above example, if [.filename]#ada0# fails, the mirror will continue to work, providing data from the remaining working drive, [.filename]#ada1#. To replace the failed drive, shut down the system and physically replace the failed drive with a new drive of equal or greater capacity. Manufacturers use somewhat arbitrary values when rating drives in gigabytes, and the only way to really be sure is to compare the total count of sectors shown by `diskinfo -v`. A drive with larger capacity than the mirror will work, although the extra space on the new drive will not be used. After the computer is powered back up, the mirror will be running in a "degraded" mode with only one drive. The mirror is told to forget drives that are not currently connected: [source,shell] .... # gmirror forget gm0 .... Any old metadata should be cleared from the replacement disk using the -instructions in crossref:geom[geom-mirror-metadata]. +instructions in crossref:geom[geom-mirror-metadata, Metadata Issues]. Then the replacement disk, [.filename]#ada4# for this example, is inserted into the mirror: [source,shell] .... # gmirror insert gm0 /dev/ada4 .... Resynchronization begins when the new drive is inserted into the mirror. This process of copying mirror data to a new drive can take a while. Performance of the mirror will be greatly reduced during the copy, so inserting new drives is best done when there is low demand on the computer. Progress can be monitored with `gmirror status`, which shows drives that are being synchronized and the percentage of completion. During resynchronization, the status will be `DEGRADED`, changing to `COMPLETE` when the process is finished. [[geom-raid3]] == RAID3 - Byte-level Striping with Dedicated Parity RAID3 is a method used to combine several disk drives into a single volume with a dedicated parity disk. In a RAID3 system, data is split up into a number of bytes that are written across all the drives in the array except for one disk which acts as a dedicated parity disk. This means that disk reads from a RAID3 implementation access all disks in the array. Performance can be enhanced by using multiple disk controllers. The RAID3 array provides a fault tolerance of 1 drive, while providing a capacity of 1 - 1/n times the total capacity of all drives in the array, where n is the number of hard drives in the array. Such a configuration is mostly suitable for storing data of larger sizes such as multimedia files. At least 3 physical hard drives are required to build a RAID3 array. Each disk must be of the same size, since I/O requests are interleaved to read or write to multiple disks in parallel. Also, due to the nature of RAID3, the number of drives must be equal to 3, 5, 9, 17, and so on, or 2^n + 1. This section demonstrates how to create a software RAID3 on a FreeBSD system. [NOTE] ==== While it is theoretically possible to boot from a RAID3 array on FreeBSD, that configuration is uncommon and is not advised. ==== === Creating a Dedicated RAID3 Array In FreeBSD, support for RAID3 is implemented by the man:graid3[8] GEOM class. Creating a dedicated RAID3 array on FreeBSD requires the following steps. [.procedure] . First, load the [.filename]#geom_raid3.ko# kernel module by issuing one of the following commands: + [source,shell] .... # graid3 load .... + or: + [source,shell] .... # kldload geom_raid3 .... . Ensure that a suitable mount point exists. This command creates a new directory to use as the mount point: + [source,shell] .... # mkdir /multimedia .... . Determine the device names for the disks which will be added to the array, and create the new RAID3 device. The final device listed will act as the dedicated parity disk. This example uses three unpartitioned ATA drives: [.filename]#ada1# and [.filename]#ada2# for data, and [.filename]#ada3# for parity. + [source,shell] .... # graid3 label -v gr0 /dev/ada1 /dev/ada2 /dev/ada3 Metadata value stored on /dev/ada1. Metadata value stored on /dev/ada2. Metadata value stored on /dev/ada3. Done. .... . Partition the newly created [.filename]#gr0# device and put a UFS file system on it: + [source,shell] .... # gpart create -s GPT /dev/raid3/gr0 # gpart add -t freebsd-ufs /dev/raid3/gr0 # newfs -j /dev/raid3/gr0p1 .... + Many numbers will glide across the screen, and after a bit of time, the process will be complete. The volume has been created and is ready to be mounted: + [source,shell] .... # mount /dev/raid3/gr0p1 /multimedia/ .... + The RAID3 array is now ready to use. Additional configuration is needed to retain this setup across system reboots. [.procedure] . The [.filename]#geom_raid3.ko# module must be loaded before the array can be mounted. To automatically load the kernel module during system initialization, add the following line to [.filename]#/boot/loader.conf#: + [.programlisting] .... geom_raid3_load="YES" .... . The following volume information must be added to [.filename]#/etc/fstab# in order to automatically mount the array's file system during the system boot process: + [.programlisting] .... /dev/raid3/gr0p1 /multimedia ufs rw 2 2 .... [[geom-graid]] == Software RAID Devices Some motherboards and expansion cards add some simple hardware, usually just a ROM, that allows the computer to boot from a RAID array. After booting, access to the RAID array is handled by software running on the computer's main processor. This "hardware-assisted software RAID" gives RAID arrays that are not dependent on any particular operating system, and which are functional even before an operating system is loaded. Several levels of RAID are supported, depending on the hardware in use. See man:graid[8] for a complete list. man:graid[8] requires the [.filename]#geom_raid.ko# kernel module, which is included in the [.filename]#GENERIC# kernel starting with FreeBSD 9.1. If needed, it can be loaded manually with `graid load`. [[geom-graid-creating]] === Creating an Array Software RAID devices often have a menu that can be entered by pressing special keys when the computer is booting. The menu can be used to create and delete RAID arrays. man:graid[8] can also create arrays directly from the command line. `graid label` is used to create a new array. The motherboard used for this example has an Intel software RAID chipset, so the Intel metadata format is specified. The new array is given a label of [.filename]#gm0#, it is a mirror (RAID1), and uses drives [.filename]#ada0# and [.filename]#ada1#. [CAUTION] ==== Some space on the drives will be overwritten when they are made into a new array. Back up existing data first! ==== [source,shell] .... # graid label Intel gm0 RAID1 ada0 ada1 GEOM_RAID: Intel-a29ea104: Array Intel-a29ea104 created. GEOM_RAID: Intel-a29ea104: Disk ada0 state changed from NONE to ACTIVE. GEOM_RAID: Intel-a29ea104: Subdisk gm0:0-ada0 state changed from NONE to ACTIVE. GEOM_RAID: Intel-a29ea104: Disk ada1 state changed from NONE to ACTIVE. GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-ada1 state changed from NONE to ACTIVE. GEOM_RAID: Intel-a29ea104: Array started. GEOM_RAID: Intel-a29ea104: Volume gm0 state changed from STARTING to OPTIMAL. Intel-a29ea104 created GEOM_RAID: Intel-a29ea104: Provider raid/r0 for volume gm0 created. .... A status check shows the new mirror is ready for use: [source,shell] .... # graid status Name Status Components raid/r0 OPTIMAL ada0 (ACTIVE (ACTIVE)) ada1 (ACTIVE (ACTIVE)) .... The array device appears in [.filename]#/dev/raid/#. The first array is called [.filename]#r0#. Additional arrays, if present, will be [.filename]#r1#, [.filename]#r2#, and so on. The BIOS menu on some of these devices can create arrays with special characters in their names. To avoid problems with those special characters, arrays are given simple numbered names like [.filename]#r0#. To show the actual labels, like [.filename]#gm0# in the example above, use man:sysctl[8]: [source,shell] .... # sysctl kern.geom.raid.name_format=1 .... [[geom-graid-volumes]] === Multiple Volumes Some software RAID devices support more than one _volume_ on an array. Volumes work like partitions, allowing space on the physical drives to be split and used in different ways. For example, Intel software RAID devices support two volumes. This example creates a 40 G mirror for safely storing the operating system, followed by a 20 G RAID0 (stripe) volume for fast temporary storage: [source,shell] .... # graid label -S 40G Intel gm0 RAID1 ada0 ada1 # graid add -S 20G gm0 RAID0 .... Volumes appear as additional [.filename]#rX# entries in [.filename]#/dev/raid/#. An array with two volumes will show [.filename]#r0# and [.filename]#r1#. See man:graid[8] for the number of volumes supported by different software RAID devices. [[geom-graid-converting]] === Converting a Single Drive to a Mirror Under certain specific conditions, it is possible to convert an existing single drive to a man:graid[8] array without reformatting. To avoid data loss during the conversion, the existing drive must meet these minimum requirements: * The drive must be partitioned with the MBR partitioning scheme. GPT or other partitioning schemes with metadata at the end of the drive will be overwritten and corrupted by the man:graid[8] metadata. * There must be enough unpartitioned and unused space at the end of the drive to hold the man:graid[8] metadata. This metadata varies in size, but the largest occupies 64 M, so at least that much free space is recommended. If the drive meets these requirements, start by making a full backup. Then create a single-drive mirror with that drive: [source,shell] .... # graid label Intel gm0 RAID1 ada0 NONE .... man:graid[8] metadata was written to the end of the drive in the unused space. A second drive can now be inserted into the mirror: [source,shell] .... # graid insert raid/r0 ada1 .... Data from the original drive will immediately begin to be copied to the second drive. The mirror will operate in degraded status until the copy is complete. [[geom-graid-inserting]] === Inserting New Drives into the Array Drives can be inserted into an array as replacements for drives that have failed or are missing. If there are no failed or missing drives, the new drive becomes a spare. For example, inserting a new drive into a working two-drive mirror results in a two-drive mirror with one spare drive, not a three-drive mirror. In the example mirror array, data immediately begins to be copied to the newly-inserted drive. Any existing information on the new drive will be overwritten. [source,shell] .... # graid insert raid/r0 ada1 GEOM_RAID: Intel-a29ea104: Disk ada1 state changed from NONE to ACTIVE. GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-ada1 state changed from NONE to NEW. GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-ada1 state changed from NEW to REBUILD. GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-ada1 rebuild start at 0. .... [[geom-graid-removing]] === Removing Drives from the Array Individual drives can be permanently removed from a from an array and their metadata erased: [source,shell] .... # graid remove raid/r0 ada1 GEOM_RAID: Intel-a29ea104: Disk ada1 state changed from ACTIVE to OFFLINE. GEOM_RAID: Intel-a29ea104: Subdisk gm0:1-[unknown] state changed from ACTIVE to NONE. GEOM_RAID: Intel-a29ea104: Volume gm0 state changed from OPTIMAL to DEGRADED. .... [[geom-graid-stopping]] === Stopping the Array An array can be stopped without removing metadata from the drives. The array will be restarted when the system is booted. [source,shell] .... # graid stop raid/r0 .... [[geom-graid-status]] === Checking Array Status Array status can be checked at any time. After a drive was added to the mirror in the example above, data is being copied from the original drive to the new drive: [source,shell] .... # graid status Name Status Components raid/r0 DEGRADED ada0 (ACTIVE (ACTIVE)) ada1 (ACTIVE (REBUILD 28%)) .... Some types of arrays, like `RAID0` or `CONCAT`, may not be shown in the status report if disks have failed. To see these partially-failed arrays, add `-ga`: [source,shell] .... # graid status -ga Name Status Components Intel-e2d07d9a BROKEN ada6 (ACTIVE (ACTIVE)) .... [[geom-graid-deleting]] === Deleting Arrays Arrays are destroyed by deleting all of the volumes from them. When the last volume present is deleted, the array is stopped and metadata is removed from the drives: [source,shell] .... # graid delete raid/r0 .... [[geom-graid-unexpected]] === Deleting Unexpected Arrays Drives may unexpectedly contain man:graid[8] metadata, either from previous use or manufacturer testing. man:graid[8] will detect these drives and create an array, interfering with access to the individual drive. To remove the unwanted metadata: [.procedure] . Boot the system. At the boot menu, select `2` for the loader prompt. Enter: + [source,shell] .... OK set kern.geom.raid.enable=0 OK boot .... + The system will boot with man:graid[8] disabled. . Back up all data on the affected drive. . As a workaround, man:graid[8] array detection can be disabled by adding + [.programlisting] .... kern.geom.raid.enable=0 .... + to [.filename]#/boot/loader.conf#. + To permanently remove the man:graid[8] metadata from the affected drive, boot a FreeBSD installation CD-ROM or memory stick, and select `Shell`. Use `status` to find the name of the array, typically `raid/r0`: + [source,shell] .... # graid status Name Status Components raid/r0 OPTIMAL ada0 (ACTIVE (ACTIVE)) ada1 (ACTIVE (ACTIVE)) .... + Delete the volume by name: + [source,shell] .... # graid delete raid/r0 .... + If there is more than one volume shown, repeat the process for each volume. After the last array has been deleted, the volume will be destroyed. + Reboot and verify data, restoring from backup if necessary. After the metadata has been removed, the `kern.geom.raid.enable=0` entry in [.filename]#/boot/loader.conf# can also be removed. [[geom-ggate]] == GEOM Gate Network GEOM provides a simple mechanism for providing remote access to devices such as disks, CDs, and file systems through the use of the GEOM Gate network daemon, ggated. The system with the device runs the server daemon which handles requests made by clients using ggatec. The devices should not contain any sensitive data as the connection between the client and the server is not encrypted. Similar to NFS, which is discussed in crossref:network-servers[network-nfs,"Network File System (NFS)"], ggated is configured using an exports file. This file specifies which systems are permitted to access the exported resources and what level of access they are offered. For example, to give the client `192.168.1.5` read and write access to the fourth slice on the first SCSI disk, create [.filename]#/etc/gg.exports# with this line: [.programlisting] .... 192.168.1.5 RW /dev/da0s4d .... Before exporting the device, ensure it is not currently mounted. Then, start ggated: [source,shell] .... # ggated .... Several options are available for specifying an alternate listening port or changing the default location of the exports file. Refer to man:ggated[8] for details. To access the exported device on the client machine, first use `ggatec` to specify the IP address of the server and the device name of the exported device. If successful, this command will display a `ggate` device name to mount. Mount that specified device name on a free mount point. This example connects to the [.filename]#/dev/da0s4d# partition on `192.168.1.1`, then mounts [.filename]#/dev/ggate0# on [.filename]#/mnt#: [source,shell] .... # ggatec create -o rw 192.168.1.1 /dev/da0s4d ggate0 # mount /dev/ggate0 /mnt .... The device on the server may now be accessed through [.filename]#/mnt# on the client. For more details about `ggatec` and a few usage examples, refer to man:ggatec[8]. [NOTE] ==== The mount will fail if the device is currently mounted on either the server or any other client on the network. If simultaneous access is needed to network resources, use NFS instead. ==== When the device is no longer needed, unmount it with `umount` so that the resource is available to other clients. [[geom-glabel]] == Labeling Disk Devices During system initialization, the FreeBSD kernel creates device nodes as devices are found. This method of probing for devices raises some issues. For instance, what if a new disk device is added via USB? It is likely that a flash device may be handed the device name of [.filename]#da0# and the original [.filename]#da0# shifted to [.filename]#da1#. This will cause issues mounting file systems if they are listed in [.filename]#/etc/fstab# which may also prevent the system from booting. One solution is to chain SCSI devices in order so a new device added to the SCSI card will be issued unused device numbers. But what about USB devices which may replace the primary SCSI disk? This happens because USB devices are usually probed before the SCSI card. One solution is to only insert these devices after the system has been booted. Another method is to use only a single ATA drive and never list the SCSI devices in [.filename]#/etc/fstab#. A better solution is to use `glabel` to label the disk devices and use the labels in [.filename]#/etc/fstab#. Since `glabel` stores the label in the last sector of a given provider, the label will remain persistent across reboots. By using this label as a device, the file-system may always be mounted regardless of what device node it is accessed through. [NOTE] ==== `glabel` can create both transient and permanent labels. Only permanent labels are consistent across reboots. Refer to man:glabel[8] for more information on the differences between labels. ==== === Label Types and Examples Permanent labels can be a generic or a file system label. Permanent file system labels can be created with man:tunefs[8] or man:newfs[8]. These types of labels are created in a sub-directory of [.filename]#/dev#, and will be named according to the file system type. For example, UFS2 file system labels will be created in [.filename]#/dev/ufs#. Generic permanent labels can be created with `glabel label`. These are not file system specific and will be created in [.filename]#/dev/label#. Temporary labels are destroyed at the next reboot. These labels are created in [.filename]#/dev/label# and are suited to experimentation. A temporary label can be created using `glabel create`. To create a permanent label for a UFS2 file system without destroying any data, issue the following command: [source,shell] .... # tunefs -L home /dev/da3 .... A label should now exist in [.filename]#/dev/ufs# which may be added to [.filename]#/etc/fstab#: [.programlisting] .... /dev/ufs/home /home ufs rw 2 2 .... [NOTE] ==== The file system must not be mounted while attempting to run `tunefs`. ==== Now the file system may be mounted: [source,shell] .... # mount /home .... From this point on, so long as the [.filename]#geom_label.ko# kernel module is loaded at boot with [.filename]#/boot/loader.conf# or the `GEOM_LABEL` kernel option is present, the device node may change without any ill effect on the system. File systems may also be created with a default label by using the `-L` flag with `newfs`. Refer to man:newfs[8] for more information. The following command can be used to destroy the label: [source,shell] .... # glabel destroy home .... The following example shows how to label the partitions of a boot disk. .Labeling Partitions on the Boot Disk [example] ==== By permanently labeling the partitions on the boot disk, the system should be able to continue to boot normally, even if the disk is moved to another controller or transferred to a different system. For this example, it is assumed that a single ATA disk is used, which is currently recognized by the system as [.filename]#ad0#. It is also assumed that the standard FreeBSD partition scheme is used, with [.filename]#/#, [.filename]#/var#, [.filename]#/usr# and [.filename]#/tmp#, as well as a swap partition. Reboot the system, and at the man:loader[8] prompt, press kbd:[4] to boot into single user mode. Then enter the following commands: [source,shell] .... # glabel label rootfs /dev/ad0s1a GEOM_LABEL: Label for provider /dev/ad0s1a is label/rootfs # glabel label var /dev/ad0s1d GEOM_LABEL: Label for provider /dev/ad0s1d is label/var # glabel label usr /dev/ad0s1f GEOM_LABEL: Label for provider /dev/ad0s1f is label/usr # glabel label tmp /dev/ad0s1e GEOM_LABEL: Label for provider /dev/ad0s1e is label/tmp # glabel label swap /dev/ad0s1b GEOM_LABEL: Label for provider /dev/ad0s1b is label/swap # exit .... The system will continue with multi-user boot. After the boot completes, edit [.filename]#/etc/fstab# and replace the conventional device names, with their respective labels. The final [.filename]#/etc/fstab# will look like this: [.programlisting] .... # Device Mountpoint FStype Options Dump Pass# /dev/label/swap none swap sw 0 0 /dev/label/rootfs / ufs rw 1 1 /dev/label/tmp /tmp ufs rw 2 2 /dev/label/usr /usr ufs rw 2 2 /dev/label/var /var ufs rw 2 2 .... The system can now be rebooted. If everything went well, it will come up normally and `mount` will show: [source,shell] .... # mount /dev/label/rootfs on / (ufs, local) devfs on /dev (devfs, local) /dev/label/tmp on /tmp (ufs, local, soft-updates) /dev/label/usr on /usr (ufs, local, soft-updates) /dev/label/var on /var (ufs, local, soft-updates) .... ==== The man:glabel[8] class supports a label type for UFS file systems, based on the unique file system id, `ufsid`. These labels may be found in [.filename]#/dev/ufsid# and are created automatically during system startup. It is possible to use `ufsid` labels to mount partitions using [.filename]#/etc/fstab#. Use `glabel status` to receive a list of file systems and their corresponding `ufsid` labels: [source,shell] .... % glabel status Name Status Components ufsid/486b6fc38d330916 N/A ad4s1d ufsid/486b6fc16926168e N/A ad4s1f .... In the above example, [.filename]#ad4s1d# represents [.filename]#/var#, while [.filename]#ad4s1f# represents [.filename]#/usr#. Using the `ufsid` values shown, these partitions may now be mounted with the following entries in [.filename]#/etc/fstab#: [.programlisting] .... /dev/ufsid/486b6fc38d330916 /var ufs rw 2 2 /dev/ufsid/486b6fc16926168e /usr ufs rw 2 2 .... Any partitions with `ufsid` labels can be mounted in this way, eliminating the need to manually create permanent labels, while still enjoying the benefits of device name independent mounting. [[geom-gjournal]] == UFS Journaling Through GEOM Support for journals on UFS file systems is available on FreeBSD. The implementation is provided through the GEOM subsystem and is configured using `gjournal`. Unlike other file system journaling implementations, the `gjournal` method is block based and not implemented as part of the file system. It is a GEOM extension. Journaling stores a log of file system transactions, such as changes that make up a complete disk write operation, before meta-data and file writes are committed to the disk. This transaction log can later be replayed to redo file system transactions, preventing file system inconsistencies. This method provides another mechanism to protect against data loss and inconsistencies of the file system. Unlike Soft Updates, which tracks and enforces meta-data updates, and snapshots, which create an image of the file system, a log is stored in disk space specifically for this task. For better performance, the journal may be stored on another disk. In this configuration, the journal provider or storage device should be listed after the device to enable journaling on. The [.filename]#GENERIC# kernel provides support for `gjournal`. To automatically load the [.filename]#geom_journal.ko# kernel module at boot time, add the following line to [.filename]#/boot/loader.conf#: [.programlisting] .... geom_journal_load="YES" .... If a custom kernel is used, ensure the following line is in the kernel configuration file: [.programlisting] .... options GEOM_JOURNAL .... Once the module is loaded, a journal can be created on a new file system using the following steps. In this example, [.filename]#da4# is a new SCSI disk: [source,shell] .... # gjournal load # gjournal label /dev/da4 .... This will load the module and create a [.filename]#/dev/da4.journal# device node on [.filename]#/dev/da4#. A UFS file system may now be created on the journaled device, then mounted on an existing mount point: [source,shell] .... # newfs -O 2 -J /dev/da4.journal # mount /dev/da4.journal /mnt .... [NOTE] ==== In the case of several slices, a journal will be created for each individual slice. For instance, if [.filename]#ad4s1# and [.filename]#ad4s2# are both slices, then `gjournal` will create [.filename]#ad4s1.journal# and [.filename]#ad4s2.journal#. ==== Journaling may also be enabled on current file systems by using `tunefs`. However, _always_ make a backup before attempting to alter an existing file system. In most cases, `gjournal` will fail if it is unable to create the journal, but this does not protect against data loss incurred as a result of misusing `tunefs`. Refer to man:gjournal[8] and man:tunefs[8] for more information about these commands. It is possible to journal the boot disk of a FreeBSD system. Refer to the article extref:{gjournal-desktop}[Implementing UFS Journaling on a Desktop PC] for detailed instructions. diff --git a/documentation/content/en/books/handbook/jails/_index.adoc b/documentation/content/en/books/handbook/jails/_index.adoc index 585bc7bb0b..22fee38e51 100644 --- a/documentation/content/en/books/handbook/jails/_index.adoc +++ b/documentation/content/en/books/handbook/jails/_index.adoc @@ -1,1225 +1,1225 @@ --- title: Chapter 17. Jails and Containers part: Part III. System Administration prev: books/handbook/security next: books/handbook/mac description: Jails improve on the concept of the traditional chroot environment in several ways tags: ["jails", "creating", "managing", "updating"] showBookMenu: true weight: 21 path: "/books/handbook/jails/" --- [[jails]] = Jails and Containers :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 17 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/jails/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[jails-synopsis]] == Synopsis Since system administration is a difficult task, many tools have been developed to make life easier for the administrator. These tools often enhance the way systems are installed, configured, and maintained. One of the tools which can be used to enhance the security of a FreeBSD system is _jails_. Jails have been available since FreeBSD 4.X and continue to be enhanced in their usefulness, performance, reliability, and security. Jails build upon the man:chroot[2] concept, which is used to change the root directory of a set of processes. This creates a safe environment, separate from the rest of the system. Processes created in the chrooted environment can not access files or resources outside of it. For that reason, compromising a service running in a chrooted environment should not allow the attacker to compromise the entire system. However, a chroot has several limitations. It is suited to easy tasks which do not require much flexibility or complex, advanced features. Over time, many ways have been found to escape from a chrooted environment, making it a less than ideal solution for securing services. Jails improve on the concept of the traditional chroot environment in several ways. In a traditional chroot environment, processes are only limited in the part of the file system they can access. The rest of the system resources, system users, running processes, and the networking subsystem are shared by the chrooted processes and the processes of the host system. Jails expand this model by virtualizing access to the file system, the set of users, and the networking subsystem. More fine-grained controls are available for tuning the access of a jailed environment. Jails can be considered as a type of operating system-level virtualization. This chapter covers: * What a jail is and what purpose it may serve in FreeBSD installations. * The different types of jail. * The different ways to configure the network for a jail. * The jail configuration file. * How to create the different types of jail. * How to start, stop, and restart a jail. * The basics of jail administration, both from inside and outside the jail. * How to upgrade the different types of jail. * A incomplete list of the different FreeBSD jail managers. [[jail-types]] == Jail Types Some administrators divide jails into different types, although the underlying technology is the same. Each administrator will have to assess what type of jail to create in each case depending on the problem they have to solve. Below can be found a list of the different types, their characteristics, and considerations for use. [[thick-jails]] === Thick Jails A thick jail is a traditional form of FreeBSD Jail. In a thick jail, a complete copy of the base system is replicated within the jail's environment. This means that the jail has its own separate instance of the FreeBSD base system, including libraries, executables, and configuration files. The jail can be thought of as an almost complete standalone FreeBSD installation, but running within the confines of the host system. This isolation ensures that the processes within the jail are kept separate from those on the host and other jails. Advantages of Thick Jails: * High degree of isolation: Processes within the jail are isolated from the host system and other jails. * Independence: Thick jails can have different versions of libraries, configurations, and software than the host system or other jails. * Security: Since the jail contains its own base system, vulnerabilities or issues affecting the jail environment won't directly impact the host or other jails. Disadvantages of Thick Jails: * Resource overhead: Because each jail maintains its own separate base system, thick jails consume more resources compared to thin jails. * Maintenance: Each jail requires its own maintenance and updates for its base system components. [[thin-jails]] === Thin Jails A thin jail shares the base system using OpenZFS snapshots or NullFS mounts from a template. Only a minimal subset of base system is duplicated for each thin jail, resulting in less resource consumption compared to a thick jail. However, this also means that thin jails have less isolation and independence compared to thick jails. Changes in shared components could potentially affect multiple thin jails simultaneously. In summary, a FreeBSD Thin Jail is a type of FreeBSD Jail that replicates a substantial portion, but not all, of the base system within the isolated environment. Advantages of Thin Jails: * Resource Efficiency: Thin jails are more resource-efficient compared to thick jails. Since they share most of the base system, they consume less disk space and memory. This makes it possible to run more jails on the same hardware without consuming excessive resources. * Faster Deployment: Creating and launching thin jails is generally faster compared to thick jails. This can be particularly advantageous when you need to rapidly deploy multiple instances. * Unified Maintenance: Since thin jails share the majority of their base system with the host system, updates and maintenance of common base system components (such as libraries and binaries) only need to be done once on the host. This simplifies the maintenance process compared to maintaining an individual base system for each thick jail. * Shared Resources: Thin jails can more easily share common resources such as libraries and binaries with the host system. This can potentially lead to more efficient disk caching and improved performance for applications within the jail. Disadvantages of Thin Jails: * Reduced Isolation: The primary disadvantage of thin jails is that they offer less isolation compared to thick jails. Since they share a significant portion of the template's base system, vulnerabilities or issues affecting shared components could potentially impact multiple jails simultaneously. * Security Concerns: The reduced isolation in thin jails could pose security risks, as a compromise in one jail might have a greater potential to affect other jails or the host system. * Dependency Conflicts: If multiple thin jails require different versions of the same libraries or software, managing dependencies can become complex. In some cases, this might require additional effort to ensure compatibility. * Compatibility Challenges: Applications within a thin jail might encounter compatibility issues if they assume a certain base system environment that differs from the shared components provided by the template. [[service-jails]] === Service Jails A service jail shares the complete filesystem tree directly with the host (the jail root path is [.filename]#/#) and as such can access and modify any file on the host, and shares the same user accounts with the host. By default it has no access to the network or other resources which are restricted in jails, but they can be configured to re-use the network of the host and to remove some of the jail-restrictions. The use case for service jails is automatic confinement of services/daemons inside a jail with minimal configuration, and without any knowledge of the files needed by such service/daemon. Service jails exist since FreeBSD 15. Advantages of Service Jails: * Zero Administration: A service jail ready service needs only one config line in [.filename]#/etc/rc.conf#, a service which is not service jails ready needs two config lines. * Resource Efficiency: Service jails are more resource efficient than thin jails, as they do not need any additional disk space or network resource. * Faster Deployment: Creating and launching service jails is generally faster compared to thin jails if only distinct services/daemons shall be jailed and no parallel instances of the same service/daemon is needed. * Shared Resources: Service jails share all resources such as libraries and binaries with the host system. This can potentially lead to more efficient disk caching and improved performance for applications within the jail. * Process Isolation: Service jails isolate a particular service, it can not see processes which are not a child of the service jail, even if they run within the same user account. Disadvantages of Service Jails: * Reduced Isolation: The primary disadvantage of service jails is that they offer no filesystem isolation compared to thick or thin jails. * Security Concerns: The reduced isolation in service jails could pose security risks, as a compromise in one jail might have a greater potential to affect everything on the host system. Most of the configuration of jails which is discussed below is not needed for service jails. To understand how jails work, it is recommended to understand those configuration possibilities. The details about what is needed to configure a service jail is in crossref:jails[service-jails-config, Configuring service jails]. [[vnet-jails]] === VNET Jails A FreeBSD VNET jail is a virtualized environment that allows for the isolation and control of network resources for processes running within it. It provides a high level of network segmentation and security by creating a separate network stack for processes within the jail, ensuring that network traffic within the jail is isolated from the host system and other jails. In essence, FreeBSD VNET jails add a network configuration mechanism. This means a VNET jail can be created as a Thick or Thin Jail. [[linux-jails]] === Linux Jails A FreeBSD Linux Jail is a feature in the FreeBSD operating system that enables the use of Linux binaries and applications within a FreeBSD jail. This functionality is achieved by incorporating a compatibility layer that allows certain Linux system calls and libraries to be translated and executed on the FreeBSD kernel. The purpose of a Linux Jail is to facilitate the execution of Linux software on a FreeBSD system without needing a separate Linux virtual machine or environment. [[host-configuration]] == Host Configuration Before creating any jail on the host system it is necessary to perform certain configuration and obtain some information from the host system. It will be necessary to configure the man:jail[8] utility, create the necessary directories to configure and install jails, obtain information from the host's network, and check whether the host uses OpenZFS or UFS as its file system. [TIP] ==== The FreeBSD version running in the jail can not be newer than the version running in the host. ==== [[host-configuration-jail-utility]] === Jail Utility The man:jail[8] utility manages jails. To start jails when the system boots, run the following commands: [source,shell] .... # sysrc jail_enable="YES" # sysrc jail_parallel_start="YES" .... [TIP] ==== With `jail_parallel_start`, all configured jails will be started in the background. ==== [[jails-networking]] === Networking Networking for FreeBSD jails can be configured several different ways: Host Networking Mode (IP Sharing):: In host networking mode, a jail shares the same networking stack as the host system. When a jail is created in host networking mode it uses the same network interface and IP address. This means that the jail doesn't have a separate IP address, and its network traffic is associated with the host's IP. Virtual Networks (VNET):: Virtual Networks are a feature of FreeBSD jails that offer more advanced and flexible networking solutions than a basic networking mode like host networking. VNET allows the creation of isolated network stacks for each jail, providing them with their own separate IP addresses, routing tables, and network interfaces. This offers a higher level of network isolation and allows jails to function as if they are running on separate virtual machines. The netgraph system:: man:netgraph[4] is a versatile kernel framework for creating custom network configurations. It can be used to define how network traffic flows between jails and the host system and between different jails. [[host-configuration-directories]] === Setting Up the Jail Directory Tree There is no specific place to put the files for the jails. Some administrators use [.filename]#/jail#, others [.filename]#/usr/jail#, and still others [.filename]#/usr/local/jails#. In this chapter [.filename]#/usr/local/jails# will be used. Apart from [.filename]#/usr/local/jails# other directories will be created: * [.filename]#media# will contain the compressed files of the downloaded userlands. * [.filename]#templates# will contain the templates when using Thin Jails. * [.filename]#containers# will contain the jails. When using OpenZFS, execute the following commands to create datasets for these directories: [source,shell] .... # zfs create -o mountpoint=/usr/local/jails zroot/jails # zfs create zroot/jails/media # zfs create zroot/jails/templates # zfs create zroot/jails/containers .... [TIP] ==== In this case, `zroot` was used for the parent dataset, but other datasets could have been used. ==== When using UFS, execute the following commands to create the directories: [source,shell] .... # mkdir /usr/local/jails/ # mkdir /usr/local/jails/media # mkdir /usr/local/jails/templates # mkdir /usr/local/jails/containers .... [[jail-configuration-files]] === Jail Configuration Files There are two ways to configure jails. The first one is to add an entry for each jail to the file [.filename]#/etc/jail.conf#. The other option is to create a file for each jail in the directory [.filename]#/etc/jail.conf.d/#. In case a host system has few jails, an entry for each jail can be added in the file [.filename]#/etc/jail.conf#. If the host system has many jails, it is a good idea to have one configuration file for each jail in the [.filename]#/etc/jail.conf.d/# directory. The files in [.filename]#/etc/jail.conf.d/# must have `.conf` as their extension and have to be included in [.filename]#/etc/jail.conf#: [.programlisting] .... .include "/etc/jail.conf.d/*.conf"; .... A typical jail entry would look like this: [.programlisting] .... jailname { <.> # STARTUP/LOGGING exec.start = "/bin/sh /etc/rc"; <.> exec.stop = "/bin/sh /etc/rc.shutdown"; <.> exec.consolelog = "/var/log/jail_console_${name}.log"; <.> # PERMISSIONS allow.raw_sockets; <.> exec.clean; <.> mount.devfs; <.> # HOSTNAME/PATH host.hostname = "${name}"; <.> path = "/usr/local/jails/containers/${name}"; <.> # NETWORK ip4.addr = 192.168.1.151; <.> ip6.addr = ::ffff:c0a8:197 <.> interface = em0; <.> } .... <.> `jailname` - Name of the jail. <.> `exec.start` - Command(s) to run in the jail environment when a jail is created. A typical command to run is "/bin/sh /etc/rc". <.> `exec.stop` - Command(s) to run in the jail environment before a jail is removed. A typical command to run is "/bin/sh /etc/rc.shutdown". <.> `exec.consolelog` - A file to direct command output (stdout and stderr) to. <.> `allow.raw_sockets` - Allow creating raw sockets inside the jail. Setting this parameter allows utilities like man:ping[8] and man:traceroute[8] to operate inside the jail. <.> `exec.clean` - Run commands in a clean environment. <.> `mount.devfs` - Mount a man:devfs[5] filesystem on the chrooted [.filename]#/dev# directory, and apply the ruleset in the devfs_ruleset parameter to restrict the devices visible inside the jail. <.> `host.hostname` - The hostname of the jail. <.> `path` - The directory which is to be the root of the jail. Any commands that are run inside the jail, either by jail or from man:jexec[8], are run from this directory. <.> `ip4.addr` - IPv4 address. There are two configuration possibilities for IPv4. The first is to establish an IP or a list of IPs as has been done in the example. The other is to use `ip4` instead and set the `inherit` value to inherit the host's IP address. <.> `ip6.addr` - IPv6 address. There are two configuration possibilities for IPv6. The first is to establish an IP or a list of IPs as has been done in the example. The other is to use `ip6` instead and set the `inherit` value to inherit the host's IP address. <.> `interface` - A network interface to add the jail's IP addresses. Usually the host interface. More information about configuration variables can be found in man:jail[8] and man:jail.conf[5]. [[classic-jail]] == Classic Jail (Thick Jail) These jails resemble a real FreeBSD system. They can be managed more or less like a normal host system and updated independently. [[creating-classic-jail]] === Creating a Classic Jail In principle, a jail only needs a hostname, a root directory, an IP address, and a userland. The userland for the jail can be obtained from the official FreeBSD download servers. Execute the following command to download the userland: [source,shell] .... # fetch https://download.freebsd.org/ftp/releases/amd64/amd64/13.2-RELEASE/base.txz -o /usr/local/jails/media/13.2-RELEASE-base.txz .... Once the download is complete, it will be necessary to extract the contents into the jail directory. Execute the following commands to extract the userland into the jail's directory: [source,shell] .... # mkdir -p /usr/local/jails/containers/classic # tar -xf /usr/local/jails/media/13.2-RELEASE-base.txz -C /usr/local/jails/containers/classic --unlink .... With the userland extracted in the jail directory, it will be necessary to copy the timezone and DNS server files: [source,shell] .... # cp /etc/resolv.conf /usr/local/jails/containers/classic/etc/resolv.conf # cp /etc/localtime /usr/local/jails/containers/classic/etc/localtime .... With the files copied, the next thing to do is update to the latest patch level by executing the following command: [source,shell] .... # freebsd-update -b /usr/local/jails/containers/classic/ fetch install .... The last step is to configure the jail. It will be necessary to add an entry to the configuration file [.filename]#/etc/jail.conf# or in [.filename]#jail.conf.d# with the parameters of the jail. An example would be the following: [.programlisting] .... classic { # STARTUP/LOGGING exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.consolelog = "/var/log/jail_console_${name}.log"; # PERMISSIONS allow.raw_sockets; exec.clean; mount.devfs; # HOSTNAME/PATH host.hostname = "${name}"; path = "/usr/local/jails/containers/${name}"; # NETWORK ip4.addr = 192.168.1.151; interface = em0; } .... Execute the following command to start the jail: [source,shell] .... # service jail start classic .... -More information on how to manage jails can be found in the section crossref:jails[jail-management]. +More information on how to manage jails can be found in the section crossref:jails[jail-management, Jail Management]. [[thin-jail]] == Thin Jails Although Thin Jails use the same technology as Thick Jails, the creation procedure is different. Thin jails can be created using OpenZFS snapshots or using templates and NullFS. The use of OpenZFS snapshots and templates using NullFS have certain advantages over classic jails, such as being able to create them faster from snapshots or being able to update multiple jails using NullFS. [[creating-thin-jail-openzfs-snapshots]] === Creating a Thin Jail Using OpenZFS Snapshots Due to the good integration between FreeBSD and OpenZFS it is very easy to create new Thin Jails using OpenZFS Snapshots. To create a Thin Jail using OpenZFS Snapshots the first step is to create a template. Templates will only be used to create new jails. For this reason they are created in "read-only" mode so that jails are created with an immutable base. To create the dataset for the template, execute the following command: [source,shell] .... # zfs create -p zroot/jails/templates/13.2-RELEASE .... Then execute the following command to download the userland: [source,shell] .... # fetch https://download.freebsd.org/ftp/releases/amd64/amd64/13.2-RELEASE/base.txz -o /usr/local/jails/media/13.2-RELEASE-base.txz .... Once the download is complete, it will be necessary to extract the contents in the template directory by executing the following command: [source,shell] .... # tar -xf /usr/local/jails/media/13.2-RELEASE-base.txz -C /usr/local/jails/templates/13.2-RELEASE --unlink .... With the userland extracted in the templates directory, it will be necessary to copy the timezone and DNS server files to the template directory by executing the following command: [source,shell] .... # cp /etc/resolv.conf /usr/local/jails/templates/13.2-RELEASE/etc/resolv.conf # cp /etc/localtime /usr/local/jails/templates/13.2-RELEASE/etc/localtime .... The next thing to do is update to the latest patch level by executing the following command: [source,shell] .... # freebsd-update -b /usr/local/jails/templates/13.2-RELEASE/ fetch install .... Once the update is finished, the template is ready. To create an OpenZFS Snapshot from the template, execute the following command: [source,shell] .... # zfs snapshot zroot/jails/templates/13.2-RELEASE@base .... Once the OpenZFS Snapshot has been created, infinite jails can be created using the OpenZFS clone function. To create a Thin Jail named `thinjail`, execute the following command: [source,shell] .... # zfs clone zroot/jails/templates/13.2-RELEASE@base zroot/jails/containers/thinjail .... The last step is to configure the jail. It will be necessary to add an entry to the configuration file [.filename]#/etc/jail.conf# or in [.filename]#jail.conf.d# with the parameters of the jail. An example would be the following: [.programlisting] .... thinjail { # STARTUP/LOGGING exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.consolelog = "/var/log/jail_console_${name}.log"; # PERMISSIONS allow.raw_sockets; exec.clean; mount.devfs; # HOSTNAME/PATH host.hostname = "${name}"; path = "/usr/local/jails/containers/${name}"; # NETWORK ip4 = inherit; interface = em0; } .... Execute the following command to start the jail: [source,shell] .... # service jail start thinjail .... More information on how to manage jails can be found in the section -crossref:jails[jail-management]. +crossref:jails[jail-management, Jail Management]. [[creating-thin-jail-nullfs]] === Creating a Thin Jail Using NullFS A jail can be created with reduced duplication of system files by using the Thin Jail technique and using NullFS to selectively share specific directories from the host system into the jail. The first step is to create the dataset to save the template, execute the following command if using OpenZFS: [source,shell] .... # zfs create -p zroot/jails/templates/13.2-RELEASE-base .... Or this one if using UFS: [source,shell] .... # mkdir /usr/local/jails/templates/13.2-RELEASE-base .... Then execute the following command to download the userland: [source,shell] .... # fetch https://download.freebsd.org/ftp/releases/amd64/amd64/13.2-RELEASE/base.txz -o /usr/local/jails/media/13.2-RELEASE-base.txz .... Once the download is complete, it will be necessary to extract the contents in the template directory by executing the following command: [source,shell] .... # tar -xf /usr/local/jails/media/13.2-RELEASE-base.txz -C /usr/local/jails/templates/13.2-RELEASE-base --unlink .... Once the userland is extracted in the templates directory, it will be necessary to copy the timezone and DNS server files to the template directory by executing the following command: [source,shell] .... # cp /etc/resolv.conf /usr/local/jails/templates/13.2-RELEASE-base/etc/resolv.conf # cp /etc/localtime /usr/local/jails/templates/13.2-RELEASE-base/etc/localtime .... With the files moved to the template, the next thing to do is update to the latest patch level by executing the following command: [source,shell] .... # freebsd-update -b /usr/local/jails/templates/13.2-RELEASE-base/ fetch install .... In addition to the base template, it is also necessary to create a directory where the `skeleton` will be located. Some directories will be copied from the template to the `skeleton`. Execute the following command to create the dataset for the `skeleton` in case of using OpenZFS: [source,shell] .... # zfs create -p zroot/jails/templates/13.2-RELEASE-skeleton .... Or this one in case of using UFS: [source,shell] .... # mkdir /usr/local/jails/templates/13.2-RELEASE-skeleton .... Then create the `skeleton` directories. The `skeleton` directories will hold the local directories of the jails. Execute the following commands to create the directories: [source,shell] .... # mkdir -p /usr/local/jails/templates/13.2-RELEASE-skeleton/home # mkdir -p /usr/local/jails/templates/13.2-RELEASE-skeleton/usr # mv /usr/local/jails/templates/13.2-RELEASE-base/etc /usr/local/jails/templates/13.2-RELEASE-skeleton/etc # mv /usr/local/jails/templates/13.2-RELEASE-base/usr/local /usr/local/jails/templates/13.2-RELEASE-skeleton/usr/local # mv /usr/local/jails/templates/13.2-RELEASE-base/tmp /usr/local/jails/templates/13.2-RELEASE-skeleton/tmp # mv /usr/local/jails/templates/13.2-RELEASE-base/var /usr/local/jails/templates/13.2-RELEASE-skeleton/var # mv /usr/local/jails/templates/13.2-RELEASE-base/root /usr/local/jails/templates/13.2-RELEASE-skeleton/root .... The next step is to create the symlinks to the `skeleton` by executing the following commands: [source,shell] .... # cd /usr/local/jails/templates/13.2-RELEASE-base/ # mkdir skeleton # ln -s skeleton/etc etc # ln -s skeleton/home home # ln -s skeleton/root root # ln -s ../skeleton/usr/local usr/local # ln -s skeleton/tmp tmp # ln -s skeleton/var var .... With the `skeleton` ready, it will be necessary to copy the data to the jail directory. In case of using OpenZFS, OpenZFS snapshots can be used to easily create as many jails as necessary by executing the following commands: [source,shell] .... # zfs snapshot zroot/jails/templates/13.2-RELEASE-skeleton@base # zfs clone zroot/jails/templates/13.2-RELEASE-skeleton@base zroot/jails/containers/thinjail .... In case of using UFS the man:cp[1] program can be used by executing the following command: [source,shell] .... # cp -R /usr/local/jails/templates/13.2-RELEASE-skeleton /usr/local/jails/containers/thinjail .... Then create the directory in which the base template and the skeleton will be mounted: [source,shell] .... # mkdir -p /usr/local/jails/thinjail-nullfs-base .... Add a jail entry in [.filename]#/etc/jail.conf# or a file in [.filename]#jail.conf.d# as follows: [.programlisting] .... thinjail { # STARTUP/LOGGING exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.consolelog = "/var/log/jail_console_${name}.log"; # PERMISSIONS allow.raw_sockets; exec.clean; mount.devfs; # HOSTNAME/PATH host.hostname = "${name}"; path = "/usr/local/jails/${name}-nullfs-base"; # NETWORK ip4.addr = 192.168.1.153; interface = em0; # MOUNT mount.fstab = "/usr/local/jails/${name}-nullfs-base.fstab"; } .... Then the create the [.filename]#/usr/local/jails/thinjail-nullfs-base.fstab# file as follows: [.programlisting] .... /usr/local/jails/templates/13.2-RELEASE-base /usr/local/jails/thinjail-nullfs-base/ nullfs ro 0 0 /usr/local/jails/containers/thinjail /usr/local/jails/thinjail-nullfs-base/skeleton nullfs rw 0 0 .... Execute the following command to start the jail: [source,shell] .... # service jail start thinjail .... [[creating-vnet-jail]] === Creating a VNET Jail FreeBSD VNET Jails have their own distinct networking stack, including interfaces, IP addresses, routing tables, and firewall rules. The first step to create a VNET jail is to create the man:bridge[4] by executing the following command: [source,shell] .... # ifconfig bridge create .... The output should be similar to the following: [.programlisting] .... bridge0 .... With the `bridge` created, it will be necessary to attach it to the `em0` interface by executing the following command: [source,shell] .... # ifconfig bridge0 addm em0 .... To make this setting persist across reboots, add the following lines to [.filename]#/etc/rc.conf#: [.programlisting] .... defaultrouter="192.168.1.1" cloned_interfaces="bridge0" ifconfig_bridge0="inet 192.168.1.150/24 addm em0 up" .... The next step is to create the jail as indicated above. -Either the crossref:jails[classic-jail] procedure and the -crossref:jails[thin-jail] procedure can be used. +Either the crossref:jails[classic-jail, Classic Jail (Thick Jail)] procedure and the +crossref:jails[thin-jail, Thin Jails] procedure can be used. The only thing that will change is the configuration in the [.filename]#/etc/jail.conf# file. The path [.filename]#/usr/local/jails/containers/vnet# will be used as an example for the created jail. The following is an example configuration for a VNET jail: [.programlisting] .... vnet { # STARTUP/LOGGING exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.consolelog = "/var/log/jail_console_${name}.log"; # PERMISSIONS allow.raw_sockets; exec.clean; mount.devfs; devfs_ruleset = 5; # PATH/HOSTNAME path = "/usr/local/jails/containers/${name}"; host.hostname = "${name}"; # VNET/VIMAGE vnet; vnet.interface = "${epair}b"; # NETWORKS/INTERFACES $id = "154"; <.> $ip = "192.168.1.${id}/24"; $gateway = "192.168.1.1"; $bridge = "bridge0"; <.> $epair = "epair${id}"; # ADD TO bridge INTERFACE exec.prestart = "/sbin/ifconfig ${epair} create up"; exec.prestart += "/sbin/ifconfig ${epair}a up descr jail:${name}"; exec.prestart += "/sbin/ifconfig ${bridge} addm ${epair}a up"; exec.start += "/sbin/ifconfig ${epair}b ${ip} up"; exec.start += "/sbin/route add default ${gateway}"; exec.poststop = "/sbin/ifconfig ${bridge} deletem ${epair}a"; exec.poststop += "/sbin/ifconfig ${epair}a destroy"; } .... <.> Represents the IP of the Jail, it must be *unique*. <.> Refers to the bridge created previously. [[creating-linux-jail]] === Creating a Linux Jail FreeBSD can run Linux inside a jail using crossref:linuxemu[linuxemu,Linux Binary Compatibility] and man:debootstrap[8]. Jails do not have a kernel. They run on the host's kernel. Therefore it is necessary to enable Linux Binary Compatibility in the host system. To enable the Linux ABI at boot time, execute the following command: [source,shell] .... # sysrc linux_enable="YES" .... Once enabled, it can be started without rebooting by executing the following command: [source,shell] .... # service linux start .... The next step will be to create a jail as indicated above, for example in -crossref:jails[creating-thin-jail-openzfs-snapshots], but *without* performing the configuration. +crossref:jails[creating-thin-jail-openzfs-snapshots, Creating a Thin Jail Using OpenZFS Snapshots], but *without* performing the configuration. FreeBSD Linux jails require a specific configuration that will be detailed below. Once the jail has been created as explained above, execute the following command to perform required configuration for the jail and start it: [source,shell] .... # jail -cm \ name=ubuntu \ host.hostname="ubuntu.example.com" \ path="/usr/local/jails/ubuntu" \ interface="em0" \ ip4.addr="192.168.1.150" \ exec.start="/bin/sh /etc/rc" \ exec.stop="/bin/sh /etc/rc.shutdown" \ mount.devfs \ devfs_ruleset=4 \ allow.mount \ allow.mount.devfs \ allow.mount.fdescfs \ allow.mount.procfs \ allow.mount.linprocfs \ allow.mount.linsysfs \ allow.mount.tmpfs \ enforce_statfs=1 .... To access the jail, it will be necessary to install package:sysutils/debootstrap[]. Execute the following command to access the FreeBSD Linux jail: [source,shell] .... # jexec -u root ubuntu .... Inside the jail, execute the following commands to install package:sysutils/debootstrap[] and prepare the Ubuntu environment: [source,shell] .... # pkg install debootstrap # debootstrap jammy /compat/ubuntu .... When the process has finished and the message `Base system installed successfully` is displayed on the console, it will be necessary to stop the jail from the host system by executing the following command: [source,shell] .... # service jail onestop ubuntu .... Then add an entry in [.filename]#/etc/jail.conf# for the Linux jail: [.programlisting] .... ubuntu { # STARTUP/LOGGING exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.consolelog = "/var/log/jail_console_${name}.log"; # PERMISSIONS allow.raw_sockets; exec.clean; mount.devfs; devfs_ruleset = 4; # HOSTNAME/PATH host.hostname = "${name}"; path = "/usr/local/jails/containers/${name}"; # NETWORK ip4.addr = 192.168.1.155; interface = em0; # MOUNT mount += "devfs $path/compat/ubuntu/dev devfs rw 0 0"; mount += "tmpfs $path/compat/ubuntu/dev/shm tmpfs rw,size=1g,mode=1777 0 0"; mount += "fdescfs $path/compat/ubuntu/dev/fd fdescfs rw,linrdlnk 0 0"; mount += "linprocfs $path/compat/ubuntu/proc linprocfs rw 0 0"; mount += "linsysfs $path/compat/ubuntu/sys linsysfs rw 0 0"; mount += "/tmp $path/compat/ubuntu/tmp nullfs rw 0 0"; mount += "/home $path/compat/ubuntu/home nullfs rw 0 0"; } .... Then the jail can be started as usual with the following command: [source,shell] .... # service jail start ubuntu .... The Ubuntu environment can be accessed using the following command: [source,shell] .... # jexec ubuntu chroot /compat/ubuntu /bin/bash .... More information can be found in the chapter crossref:linuxemu[linuxemu,Linux Binary Compatibility]. [[service-jails-config]] === Configuring Service Jails A service jail is configured completely via [.filename]#/etc/rc.conf# or man:sysrc[8]. The base system services are service jails ready. They contain a config line which enables networking or lift other restrictions of jails. Base system services which do not make sense to run inside jails are configured to not be started as a service jail, even if enabled in [.filename]#/etc/rc.conf#. Some examples of such a service are services which want to mount or unmount something in the start of stop method, or only configure something like a route, or firewall, or the like. Third party services may or may not be service jails ready. To check if a service is service jail ready, the following command can be used: [source,shell] .... # grep _svcj_options /path/to/rc.d/servicename .... If there is no output, the service is not service jail ready, or does not need any additional privileges like e.g. network access. If the service is not service jail ready, and needs network access, it can be made ready by adding the necessary config to [.filename]#/etc/rc.conf#: [source,shell] .... # sysrc servicename_svcj_options=net_basic .... For all possible `_svcj_options` see the man:rc.conf[5] man-page. To enable a service jail for a given service, the service needs to be stopped and the `servicename_svcj` variable needs to be set to YES. To put man:syslogd[8] into a service jail, use the following sequence of commands: [source,shell] .... # service syslogd stop # sysrc syslogd_svcj=YES # service syslogd start .... If the `servicename_svcj` variable is changed, the service needs to be stopped before it is changed. If it is not stopped, the rc framework will not detect the correct state of the service and will not be able to do what is requested. Service jails are managed only via man:rc.conf[5]/man:sysrc[8] and the man:service[8] command. The jail utilities, like man:jls[8] as described in crossref:jails[jail-management,Jail Management] can be used to investigate the operation, but the man:jail[8] command is not supposed to be used to manage them. [[jail-management]] == Jail Management Once the jail is created, there are a number of operations that can be performed, like starting, rebooting or deleting the jail, installing software in it, etc. In this section the different actions that can be done with jails from the host will be described. [[list-running-jails]] === List Running Jails To list the jails that are running on the host system, the command man:jls[8] can be used: [source,shell] .... # jls .... The output should be similar to the following: .... JID IP Address Hostname Path 1 192.168.250.70 classic /usr/local/jails/containers/classic .... man:jls[8] supports the `--libxo` argument, which through the man:libxo[3] library allows other types of formats to be displayed, such as `JSON`, `HTML`, etc. For example, execute the following command to get the `JSON` output: [source,shell] .... # jls --libxo=json .... The output should be similar to the following: .... {"__version": "2", "jail-information": {"jail": [{"jid":1,"ipv4":"192.168.250.70","hostname":"classic","path":"/usr/local/jails/containers/classic"}]}} .... [[start-jail]] === Start, Restart, and Stop a Jail man:service[8] is used to start, reboot, or stop a jail on the host. For example, to start a jail, run the following command: [source,shell] .... # service jail start jailname .... Change the `start` argument to `restart` or `stop` to perform other actions on the jail. [[destroy-jail]] === Destroy a Jail Destroying a jail is not as simple as stopping the jail using man:service[8] and removing the jail directory and [.filename]#/etc/jail.conf# entry. FreeBSD takes system security very seriously. For this reason there are certain files that not even the root user can delete. This functionality is known as File Flags. The first step is to stop the desired jail executing the following command: [source,shell] .... # service jail stop jailname .... The second step is to remove these flags with man:chflags[1] by executing the following command, in which `classic` is the name of the jail to remove: [source,shell] .... # chflags -R 0 /usr/local/jails/containers/classic .... The third step is to delete the directory where the jail was: [source,shell] .... # rm -rf /usr/local/jails/containers/classic .... Finally, it will be necessary to remove the jail entry in [.filename]#/etc/jail.conf# or in [.filename]#jail.conf.d#. [[handle-packages-jail]] === Handle Packages in a Jail The man:pkg[8] tool supports the `-j` argument in order to handle packages installed inside the jail. For example, to install package:nginx-lite[] in the jail, the next command can be executed *from the host*: [source,shell] .... # pkg -j classic install nginx-lite .... For more information on working with packages in FreeBSD, see crossref:ports[ports,"Installing Applications: Packages and Ports"]. [[access-jail]] === Access a Jail While it has been stated above that it is best to manage jails from the host system, a jail can be entered with man:jexec[8]. The jail can be entered by running man:jexec[8] from the host: [source,shell] .... # jexec -u root jailname .... When gaining access to the jail, the message configured in man:motd[5] will be displayed. [[execute-commands-jail]] === Execute Commands in a Jail To execute a command from the host system in a jail the man:jexec[8] can be used. For example, to stop a service that is running inside a jail, the command will be executed: [source,shell] .... # jexec -l jailname service nginx stop .... [[jail-upgrading]] == Jail Upgrading Upgrading FreeBSD Jails ensures that the isolated environments remain secure, up-to-date, and in line with the latest features and improvements available in the FreeBSD ecosystem. [[jails-updating]] === Upgrading a Classic Jail or a Thin Jail using OpenZFS Snapshots Jails *must be updated from the host* operating system. The default behavior in FreeBSD is to disallow the use of man:chflags[1] in a jail. This will prevent the update of some files so updating from within the jail will fail. To update the jail to the latest patch release of the version of FreeBSD it is running, execute the following commands on the host: [source,shell] .... # freebsd-update -j classic fetch install # service jail restart classic .... To upgrade the jail to a new major or minor version, first upgrade the host system as described in crossref:cutting-edge[freebsdupdate-upgrade,"Performing Major and Minor Version Upgrades"]. Once the host has been upgraded and rebooted, the jail can then be upgraded. [TIP] ==== In case of upgrade from one version to another, it is easier to create a new jail than to upgrade completely. ==== For example to upgrade from 13.1-RELEASE to 13.2-RELEASE, execute the following commands on the host: [source,shell] .... # freebsd-update -j classic -r 13.2-RELEASE upgrade # freebsd-update -j classic install # service jail restart classic # freebsd-update -j classic install # service jail restart classic .... [NOTE] ==== It is necessary to execute the `install` step two times. The first one upgrades the kernel, and the second one upgrades the rest of the components. ==== Then, if it was a major version upgrade, reinstall all installed packages and restart the jail again. This is required because the ABI version changes when upgrading between major versions of FreeBSD. From the host: [source,shell] .... # pkg -j jailname upgrade -f # service jail restart jailname .... [[upgrading-thin-jail]] === Upgrading a Thin Jail Using NullFS Since Thin Jails that use NullFS share the majority of system directories, they are very easy to update. It is enough to update the template. This allows updating multiple jails at the same time. To update the template to the latest patch release of the version of FreeBSD it is running, execute the following commands on the host: [source,shell] .... # freebsd-update -b /usr/local/jails/templates/13.1-RELEASE-base/ fetch install # service jail restart .... To upgrade the template to a new major or minor version, first upgrade the host system as described in crossref:cutting-edge[freebsdupdate-upgrade,"Performing Major and Minor Version Upgrades"]. Once the host has been upgraded and rebooted, the template can then be upgraded. For example, to upgrade from 13.1-RELEASE to 13.2-RELEASE, execute the following commands on the host: [source,shell] .... # freebsd-update -b /usr/local/jails/templates/13.1-RELEASE-base/ -r 13.2-RELEASE upgrade # freebsd-update -b /usr/local/jails/templates/13.1-RELEASE-base/ install # service jail restart # freebsd-update -b /usr/local/jails/templates/13.1-RELEASE-base/ install # service jail restart .... [[jail-resource-limits]] == Jail Resource Limits Controlling the resources that a jail uses from the host system is a task to be taken into account by the system administrator. man:rctl[8] allows you to manage the resources that a jail can use from the host system. [TIP] ==== The `kern.racct.enable` tunable must be enabled at [.filename]#/boot/loader.conf#. ==== The syntax to limit the resources of a jail is as follows: [.programlisting] .... rctl -a jail::resource:action=amount/percentage .... For example, to limit the maximum RAM that a jail can access, run the following command: [source,shell] .... # rctl -a jail:classic:memoryuse:deny=2G .... To make the limitation persistent across reboots of the host system, it will be necessary to add the rule to the [.filename]#/etc/rctl.conf# file as follows: [.programlisting] .... jail:classic:memoryuse:deny=2G/jail .... More information on resource limits can be found in the security chapter in the crossref:security[security-resourcelimits,"Resource Limits section"]. [[jail-managers-and-containers]] == Jail Managers and Containers As previously explained, each type of FreeBSD Jail can be created and configured manually, but FreeBSD also has third-party utilities to make configuration and administration easier. Below is an incomplete list of the different FreeBSD Jail managers: .Jail Managers [options="header", cols="1,1,1,1"] |=== | Name | License | Package | Documentation | BastilleBSD | BSD-3 | package:sysutils/bastille[] | link:https://bastille.readthedocs.io/en/latest/[Documentation] | pot | BSD-3 | package:sysutils/pot[] | link:https://pot.pizzamig.dev/[Documentation] | cbsd | BSD-2 | package:sysutils/cbsd[] | link:https://www.bsdstore.ru/en/docs.html[Documentation] | AppJail | BSD-3 | package:sysutils/appjail[], for devel package:sysutils/appjail-devel[] | link:https://github.com/DtxdF/AppJail#getting-started[Documentation] | iocage | BSD-2 | package:sysutils/iocage[] | link:https://iocage.readthedocs.io/en/latest/[Documentation] | ezjail | link:https://erdgeist.org/beerware.html[Beer Ware] | package:sysutils/ezjail[] | link:https://erdgeist.org/arts/software/ezjail/[Documentation] |=== diff --git a/documentation/content/en/books/handbook/l10n/_index.adoc b/documentation/content/en/books/handbook/l10n/_index.adoc index 72bed18137..6e5df10648 100644 --- a/documentation/content/en/books/handbook/l10n/_index.adoc +++ b/documentation/content/en/books/handbook/l10n/_index.adoc @@ -1,644 +1,644 @@ --- title: Chapter 25. Localization - i18n/L10n Usage and Setup part: Part III. System Administration prev: books/handbook/virtualization next: books/handbook/cutting-edge description: FreeBSD supports localization into many languages, allowing users to view, input, or process data in non-English languages tags: ["i18n", "L10n", "localization", "Locale", "LANG", "MM_CHARSET", "cap_mkdb"] showBookMenu: true weight: 29 path: "/books/handbook/l10n/" --- [[l10n]] = Localization - i18n/L10n Usage and Setup :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 25 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/l10n/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[l10n-synopsis]] == Synopsis FreeBSD is a distributed project with users and contributors located all over the world. As such, FreeBSD supports localization into many languages, allowing users to view, input, or process data in non-English languages. One can choose from most of the major languages, including, but not limited to: Chinese, German, Japanese, Korean, French, Russian, and Vietnamese. The term internationalization has been shortened to i18n, which represents the number of letters between the first and the last letters of `internationalization`. L10n uses the same naming scheme, but from `localization`. The i18n/L10n methods, protocols, and applications allow users to use languages of their choice. This chapter discusses the internationalization and localization features of FreeBSD. After reading this chapter, you will know: * How locale names are constructed. * How to set the locale for a login shell. * How to configure the console for non-English languages. * How to configure Xorg for different languages. * How to find i18n-compliant applications. * Where to find more information for configuring specific languages. Before reading this chapter, you should: * Know how to crossref:ports[ports,install additional third-party applications]. [[using-localization]] == Using Localization Localization settings are based on three components: the language code, country code, and encoding. Locale names are constructed from these parts as follows: [.programlisting] .... LanguageCode_CountryCode.Encoding .... The _LanguageCode_ and _CountryCode_ are used to determine the country and the specific language variation. -crossref:l10n[locale-lang-country] provides some examples of __LanguageCode_CountryCode__: +crossref:l10n[locale-lang-country,.Common Language and Country Codes] provides some examples of __LanguageCode_CountryCode__: [[locale-lang-country]] .Common Language and Country Codes [cols="1,1", frame="none", options="header"] |=== | LanguageCode_Country Code | Description |en_US |English, United States |ru_RU |Russian, Russia |zh_TW |Traditional Chinese, Taiwan |=== A complete listing of available locales can be found by typing: [source,shell] .... % locale -a | more .... To determine the current locale setting: [source,shell] .... % locale .... Language specific character sets, such as ISO8859-1, ISO8859-15, KOI8-R, and CP437, are described in man:multibyte[3]. The active list of character sets can be found at the http://www.iana.org/assignments/character-sets[IANA Registry]. Some languages, such as Chinese or Japanese, cannot be represented using ASCII characters and require an extended language encoding using either wide or multibyte characters. Examples of wide or multibyte encodings include EUC and Big5. Older applications may mistake these encodings for control characters while newer applications usually recognize these characters. Depending on the implementation, users may be required to compile an application with wide or multibyte character support, or to configure it correctly. [NOTE] ==== FreeBSD uses Xorg-compatible locale encodings. ==== The rest of this section describes the various methods for configuring the locale on a FreeBSD system. The next section will discuss the considerations for finding and compiling applications with i18n support. [[setting-locale]] === Setting Locale for Login Shell Locale settings are configured either in a user's [.filename]#~/.login_conf# or in the startup file of the user's shell: [.filename]#~/.profile#, [.filename]#~/.bashrc#, or [.filename]#~/.cshrc#. Two environment variables should be set: * `LANG`, which sets the locale * `MM_CHARSET`, which sets the MIME character set used by applications In addition to the user's shell configuration, these variables should also be set for specific application configuration and Xorg configuration. Two methods are available for making the needed variable assignments: the crossref:l10n[login-class,login class] method, which is the recommended method, and the crossref:l10n[startup-file,startup file] method. The next two sections demonstrate how to use both methods. [[login-class]] ==== Login Classes Method This first method is the recommended method as it assigns the required environment variables for locale name and MIME character sets for every possible shell. This setup can either be performed by each user or it can be configured for all users by the superuser. This minimal example sets both variables for Latin-1 encoding in the [.filename]#.login_conf# of an individual user's home directory: [.programlisting] .... me:\ :charset=ISO-8859-1:\ :lang=de_DE.ISO8859-1: .... Here is an example of a user's [.filename]#~/.login_conf# that sets the variables for Traditional Chinese in BIG-5 encoding. More variables are needed because some applications do not correctly respect locale variables for Chinese, Japanese, and Korean: [.programlisting] .... #Users who do not wish to use monetary units or time formats #of Taiwan can manually change each variable me:\ :lang=zh_TW.Big5:\ :setenv=LC_ALL=zh_TW.Big5,LC_COLLATE=zh_TW.Big5,LC_CTYPE=zh_TW.Big5,LC_MESSAGES=zh_TW.Big5,LC_MONETARY=zh_TW.Big5,LC_NUMERIC=zh_TW.Big5,LC_TIME=zh_TW.Big5:\ :charset=big5:\ :xmodifiers="@im=gcin": #Set gcin as the XIM Input Server .... Alternately, the superuser can configure all users of the system for localization. The following variables in [.filename]#/etc/login.conf# are used to set the locale and MIME character set: [.programlisting] .... language_name|Account Type Description:\ :charset=MIME_charset:\ :lang=locale_name:\ :tc=default: .... So, the previous Latin-1 example would look like this: [.programlisting] .... german|German Users Accounts:\ :charset=ISO-8859-1:\ :lang=de_DE.ISO8859-1:\ :tc=default: .... See man:login.conf[5] for more details about these variables. Note that it already contains pre-defined _russian_ class. Whenever [.filename]#/etc/login.conf# is edited, remember to execute the following command to update the capability database: [source,shell] .... # cap_mkdb /etc/login.conf .... [NOTE] ==== For an end user, the `cap_mkdb` command will need to be run on their [.filename]#~/.login_conf# for any changes to take effect. ==== ===== Utilities Which Change Login Classes In addition to manually editing [.filename]#/etc/login.conf#, several utilities are available for setting the locale for newly created users. When using `vipw` to add new users, specify the _language_ to set the locale: [.programlisting] .... user:password:1111:11:language:0:0:User Name:/home/user:/bin/sh .... When using `adduser` to add new users, the default language can be pre-configured for all new users or specified for an individual user. If all new users use the same language, set `defaultclass=_language_` in [.filename]#/etc/adduser.conf#. To override this setting when creating a user, either input the required locale at this prompt: [source,shell] .... Enter login class: default []: .... or specify the locale to set when invoking `adduser`: [source,shell] .... # adduser -class language .... If `pw` is used to add new users, specify the locale as follows: [source,shell] .... # pw useradd user_name -L language .... To change the login class of an existing user, `chpass` can be used. Invoke it as superuser and provide the username to edit as the argument. [source,shell] .... # chpass user_name .... [[startup-file]] ==== Shell Startup File Method This second method is not recommended as each shell that is used requires manual configuration, where each shell has a different configuration file and differing syntax. As an example, to set the German language for the `sh` shell, these lines could be added to [.filename]#~/.profile# to set the shell for that user only. These lines could also be added to [.filename]#/etc/profile# or [.filename]#/usr/share/skel/dot.profile# to set that shell for all users: [.programlisting] .... LANG=de_DE.ISO8859-1; export LANG MM_CHARSET=ISO-8859-1; export MM_CHARSET .... However, the name of the configuration file and the syntax used differs for the `csh` shell. These are the equivalent settings for [.filename]#~/.login#, [.filename]#/etc/csh.login#, or [.filename]#/usr/share/skel/dot.login#: [.programlisting] .... setenv LANG de_DE.ISO8859-1 setenv MM_CHARSET ISO-8859-1 .... To complicate matters, the syntax needed to configure Xorg in [.filename]#~/.xinitrc# also depends upon the shell. The first example is for the `sh` shell and the second is for the `csh` shell: [.programlisting] .... LANG=de_DE.ISO8859-1; export LANG .... [.programlisting] .... setenv LANG de_DE.ISO8859-1 .... [[setting-console]] === Console Setup Several localized fonts are available for the console. To see a listing of available fonts, type `ls /usr/share/syscons/fonts`. To configure the console font, specify the _font_name_, without the [.filename]#.fnt# suffix, in [.filename]#/etc/rc.conf#: [.programlisting] .... font8x16=font_name font8x14=font_name font8x8=font_name .... The keymap and screenmap can be set by adding the following to [.filename]#/etc/rc.conf#: [.programlisting] .... scrnmap=screenmap_name keymap=keymap_name keychange="fkey_number sequence" .... To see the list of available screenmaps, type `ls /usr/share/syscons/scrnmaps`. Do not include the [.filename]#.scm# suffix when specifying _screenmap_name_. A screenmap with a corresponding mapped font is usually needed as a workaround for expanding bit 8 to bit 9 on a VGA adapter's font character matrix so that letters are moved out of the pseudographics area if the screen font uses a bit 8 column. To see the list of available keymaps, type `ls /usr/share/syscons/keymaps`. When specifying the _keymap_name_, do not include the [.filename]#.kbd# suffix. To test keymaps without rebooting, use man:kbdmap[1]. The `keychange` entry is usually needed to program function keys to match the selected terminal type because function key sequences cannot be defined in the keymap. Next, set the correct console terminal type in [.filename]#/etc/ttys# for all virtual terminal entries. -crossref:l10n[locale-charset] summarizes the available terminal types.: +crossref:l10n[locale-charset,.Defined Terminal Types for Character Sets] summarizes the available terminal types.: [[locale-charset]] .Defined Terminal Types for Character Sets [cols="1,1", frame="none", options="header"] |=== | Character Set | Terminal Type |ISO8859-1 or ISO8859-15 |`cons25l1` |ISO8859-2 |`cons25l2` |ISO8859-7 |`cons25l7` |KOI8-R |`cons25r` |KOI8-U |`cons25u` |CP437 (VGA default) |`cons25` |US-ASCII |`cons25w` |=== For languages with wide or multibyte characters, install a console for that language from the FreeBSD Ports Collection. -The available ports are summarized in crossref:l10n[locale-console]. +The available ports are summarized in crossref:l10n[locale-console,.Available Console from Ports Collection]. Once installed, refer to the port's [.filename]#pkg-message# or man pages for configuration and usage instructions. [[locale-console]] .Available Console from Ports Collection [cols="1,1", frame="none", options="header"] |=== | Language | Port Location |Traditional Chinese (BIG-5) |package:chinese/big5con[] |Chinese/Japanese/Korean |package:chinese/cce[] |Chinese/Japanese/Korean |package:chinese/zhcon[] |Japanese |package:chinese/kon2[] |Japanese |package:japanese/kon2-14dot[] |Japanese |package:japanese/kon2-16dot[] |=== If moused is enabled in [.filename]#/etc/rc.conf#, additional configuration may be required. By default, the mouse cursor of the man:syscons[4] driver occupies the `0xd0`-`0xd3` range in the character set. If the language uses this range, move the cursor's range by adding the following line to [.filename]#/etc/rc.conf#: [.programlisting] .... mousechar_start=3 .... === Xorg Setup crossref:x11[x11,The X Window System] describes how to install and configure Xorg. When configuring Xorg for localization, additional fonts and input methods are available from the FreeBSD Ports Collection. Application specific i18n settings such as fonts and menus can be tuned in [.filename]#~/.Xresources# and should allow users to view their selected language in graphical application menus. The X Input Method (XIM) protocol is an Xorg standard for inputting non-English characters. -crossref:l10n[locale-xim] summarizes the input method applications which are available in the FreeBSD Ports Collection. +crossref:l10n[locale-xim,.Available Input Methods] summarizes the input method applications which are available in the FreeBSD Ports Collection. Additional Fcitx and Uim applications are also available. [[locale-xim]] .Available Input Methods [cols="1,1", frame="none", options="header"] |=== | Language | Input Method |Chinese |package:chinese/gcin[] |Chinese |package:chinese/ibus-chewing[] |Chinese |package:chinese/ibus-pinyin[] |Chinese |package:chinese/oxim[] |Chinese |package:chinese/scim-fcitx[] |Chinese |package:chinese/scim-pinyin[] |Chinese |package:chinese/scim-tables[] |Japanese |package:japanese/ibus-anthy[] |Japanese |package:japanese/ibus-mozc[] |Japanese |package:japanese/ibus-skk[] |Japanese |package:japanese/im-ja[] |Japanese |package:japanese/kinput2[] |Japanese |package:japanese/scim-anthy[] |Japanese |package:japanese/scim-canna[] |Japanese |package:japanese/scim-honoka[] |Japanese |package:japanese/scim-honoka-plugin-romkan[] |Japanese |package:japanese/scim-honoka-plugin-wnn[] |Japanese |package:japanese/scim-prime[] |Japanese |package:japanese/scim-skk[] |Japanese |package:japanese/scim-tables[] |Japanese |package:japanese/scim-tomoe[] |Japanese |package:japanese/scim-uim[] |Japanese |package:japanese/skkinput[] |Japanese |package:japanese/skkinput3[] |Japanese |package:japanese/uim-anthy[] |Korean |package:korean/ibus-hangul[] |Korean |package:korean/imhangul[] |Korean |package:korean/nabi[] |Korean |package:korean/scim-hangul[] |Korean |package:korean/scim-tables[] |Vietnamese |package:vietnamese/xvnkb[] |Vietnamese |package:vietnamese/x-unikey[] |=== [[l10n-compiling]] == Finding i18n Applications i18n applications are programmed using i18n kits under libraries. These allow developers to write a simple file and translate displayed menus and texts to each language. The link:https://ports.FreeBSD.org[FreeBSD Ports Collection] contains many applications with built-in support for wide or multibyte characters for several languages. Such applications include `i18n` in their names for easy identification. However, they do not always support the language needed. Some applications can be compiled with the specific charset. This is usually done in the port's [.filename]#Makefile# or by passing a value to configure. Refer to the i18n documentation in the respective FreeBSD port's source for more information on how to determine the needed configure value or the port's [.filename]#Makefile# to determine which compile options to use when building the port. [[lang-setup]] == Locale Configuration for Specific Languages This section provides configuration examples for localizing a FreeBSD system for the Russian language. It then provides some additional resources for localizing other languages. [[ru-localize]] === Russian Language (KOI8-R Encoding) This section shows the specific settings needed to localize a FreeBSD system for the Russian language. Refer to crossref:l10n[using-localization,Using Localization] for a complete description of each type of setting. To set this locale for the login shell, add the following lines to each user's [.filename]#~/.login_conf#: [.programlisting] .... me:My Account:\ :charset=KOI8-R:\ :lang=ru_RU.KOI8-R: .... To configure the console, add the following lines to [.filename]#/etc/rc.conf#: [.programlisting] .... keymap="ru.utf-8" scrnmap="utf-82cp866" font8x16="cp866b-8x16" font8x14="cp866-8x14" font8x8="cp866-8x8" mousechar_start=3 .... For each `ttyv` entry in [.filename]#/etc/ttys#, use `cons25r` as the terminal type. To configure printing, a special output filter is needed to convert from KOI8-R to CP866 since most printers with Russian characters come with hardware code page CP866. FreeBSD includes a default filter for this purpose, [.filename]#/usr/libexec/lpr/ru/koi2alt#. To use this filter, add this entry to [.filename]#/etc/printcap#: [.programlisting] .... lp|Russian local line printer:\ :sh:of=/usr/libexec/lpr/ru/koi2alt:\ :lp=/dev/lpt0:sd=/var/spool/output/lpd:lf=/var/log/lpd-errs: .... Refer to man:printcap[5] for a more detailed explanation. To configure support for Russian filenames in mounted MS-DOS(R) file systems, include `-L` and the locale name when adding an entry to [.filename]#/etc/fstab#: [.programlisting] .... /dev/ad0s2 /dos/c msdos rw,-Lru_RU.KOI8-R 0 0 .... Refer to man:mount_msdosfs[8] for more details. To configure Russian fonts for Xorg, install the package:x11-fonts/xorg-fonts-cyrillic[] package. Then, check the `"Files"` section in [.filename]#/etc/X11/xorg.conf#. The following line must be added _before_ any other `FontPath` entries: [.programlisting] .... FontPath "/usr/local/lib/X11/fonts/cyrillic" .... Additional Cyrillic fonts are available in the Ports Collection. To activate a Russian keyboard, add the following to the `"Keyboard"` section of [.filename]#/etc/xorg.conf#: [.programlisting] .... Option "XkbLayout" "us,ru" Option "XkbOptions" "grp:toggle" .... Make sure that `XkbDisable` is commented out in that file. For `grp:toggle` use kbd:[Right Alt], for `grp:ctrl_shift_toggle` use kbd:[Ctrl+Shift]. For `grp:caps_toggle` use kbd:[CapsLock]. The old kbd:[CapsLock] function is still available in LAT mode only using kbd:[Shift+CapsLock]. `grp:caps_toggle` does not work in Xorg for some unknown reason. If the keyboard has "Windows(R)" keys, and some non-alphabetical keys are mapped incorrectly, add the following line to [.filename]#/etc/xorg.conf#: [.programlisting] .... Option "XkbVariant" ",winkeys" .... [NOTE] ==== The Russian XKB keyboard may not work with non-localized applications. Minimally localized applications should call a `XtSetLanguageProc (NULL, NULL, NULL);` function early in the program. ==== See http://koi8.pp.ru/xwin.html[http://koi8.pp.ru/xwin.html] for more instructions on localizing Xorg applications. For more general information about KOI8-R encoding, refer to http://koi8.pp.ru/[http://koi8.pp.ru/]. === Additional Language-Specific Resources This section lists some additional resources for configuring other locales. Traditional Chinese for Taiwan:: The FreeBSD-Taiwan Project has a Chinese HOWTO for FreeBSD at http://netlab.cse.yzu.edu.tw/\~statue/freebsd/zh-tut/[http://netlab.cse.yzu.edu.tw/~statue/freebsd/zh-tut/]. Greek Language Localization:: A complete article on Greek support in FreeBSD is available https://www.FreeBSD.org/doc/gr/articles/greek-language-support/[here], in Greek only, as part of the official FreeBSD Greek documentation. Japanese and Korean Language Localization:: For Japanese, refer to http://www.jp.FreeBSD.org/[http://www.jp.FreeBSD.org/], and for Korean, refer to http://www.kr.FreeBSD.org/[http://www.kr.FreeBSD.org/]. Non-English FreeBSD Documentation:: Some FreeBSD contributors have translated parts of the FreeBSD documentation to other languages. They are available through links on the link:https://www.FreeBSD.org/[FreeBSD web site] or in [.filename]#/usr/share/doc#. diff --git a/documentation/content/en/books/handbook/mac/_index.adoc b/documentation/content/en/books/handbook/mac/_index.adoc index d324e3f814..db0bc164aa 100644 --- a/documentation/content/en/books/handbook/mac/_index.adoc +++ b/documentation/content/en/books/handbook/mac/_index.adoc @@ -1,967 +1,967 @@ --- title: Chapter 18. Mandatory Access Control part: Part III. System Administration prev: books/handbook/jails next: books/handbook/audit description: "This chapter focuses on the MAC framework and the set of pluggable security policy modules FreeBSD provides for enabling various security mechanisms" tags: ["MAC", "labels", "security", "configuration", "nagios"] showBookMenu: true weight: 22 path: "/books/handbook/mac/" --- [[mac]] = Mandatory Access Control :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 18 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/mac/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[mac-synopsis]] == Synopsis FreeBSD supports security extensions based on the POSIX(R).1e draft. These security mechanisms include file system Access Control Lists (crossref:security[fs-acl,“Access Control Lists”]) and Mandatory Access Control (MAC). MAC allows access control modules to be loaded in order to implement security policies. Some modules provide protections for a narrow subset of the system, hardening a particular service. Others provide comprehensive labeled security across all subjects and objects. The mandatory part of the definition indicates that enforcement of controls is performed by administrators and the operating system. This is in contrast to the default security mechanism of Discretionary Access Control (DAC) where enforcement is left to the discretion of users. This chapter focuses on the MAC framework and the set of pluggable security policy modules FreeBSD provides for enabling various security mechanisms. After reading this chapter, you will know: * The terminology associated with the MAC framework. * The capabilities of MAC security policy modules as well as the difference between a labeled and non-labeled policy. * The considerations to take into account before configuring a system to use the MAC framework. * Which MAC security policy modules are included in FreeBSD and how to configure them. * How to implement a more secure environment using the MAC framework. * How to test the MAC configuration to ensure the framework has been properly implemented. Before reading this chapter, you should: * Understand UNIX(R) and FreeBSD basics (crossref:basics[basics,FreeBSD Basics]). * Have some familiarity with security and how it pertains to FreeBSD (crossref:security[security,Security]). [WARNING] ==== Improper MAC configuration may cause loss of system access, aggravation of users, or inability to access the features provided by Xorg. More importantly, MAC should not be relied upon to completely secure a system. The MAC framework only augments an existing security policy. Without sound security practices and regular security checks, the system will never be completely secure. The examples contained within this chapter are for demonstration purposes and the example settings should _not_ be implemented on a production system. Implementing any security policy takes a good deal of understanding, proper design, and thorough testing. ==== While this chapter covers a broad range of security issues relating to the MAC framework, the development of new MAC security policy modules will not be covered. A number of security policy modules included with the MAC framework have specific characteristics which are provided for both testing and new module development. Refer to man:mac_test[4], man:mac_stub[4] and man:mac_none[4] for more information on these security policy modules and the various mechanisms they provide. [[mac-inline-glossary]] == Key Terms The following key terms are used when referring to the MAC framework: * _compartment_: a set of programs and data to be partitioned or separated, where users are given explicit access to specific component of a system. A compartment represents a grouping, such as a work group, department, project, or topic. Compartments make it possible to implement a need-to-know-basis security policy. * _integrity_: the level of trust which can be placed on data. As the integrity of the data is elevated, so does the ability to trust that data. * _level_: the increased or decreased setting of a security attribute. As the level increases, its security is considered to elevate as well. * _label_: a security attribute which can be applied to files, directories, or other items in the system. It could be considered a confidentiality stamp. When a label is placed on a file, it describes the security properties of that file and will only permit access by files, users, and resources with a similar security setting. The meaning and interpretation of label values depends on the policy configuration. Some policies treat a label as representing the integrity or secrecy of an object while other policies might use labels to hold rules for access. * _multilabel_: this property is a file system option which can be set in single-user mode using man:tunefs[8], during boot using man:fstab[5], or during the creation of a new file system. This option permits an administrator to apply different MAC labels on different objects. This option only applies to security policy modules which support labeling. * _single label_: a policy where the entire file system uses one label to enforce access control over the flow of data. Whenever `multilabel` is not set, all files will conform to the same label setting. * _object_: an entity through which information flows under the direction of a _subject_. This includes directories, files, fields, screens, keyboards, memory, magnetic storage, printers or any other data storage or moving device. An object is a data container or a system resource. Access to an object effectively means access to its data. * _subject_: any active entity that causes information to flow between _objects_ such as a user, user process, or system process. On FreeBSD, this is almost always a thread acting in a process on behalf of a user. * _policy_: a collection of rules which defines how objectives are to be achieved. A policy usually documents how certain items are to be handled. This chapter considers a policy to be a collection of rules which controls the flow of data and information and defines who has access to that data and information. * _high-watermark_: this type of policy permits the raising of security levels for the purpose of accessing higher level information. In most cases, the original level is restored after the process is complete. Currently, the FreeBSD MAC framework does not include this type of policy. * _low-watermark_: this type of policy permits lowering security levels for the purpose of accessing information which is less secure. In most cases, the original security level of the user is restored after the process is complete. The only security policy module in FreeBSD to use this is man:mac_lomac[4]. * _sensitivity_: usually used when discussing Multilevel Security (MLS). A sensitivity level describes how important or secret the data should be. As the sensitivity level increases, so does the importance of the secrecy, or confidentiality, of the data. [[mac-understandlabel]] == Understanding MAC Labels A MAC label is a security attribute which may be applied to subjects and objects throughout the system. When setting a label, the administrator must understand its implications in order to prevent unexpected or undesired behavior of the system. The attributes available on an object depend on the loaded policy module, as policy modules interpret their attributes in different ways. The security label on an object is used as a part of a security access control decision by a policy. With some policies, the label contains all of the information necessary to make a decision. In other policies, the labels may be processed as part of a larger rule set. There are two types of label policies: single label and multi label. By default, the system will use single label. The administrator should be aware of the pros and cons of each in order to implement policies which meet the requirements of the system's security model. A single label security policy only permits one label to be used for every subject or object. Since a single label policy enforces one set of access permissions across the entire system, it provides lower administration overhead, but decreases the flexibility of policies which support labeling. However, in many environments, a single label policy may be all that is required. A single label policy is somewhat similar to DAC as `root` configures the policies so that users are placed in the appropriate categories and access levels. A notable difference is that many policy modules can also restrict `root`. Basic control over objects will then be released to the group, but `root` may revoke or modify the settings at any time. When appropriate, a multi label policy can be set on a UFS file system by passing `multilabel` to man:tunefs[8]. A multi label policy permits each subject or object to have its own independent MAC label. The decision to use a multi label or single label policy is only required for policies which implement the labeling feature, such as `biba`, `lomac`, and `mls`. Some policies, such as `seeotheruids`, `portacl` and `partition`, do not use labels at all. Using a multi label policy on a partition and establishing a multi label security model can increase administrative overhead as everything in that file system has a label. This includes directories, files, and even device nodes. The following command will set `multilabel` on the specified UFS file system. This may only be done in single-user mode and is not a requirement for the swap file system: [source,shell] .... # tunefs -l enable / .... [NOTE] ==== Some users have experienced problems with setting the `multilabel` flag on the root partition. -If this is the case, please review crossref:mac[mac-troubleshoot]. +If this is the case, please review crossref:mac[mac-troubleshoot, Troubleshooting the MAC Framework]. ==== Since the multi label policy is set on a per-file system basis, a multi label policy may not be needed if the file system layout is well designed. Consider an example security MAC model for a FreeBSD web server. This machine uses the single label, `biba/high`, for everything in the default file systems. If the web server needs to run at `biba/low` to prevent write up capabilities, it could be installed to a separate UFS [.filename]#/usr/local# file system set at `biba/low`. === Label Configuration Virtually all aspects of label policy module configuration will be performed using the base system utilities. These commands provide a simple interface for object or subject configuration or the manipulation and verification of the configuration. All configuration may be done using `setfmac`, which is used to set MAC labels on system objects, and `setpmac`, which is used to set the labels on system subjects. For example, to set the `biba` MAC label to `high` on [.filename]#test#: [source,shell] .... # setfmac biba/high test .... If the configuration is successful, the prompt will be returned without error. A common error is `Permission denied` which usually occurs when the label is being set or modified on a restricted object. Other conditions may produce different failures. For instance, the file may not be owned by the user attempting to relabel the object, the object may not exist, or the object may be read-only. A mandatory policy will not allow the process to relabel the file, maybe because of a property of the file, a property of the process, or a property of the proposed new label value. For example, if a user running at low integrity tries to change the label of a high integrity file, or a user running at low integrity tries to change the label of a low integrity file to a high integrity label, these operations will fail. The system administrator may use `setpmac` to override the policy module's settings by assigning a different label to the invoked process: [source,shell] .... # setfmac biba/high test Permission denied # setpmac biba/low setfmac biba/high test # getfmac test test: biba/high .... For currently running processes, such as sendmail, `getpmac` is usually used instead. This command takes a process ID (PID) in place of a command name. If users attempt to manipulate a file not in their access, subject to the rules of the loaded policy modules, the `Operation not permitted` error will be displayed. === Predefined Labels A few FreeBSD policy modules which support the labeling feature offer three predefined labels: `low`, `equal`, and `high`, where: * `low` is considered the lowest label setting an object or subject may have. Setting this on objects or subjects blocks their access to objects or subjects marked high. * `equal` sets the subject or object to be disabled or unaffected and should only be placed on objects considered to be exempt from the policy. * `high` grants an object or subject the highest setting available in the Biba and MLS policy modules. Such policy modules include man:mac_biba[4], man:mac_mls[4] and man:mac_lomac[4]. Each of the predefined labels establishes a different information flow directive. Refer to the manual page of the module to determine the traits of the generic label configurations. === Numeric Labels The Biba and MLS policy modules support a numeric label which may be set to indicate the precise level of hierarchical control. This numeric level is used to partition or sort information into different groups of classification, only permitting access to that group or a higher group level. For example: [.programlisting] .... biba/10:2+3+6(5:2+3-20:2+3+4+5+6) .... may be interpreted as "Biba Policy Label/Grade 10:Compartments 2, 3 and 6: (grade 5 ...") In this example, the first grade would be considered the effective grade with effective compartments, the second grade is the low grade, and the last one is the high grade. In most configurations, such fine-grained settings are not needed as they are considered to be advanced configurations. System objects only have a current grade and compartment. System subjects reflect the range of available rights in the system, and network interfaces, where they are used for access control. The grade and compartments in a subject and object pair are used to construct a relationship known as _dominance_, in which a subject dominates an object, the object dominates the subject, neither dominates the other, or both dominate each other. The "both dominate" case occurs when the two labels are equal. Due to the information flow nature of Biba, a user has rights to a set of compartments that might correspond to projects, but objects also have a set of compartments. Users may have to subset their rights using `su` or `setpmac` in order to access objects in a compartment from which they are not restricted. === User Labels Users are required to have labels so that their files and processes properly interact with the security policy defined on the system. This is configured in [.filename]#/etc/login.conf# using login classes. Every policy module that uses labels will implement the user class setting. To set the user class default label which will be enforced by MAC, add a `label` entry. An example `label` entry containing every policy module is displayed below. Note that in a real configuration, the administrator would never enable every policy module. It is recommended that the rest of this chapter be reviewed before any configuration is implemented. [.programlisting] .... default:\ :copyright=/etc/COPYRIGHT:\ :welcome=/etc/motd:\ :setenv=MAIL=/var/mail/$,BLOCKSIZE=K:\ :path=~/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:\ :manpath=/usr/share/man /usr/local/man:\ :nologin=/usr/sbin/nologin:\ :cputime=1h30m:\ :datasize=8M:\ :vmemoryuse=100M:\ :stacksize=2M:\ :memorylocked=4M:\ :memoryuse=8M:\ :filesize=8M:\ :coredumpsize=8M:\ :openfiles=24:\ :maxproc=32:\ :priority=0:\ :requirehome:\ :passwordtime=91d:\ :umask=022:\ :ignoretime@:\ :label=partition/13,mls/5,biba/10(5-15),lomac/10[2]: .... While users can not modify the default value, they may change their label after they login, subject to the constraints of the policy. The example above tells the Biba policy that a process's minimum integrity is `5`, its maximum is `15`, and the default effective label is `10`. The process will run at `10` until it chooses to change label, perhaps due to the user using `setpmac`, which will be constrained by Biba to the configured range. After any change to [.filename]#login.conf#, the login class capability database must be rebuilt using `cap_mkdb`. Many sites have a large number of users requiring several different user classes. In depth planning is required as this can become difficult to manage. === Network Interface Labels Labels may be set on network interfaces to help control the flow of data across the network. Policies using network interface labels function in the same way that policies function with respect to objects. Users at high settings in Biba, for example, will not be permitted to access network interfaces with a label of `low`. When setting the MAC label on network interfaces, `maclabel` may be passed to `ifconfig`: [source,shell] .... # ifconfig bge0 maclabel biba/equal .... This example will set the MAC label of `biba/equal` on the `bge0` interface. When using a setting similar to `biba/high(low-high)`, the entire label should be quoted to prevent an error from being returned. Each policy module which supports labeling has a tunable which may be used to disable the MAC label on network interfaces. Setting the label to `equal` will have a similar effect. Review the output of `sysctl`, the policy manual pages, and the information in the rest of this chapter for more information on those tunables. [[mac-planning]] == Planning the Security Configuration Before implementing any MAC policies, a planning phase is recommended. During the planning stages, an administrator should consider the implementation requirements and goals, such as: * How to classify information and resources available on the target systems. * Which information or resources to restrict access to along with the type of restrictions that should be applied. * Which MAC modules will be required to achieve this goal. A trial run of the trusted system and its configuration should occur _before_ a MAC implementation is used on production systems. Since different environments have different needs and requirements, establishing a complete security profile will decrease the need of changes once the system goes live. Consider how the MAC framework augments the security of the system as a whole. The various security policy modules provided by the MAC framework could be used to protect the network and file systems or to block users from accessing certain ports and sockets. Perhaps the best use of the policy modules is to load several security policy modules at a time in order to provide a MLS environment. This approach differs from a hardening policy, which typically hardens elements of a system which are used only for specific purposes. The downside to MLS is increased administrative overhead. The overhead is minimal when compared to the lasting effect of a framework which provides the ability to pick and choose which policies are required for a specific configuration and which keeps performance overhead down. The reduction of support for unneeded policies can increase the overall performance of the system as well as offer flexibility of choice. A good implementation would consider the overall security requirements and effectively implement the various security policy modules offered by the framework. A system utilizing MAC guarantees that a user will not be permitted to change security attributes at will. All user utilities, programs, and scripts must work within the constraints of the access rules provided by the selected security policy modules and control of the MAC access rules is in the hands of the system administrator. It is the duty of the system administrator to carefully select the correct security policy modules. For an environment that needs to limit access control over the network, the man:mac_portacl[4], man:mac_ifoff[4], and man:mac_biba[4] policy modules make good starting points. For an environment where strict confidentiality of file system objects is required, consider the man:mac_bsdextended[4] and man:mac_mls[4] policy modules. Policy decisions could be made based on network configuration. If only certain users should be permitted access to man:ssh[1], the man:mac_portacl[4] policy module is a good choice. In the case of file systems, access to objects might be considered confidential to some users, but not to others. As an example, a large development team might be broken off into smaller projects where developers in project A might not be permitted to access objects written by developers in project B. Yet both projects might need to access objects created by developers in project C. Using the different security policy modules provided by the MAC framework, users could be divided into these groups and then given access to the appropriate objects. Each security policy module has a unique way of dealing with the overall security of a system. Module selection should be based on a well thought out security policy which may require revision and reimplementation. Understanding the different security policy modules offered by the MAC framework will help administrators choose the best policies for their situations. The rest of this chapter covers the available modules, describes their use and configuration, and in some cases, provides insight on applicable situations. [CAUTION] ==== Implementing MAC is much like implementing a firewall since care must be taken to prevent being completely locked out of the system. The ability to revert back to a previous configuration should be considered and the implementation of MAC over a remote connection should be done with extreme caution. ==== [[mac-policies]] == Available MAC Policies The default FreeBSD kernel includes `options MAC`. This means that every module included with the MAC framework can be loaded with `kldload` as a run-time kernel module. After testing the module, add the module name to [.filename]#/boot/loader.conf# so that it will load during boot. Each module also provides a kernel option for those administrators who choose to compile their own custom kernel. FreeBSD includes a group of policies that will cover most security requirements. Each policy is summarized below. The last three policies support integer settings in place of the three default labels. [[mac-seeotheruids]] === The MAC See Other UIDs Policy Module name: [.filename]#mac_seeotheruids.ko# Kernel configuration line: `options MAC_SEEOTHERUIDS` Boot option: `mac_seeotheruids_load="YES"` The man:mac_seeotheruids[4] module extends the `security.bsd.see_other_uids` and `security.bsd.see_other_gids sysctl` tunables. This option does not require any labels to be set before configuration and can operate transparently with other modules. After loading the module, the following `sysctl` tunables may be used to control its features: * `security.mac.seeotheruids.enabled` enables the module and implements the default settings which deny users the ability to view processes and sockets owned by other users. * `security.mac.seeotheruids.specificgid_enabled` allows specified groups to be exempt from this policy. To exempt specific groups, use the `security.mac.seeotheruids.specificgid=_XXX_ sysctl` tunable, replacing _XXX_ with the numeric group ID to be exempted. * `security.mac.seeotheruids.primarygroup_enabled` is used to exempt specific primary groups from this policy. When using this tunable, `security.mac.seeotheruids.specificgid_enabled` may not be set. [[mac-bsdextended]] === The MAC BSD Extended Policy Module name: [.filename]#mac_bsdextended.ko# Kernel configuration line: `options MAC_BSDEXTENDED` Boot option: `mac_bsdextended_load="YES"` The man:mac_bsdextended[4] module enforces a file system firewall. It provides an extension to the standard file system permissions model, permitting an administrator to create a firewall-like ruleset to protect files, utilities, and directories in the file system hierarchy. When access to a file system object is attempted, the list of rules is iterated until either a matching rule is located or the end is reached. This behavior may be changed using `security.mac.bsdextended.firstmatch_enabled`. Similar to other firewall modules in FreeBSD, a file containing the access control rules can be created and read by the system at boot time using an man:rc.conf[5] variable. The rule list may be entered using man:ugidfw[8] which has a syntax similar to man:ipfw[8]. More tools can be written by using the functions in the man:libugidfw[3] library. After the man:mac_bsdextended[4] module has been loaded, the following command may be used to list the current rule configuration: [source,shell] .... # ugidfw list 0 slots, 0 rules .... By default, no rules are defined and everything is completely accessible. To create a rule which blocks all access by users but leaves `root` unaffected: [source,shell] .... # ugidfw add subject not uid root new object not uid root mode n .... While this rule is simple to implement, it is a very bad idea as it blocks all users from issuing any commands. A more realistic example blocks `user1` all access, including directory listings, to ``_user2_``'s home directory: [source,shell] .... # ugidfw set 2 subject uid user1 object uid user2 mode n # ugidfw set 3 subject uid user1 object gid user2 mode n .... Instead of `user1`, `not uid _user2_` could be used in order to enforce the same access restrictions for all users. However, the `root` user is unaffected by these rules. [NOTE] ==== Extreme caution should be taken when working with this module as incorrect use could block access to certain parts of the file system. ==== [[mac-ifoff]] === The MAC Interface Silencing Policy Module name: [.filename]#mac_ifoff.ko# Kernel configuration line: `options MAC_IFOFF` Boot option: `mac_ifoff_load="YES"` The man:mac_ifoff[4] module is used to disable network interfaces on the fly and to keep network interfaces from being brought up during system boot. It does not use labels and does not depend on any other MAC modules. Most of this module's control is performed through these `sysctl` tunables: * `security.mac.ifoff.lo_enabled` enables or disables all traffic on the loopback, man:lo[4], interface. * `security.mac.ifoff.bpfrecv_enabled` enables or disables all traffic on the Berkeley Packet Filter interface, man:bpf[4]. * `security.mac.ifoff.other_enabled` enables or disables traffic on all other interfaces. One of the most common uses of man:mac_ifoff[4] is network monitoring in an environment where network traffic should not be permitted during the boot sequence. Another use would be to write a script which uses an application such as package:security/aide[] to automatically block network traffic if it finds new or altered files in protected directories. [[mac-portacl]] === The MAC Port Access Control List Policy Module name: [.filename]#mac_portacl.ko# Kernel configuration line: `MAC_PORTACL` Boot option: `mac_portacl_load="YES"` The man:mac_portacl[4] module is used to limit binding to local TCP and UDP ports, making it possible to allow non-`root` users to bind to specified privileged ports below 1024. Once loaded, this module enables the MAC policy on all sockets. The following tunables are available: * `security.mac.portacl.enabled` enables or disables the policy completely. * `security.mac.portacl.port_high` sets the highest port number that man:mac_portacl[4] protects. * `security.mac.portacl.suser_exempt`, when set to a non-zero value, exempts the `root` user from this policy. * `security.mac.portacl.rules` specifies the policy as a text string of the form `rule[,rule,...]`, with as many rules as needed, and where each rule is of the form `idtype:id:protocol:port`. The `idtype` is either `uid` or `gid`. The `protocol` parameter can be `tcp` or `udp`. The `port` parameter is the port number to allow the specified user or group to bind to. Only numeric values can be used for the user ID, group ID, and port parameters. By default, ports below 1024 can only be used by privileged processes which run as `root`. For man:mac_portacl[4] to allow non-privileged processes to bind to ports below 1024, set the following tunables as follows: [source,shell] .... # sysctl security.mac.portacl.port_high=1023 # sysctl net.inet.ip.portrange.reservedlow=0 # sysctl net.inet.ip.portrange.reservedhigh=0 .... To prevent the `root` user from being affected by this policy, set `security.mac.portacl.suser_exempt` to a non-zero value. [source,shell] .... # sysctl security.mac.portacl.suser_exempt=1 .... To allow the `www` user with UID 80 to bind to port 80 without ever needing `root` privilege: [source,shell] .... # sysctl security.mac.portacl.rules=uid:80:tcp:80 .... This next example permits the user with the UID of 1001 to bind to TCP ports 110 (POP3) and 995 (POP3s): [source,shell] .... # sysctl security.mac.portacl.rules=uid:1001:tcp:110,uid:1001:tcp:995 .... [[mac-partition]] === The MAC Partition Policy Module name: [.filename]#mac_partition.ko# Kernel configuration line: `options MAC_PARTITION` Boot option: `mac_partition_load="YES"` The man:mac_partition[4] policy drops processes into specific "partitions" based on their MAC label. Most configuration for this policy is done using man:setpmac[8]. One `sysctl` tunable is available for this policy: * `security.mac.partition.enabled` enables the enforcement of MAC process partitions. When this policy is enabled, users will only be permitted to see their processes, and any others within their partition, but will not be permitted to work with utilities outside the scope of this partition. For instance, a user in the `insecure` class will not be permitted to access `top` as well as many other commands that must spawn a process. This example adds `top` to the label set on users in the `insecure` class. All processes spawned by users in the `insecure` class will stay in the `partition/13` label. [source,shell] .... # setpmac partition/13 top .... This command displays the partition label and the process list: [source,shell] .... # ps Zax .... This command displays another user's process partition label and that user's currently running processes: [source,shell] .... # ps -ZU trhodes .... [NOTE] ==== Users can see processes in ``root``'s label unless the man:mac_seeotheruids[4] policy is loaded. ==== [[mac-mls]] === The MAC Multi-Level Security Module Module name: [.filename]#mac_mls.ko# Kernel configuration line: `options MAC_MLS` Boot option: `mac_mls_load="YES"` The man:mac_mls[4] policy controls access between subjects and objects in the system by enforcing a strict information flow policy. In MLS environments, a "clearance" level is set in the label of each subject or object, along with compartments. Since these clearance levels can reach numbers greater than several thousand, it would be a daunting task to thoroughly configure every subject or object. To ease this administrative overhead, three labels are included in this policy: `mls/low`, `mls/equal`, and `mls/high`, where: * Anything labeled with `mls/low` will have a low clearance level and not be permitted to access information of a higher level. This label also prevents objects of a higher clearance level from writing or passing information to a lower level. * `mls/equal` should be placed on objects which should be exempt from the policy. * `mls/high` is the highest level of clearance possible. Objects assigned this label will hold dominance over all other objects in the system; however, they will not permit the leaking of information to objects of a lower class. MLS provides: * A hierarchical security level with a set of non-hierarchical categories. * Fixed rules of `no read up, no write down`. This means that a subject can have read access to objects on its own level or below, but not above. Similarly, a subject can have write access to objects on its own level or above, but not beneath. * Secrecy, or the prevention of inappropriate disclosure of data. * A basis for the design of systems that concurrently handle data at multiple sensitivity levels without leaking information between secret and confidential. The following `sysctl` tunables are available: * `security.mac.mls.enabled` is used to enable or disable the MLS policy. * `security.mac.mls.ptys_equal` labels all man:pty[4] devices as `mls/equal` during creation. * `security.mac.mls.revocation_enabled` revokes access to objects after their label changes to a label of a lower grade. * `security.mac.mls.max_compartments` sets the maximum number of compartment levels allowed on a system. To manipulate MLS labels, use man:setfmac[8]. To assign a label to an object: [source,shell] .... # setfmac mls/5 test .... To get the MLS label for the file [.filename]#test#: [source,shell] .... # getfmac test .... Another approach is to create a master policy file in [.filename]#/etc/# which specifies the MLS policy information and to feed that file to `setfmac`. When using the MLS policy module, an administrator plans to control the flow of sensitive information. The default `block read up block write down` sets everything to a low state. Everything is accessible and an administrator slowly augments the confidentiality of the information. Beyond the three basic label options, an administrator may group users and groups as required to block the information flow between them. It might be easier to look at the information in clearance levels using descriptive words, such as classifications of `Confidential`, `Secret`, and `Top Secret`. Some administrators instead create different groups based on project levels. Regardless of the classification method, a well thought out plan must exist before implementing a restrictive policy. Some example situations for the MLS policy module include an e-commerce web server, a file server holding critical company information, and financial institution environments. [[mac-biba]] === The MAC Biba Module Module name: [.filename]#mac_biba.ko# Kernel configuration line: `options MAC_BIBA` Boot option: `mac_biba_load="YES"` The man:mac_biba[4] module loads the MAC Biba policy. This policy is similar to the MLS policy with the exception that the rules for information flow are slightly reversed. This is to prevent the downward flow of sensitive information whereas the MLS policy prevents the upward flow of sensitive information. In Biba environments, an "integrity" label is set on each subject or object. These labels are made up of hierarchical grades and non-hierarchical components. As a grade ascends, so does its integrity. Supported labels are `biba/low`, `biba/equal`, and `biba/high`, where: * `biba/low` is considered the lowest integrity an object or subject may have. Setting this on objects or subjects blocks their write access to objects or subjects marked as `biba/high`, but will not prevent read access. * `biba/equal` should only be placed on objects considered to be exempt from the policy. * `biba/high` permits writing to objects set at a lower label, but does not permit reading that object. It is recommended that this label be placed on objects that affect the integrity of the entire system. Biba provides: * Hierarchical integrity levels with a set of non-hierarchical integrity categories. * Fixed rules are `no write up, no read down`, the opposite of MLS. A subject can have write access to objects on its own level or below, but not above. Similarly, a subject can have read access to objects on its own level or above, but not below. * Integrity by preventing inappropriate modification of data. * Integrity levels instead of MLS sensitivity levels. The following tunables can be used to manipulate the Biba policy: * `security.mac.biba.enabled` is used to enable or disable enforcement of the Biba policy on the target machine. * `security.mac.biba.ptys_equal` is used to disable the Biba policy on man:pty[4] devices. * `security.mac.biba.revocation_enabled` forces the revocation of access to objects if the label is changed to dominate the subject. To access the Biba policy setting on system objects, use `setfmac` and `getfmac`: [source,shell] .... # setfmac biba/low test # getfmac test test: biba/low .... Integrity, which is different from sensitivity, is used to guarantee that information is not manipulated by untrusted parties. This includes information passed between subjects and objects. It ensures that users will only be able to modify or access information they have been given explicit access to. The man:mac_biba[4] security policy module permits an administrator to configure which files and programs a user may see and invoke while assuring that the programs and files are trusted by the system for that user. During the initial planning phase, an administrator must be prepared to partition users into grades, levels, and areas. The system will default to a high label once this policy module is enabled, and it is up to the administrator to configure the different grades and levels for users. Instead of using clearance levels, a good planning method could include topics. For instance, only allow developers modification access to the source code repository, source code compiler, and other development utilities. Other users would be grouped into other categories such as testers, designers, or end users and would only be permitted read access. A lower integrity subject is unable to write to a higher integrity subject and a higher integrity subject cannot list or read a lower integrity object. Setting a label at the lowest possible grade could make it inaccessible to subjects. Some prospective environments for this security policy module would include a constrained web server, a development and test machine, and a source code repository. A less useful implementation would be a personal workstation, a machine used as a router, or a network firewall. [[mac-lomac]] === The MAC Low-watermark Module Module name: [.filename]#mac_lomac.ko# Kernel configuration line: `options MAC_LOMAC` Boot option: `mac_lomac_load="YES"` Unlike the MAC Biba policy, the man:mac_lomac[4] policy permits access to lower integrity objects only after decreasing the integrity level to not disrupt any integrity rules. The Low-watermark integrity policy works almost identically to Biba, with the exception of using floating labels to support subject demotion via an auxiliary grade compartment. This secondary compartment takes the form `[auxgrade]`. When assigning a policy with an auxiliary grade, use the syntax `lomac/10[2]`, where `2` is the auxiliary grade. This policy relies on the ubiquitous labeling of all system objects with integrity labels, permitting subjects to read from low integrity objects and then downgrading the label on the subject to prevent future writes to high integrity objects using `[auxgrade]`. The policy may provide greater compatibility and require less initial configuration than Biba. Like the Biba and MLS policies, `setfmac` and `setpmac` are used to place labels on system objects: [source,shell] .... # setfmac /usr/home/trhodes lomac/high[low] # getfmac /usr/home/trhodes lomac/high[low] .... The auxiliary grade `low` is a feature provided only by the MACLOMAC policy. [[mac-userlocked]] == User Lock Down This example considers a relatively small storage system with fewer than fifty users. Users will have login capabilities and are permitted to store data and access resources. For this scenario, the man:mac_bsdextended[4] and man:mac_seeotheruids[4] policy modules could co-exist and block access to system objects while hiding user processes. Begin by adding the following line to [.filename]#/boot/loader.conf#: [.programlisting] .... mac_seeotheruids_load="YES" .... The man:mac_bsdextended[4] security policy module may be activated by adding this line to [.filename]#/etc/rc.conf#: [.programlisting] .... ugidfw_enable="YES" .... Default rules stored in [.filename]#/etc/rc.bsdextended# will be loaded at system initialization. However, the default entries may need modification. Since this machine is expected only to service users, everything may be left commented out except the last two lines in order to force the loading of user owned system objects by default. Add the required users to this machine and reboot. For testing purposes, try logging in as a different user across two consoles. Run `ps aux` to see if processes of other users are visible. Verify that running man:ls[1] on another user's home directory fails. Do not try to test with the `root` user unless the specific ``sysctl``s have been modified to block super user access. [NOTE] ==== When a new user is added, their man:mac_bsdextended[4] rule will not be in the ruleset list. To update the ruleset quickly, unload the security policy module and reload it again using man:kldunload[8] and man:kldload[8]. ==== [[mac-implementing]] == Nagios in a MAC Jail This section demonstrates the steps that are needed to implement the Nagios network monitoring system in a MAC environment. This is meant as an example which still requires the administrator to test that the implemented policy meets the security requirements of the network before using in a production environment. This example requires `multilabel` to be set on each file system. It also assumes that package:net-mgmt/nagios-plugins[], package:net-mgmt/nagios[], and package:www/apache22[] are all installed, configured, and working correctly before attempting the integration into the MAC framework. === Create an Insecure User Class Begin the procedure by adding the following user class to [.filename]#/etc/login.conf#: [.programlisting] .... insecure:\ :copyright=/etc/COPYRIGHT:\ :welcome=/etc/motd:\ :setenv=MAIL=/var/mail/$,BLOCKSIZE=K:\ :path=~/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin :manpath=/usr/share/man /usr/local/man:\ :nologin=/usr/sbin/nologin:\ :cputime=1h30m:\ :datasize=8M:\ :vmemoryuse=100M:\ :stacksize=2M:\ :memorylocked=4M:\ :memoryuse=8M:\ :filesize=8M:\ :coredumpsize=8M:\ :openfiles=24:\ :maxproc=32:\ :priority=0:\ :requirehome:\ :passwordtime=91d:\ :umask=022:\ :ignoretime@:\ :label=biba/10(10-10): .... Then, add the following line to the default user class section: [.programlisting] .... :label=biba/high: .... Save the edits and issue the following command to rebuild the database: [source,shell] .... # cap_mkdb /etc/login.conf .... === Configure Users Set the `root` user to the default class using: [source,shell] .... # pw usermod root -L default .... All user accounts that are not `root` will now require a login class. The login class is required, otherwise users will be refused access to common commands. The following `sh` script should do the trick: [source,shell] .... # for x in `awk -F: '($3 >= 1001) && ($3 != 65534) { print $1 }' \ /etc/passwd`; do pw usermod $x -L default; done; .... Next, drop the `nagios` and `www` accounts into the insecure class: [source,shell] .... # pw usermod nagios -L insecure # pw usermod www -L insecure .... === Create the Contexts File A contexts file should now be created as [.filename]#/etc/policy.contexts#: [.programlisting] .... # This is the default BIBA policy for this system. # System: /var/run(/.*)? biba/equal /dev/(/.*)? biba/equal /var biba/equal /var/spool(/.*)? biba/equal /var/log(/.*)? biba/equal /tmp(/.*)? biba/equal /var/tmp(/.*)? biba/equal /var/spool/mqueue biba/equal /var/spool/clientmqueue biba/equal # For Nagios: /usr/local/etc/nagios(/.*)? biba/10 /var/spool/nagios(/.*)? biba/10 # For apache /usr/local/etc/apache(/.*)? biba/10 .... This policy enforces security by setting restrictions on the flow of information. In this specific configuration, users, including `root`, should never be allowed to access Nagios. Configuration files and processes that are a part of Nagios will be completely self contained or jailed. This file will be read after running `setfsmac` on every file system. This example sets the policy on the root file system: [source,shell] .... # setfsmac -ef /etc/policy.contexts / .... Next, add these edits to the main section of [.filename]#/etc/mac.conf#: [.programlisting] .... default_labels file ?biba default_labels ifnet ?biba default_labels process ?biba default_labels socket ?biba .... === Loader Configuration To finish the configuration, add the following lines to [.filename]#/boot/loader.conf#: [.programlisting] .... mac_biba_load="YES" mac_seeotheruids_load="YES" security.mac.biba.trust_all_interfaces=1 .... And the following line to the network card configuration stored in [.filename]#/etc/rc.conf#. If the primary network configuration is done via DHCP, this may need to be configured manually after every system boot: [.programlisting] .... maclabel biba/equal .... === Testing the Configuration First, ensure that the web server and Nagios will not be started on system initialization and reboot. Ensure that `root` cannot access any of the files in the Nagios configuration directory. If `root` can list the contents of [.filename]#/var/spool/nagios#, something is wrong. Instead, a "permission denied" error should be returned. If all seems well, Nagios, Apache, and Sendmail can now be started: [source,shell] .... # cd /etc/mail && make stop && \ setpmac biba/equal make start && setpmac biba/10\(10-10\) apachectl start && \ setpmac biba/10\(10-10\) /usr/local/etc/rc.d/nagios.sh forcestart .... Double check to ensure that everything is working properly. If not, check the log files for error messages. If needed, use man:sysctl[8] to disable the man:mac_biba[4] security policy module and try starting everything again as usual. [NOTE] ==== The `root` user can still change the security enforcement and edit its configuration files. The following command will permit the degradation of the security policy to a lower grade for a newly spawned shell: [source,shell] .... # setpmac biba/10 csh .... To block this from happening, force the user into a range using man:login.conf[5]. If man:setpmac[8] attempts to run a command outside of the compartment's range, an error will be returned and the command will not be executed. In this case, set root to `biba/high(high-high)`. ==== [[mac-troubleshoot]] == Troubleshooting the MAC Framework This section discusses common configuration errors and how to resolve them. The `multilabel` flag does not stay enabled on the root ([.filename]#/#) partition::: The following steps may resolve this transient error: [.procedure] ==== . Edit [.filename]#/etc/fstab# and set the root partition to `ro` for read-only. . Reboot into single user mode. . Run `tunefs -l enable` on [.filename]#/#. . Reboot the system. . Run `mount -urw`[.filename]#/# and change the `ro` back to `rw` in [.filename]#/etc/fstab# and reboot the system again. . Double-check the output from `mount` to ensure that `multilabel` has been properly set on the root file system. ==== After establishing a secure environment with MAC, Xorg no longer starts::: This could be caused by the MAC `partition` policy or by a mislabeling in one of the MAC labeling policies. To debug, try the following: [.procedure] ==== . Check the error message. If the user is in the `insecure` class, the `partition` policy may be the culprit. Try setting the user's class back to the `default` class and rebuild the database with `cap_mkdb`. If this does not alleviate the problem, go to step two. . Double-check that the label policies are set correctly for the user, Xorg, and the [.filename]#/dev# entries. . If neither of these resolve the problem, send the error message and a description of the environment to the {freebsd-questions}. ==== The `_secure_path: unable to stat .login_conf` error appears::: This error can appear when a user attempts to switch from the `root` user to another user in the system. This message usually occurs when the user has a higher label setting than that of the user they are attempting to become. For instance, if `joe` has a default label of `biba/low` and `root` has a label of `biba/high`, `root` cannot view ``joe``'s home directory. This will happen whether or not `root` has used `su` to become `joe` as the Biba integrity model will not permit `root` to view objects set at a lower integrity level. The system no longer recognizes `root`::: When this occurs, `whoami` returns `0` and `su` returns `who are you?`. + This can happen if a labeling policy has been disabled by man:sysctl[8] or the policy module was unloaded. If the policy is disabled, the login capabilities database needs to be reconfigured. Double check [.filename]#/etc/login.conf# to ensure that all `label` options have been removed and rebuild the database with `cap_mkdb`. + This may also happen if a policy restricts access to [.filename]#master.passwd#. This is usually caused by an administrator altering the file under a label which conflicts with the general policy being used by the system. In these cases, the user information would be read by the system and access would be blocked as the file has inherited the new label. Disable the policy using man:sysctl[8] and everything should return to normal. diff --git a/documentation/content/en/books/handbook/mail/_index.adoc b/documentation/content/en/books/handbook/mail/_index.adoc index 6e4ea0e00f..5128c829a2 100644 --- a/documentation/content/en/books/handbook/mail/_index.adoc +++ b/documentation/content/en/books/handbook/mail/_index.adoc @@ -1,964 +1,964 @@ --- title: Chapter 31. Electronic Mail part: IV. Network Communication prev: books/handbook/ppp-and-slip next: books/handbook/network-servers description: This chapter provides a basic introduction to running a mail server on FreeBSD, as well as an introduction to sending and receiving email using FreeBSD tags: ["mail", "sendmail", "dma", "MTA", "SMTP", "mail user agents", "fetchmail", "procmail", "alpine", "mutt", "postfix"] showBookMenu: true weight: 36 path: "/books/handbook/mail/" --- [[mail]] = Electronic Mail :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 31 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/mail/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[mail-synopsis]] == Synopsis "Electronic Mail", better known as email, is one of the most widely used forms of communication today. This chapter provides a basic introduction to running a mail server on FreeBSD, as well as an introduction to sending and receiving email using FreeBSD. For a complete coverage of this subject, refer to the books listed in crossref:bibliography[bibliography,Bibliography]. This chapter covers: * Which software components are involved in sending and receiving electronic mail. * How to configure DragonFly Mail Agent. * Where basic Sendmail configuration files are located in FreeBSD. * The difference between remote and local mailboxes. * How to install and configure an alternate Mail Transfer Agent, replacing DragonFly Mail Agent or Sendmail. * How to troubleshoot common mail server problems. * How to configure Sendmail to only send mail. * How to configure SMTP authentication for added security in Sendmail. * How to install and use a Mail User Agent, such as mutt, to send and receive email. * How to download mail from a remote POP or IMAP server. * How to automatically apply filters and rules to incoming email. [[mail-using]] == Mail Components There are five major parts involved in an email exchange: the Mail User Agent (MUA), the Mail Transfer Agent (MTA), a mail host, a remote or local mailbox, and DNS. This section provides an overview of these components. Mail User Agent (MUA):: The Mail User Agent (MUA) is an application which is used to compose, send, and receive emails. This application can be a command line program, such as the built-in `mail` utility or a third-party application from the Ports Collection, such as alpine, elm, or mutt. Dozens of graphical programs are also available in the Ports Collection, including Claws Mail, Evolution, and Thunderbird. Some organizations provide a web mail program which can be accessed through a web browser. More information about installing and using a MUA on FreeBSD can be found in -crossref:mail[mail-agents]. +crossref:mail[mail-agents, Mail User Agents]. Mail Transfer Agent (MTA):: The Mail Transfer Agent (MTA) is responsible for receiving incoming mail and delivering outgoing mail. Starting with FreeBSD version 14.0, the default MTA is DragonFly Mail Agent (man:dma[8]); in earlier versions, it is man:sendmail[8]. Other MTAs, including Exim, Postfix, and qmail, may be installed to replace the default MTA. Mail Host and Mailboxes:: The mail host is a server that is responsible for delivering and receiving mail for a host or a network. The mail host collects all mail sent to the domain and stores it either in the default `mbox` or the alternative Maildir format, depending on the configuration. Once mail has been stored, it may either be read locally using a MUA or remotely accessed and collected using protocols such as POP or IMAP. If mail is read locally, a POP or IMAP server does not need to be installed. Domain Name System (DNS):: The Domain Name System (DNS) and its daemon man:named[8] play a large role in the delivery of mail. In order to deliver mail from one site to another, the MTA will look up the remote site in DNS to determine which host will receive mail for the destination. This process also occurs when mail is sent from a remote host to the MTA. [[dragonFly-mail-agent]] == DragonFly Mail Agent (DMA) DragonFly Mail Agent (DMA) is the default MTA in FreeBSD starting with version 14.0. man:dma[8] is a small Mail Transport Agent (MTA), designed for home and office use. It accepts mails from locally installed Mail User Agents (MUA) and delivers the mails either locally or to a remote destination. Remote delivery includes several features like TLS/SSL support and SMTP authentication. man:dma[8] is not intended as a replacement for real, big MTAs like man:sendmail[8] or man:postfix[1]. Consequently, man:dma[8] does not listen on port 25 for incoming connections. [[configuring-dragonfly-mail-agent]] === Configuring DragonFly Mail Agent (DMA) DMA comes with a default configuration that will be suitable for many deployments. Custom settings are defined in [.filename]#/etc/dma/dma.conf#, and SMTP authentication is configured in [.filename]#/etc/dma/auth.conf#. [[configuring-gmail-dma]] ==== Using DMA to Route Outgoing Mail through Gmail (STARTTLS:SMTP example) This example [.filename]#/etc/dma/dma.conf# can be used to send mail using Google's SMTP servers. [.programlisting] .... SMARTHOST smtp.gmail.com PORT 587 AUTHPATH /etc/dma/auth.conf SECURETRANSFER STARTTLS MASQUERADE username@gmail.com .... Authentication can be set with one line in [.filename]#/etc/dma/auth.conf#: [.programlisting] .... username@gmail.com|smtp.gmail.com:password .... Execute the following command to test the configuration: [source,shell] .... % echo this is a test | mail -v -s testing-email username@gmail.com .... [[configuring-fastmail-dma]] ==== Using DMA to Route Outgoing Mail through Fastmail (SSL/TLS example) This example [.filename]#/etc/dma/dma.conf# can be used to send mail using Fastmail's SMTP servers. [.programlisting] .... SMARTHOST smtp.fastmail.com PORT 465 AUTHPATH /etc/dma/auth.conf SECURETRANSFER MAILNAME example.server.com .... Authentication can be set with one line in [.filename]#/etc/dma/auth.conf#: [.programlisting] .... username@fastmail.com|smtp.fastmail.com:password .... Execute the following command to test the configuration: [source,shell] .... % echo this is a test | mail -v -s testing-email username@fastmail.com .... [[configuring-custom-dma]] ==== Using DMA to Route Outgoing Mail through a Custom Mail Host This example [.filename]#/etc/dma/dma.conf# can be used to send mail using a custom mail host. [.programlisting] .... SMARTHOST mail.example.org PORT 587 AUTHPATH /etc/dma/auth.conf SECURETRANSFER STARTTLS .... Authentication can be set with one line in [.filename]#/etc/dma/auth.conf#: [.programlisting] .... username@example.org|mail.example.org:password .... Execute the following command to test the configuration: [source,shell] .... % echo this is a test | mail -v -s testing-email username@example.org .... [[sendmail]] == Sendmail Sendmail is a venerable and versatile Mail Transfer Agent (MTA) with a long history in UNIX(R) and UNIX-like systems. It was a part of the FreeBSD base system until FreeBSD 13, offering robust email transport capabilities, extensive customization options, and support for complex routing and filtering. [[configuring-sendmail]] === Configuration Files The configuration files for Sendmail are located in [.filename]#/etc/mail/#. [.filename]#/etc/mail/access#:: This access database file defines which hosts or IP addresses have access to the local mail server and what kind of access they have. Hosts listed as `OK`, which is the default option, are allowed to send mail to this host as long as the mail's final destination is the local machine. Hosts listed as `REJECT` are rejected for all mail connections. Hosts listed as `RELAY` are allowed to send mail for any destination using this mail server. Hosts listed as `ERROR` will have their mail returned with the specified mail error. If a host is listed as `SKIP`, Sendmail will abort the current search for this entry without accepting or rejecting the mail. Hosts listed as `QUARANTINE` will have their messages held and will receive the specified text as the reason for the hold. + Examples of using these options for both IPv4 and IPv6 addresses can be found in the FreeBSD sample configuration, [.filename]#/etc/mail/access.sample#: + To configure the access database, use the format shown in the sample to make entries in [.filename]#/etc/mail/access#, but do not put a comment symbol (`+#+`) in front of the entries. Create an entry for each host or network whose access should be configured. Mail senders that match the left side of the table are affected by the action on the right side of the table. + Whenever this file is updated, update its database and restart Sendmail: + [source,shell] .... # makemap hash /etc/mail/access < /etc/mail/access # service sendmail restart .... [.filename]#/etc/mail/aliases#:: This database file contains a list of virtual mailboxes that are expanded to users, files, programs, or other aliases. Here are a few entries to illustrate the file format: + [.programlisting] .... root: localuser ftp-bugs: joe,eric,paul bit.bucket: /dev/null procmail: "|/usr/local/bin/procmail" .... + The mailbox name on the left side of the colon is expanded to the target(s) on the right. The first entry expands the `root` mailbox to the `localuser` mailbox, which is then looked up in the [.filename]#/etc/mail/aliases# database. If no match is found, the message is delivered to `localuser`. The second entry shows a mail list. Mail to `ftp-bugs` is expanded to the three local mailboxes `joe`, `eric`, and `paul`. A remote mailbox could be specified as _user@example.com_. The third entry shows how to write mail to a file, in this case [.filename]#/dev/null#. The last entry demonstrates how to send mail to a program, [.filename]#/usr/local/bin/procmail#, through a UNIX(R) pipe. Refer to man:aliases[5] for more information about the format of this file. + Whenever this file is updated, run `newaliases` to update and initialize the aliases database. [.filename]#/etc/mail/sendmail.cf#:: This is the master configuration file for Sendmail. It controls the overall behavior of Sendmail, including everything from rewriting email addresses to printing rejection messages to remote mail servers. Accordingly, this configuration file is quite complex. Fortunately, this file rarely needs to be changed for standard mail servers. + The master Sendmail configuration file can be built from man:m4[1] macros that define the features and behavior of Sendmail. Refer to [.filename]#/usr/src/contrib/sendmail/cf/README# for some of the details. + Whenever changes to this file are made, Sendmail needs to be restarted for the changes to take effect. [.filename]#/etc/mail/virtusertable#:: This database file maps mail addresses for virtual domains and users to real mailboxes. These mailboxes can be local, remote, aliases defined in [.filename]#/etc/mail/aliases#, or files. This allows multiple virtual domains to be hosted on one machine. + FreeBSD provides a sample configuration file in [.filename]#/etc/mail/virtusertable.sample# to further demonstrate its format. The following example demonstrates how to create custom entries using that format: + [.programlisting] .... root@example.com root postmaster@example.com postmaster@noc.example.net @example.com joe .... + This file is processed in a first match order. When an email address matches the address on the left, it is mapped to the local mailbox listed on the right. The format of the first entry in this example maps a specific email address to a local mailbox, whereas the format of the second entry maps a specific email address to a remote mailbox. Finally, any email address from `example.com` which has not matched any of the previous entries will match the last mapping and be sent to the local mailbox `joe`. When creating custom entries, use this format and add them to [.filename]#/etc/mail/virtusertable#. Whenever this file is edited, update its database and restart Sendmail: + [source,shell] .... # makemap hash /etc/mail/virtusertable < /etc/mail/virtusertable # service sendmail restart .... [.filename]#/etc/mail/relay-domains#:: In a default FreeBSD installation, Sendmail is configured to only send mail from the host it is running on. For example, if a POP server is available, users will be able to check mail from remote locations but they will not be able to send outgoing emails from outside locations. Typically, a few moments after the attempt, an email will be sent from `MAILER-DAEMON` with a `5.7 Relaying Denied` message. + The most straightforward solution is to add the ISP's FQDN to [.filename]#/etc/mail/relay-domains#. If multiple addresses are needed, add them one per line: + [.programlisting] .... your.isp.example.com other.isp.example.net users-isp.example.org www.example.org .... + After creating or editing this file, restart Sendmail with `service sendmail restart`. + Now any mail sent through the system by any host in this list, provided the user has an account on the system, will succeed. This allows users to send mail from the system remotely without opening the system up to relaying SPAM from the Internet. [[mail-changingmta]] == Changing the Mail Transfer Agent Starting with FreeBSD version 14.0, man:dma[8] is the default MTA, and before 14.0, the default MTA is man:sendmail[8]. However, the system administrator can change the system's MTA. A wide choice of alternative MTAs is available from the `mail` category of the FreeBSD Ports Collection. [WARNING] ==== If the default's outgoing mail service is disabled, it is important that it is replaced with an alternative mail delivery system. Otherwise, system functions such as man:periodic[8] will be unable to deliver their results by email. Many parts of the system expect a functional MTA. If applications continue to use the default binaries to try to send email after they are disabled, mail could go into an inactive queue and never be delivered. ==== [[replace-sendmail-dma]] === Replacing Sendmail with Other MTA In order to completely disable man:sendmail[8] execute the following commands: [source,shell] .... # sysrc sendmail_enable="NO" # sysrc sendmail_submit_enable="NO" # sysrc sendmail_outbound_enable="NO" # sysrc sendmail_msp_queue_enable="NO" .... To only disable man:sendmail[8]'s incoming mail service execute the following command: [source,shell] .... # sysrc sendmail_enable="NO" .... Then stop the man:sendmail[8] service: [source,shell] .... # service sendmail onestop .... Some extra configuration is needed as man:sendmail[8] is so ubiquitous that some software assumes it is already installed and configured. Check [.filename]#/etc/periodic.conf# and make sure that these values are set to `NO`. If this file does not exist, create it with these entries: [.programlisting] .... daily_clean_hoststat_enable="NO" daily_status_mail_rejects_enable="NO" daily_status_include_submit_mailq="NO" daily_submit_queuerun="NO" .... The next step is to install another MTA, man:dma[8] will be used in this example. As pointed above, man:dma[8] is the default MTA in FreeBSD starting with version 14.0. Therefore, it is only necessary to install it from the ports if you are using a previous version. To install it execute the following command: [source,shell] .... # pkg install dma .... -Perform the configuration as indicated in crossref:mail[configuring-dragonfly-mail-agent]. +Perform the configuration as indicated in crossref:mail[configuring-dragonfly-mail-agent, Configuring DragonFly Mail Agent (DMA)]. Then change all the entries in the file [.filename]#/etc/mail/mailer.conf# to man:dma[8]: [.programlisting] .... # Execute the "real" sendmail program, named /usr/libexec/sendmail/sendmail # # If dma(8) is installed, an example mailer.conf that uses dma(8) instead can # be found in /usr/share/examples/dma # sendmail /usr/local/libexec/dma mailq /usr/local/libexec/dma newaliases /usr/local/libexec/dma .... [NOTE] ==== When using the version of man:dma[8] included in the base system, the paths will change to [.filename]#/usr/libexec/dma#. ==== To ensure that anything in the queue is flushed at boot or before shutdown, execute the following command: [source,shell] .... # sysrc dma_flushq_enable="YES" .... Once everything is configured, it is recommended to reboot the system. Rebooting provides the opportunity to ensure that the system is correctly configured to start the new MTA automatically on boot. [[replace-dma]] === Replacing DragonFly Mail Agent (DMA) with Other MTA As noted above, starting with FreeBSD version 14.0, the default MTA is DMA. In this example, package:mail/postfix[] will be used as the alternative MTA. Before installing package:mail/postfix[] some extra configuration is needed. Check [.filename]#/etc/periodic.conf# and make sure that these values are set to `NO`. If this file does not exist, create it with these entries: [.programlisting] .... daily_clean_hoststat_enable="NO" daily_status_mail_rejects_enable="NO" daily_status_include_submit_mailq="NO" daily_submit_queuerun="NO" .... Then install package:mail/postfix[]: [source,shell] .... # pkg install postfix .... To start package:mail/postfix[] at system boot execute the following command: [source,shell] .... # sysrc postfix_enable="YES" .... [TIP] ==== It is good practice to read the installation message after installing an application. Provides useful information about settings, etc. ==== If postfix is *not* already activated in [.filename]#/usr/local/etc/mail/mailer.conf# execute the following commands: [source,shell] .... mv /usr/local/etc/mail/mailer.conf /usr/local/etc/mail/mailer.conf.old install -d /usr/local/etc/mail install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf .... When employing SASL, ensure that postfix has access to read the sasldb file. This is accomplished by adding postfix to group mail and making the [.filename]#/usr/local/etc/sasldb*# file(s) readable by group mail (this should be the default for new installs). Once everything is configured, it is recommended to reboot the system. Rebooting provides the opportunity to ensure that the system is correctly configured to start the new MTA automatically on boot. [[mail-agents]] == Mail User Agents A MUA is an application that is used to send and receive email. As email "evolves" and becomes more complex, MUAs are becoming increasingly powerful and provide users increased functionality and flexibility. The `mail` category of the FreeBSD Ports Collection contains numerous MUAs. These include graphical email clients such as Evolution or Balsa and console based clients such as mutt or alpine. [[mail-command]] === mail man:mail[1] is the default MUA installed with FreeBSD. It is a console based MUA that offers the basic functionality required to send and receive text-based email. It provides limited attachment support and can only access local mailboxes. Although man:mail[1] does not natively support interaction with POP or IMAP servers, these mailboxes may be downloaded to a local `mbox` using an application such as fetchmail or getmail. In order to send and receive email, run man:mail[1]: [source,shell] .... % mail .... The contents of the user's mailbox in [.filename]#/var/mail# are automatically read by man:mail[1]. Should the mailbox be empty, the utility exits with a message indicating that no mail could be found. If mail exists, the application interface starts, and a list of messages will be displayed. Messages are automatically numbered, as can be seen in the following example: [.programlisting] .... Mail version 8.1 6/6/93. Type ? for help. "/var/mail/username": 3 messages 3 new >N 1 root@localhost Mon Mar 8 14:05 14/510 "test" N 2 root@localhost Mon Mar 8 14:05 14/509 "user account" N 3 root@localhost Mon Mar 8 14:05 14/509 "sample" .... Messages can now be read by typing kbd:[t] followed by the message number. This example reads the first email: [.programlisting] .... & t 1 Message 1: From root@localhost Mon Mar 8 14:05:52 2004 X-Original-To: username@localhost Delivered-To: username@localhost To: username@localhost Subject: test Date: Mon, 8 Mar 2004 14:05:52 +0200 (SAST) From: root@localhost (Charlie Root) This is a test message, please reply if you receive it. .... As seen in this example, the message will be displayed with full headers. To display the list of messages again, press kbd:[h]. If the email requires a reply, press either kbd:[R] or kbd:[r] man:mail[1] keys. kbd:[R] instructs man:mail[1] to reply only to the sender of the email, while kbd:[r] replies to all other recipients of the message. These commands can be suffixed with the mail number of the message to reply to. After typing the response, the end of the message should be marked by a single kbd:[.] on its own line. An example can be seen below: [.programlisting] .... & R 1 To: root@localhost Subject: Re: test Thank you, I did get your email. . EOT .... In order to send a new email, press kbd:[m], followed by the recipient email address. Multiple recipients may be specified by separating each address with the kbd:[,] delimiter. The subject of the message may then be entered, followed by the message contents. The end of the message should be specified by putting a single kbd:[.] on its own line. [.programlisting] .... & mail root@localhost Subject: I mastered mail Now I can send and receive email using mail ... :) . EOT .... While using man:mail[1], press kbd:[?] to display help at any time. Refer to man:mail[1] for more help on how to use man:mail[1]. [NOTE] ==== man:mail[1] was not designed to handle attachments and thus deals with them poorly. Newer MUAs handle attachments in a more intelligent way. ==== [[mutt-command]] === Mutt Mutt is a powerful MUA, with many features, including: * The ability to thread messages. * PGP support for digital signing and encryption of email. * MIME support. * Maildir support. * Highly customizable. Refer to link:http://www.mutt.org[http://www.mutt.org] for more information on Mutt. [TIP] ==== A Mutt fork called NeoMutt is worth mentioning, which brings added features. See more on the link:https://neomutt.org/about.html[NeoMutt website]. If NeoMutt was chosen, replace the following command examples from `mutt` to `neomutt`. ==== Mutt may be installed using the package:mail/mutt[] port. After the port has been installed, Mutt can be started by issuing the following command: [source,shell] .... % mutt .... Mutt will automatically read and display the contents of the user mailbox in [.filename]#/var/mail#. If no mails are found, Mutt will wait for commands from the user. The example below shows Mutt displaying a list of messages: image::mutt1.png[Mutt email client showing a list of messages] To read an email, select it using the cursor keys and press kbd:[Enter]. An example of Mutt displaying email can be seen below: image::mutt2.png[Mutt email client displaying an email] Similar to man:mail[1], Mutt can be used to reply only to the sender of the message as well as to all recipients. To reply only to the sender of the email, press kbd:[r]. To send a group reply to the original sender as well as all the message recipients, press kbd:[g]. [NOTE] ==== By default, Mutt uses the man:vi[1] editor for creating and replying to emails. Each user can customize this by creating or editing the [.filename]#.muttrc# in their home directory and setting the `editor` variable or by setting the `EDITOR` environment variable. Refer to link:http://www.mutt.org/[http://www.mutt.org/] for more information about configuring Mutt. ==== To compose a new mail message, press kbd:[m]. After a valid subject has been given, Mutt will start man:vi[1] so the email can be written. Once the contents of the email are complete, save and quit from `vi`. Mutt will resume, displaying a summary screen of the mail that is to be delivered. In order to send the mail, press kbd:[y]. An example of the summary screen can be seen below: image::mutt3.png[Mutt email client showing the summary screen] Mutt contains extensive help which can be accessed from most of the menus by pressing kbd:[?]. The top line also displays the keyboard shortcuts where appropriate. [[alpine-command]] === alpine alpine is aimed at a beginner user, but also includes some advanced features. [WARNING] ==== alpine has had several remote vulnerabilities discovered in the past, which allowed remote attackers to execute arbitrary code as users on the local system, by the action of sending a specially-prepared email. While _known_ problems have been fixed, alpine code is written in an insecure style and the FreeBSD Security Officer believes there are likely to be other undiscovered vulnerabilities. Users install alpine at their own risk. ==== The current version of alpine may be installed using the package:mail/alpine[] port. Once the port has installed, alpine can be started by issuing the following command: [source,shell] .... % alpine .... The first time alpine runs, it displays a greeting page with a brief introduction, as well as a request from the alpine development team to send an anonymous email message allowing them to judge how many users are using their client. To send this anonymous message, press kbd:[Enter]. Alternatively, press kbd:[E] to exit the greeting without sending an anonymous message. An example of the greeting page is shown below: image::pine1.png[alpine email client showing the greeting page] The main menu is then presented, which can be navigated using the cursor keys. This main menu provides shortcuts for the composing new mails, browsing mail directories, and administering address book entries. Below the main menu, relevant keyboard shortcuts to perform functions specific to the task at hand are shown. The default directory opened by alpine is [.filename]#inbox#. To view the message index, press kbd:[I], or select the [.guimenuitem]#MESSAGE INDEX# option shown below: image::pine2.png[alpine email client showing the default directory] The message index shows messages in the current directory and can be navigated by using the cursor keys. Highlighted messages can be read by pressing kbd:[Enter]. image::pine3.png[alpine email client showing the message index] In the screenshot below, a sample message is displayed by alpine. Contextual keyboard shortcuts are displayed at the bottom of the screen. An example of one of a shortcut is kbd:[r], which tells the MUA to reply to the current message being displayed. image::pine4.png[alpine email client showing an email] Replying to an email in alpine is done using the pico editor, which is installed by default with alpine. pico makes it easy to navigate the message and is easier for novice users to use than man:vi[1] or man:mail[1]. Once the reply is complete, the message can be sent by pressing kbd:[Ctrl+X]. alpine will ask for confirmation before sending the message. image::pine5.png[alpine email client showing the message compose window] alpine can be customized using the [.guimenuitem]#SETUP# option from the main menu. [[mail-advanced]] == Advanced Topics This section covers more involved topics such as mail configuration and setting up mail for an entire domain. [[mail-config]] === Basic Configuration Out of the box, one can send email to external hosts as long as [.filename]#/etc/resolv.conf# is configured or the network has access to a configured DNS server. To have email delivered to the MTA on the FreeBSD host, do one of the following: * Run a DNS server for the domain. * Get mail delivered directly to the FQDN for the machine. In order to have mail delivered directly to a host, it must have a permanent static IP address, not a dynamic IP address. If the system is behind a firewall, it must be configured to allow SMTP traffic. To receive mail directly at a host, one of these two must be configured: * Make sure that the lowest-numbered MX record in DNS points to the host's static IP address. * Make sure there is no MX entry in the DNS for the host. Either of the above will allow mail to be received directly at the host. Try this: [source,shell] .... # hostname .... The output should be similar to the following: [.programlisting] .... example.FreeBSD.org .... [source,shell] .... # host example.FreeBSD.org .... The output should be similar to the following: [.programlisting] .... example.FreeBSD.org has address 204.216.27.XX .... In this example, mail sent directly to mailto:yourlogin@example.FreeBSD.org[yourlogin@example.FreeBSD.org] should work without problems, assuming a full-featured MTA is running correctly on `example.FreeBSD.org`. Note that man:dma[8] does not listen on port 25 for incoming connections and cannot be used in this scenario. For this example: [source,shell] .... # host example.FreeBSD.org .... The output should be similar to the following: [.programlisting] .... example.FreeBSD.org has address 204.216.27.XX example.FreeBSD.org mail is handled (pri=10) by nevdull.FreeBSD.org .... All mail sent to `example.FreeBSD.org` will be collected on `nevdull` under the same username instead of being sent directly to your host. The above information is handled by the DNS server. The DNS record that carries mail routing information is the link:https://en.wikipedia.org/wiki/MX_record[mail exchanger record (MX record)]. If no MX record exists, mail will be delivered directly to the host by way of its IP address. The MX entry for `freefall.FreeBSD.org` at one time looked like this: [.programlisting] .... freefall MX 30 mail.crl.net freefall MX 40 agora.rdrop.com freefall MX 10 freefall.FreeBSD.org freefall MX 20 who.cdrom.com .... `freefall` had many MX entries. The lowest MX number is the host that receives mail directly, if available. If it is not accessible for some reason, the next lower-numbered host will accept messages temporarily, and pass it along when a lower-numbered host becomes available. Alternate MX sites should have separate Internet connections in order to be most useful. Your ISP can provide this service. [[mail-domain]] === Mail for a Domain When configuring an MTA for a network, any mail sent to hosts in its domain should be diverted to the MTA so that users can receive their mail on the master mail server. To make life easiest, a user account with the same _username_ should exist on both the MTA and the system with the MUA. Use man:adduser[8] to create the user accounts. [TIP] ==== In addition to adding local users to the host, there are alternative methods known as virtual users. Programs like link:https://www.cyrusimap.org/[Cyrus] and link:https://www.dovecot.org/[Dovecot] can be integrated into MTAs to handle users, mail storage, and also provide access via POP3 and IMAP. ==== The MTA must be the designated mail exchanger for each workstation on the network. This is done in the DNS configuration with an MX record: [.programlisting] .... example.FreeBSD.org A 204.216.27.XX ; Workstation MX 10 nevdull.FreeBSD.org ; Mailhost .... This will redirect mail for the workstation to the MTA no matter where the A record points. The mail is sent to the MX host. This must be configured on a DNS server. If the network does not run its own DNS server, talk to the ISP or DNS provider. The following is an example of virtual email hosting. Consider a customer with the domain `customer1.org`, where all the mail for `customer1.org` should be sent to `mail.myhost.com`. The DNS entry should look like this: [.programlisting] .... customer1.org MX 10 mail.myhost.com .... An `A` record is _not_ needed for `customer1.org` in order to only handle email for that domain. However, running `ping` against `customer1.org` will not work unless an `A` record exists for it. Tell the MTA which domains and/or hostnames it should accept mail for. Either of the following will work for Sendmail: * Add the hosts to [.filename]#/etc/mail/local-host-names# when using the `FEATURE(use_cw_file)`. * Add a `Cwyour.host.com` line to [.filename]#/etc/sendmail.cf#. [[outgoing-only]] === Setting Up to Send Only There are many instances where one may only want to send mail through a relay. Some examples are: * The computer is a desktop machine that needs to use programs such as man:mail[1], using the ISP's mail relay. * The computer is a server that does not handle mail locally, but needs to pass off all mail to a relay for processing. While any MTA is capable of filling this particular niche, it can be difficult to properly configure a full-featured MTA just to handle offloading mail. Programs such as Sendmail and Postfix are overkill for this use. Additionally, a typical Internet access service agreement may forbid one from running a "mail server". The easiest way to fulfill those needs is to use the man:dma[8] MTA included in the crossref:mail[configuring-dragonfly-mail-agent, base system]. For systems up to 13.2, need be to installed from ports. In addition to man:dma[8], third-party software can be used to achieve the same, like package:mail/ssmtp[]. [source,shell] .... # cd /usr/ports/mail/ssmtp # make install replace clean .... Once installed, package:mail/ssmtp[] can be configured with [.filename]#/usr/local/etc/ssmtp/ssmtp.conf#: [.programlisting] .... root=yourrealemail@example.com mailhub=mail.example.com rewriteDomain=example.com hostname=_HOSTNAME_ .... Use the real email address for `root`. Enter the ISP's outgoing mail relay in place of `mail.example.com`. Some ISPs call this the "outgoing mail server" or "SMTP server". Make sure to disable Sendmail, including the outgoing mail service. See crossref:mail[mail-disable-sendmail] for details. package:mail/ssmtp[] has some other options available. Refer to the examples in [.filename]#/usr/local/etc/ssmtp# or the manual page of ssmtp for more information. Setting up ssmtp in this manner allows any software on the computer that needs to send mail to function properly, while not violating the ISP's usage policy or allowing the computer to be hijacked for spamming. [[SMTP-Auth]] === SMTP Authentication in Sendmail Configuring SMTP authentication on the MTA provides a number of benefits. SMTP authentication adds a layer of security to Sendmail, and provides mobile users who switch hosts the ability to use the same MTA without the need to reconfigure their mail client's settings each time. Install package:security/cyrus-sasl2[] from the Ports Collection. This port supports a number of compile-time options. For the SMTP authentication method demonstrated in this example, make sure that `LOGIN` is not disabled. After installing package:security/cyrus-sasl2[], edit [.filename]#/usr/local/lib/sasl2/Sendmail.conf#, or create it if it does not exist, and add the following line: [.programlisting] .... pwcheck_method: saslauthd .... Next, install package:security/cyrus-sasl2-saslauthd[] and add execute the following command: [source,shell] .... # sysrc saslauthd_enable="YES" .... Finally, start the saslauthd daemon: [source,shell] .... # service saslauthd start .... This daemon serves as a broker for Sendmail to authenticate against the FreeBSD man:passwd[5] database. This saves the trouble of creating a new set of usernames and passwords for each user that needs to use SMTP authentication, and keeps the login and mail password the same. Next, edit [.filename]#/etc/make.conf# and add the following lines: [.programlisting] .... SENDMAIL_CFLAGS=-I/usr/local/include/sasl -DSASL SENDMAIL_LDADD=/usr/local/lib/libsasl2.so .... These lines provide Sendmail the proper configuration options for linking to package:cyrus-sasl2[] at compile time. Make sure that package:cyrus-sasl2[] has been installed before recompiling Sendmail. Recompile Sendmail by executing the following commands: [source,shell] .... # cd /usr/src/lib/libsmutil # make cleandir && make obj && make # cd /usr/src/lib/libsm # make cleandir && make obj && make # cd /usr/src/usr.sbin/sendmail # make cleandir && make obj && make && make install .... This compile should not have any problems if [.filename]#/usr/src# has not changed extensively and the shared libraries it needs are available. After Sendmail has been compiled and reinstalled, edit [.filename]#/etc/mail/freebsd.mc# or the local [.filename]#.mc#. Many administrators choose to use the output from man:hostname[1] as the name of [.filename]#.mc# for uniqueness. Add these lines: [.programlisting] .... dnl set SASL options TRUST_AUTH_MECH(`GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN')dnl define(`confAUTH_MECHANISMS', `GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN')dnl .... These options configure the different methods available to Sendmail for authenticating users. To use a method other than pwcheck, refer to the Sendmail documentation. Finally, run man:make[1] while in [.filename]#/etc/mail#. That will run the new [.filename]#.mc# and create a [.filename]#.cf# named either [.filename]#freebsd.cf# or the name used for the local [.filename]#.mc#. Then, run `make install restart`, which will copy the file to [.filename]#sendmail.cf#, and properly restart Sendmail. For more information about this process, refer to [.filename]#/etc/mail/Makefile#. To test the configuration, use a MUA to send a test message. For further investigation, set the `LogLevel` of Sendmail to `13` and watch [.filename]#/var/log/maillog# for any errors. For more information, refer to http://www.sendmail.org/~ca/email/auth.html[SMTP authentication]. diff --git a/documentation/content/en/books/handbook/mirrors/_index.adoc b/documentation/content/en/books/handbook/mirrors/_index.adoc index fc806feb07..fef82f8902 100644 --- a/documentation/content/en/books/handbook/mirrors/_index.adoc +++ b/documentation/content/en/books/handbook/mirrors/_index.adoc @@ -1,599 +1,599 @@ --- title: Appendix A. Obtaining FreeBSD part: Part V. Appendices prev: books/handbook/partv next: books/handbook/bibliography description: "How to get FreeBSD: CD and DVD sets, FTP sites and how to install and use Git" tags: ["Obtaining", "CD", "DVD", "FTP", "Git"] showBookMenu: true weight: 41 path: "/books/handbook/mirrors/" --- [appendix] = Obtaining FreeBSD :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: A :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/mirrors/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[mirrors]] == Mirrors The official mirrors of the FreeBSD project are made up of many machines operated by the project cluster administrators and behind GeoDNS to direct users to the closest available mirror. Current locations are Australia, Brazil, Germany, Japan (two sites), Malaysia, South Africa, Sweden, Taiwan, United Kingdom, United States of America (California, New Jersey, and Washington). Official mirrors service: [cols="1,1,3"] |=== | Service Name | Protocols | More information | **docs.FreeBSD.org** | link:https://docs.FreeBSD.org/[https] | FreeBSD Documentation Portal. | **download.FreeBSD.org** | link:https://download.FreeBSD.org/[https] link:ftp://download.FreeBSD.org/pub/FreeBSD/[ftp] | Same content as `ftp.FreeBSD.org`, `ftp` is a legacy name; `download.FreeBSD.org` is recommended. | **git.FreeBSD.org** | git over `https` and `ssh` | More details on link:https://docs.freebsd.org/en/books/handbook/mirrors/#git[using git] section. | **pkg.FreeBSD.org** | man:pkg[8] over `http` and `https` | Official FreeBSD package repositories used by the man:pkg[8] program. | **vuxml.FreeBSD.org** / **www.VuXML.org** | link:https://www.vuxml.org/[https] | FreeBSD Project VuXML web page. `pkg audit` fetches the list of vulnerabilities from this service. | **www.FreeBSD.org** | link:https://www.FreeBSD.org/[https] | FreeBSD Website. |=== All official mirrors support IPv4 and IPv6. http://ftp-archive.FreeBSD.org is not in the GeoDNS Infrastructure, hosted in only one location (US). The project is looking for new locations; those willing to sponsor, please reach out to the Cluster Administrators team for more information. Mirror list maintained by the community and other companies: [cols="1,1,3"] |=== |Country | Hostname | Protocols | Australia icon:envelope[link=mailto:{mirrors-australia-email}, title="mirror contact"] | ftp.au.FreeBSD.org | link:http://ftp.au.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.au.FreeBSD.org/pub/FreeBSD[http_v6] link:rsync://ftp.au.FreeBSD.org[rsync] link:rsync://ftp.au.FreeBSD.org[rsync_v6] | | ftp3.au.FreeBSD.org | link:http://ftp3.au.FreeBSD.org/pub/FreeBSD[http] link:ftp://ftp3.au.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp3.au.FreeBSD.org[rsync] | Austria icon:envelope[link=mailto:{mirrors-austria-email}, title="mirror contact"] | ftp.at.FreeBSD.org | link:http://ftp.at.FreeBSD.org/pub/FreeBSD/[http] link:http://ftp.at.FreeBSD.org/pub/FreeBSD/[http_v6] link:ftp://ftp.at.FreeBSD.org/pub/FreeBSD/[ftp] link:ftp://ftp.at.FreeBSD.org/pub/FreeBSD/[ftp_v6] link:rsync://ftp.at.FreeBSD.org/pub/FreeBSD/[rsync] link:rsync://ftp.at.FreeBSD.org/pub/FreeBSD/[rsync_v6] | Brazil icon:envelope[link=mailto:{mirrors-brazil-email}, title="mirror contact"] | ftp2.br.FreeBSD.org | link:http://ftp2.br.FreeBSD.org/FreeBSD[http] link:rsync://ftp2.br.FreeBSD.org[rsync] link:rsync://ftp2.br.FreeBSD.org[rsync_v6] | | ftp3.br.FreeBSD.org | link:http://ftp3.br.FreeBSD.org/pub/FreeBSD[http] link:ftp://ftp3.br.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp3.br.FreeBSD.org[rsync] | Bulgaria icon:envelope[link=mailto:{mirrors-bulgaria-email}, title="mirror contact"] | ftp.bg.FreeBSD.org | link:ftp://ftp.bg.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.bg.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.bg.FreeBSD.org[rsync] link:rsync://ftp.bg.FreeBSD.org[rsync_v6] | Czech Republic icon:envelope[link=mailto:{mirrors-czech-email}, title="mirror contact"] | ftp.cz.FreeBSD.org | link:http://ftp.cz.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.cz.FreeBSD.org/pub/FreeBSD[http_v6] link:rsync://ftp.cz.FreeBSD.org[rsync] link:rsync://ftp.cz.FreeBSD.org[rsync_v6] | Denmark icon:envelope[link=mailto:{mirrors-denmark-email}, title="mirror contact"] | ftp.dk.FreeBSD.org | link:http://ftp.dk.FreeBSD.org/FreeBSD/[http] link:http://ftp.dk.FreeBSD.org/FreeBSD/[http_v6] link:ftp://ftp.dk.FreeBSD.org/FreeBSD/[ftp] link:ftp://ftp.dk.FreeBSD.org/FreeBSD/[ftp_v6] link:rsync://ftp.dk.FreeBSD.org/FreeBSD/[rsync] link:rsync://ftp.dk.FreeBSD.org/FreeBSD/[rsync_v6] | Finland icon:envelope[link=mailto:{mirrors-finland-email}, title="mirror contact"] | ftp.fi.FreeBSD.org | link:ftp://ftp.fi.FreeBSD.org/pub/FreeBSD[ftp] | France icon:envelope[link=mailto:{mirrors-france-email}, title="mirror contact"] | ftp.fr.FreeBSD.org | link:http://ftp.fr.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.fr.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp.fr.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.fr.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.fr.FreeBSD.org[rsync] link:rsync://ftp.fr.FreeBSD.org[rsync_v6] | | ftp3.fr.FreeBSD.org | link:ftp://ftp3.fr.FreeBSD.org/pub/FreeBSD[ftp] | | ftp6.fr.FreeBSD.org | link:http://ftp6.fr.FreeBSD.org/pub/FreeBSD[http] link:ftp://ftp6.fr.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp6.fr.FreeBSD.org[rsync] | Germany icon:envelope[link=mailto:{mirrors-germany-email}, title="mirror contact"] | ftp.de.FreeBSD.org | link:ftp://ftp.de.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.de.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.de.FreeBSD.org[rsync] link:rsync://ftp.de.FreeBSD.org[rsync_v6] | | ftp1.de.FreeBSD.org | link:http://ftp1.de.FreeBSD.org/pub/FreeBSD[http] link:http://ftp1.de.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp1.de.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp1.de.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp1.de.FreeBSD.org[rsync] link:rsync://ftp1.de.FreeBSD.org[rsync_v6] | | ftp2.de.FreeBSD.org | link:http://ftp2.de.FreeBSD.org/pub/FreeBSD[http] link:http://ftp2.de.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp2.de.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp2.de.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp2.de.FreeBSD.org[rsync] link:rsync://ftp2.de.FreeBSD.org[rsync_v6] | | ftp5.de.FreeBSD.org | link:ftp://ftp5.de.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp5.de.FreeBSD.org/pub/FreeBSD[ftp_v6] | | ftp7.de.FreeBSD.org | link:http://ftp7.de.FreeBSD.org/pub/FreeBSD[http] link:http://ftp7.de.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp7.de.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp7.de.FreeBSD.org/pub/FreeBSD[ftp_v6] | Greece icon:envelope[link=mailto:{mirrors-greece-email}, title="mirror contact"] | ftp.gr.FreeBSD.org | link:http://ftp.gr.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.gr.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp.gr.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.gr.FreeBSD.org/pub/FreeBSD[ftp_v6] | | ftp2.gr.FreeBSD.org | link:http://ftp2.gr.FreeBSD.org/pub/FreeBSD[http] link:http://ftp2.gr.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp2.gr.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp2.gr.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp2.gr.FreeBSD.org[rsync] | Japan icon:envelope[link=mailto:{mirrors-japan-email}, title="mirror contact"] | ftp.jp.FreeBSD.org | link:http://ftp.jp.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.jp.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp.jp.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.jp.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.jp.FreeBSD.org[rsync] link:rsync://ftp.jp.FreeBSD.org[rsync_v6] | | ftp2.jp.FreeBSD.org | link:ftp://ftp2.jp.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp2.jp.FreeBSD.org[rsync] link:rsync://ftp2.jp.FreeBSD.org[rsync_v6] | | ftp3.jp.FreeBSD.org | link:http://ftp3.jp.FreeBSD.org/pub/FreeBSD[http] link:rsync://ftp3.jp.FreeBSD.org[rsync] | | ftp4.jp.FreeBSD.org | link:ftp://ftp4.jp.FreeBSD.org/pub/FreeBSD[ftp] | | ftp6.jp.FreeBSD.org | link:http://ftp6.jp.FreeBSD.org/pub/FreeBSD[http] link:http://ftp6.jp.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp6.jp.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp6.jp.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp6.jp.FreeBSD.org[rsync] link:rsync://ftp6.jp.FreeBSD.org[rsync_v6] | Kazakhstan icon:envelope[link=mailto:support@ps.kz, title="mirror contact"] | mirror.ps.kz | http://mirror.ps.kz/freebsd[http] link:ftp://mirror.ps.kz/freebsd[ftp] | | mirror.neolabs.kz | link:http://mirror.neolabs.kz/freebsd[http] link:ftp://mirror.neolabs.kz/freebsd[ftp] | Korea icon:envelope[link=mailto:{mirrors-korea-email}, title="mirror contact"] | ftp.kr.FreeBSD.org | link:http://ftp.kr.FreeBSD.org/pub/FreeBSD[http] link:https://ftp.kr.FreeBSD.org/pub/FreeBSD[https] link:ftp://ftp.kr.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp.kr.FreeBSD.org[rsync] | | ftp2.kr.FreeBSD.org | link:rsync://ftp2.kr.FreeBSD.org[rsync] | Latvia icon:envelope[link=mailto:{mirrors-latvia-email}, title="mirror contact"] | ftp.lv.FreeBSD.org | link:http://ftp.lv.FreeBSD.org/freebsd[http] link:ftp://ftp.lv.FreeBSD.org/freebsd[ftp] | Netherlands icon:envelope[link=mailto:{mirrors-netherlands-email}, title="mirror contact"] | ftp.nl.FreeBSD.org | link:http://ftp.nl.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.nl.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp.nl.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.nl.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.nl.FreeBSD.org[rsync] link:rsync://ftp.nl.FreeBSD.org[rsync_v6] | | ftp2.nl.FreeBSD.org | link:http://ftp2.nl.FreeBSD.org/pub/FreeBSD[http] link:ftp://ftp2.nl.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp2.nl.FreeBSD.org[rsync] | | mirror.nl.altushost.com | link:https://mirror.nl.altushost.com/FreeBSD[https] | New Zealand icon:envelope[link=mailto:{mirrors-new-zealand-email}, title="mirror contact"] | ftp.nz.FreeBSD.org | link:http://ftp.nz.FreeBSD.org/pub/FreeBSD[http] link:ftp://ftp.nz.FreeBSD.org/pub/FreeBSD[ftp] | Norway icon:envelope[link=mailto:{mirrors-norway-email}, title="mirror contact"] | ftp.no.FreeBSD.org | link:ftp://ftp.no.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.no.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.no.FreeBSD.org[rsync] link:rsync://ftp.no.FreeBSD.org[rsync_v6] | Poland icon:envelope[link=mailto:{mirrors-poland-email}, title="mirror contact"] | ftp.pl.FreeBSD.org | link:http://ftp.pl.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.pl.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp.pl.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp.pl.FreeBSD.org[rsync] link:rsync://ftp.pl.FreeBSD.org[rsync_v6] | Russia icon:envelope[link=mailto:{mirrors-russia-email}, title="mirror contact"] | ftp.ru.FreeBSD.org | link:http://ftp.ru.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.ru.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp.ru.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.ru.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.ru.FreeBSD.org[rsync] link:rsync://ftp.ru.FreeBSD.org[rsync_v6] | | ftp2.ru.FreeBSD.org | link:https://ftp2.ru.FreeBSD.org/pub/FreeBSD[https] link:ftp://ftp2.ru.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp2.ru.FreeBSD.org[rsync] | Slovenia icon:envelope[link=mailto:{mirrors-slovenia-email}, title="mirror contact"] | ftp.si.FreeBSD.org | link:http://ftp.si.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.si.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp.si.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.si.FreeBSD.org/pub/FreeBSD[ftp_v6] | South Africa icon:envelope[link=mailto:{mirrors-south-africa-email}, title="mirror contact"] | ftp.za.FreeBSD.org | link:https://ftp.za.FreeBSD.org/pub/FreeBSD[https] link:https://ftp.za.FreeBSD.org/pub/FreeBSD[https_v6] link:rsync://ftp.za.FreeBSD.org[rsync] link:rsync://ftp.za.FreeBSD.org[rsync_v6] | | ftp2.za.FreeBSD.org | link:http://ftp2.za.FreeBSD.org/pub/FreeBSD[http] link:http://ftp2.za.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp2.za.FreeBSD.org/pub/FreeBSD[ftp_v6] | | ftp4.za.FreeBSD.org | link:http://ftp4.za.FreeBSD.org/pub/FreeBSD[http] link:ftp://ftp4.za.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp4.za.FreeBSD.org[rsync] | Sweden icon:envelope[link=mailto:{mirrors-sweden-email}, title="mirror contact"] | ftp.se.FreeBSD.org | link:http://ftp.se.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.se.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp.se.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.se.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.se.FreeBSD.org[rsync] link:rsync://ftp.se.FreeBSD.org[rsync_v6] | | mirror.se.altushost.com | link:https://mirror.se.altushost.com/FreeBSD[https] | Taiwan icon:envelope[link=mailto:{mirrors-taiwan-email}, title="mirror contact"] | ftp4.tw.FreeBSD.org | link:https://ftp4.tw.FreeBSD.org/pub/FreeBSD[https] link:ftp://ftp4.tw.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp4.tw.FreeBSD.org[rsync] | | ftp5.tw.FreeBSD.org | link:http://ftp5.tw.FreeBSD.org/pub/FreeBSD[http] link:ftp://ftp5.tw.FreeBSD.org/pub/FreeBSD[ftp] | Ukraine icon:envelope[link=mailto:{mirrors-ukraine-email}, title="mirror contact"] | ftp.ua.FreeBSD.org | link:http://ftp.ua.FreeBSD.org/pub/FreeBSD[http] link:ftp://ftp.ua.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.ua.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.ua.FreeBSD.org[rsync] link:rsync://ftp.ua.FreeBSD.org[rsync_v6] | United Kingdom icon:envelope[link=mailto:{mirrors-uk-email}, title="mirror contact"] | ftp.uk.FreeBSD.org | link:http://ftp.uk.FreeBSD.org/pub/FreeBSD[http] link:http://ftp.uk.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp.uk.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp.uk.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp.uk.FreeBSD.org[rsync] link:rsync://ftp.uk.FreeBSD.org[rsync_v6] | | ftp2.uk.FreeBSD.org | link:http://ftp2.uk.FreeBSD.org/pub/FreeBSD[http] link:http://ftp2.uk.FreeBSD.org/pub/FreeBSD[http_v6] link:https://ftp2.uk.FreeBSD.org/pub/FreeBSD[https] link:https://ftp2.uk.FreeBSD.org/pub/FreeBSD[https_v6] link:ftp://ftp2.uk.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp2.uk.FreeBSD.org/pub/FreeBSD[ftp_v6] | United States of America icon:envelope[link=mailto:{mirrors-us-email}, title="mirror contact"] | ftp11.FreeBSD.org | link:http://ftp11.FreeBSD.org/pub/FreeBSD[http] link:http://ftp11.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp11.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp11.FreeBSD.org/pub/FreeBSD[ftp_v6] link:rsync://ftp11.FreeBSD.org[rsync] link:rsync://ftp11.FreeBSD.org[rsync_v6] | | ftp14.FreeBSD.org | link:ftp://ftp14.FreeBSD.org/pub/FreeBSD[ftp] link:rsync://ftp14.FreeBSD.org[rsync] (Former official tier 1) | | ftp5.FreeBSD.org | link:http://ftp5.FreeBSD.org/pub/FreeBSD[http] link:http://ftp5.FreeBSD.org/pub/FreeBSD[http_v6] link:ftp://ftp5.FreeBSD.org/pub/FreeBSD[ftp] link:ftp://ftp5.FreeBSD.org/pub/FreeBSD[ftp_v6] |=== The current list of protocols supported by the community mirrors was last updated on 2022-01-31, and it's not guaranteed. [[git]] == Using Git [[git-intro]] === Introduction As of December 2020, FreeBSD uses git as the primary version control system for storing all of FreeBSD's base source code and documentation. As of April 2021, FreeBSD uses git as the only version control system for storing all of FreeBSD's Ports Collection. [NOTE] ==== Git is generally a developer tool. Users may prefer to use `freebsd-update` (crossref:cutting-edge[updating-upgrading-freebsdupdate,“FreeBSD Update”]) to update the FreeBSD base system. ==== This section demonstrates how to install Git on a FreeBSD system and use it to create a local copy of a FreeBSD source code repository. [[git-install]] === Installation Git can be installed from the Ports Collection, or as a package: [source,shell] .... # pkg install git .... [[git-usage]] === Running Git To fetch a clean copy of the sources into a local directory, use `git clone`. This directory of files is called the _working tree_. Git uses URLs to designate a repository. There are three different repositories, `src` for the FreeBSD system source code, `doc` for documentation, and `ports` for the FreeBSD Ports Collection. All three are reachable over two different protocols: HTTPS and SSH. For example, the URL `https://git.FreeBSD.org/src.git` specifies the main branch of the `src` repository, using the `https` protocol. [[git-url-table]] .FreeBSD Git Repository URL Table [options="header,footer"] |======================================================= |Item | Git URL | Read-only src repo via HTTPS | `https://git.FreeBSD.org/src.git` | Read-only src repo via anon-ssh | `ssh://anongit@git.FreeBSD.org/src.git` | Read-only doc repo via HTTPS | `https://git.FreeBSD.org/doc.git` | Read-only doc repo via anon-ssh | `ssh://anongit@git.FreeBSD.org/doc.git` | Read-only ports repo via HTTPS | `https://git.FreeBSD.org/ports.git` | Read-only ports repo via anon-ssh | `ssh://anongit@git.FreeBSD.org/ports.git` |======================================================= External mirrors maintained by project members are also available; please refer -to the crossref:mirrors[external-mirrors] section. +to the crossref:mirrors[external-mirrors, External mirrors] section. To clone a copy of the FreeBSD system source code repository: [source,shell] .... # git clone -o freebsd https://git.FreeBSD.org/src.git /usr/src .... The `-o freebsd` option specifies the origin; by convention in the FreeBSD documentation, the origin is assumed to be `freebsd`. Because the initial checkout must download the full branch of the remote repository, it can take a while. Please be patient. Initially, the working tree contains source code for the `main` branch, which corresponds to CURRENT. To switch to 13-STABLE instead: [source,shell] .... # cd /usr/src # git checkout stable/13 .... The working tree can be updated with `git pull`. To update [.filename]#/usr/src# created in the example above, use: [source,shell] .... # cd /usr/src # git pull --rebase .... The update is much quicker than a checkout, only transferring files that have changed. === Web-based repository browser The FreeBSD project uses cgit as the web-based repository browser: link:https://cgit.FreeBSD.org/[https://cgit.FreeBSD.org/]. === For Developers For information about write access to repositories see the extref:{committers-guide}[Committer's Guide, git-mini-primer]. [[external-mirrors]] === External mirrors Those mirrors are not hosted in FreeBSD.org but still maintained by the project members. Users and developers are welcome to pull or browse repositories on those mirrors. Pull requests for the `doc` and `src` GitHub repositories are being accepted; otherwise, the project workflow with those mirrors is still under discussion. Codeberg:: - doc: https://codeberg.org/FreeBSD/freebsd-doc - ports: https://codeberg.org/FreeBSD/freebsd-ports - src: https://codeberg.org/FreeBSD/freebsd-src GitHub:: - doc: https://github.com/freebsd/freebsd-doc - ports: https://github.com/freebsd/freebsd-ports - src: https://github.com/freebsd/freebsd-src GitLab:: - doc: https://gitlab.com/FreeBSD/freebsd-doc - ports: https://gitlab.com/FreeBSD/freebsd-ports - src: https://gitlab.com/FreeBSD/freebsd-src === Mailing lists The main mailing list for general usage and questions about git in the FreeBSD project is https://lists.freebsd.org/subscription/freebsd-git[freebsd-git]. For more details, including commit messages lists, see the crossref:handbook/eresources[eresources-mail, Mailing Lists] chapter. === SSH host keys * gitrepo.FreeBSD.org host key fingerprints: ** ECDSA key fingerprint is `SHA256:seWO5D27ySURcx4bknTNKlC1mgai0whP443PAKEvvZA` ** ED25519 key fingerprint is `SHA256:lNR6i4BEOaaUhmDHBA1WJsO7H3KtvjE2r5q4sOxtIWo` ** RSA key fingerprint is `SHA256:f453CUEFXEJAXlKeEHV+ajJfeEfx9MdKQUD7lIscnQI` * git.FreeBSD.org host key fingerprints: ** ECDSA key fingerprint is `SHA256:/UlirUAsGiitupxmtsn7f9b7zCWd0vCs4Yo/tpVWP9w` ** ED25519 key fingerprint is `SHA256:y1ljKrKMD3lDObRUG3xJ9gXwEIuqnh306tSyFd1tuZE` ** RSA key fingerprint is `SHA256:jBe6FQGoH4HjvrIVM23dcnLZk9kmpdezR/CvQzm7rJM` These are also published as SSHFP records in DNS. [[svn]] == Using Subversion [[svn-intro]] === Introduction As of December 2020, FreeBSD uses git as the primary version control system for storing all of FreeBSD's source code and documentation. Changes from the git repo on the `stable/11`, `stable/12` and related releng branches are exported to the Subversion repository. This export will continue through the life of these branches. From July 2012 to March 2021, FreeBSD used Subversion as the only version control system for storing all of FreeBSD's Ports Collection. As of April 2021, FreeBSD uses git as the only version control system for storing all of FreeBSD's Ports Collection. [NOTE] ==== Subversion is generally a developer tool. Users may prefer to use `freebsd-update` (crossref:cutting-edge[updating-upgrading-freebsdupdate,“FreeBSD Update”]) to update the FreeBSD base system, and `git` (crossref:ports[ports-using,“Using the Ports Collection”]) to update the FreeBSD Ports Collection. After March 2021, Subversion use is only for legacy branches (`stable/11` and `stable/12`). ==== This section demonstrates how to install Subversion on a FreeBSD system and use it to create a local copy of a FreeBSD repository. Additional information on the use of Subversion is included. [[svn-svnlite]] === Svnlite A lightweight version of Subversion is already installed on FreeBSD as `svnlite`. The port or package version of Subversion is only needed if the Python or Perl API is needed, or if a later version of Subversion is desired. The only difference from normal Subversion use is that the command name is `svnlite`. [[svn-install]] === Installation If `svnlite` is unavailable or the full version of Subversion is needed, then it must be installed. Subversion can be installed from the Ports Collection: [source,shell] .... # cd /usr/ports/devel/subversion # make install clean .... Subversion can also be installed as a package: [source,shell] .... # pkg install subversion .... [[svn-usage]] === Running Subversion To fetch a clean copy of the sources into a local directory, use `svn`. The files in this directory are called a _local working copy_. [WARNING] ==== Move or delete an existing destination directory before using `checkout` for the first time. Checkout over an existing non-`svn` directory can cause conflicts between the existing files and those brought in from the repository. ==== Subversion uses URLs to designate a repository, taking the form of _protocol://hostname/path_. The first component of the path is the FreeBSD repository to access. There are three different repositories, `base` for the FreeBSD base system source code, `ports` for the Ports Collection, and `doc` for documentation. For example, the URL `https://svn.FreeBSD.org/base/head/` specifies the main branch of the src repository, using the `https` protocol. A checkout from a given repository is performed with a command like this: [source,shell] .... # svn checkout https://svn.FreeBSD.org/repository/branch lwcdir .... where: * _repository_ is one of the Project repositories: `base`, `ports`, or `doc`. * _branch_ depends on the repository used. `ports` and `doc` are mostly updated in the `head` branch, while `base` maintains the latest version of -CURRENT under `head` and the respective latest versions of the -STABLE branches under `stable/11` (11._x_) and `stable/12` (12._x_). * _lwcdir_ is the target directory where the contents of the specified branch should be placed. This is usually [.filename]#/usr/ports# for `ports`, [.filename]#/usr/src# for `base`, and [.filename]#/usr/doc# for `doc`. This example checks out the Source Tree from the FreeBSD repository using the HTTPS protocol, placing the local working copy in [.filename]#/usr/src#. If [.filename]#/usr/src# is already present but was not created by `svn`, remember to rename or delete it before the checkout. [source,shell] .... # svn checkout https://svn.FreeBSD.org/base/head /usr/src .... Because the initial checkout must download the full branch of the remote repository, it can take a while. Please be patient. After the initial checkout, the local working copy can be updated by running: [source,shell] .... # svn update lwcdir .... To update [.filename]#/usr/src# created in the example above, use: [source,shell] .... # svn update /usr/src .... The update is much quicker than a checkout, only transferring files that have changed. An alternate way of updating the local working copy after checkout is provided by the [.filename]#Makefile# in the [.filename]#/usr/ports#, [.filename]#/usr/src#, and [.filename]#/usr/doc# directories. Set `SVN_UPDATE` and use the `update` target. For example, to update [.filename]#/usr/src#: [source,shell] .... # cd /usr/src # make update SVN_UPDATE=yes .... [[svn-mirrors]] === Subversion Mirror Sites The FreeBSD Subversion repository is: [.programlisting] .... svn.FreeBSD.org .... This is a publicly accessible mirror network that uses GeoDNS to select an appropriate back end server. To view the FreeBSD Subversion repositories through a browser, use https://svnweb.FreeBSD.org/[https://svnweb.FreeBSD.org/]. HTTPS is the preferred protocol, but the [.filename]#security/ca_root_nss# package will need to be installed in order to automatically validate certificates. === For More Information For other information about using Subversion, please see the "Subversion Book", titled http://svnbook.red-bean.com/[Version Control with Subversion], or the http://subversion.apache.org/docs/[Subversion Documentation]. [[mirrors-disc]] == Disc Copies FreeBSD disc copies are available from several online retailers: * FreeBSD Mall, Inc. + 1164 Claremont Dr + Brentwood, CA + 94513 + USA + Phone: +1 925 240-6652 + Fax: +1 925 674-0821 + Email: info@freebsdmall.com + Website: https://www.freebsdmall.com * Getlinux + Website: https://www.getlinux.fr/ * Dr. Hinner EDV + Schäftlarnstr. 10 // 4. Stock + D-81371 München + Germany + Phone: +49 171 417 544 6 + Email: infow@hinner.de + Website: http://www.hinner.de/linux/freebsd.html diff --git a/documentation/content/en/books/handbook/network-servers/_index.adoc b/documentation/content/en/books/handbook/network-servers/_index.adoc index 03e1ed0810..9150452d7f 100644 --- a/documentation/content/en/books/handbook/network-servers/_index.adoc +++ b/documentation/content/en/books/handbook/network-servers/_index.adoc @@ -1,3043 +1,3043 @@ --- title: Chapter 32. Network Servers part: IV. Network Communication prev: books/handbook/mail next: books/handbook/firewalls description: This chapter covers some of the more frequently used network services on UNIX systems tags: ["network", "servers", "inetd", "NFS", "NIS", "LDAP", "DHCP", "DNS", "Apache HTTP", "FTP", "Samba", "NTP", "iSCSI"] showBookMenu: true weight: 37 path: "/books/handbook/network-servers/" --- [[network-servers]] = Network Servers :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 32 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/network-servers/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[network-servers-synopsis]] == Synopsis This chapter covers some of the more frequently used network services on UNIX(R) systems. This includes installing, configuring, testing, and maintaining many different types of network services. Example configuration files are included throughout this chapter for reference. By the end of this chapter, readers will know: * How to manage the inetd daemon. * How to set up the Network File System (NFS). * How to set up the Network Information Server (NIS) for centralizing and sharing user accounts. * How to set FreeBSD up to act as an LDAP server or client * How to set up automatic network settings using DHCP. * How to set up a Domain Name Server (DNS). * How to set up the Apache HTTP Server. * How to set up a File Transfer Protocol (FTP) server. * How to set up a file and print server for Windows(R) clients using Samba. * How to synchronize the time and date, and set up a time server using the Network Time Protocol (NTP). * How to set up iSCSI. This chapter assumes a basic knowledge of: * [.filename]#/etc/rc# scripts. * Network terminology. * Installation of additional third-party software (crossref:ports[ports,Installing Applications: Packages and Ports]). [[network-inetd]] == The inetd Super-Server The man:inetd[8] daemon is sometimes referred to as a Super-Server because it manages connections for many services. Instead of starting multiple applications, only the inetd service needs to be started. When a connection is received for a service that is managed by inetd, it determines which program the connection is destined for, spawns a process for that program, and delegates the program a socket. Using inetd for services that are not heavily used can reduce system load, when compared to running each daemon individually in stand-alone mode. Primarily, inetd is used to spawn other daemons, but several trivial protocols are handled internally, such as chargen, auth, time, echo, discard, and daytime. This section covers the basics of configuring inetd. [[network-inetd-conf]] === Configuration File Configuration of inetd is done by editing [.filename]#/etc/inetd.conf#. Each line of this configuration file represents an application which can be started by inetd. By default, every line starts with a comment (`+#+`), meaning that inetd is not listening for any applications. To configure inetd to listen for an application's connections, remove the `+#+` at the beginning of the line for that application. After saving your edits, configure inetd to start at system boot by editing [.filename]#/etc/rc.conf#: [.programlisting] .... inetd_enable="YES" .... To start inetd now, so that it listens for the service you configured, type: [source,shell] .... # service inetd start .... Once inetd is started, it needs to be notified whenever a modification is made to [.filename]#/etc/inetd.conf#: [[network-inetd-reread]] .Reloading the inetd Configuration File [example] ==== [source,shell] .... # service inetd reload .... ==== Typically, the default entry for an application does not need to be edited beyond removing the `+#+`. In some situations, it may be appropriate to edit the default entry. As an example, this is the default entry for man:ftpd[8] over IPv4: [.programlisting] .... ftp stream tcp nowait root /usr/libexec/ftpd ftpd -l .... The seven columns in an entry are as follows: [.programlisting] .... service-name socket-type protocol {wait|nowait}[/max-child[/max-connections-per-ip-per-minute[/max-child-per-ip]]] user[:group][/login-class] server-program server-program-arguments .... where: service-name:: The service name of the daemon to start. It must correspond to a service listed in [.filename]#/etc/services#. This determines which port inetd listens on for incoming connections to that service. When using a custom service, it must first be added to [.filename]#/etc/services#. socket-type:: Either `stream`, `dgram`, `raw`, or `seqpacket`. Use `stream` for TCP connections and `dgram` for UDP services. protocol:: Use one of the following protocol names: + [.informaltable] [cols="1,1", frame="none", options="header"] |=== | Protocol Name | Explanation |tcp or tcp4 |TCP IPv4 |udp or udp4 |UDP IPv4 |tcp6 |TCP IPv6 |udp6 |UDP IPv6 |tcp46 |Both TCP IPv4 and IPv6 |udp46 |Both UDP IPv4 and IPv6 |=== {wait|nowait}[/max-child[/max-connections-per-ip-per-minute[/max-child-per-ip]]]:: In this field, `wait` or `nowait` must be specified. `max-child`, `max-connections-per-ip-per-minute` and `max-child-per-ip` are optional. + `wait|nowait` indicates whether or not the service is able to handle its own socket. `dgram` socket types must use `wait` while `stream` daemons, which are usually multi-threaded, should use `nowait`. `wait` usually hands off multiple sockets to a single daemon, while `nowait` spawns a child daemon for each new socket. + The maximum number of child daemons inetd may spawn is set by `max-child`. For example, to limit ten instances of the daemon, place a `/10` after `nowait`. Specifying `/0` allows an unlimited number of children. + `max-connections-per-ip-per-minute` limits the number of connections from any particular IP address per minute. Once the limit is reached, further connections from this IP address will be dropped until the end of the minute. For example, a value of `/10` would limit any particular IP address to ten connection attempts per minute. `max-child-per-ip` limits the number of child processes that can be started on behalf on any single IP address at any moment. These options can limit excessive resource consumption and help to prevent Denial of Service attacks. + An example can be seen in the default settings for man:fingerd[8]: + [.programlisting] .... finger stream tcp nowait/3/10 nobody /usr/libexec/fingerd fingerd -k -s .... user:: The username the daemon will run as. Daemons typically run as `root`, `daemon`, or `nobody`. server-program:: The full path to the daemon. If the daemon is a service provided by inetd internally, use `internal`. server-program-arguments:: Used to specify any command arguments to be passed to the daemon on invocation. If the daemon is an internal service, use `internal`. [[network-inetd-cmdline]] === Command-Line Options Like most server daemons, inetd has a number of options that can be used to modify its behavior. By default, inetd is started with `-wW -C 60`. These options enable TCP wrappers for all services, including internal services, and prevent any IP address from requesting any service more than 60 times per minute. To change the default options which are passed to inetd, add an entry for `inetd_flags` in [.filename]#/etc/rc.conf#. If inetd is already running, restart it with `service inetd restart`. The available rate limiting options are: -c maximum:: Specify the default maximum number of simultaneous invocations of each service, where the default is unlimited. May be overridden on a per-service basis by using `max-child` in [.filename]#/etc/inetd.conf#. -C rate:: Specify the default maximum number of times a service can be invoked from a single IP address per minute. May be overridden on a per-service basis by using `max-connections-per-ip-per-minute` in [.filename]#/etc/inetd.conf#. -R rate:: Specify the maximum number of times a service can be invoked in one minute, where the default is `256`. A rate of `0` allows an unlimited number. -s maximum:: Specify the maximum number of times a service can be invoked from a single IP address at any one time, where the default is unlimited. May be overridden on a per-service basis by using `max-child-per-ip` in [.filename]#/etc/inetd.conf#. Additional options are available. Refer to man:inetd[8] for the full list of options. [[network-inetd-security]] === Security Considerations Many of the daemons which can be managed by inetd are not security-conscious. Some daemons, such as fingerd, can provide information that may be useful to an attacker. Only enable the services which are needed and monitor the system for excessive connection attempts. `max-connections-per-ip-per-minute`, `max-child` and `max-child-per-ip` can be used to limit such attacks. By default, TCP wrappers are enabled. Consult man:hosts_access[5] for more information on placing TCP restrictions on various inetd invoked daemons. [[network-nfs]] == Network File System (NFS) FreeBSD supports the Network File System (NFS), which allows a server to share directories and files with clients over a network. With NFS, users and programs can access files on remote systems as if they were stored locally. NFS has many practical uses. Some of the more common uses include: * Data that would otherwise be duplicated on each client can be kept in a single location and accessed by clients on the network. * Several clients may need access to the [.filename]#/usr/ports/distfiles# directory. Sharing that directory allows for quick access to the source files without having to download them to each client. * On large networks, it is often more convenient to configure a central NFS server on which all user home directories are stored. Users can log into a client anywhere on the network and have access to their home directories. * Administration of NFS exports is simplified. For example, there is only one file system where security or backup policies must be set. * Removable media storage devices can be used by other machines on the network. This reduces the number of devices throughout the network and provides a centralized location to manage their security. It is often more convenient to install software on multiple machines from a centralized installation media. NFS consists of a server and one or more clients. The client remotely accesses the data that is stored on the server machine. In order for this to function properly, a few processes have to be configured and running. These daemons must be running on the server: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | Daemon | Description |nfsd |The NFS daemon which services requests from NFS clients. |mountd |The NFS mount daemon which carries out requests received from nfsd. |rpcbind | This daemon allows NFS clients to discover which port the NFS server is using. |=== Running man:nfsiod[8] on the client can improve performance, but is not required. [[network-configuring-nfs]] === Configuring the Server The file systems which the NFS server will share are specified in [.filename]#/etc/exports#. Each line in this file specifies a file system to be exported, which clients have access to that file system, and any access options. When adding entries to this file, each exported file system, its properties, and allowed hosts must occur on a single line. If no clients are listed in the entry, then any client on the network can mount that file system. The following [.filename]#/etc/exports# entries demonstrate how to export file systems. The examples can be modified to match the file systems and client names on the reader's network. There are many options that can be used in this file, but only a few will be mentioned here. See man:exports[5] for the full list of options. This example shows how to export [.filename]#/cdrom# to three hosts named _alpha_, _bravo_, and _charlie_: [.programlisting] .... /cdrom -ro alpha bravo charlie .... The `-ro` flag makes the file system read-only, preventing clients from making any changes to the exported file system. This example assumes that the host names are either in DNS or in [.filename]#/etc/hosts#. Refer to man:hosts[5] if the network does not have a DNS server. The next example exports [.filename]#/home# to three clients by IP address. This can be useful for networks without DNS or [.filename]#/etc/hosts# entries. The `-alldirs` flag allows subdirectories to be mount points. In other words, it will not automatically mount the subdirectories, but will permit the client to mount the directories that are required as needed. [.programlisting] .... /usr/home -alldirs 10.0.0.2 10.0.0.3 10.0.0.4 .... This next example exports [.filename]#/a# so that two clients from different domains may access that file system. The `-maproot=root` allows `root` on the remote system to write data on the exported file system as `root`. If `-maproot=root` is not specified, the client's `root` user will be mapped to the server's `nobody` account and will be subject to the access limitations defined for `nobody`. [.programlisting] .... /a -maproot=root host.example.com box.example.org .... A client can only be specified once per file system. For example, if [.filename]#/usr# is a single file system, these entries would be invalid as both entries specify the same host: [.programlisting] .... # Invalid when /usr is one file system /usr/src client /usr/ports client .... The correct format for this situation is to use one entry: [.programlisting] .... /usr/src /usr/ports client .... The following is an example of a valid export list, where [.filename]#/usr# and [.filename]#/exports# are local file systems: [.programlisting] .... # Export src and ports to client01 and client02, but only # client01 has root privileges on it /usr/src /usr/ports -maproot=root client01 /usr/src /usr/ports client02 # The client machines have root and can mount anywhere # on /exports. Anyone in the world can mount /exports/obj read-only /exports -alldirs -maproot=root client01 client02 /exports/obj -ro .... To enable the processes required by the NFS server at boot time, add these options to [.filename]#/etc/rc.conf#: [.programlisting] .... rpcbind_enable="YES" nfs_server_enable="YES" mountd_enable="YES" .... The server can be started now by running this command: [source,shell] .... # service nfsd start .... Whenever the NFS server is started, mountd also starts automatically. However, mountd only reads [.filename]#/etc/exports# when it is started. To make subsequent [.filename]#/etc/exports# edits take effect immediately, force mountd to reread it: [source,shell] .... # service mountd reload .... Refer to man:zfs-share[8] for a description of exporting ZFS datasets via NFS using the `sharenfs` ZFS property instead of the man:exports[5] file. Refer to man:nfsv4[4] for a description of an NFS Version 4 setup. === Configuring the Client To enable NFS clients, set this option in each client's [.filename]#/etc/rc.conf#: [.programlisting] .... nfs_client_enable="YES" .... Then, run this command on each NFS client: [source,shell] .... # service nfsclient start .... The client now has everything it needs to mount a remote file system. In these examples, the server's name is `server` and the client's name is `client`. To mount [.filename]#/home# on `server` to the [.filename]#/mnt# mount point on `client`: [source,shell] .... # mount server:/home /mnt .... The files and directories in [.filename]#/home# will now be available on `client`, in the [.filename]#/mnt# directory. To mount a remote file system each time the client boots, add it to [.filename]#/etc/fstab#: [.programlisting] .... server:/home /mnt nfs rw 0 0 .... Refer to man:fstab[5] for a description of all available options. === Locking Some applications require file locking to operate correctly. To enable locking, execute the following command on both the client and server: [source,shell] .... # sysrc rpc_lockd_enable="YES" .... Then start the man:rpc.lockd[8] service: [source,shell] .... # service lockd start .... If locking is not required on the server, the NFS client can be configured to lock locally by including `-L` when running mount. Refer to man:mount_nfs[8] for further details. [[network-autofs]] === Automating Mounts with man:autofs[5] [NOTE] ==== The man:autofs[5] automount facility is supported starting with FreeBSD 10.1-RELEASE. To use the automounter functionality in older versions of FreeBSD, use man:amd[8] instead. This chapter only describes the man:autofs[5] automounter. ==== The man:autofs[5] facility is a common name for several components that, together, allow for automatic mounting of remote and local filesystems whenever a file or directory within that file system is accessed. It consists of the kernel component, man:autofs[5], and several userspace applications: man:automount[8], man:automountd[8] and man:autounmountd[8]. It serves as an alternative for man:amd[8] from previous FreeBSD releases. amd is still provided for backward compatibility purposes, as the two use different map formats; the one used by autofs is the same as with other SVR4 automounters, such as the ones in Solaris, MacOS X, and Linux. The man:autofs[5] virtual filesystem is mounted on specified mountpoints by man:automount[8], usually invoked during boot. Whenever a process attempts to access a file within the man:autofs[5] mountpoint, the kernel will notify man:automountd[8] daemon and pause the triggering process. The man:automountd[8] daemon will handle kernel requests by finding the proper map and mounting the filesystem according to it, then signal the kernel to release blocked process. The man:autounmountd[8] daemon automatically unmounts automounted filesystems after some time, unless they are still being used. The primary autofs configuration file is [.filename]#/etc/auto_master#. It assigns individual maps to top-level mounts. For an explanation of [.filename]#auto_master# and the map syntax, refer to man:auto_master[5]. There is a special automounter map mounted on [.filename]#/net#. When a file is accessed within this directory, man:autofs[5] looks up the corresponding remote mount and automatically mounts it. For instance, an attempt to access a file within [.filename]#/net/foobar/usr# would tell man:automountd[8] to mount the [.filename]#/usr# export from the host `foobar`. .Mounting an Export with man:autofs[5] [example] ==== In this example, `showmount -e` shows the exported file systems that can be mounted from the NFS server, `foobar`: [source,shell] .... % showmount -e foobar Exports list on foobar: /usr 10.10.10.0 /a 10.10.10.0 % cd /net/foobar/usr .... ==== The output from `showmount` shows [.filename]#/usr# as an export. When changing directories to [.filename]#/host/foobar/usr#, man:automountd[8] intercepts the request and attempts to resolve the hostname `foobar`. If successful, man:automountd[8] automatically mounts the source export. To enable man:autofs[5] at boot time, add this line to [.filename]#/etc/rc.conf#: [.programlisting] .... autofs_enable="YES" .... Then man:autofs[5] can be started by running: [source,shell] .... # service automount start # service automountd start # service autounmountd start .... The man:autofs[5] map format is the same as in other operating systems. Information about this format from other sources can be useful, like the http://web.archive.org/web/20160813071113/http://images.apple.com/business/docs/Autofs.pdf[Mac OS X document]. Consult the man:automount[8], man:automountd[8], man:autounmountd[8], and man:auto_master[5] manual pages for more information. [[network-nis]] == Network Information System (NIS) Network Information System (NIS) is designed to centralize administration of UNIX(R)-like systems such as Solaris(TM), HP-UX, AIX(R), Linux, NetBSD, OpenBSD, and FreeBSD. NIS was originally known as Yellow Pages but the name was changed due to trademark issues. This is the reason why NIS commands begin with `yp`. NIS is a Remote Procedure Call (RPC)-based client/server system that allows a group of machines within an NIS domain to share a common set of configuration files. This permits a system administrator to set up NIS client systems with only minimal configuration data and to add, remove, or modify configuration data from a single location. FreeBSD uses version 2 of the NIS protocol. === NIS Terms and Processes Table 28.1 summarizes the terms and important processes used by NIS: .NIS Terminology [cols="1,1", frame="none", options="header"] |=== | Term | Description |NIS domain name |NIS servers and clients share an NIS domain name. Typically, this name does not have anything to do with DNS. |man:rpcbind[8] |This service enables RPC and must be running in order to run an NIS server or act as an NIS client. |man:ypbind[8] |This service binds an NIS client to its NIS server. It will take the NIS domain name and use RPC to connect to the server. It is the core of client/server communication in an NIS environment. If this service is not running on a client machine, it will not be able to access the NIS server. |man:ypserv[8] |This is the process for the NIS server. If this service stops running, the server will no longer be able to respond to NIS requests so hopefully, there is a slave server to take over. Some non-FreeBSD clients will not try to reconnect using a slave server and the ypbind process may need to be restarted on these clients. |man:rpc.yppasswdd[8] |This process only runs on NIS master servers. This daemon allows NIS clients to change their NIS passwords. If this daemon is not running, users will have to login to the NIS master server and change their passwords there. |=== === Machine Types There are three types of hosts in an NIS environment: * NIS master server + This server acts as a central repository for host configuration information and maintains the authoritative copy of the files used by all of the NIS clients. The [.filename]#passwd#, [.filename]#group#, and other various files used by NIS clients are stored on the master server. While it is possible for one machine to be an NIS master server for more than one NIS domain, this type of configuration will not be covered in this chapter as it assumes a relatively small-scale NIS environment. * NIS slave servers + NIS slave servers maintain copies of the NIS master's data files in order to provide redundancy. Slave servers also help to balance the load of the master server as NIS clients always attach to the NIS server which responds first. * NIS clients + NIS clients authenticate against the NIS server during log on. Information in many files can be shared using NIS. The [.filename]#master.passwd#, [.filename]#group#, and [.filename]#hosts# files are commonly shared via NIS. Whenever a process on a client needs information that would normally be found in these files locally, it makes a query to the NIS server that it is bound to instead. === Planning Considerations This section describes a sample NIS environment which consists of 15 FreeBSD machines with no centralized point of administration. Each machine has its own [.filename]#/etc/passwd# and [.filename]#/etc/master.passwd#. These files are kept in sync with each other only through manual intervention. Currently, when a user is added to the lab, the process must be repeated on all 15 machines. The configuration of the lab will be as follows: [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Machine name | IP address | Machine role |`ellington` |`10.0.0.2` |NIS master |`coltrane` |`10.0.0.3` |NIS slave |`basie` |`10.0.0.4` |Faculty workstation |`bird` |`10.0.0.5` |Client machine |`cli[1-11]` |`10.0.0.[6-17]` |Other client machines |=== If this is the first time an NIS scheme is being developed, it should be thoroughly planned ahead of time. Regardless of network size, several decisions need to be made as part of the planning process. ==== Choosing a NIS Domain Name When a client broadcasts its requests for info, it includes the name of the NIS domain that it is part of. This is how multiple servers on one network can tell which server should answer which request. Think of the NIS domain name as the name for a group of hosts. Some organizations choose to use their Internet domain name for their NIS domain name. This is not recommended as it can cause confusion when trying to debug network problems. The NIS domain name should be unique within the network and it is helpful if it describes the group of machines it represents. For example, the Art department at Acme Inc. might be in the "acme-art" NIS domain. This example will use the domain name `test-domain`. However, some non-FreeBSD operating systems require the NIS domain name to be the same as the Internet domain name. If one or more machines on the network have this restriction, the Internet domain name _must_ be used as the NIS domain name. ==== Physical Server Requirements There are several things to keep in mind when choosing a machine to use as a NIS server. Since NIS clients depend upon the availability of the server, choose a machine that is not rebooted frequently. The NIS server should ideally be a stand alone machine whose sole purpose is to be an NIS server. If the network is not heavily used, it is acceptable to put the NIS server on a machine running other services. However, if the NIS server becomes unavailable, it will adversely affect all NIS clients. === Configuring the NIS Master Server The canonical copies of all NIS files are stored on the master server. The databases used to store the information are called NIS maps. In FreeBSD, these maps are stored in [.filename]#/var/yp/[domainname]# where [.filename]#[domainname]# is the name of the NIS domain. Since multiple domains are supported, it is possible to have several directories, one for each domain. Each domain will have its own independent set of maps. NIS master and slave servers handle all NIS requests through man:ypserv[8]. This daemon is responsible for receiving incoming requests from NIS clients, translating the requested domain and map name to a path to the corresponding database file, and transmitting data from the database back to the client. Setting up a master NIS server can be relatively straight forward, depending on environmental needs. Since FreeBSD provides built-in NIS support, it only needs to be enabled by adding the following lines to [.filename]#/etc/rc.conf#: [.programlisting] .... nisdomainname="test-domain" <.> nis_server_enable="YES" <.> nis_yppasswdd_enable="YES" <.> .... <.> This line sets the NIS domain name to `test-domain`. <.> This automates the start up of the NIS server processes when the system boots. <.> This enables the man:rpc.yppasswdd[8] daemon so that users can change their NIS password from a client machine. Care must be taken in a multi-server domain where the server machines are also NIS clients. It is generally a good idea to force the servers to bind to themselves rather than allowing them to broadcast bind requests and possibly become bound to each other. Strange failure modes can result if one server goes down and others are dependent upon it. Eventually, all the clients will time out and attempt to bind to other servers, but the delay involved can be considerable and the failure mode is still present since the servers might bind to each other all over again. A server that is also a client can be forced to bind to a particular server by adding these additional lines to [.filename]#/etc/rc.conf#: [.programlisting] .... nis_client_enable="YES" <.> nis_client_flags="-S test-domain,server" <.> .... <.> This enables running client stuff as well. <.> This line sets the NIS domain name to `test-domain` and bind to itself. After saving the edits, type `/etc/netstart` to restart the network and apply the values defined in [.filename]#/etc/rc.conf#. Before initializing the NIS maps, start man:ypserv[8]: [source,shell] .... # service ypserv start .... ==== Initializing the NIS Maps NIS maps are generated from the configuration files in [.filename]#/etc# on the NIS master, with one exception: [.filename]#/etc/master.passwd#. This is to prevent the propagation of passwords to all the servers in the NIS domain. Therefore, before the NIS maps are initialized, configure the primary password files: [source,shell] .... # cp /etc/master.passwd /var/yp/master.passwd # cd /var/yp # vi master.passwd .... It is advisable to remove all entries for system accounts as well as any user accounts that do not need to be propagated to the NIS clients, such as the `root` and any other administrative accounts. [NOTE] ==== Ensure that the [.filename]#/var/yp/master.passwd# is neither group or world readable by setting its permissions to `600`. ==== After completing this task, initialize the NIS maps. FreeBSD includes the man:ypinit[8] script to do this. When generating maps for the master server, include `-m` and specify the NIS domain name: [source,shell] .... ellington# ypinit -m test-domain Server Type: MASTER Domain: test-domain Creating an YP server will require that you answer a few questions. Questions will all be asked at the beginning of the procedure. Do you want this procedure to quit on non-fatal errors? [y/n: n] n Ok, please remember to go back and redo manually whatever fails. If not, something might not work. At this point, we have to construct a list of this domains YP servers. rod.darktech.org is already known as master server. Please continue to add any slave servers, one per line. When you are done with the list, type a . master server : ellington next host to add: coltrane next host to add: ^D The current list of NIS servers looks like this: ellington coltrane Is this correct? [y/n: y] y [..output from map generation..] NIS Map update completed. ellington has been setup as an YP master server without any errors. .... This will create [.filename]#/var/yp/Makefile# from [.filename]#/var/yp/Makefile.dist#. By default, this file assumes that the environment has a single NIS server with only FreeBSD clients. Since `test-domain` has a slave server, edit this line in [.filename]#/var/yp/Makefile# so that it begins with a comment (`+#+`): [.programlisting] .... NOPUSH = "True" .... ==== Adding New Users Every time a new user is created, the user account must be added to the master NIS server and the NIS maps rebuilt. Until this occurs, the new user will not be able to login anywhere except on the NIS master. For example, to add the new user `jsmith` to the `test-domain` domain, run these commands on the master server: [source,shell] .... # pw useradd jsmith # cd /var/yp # make test-domain .... The user could also be added using `adduser jsmith` instead of `pw useradd smith`. === Setting up a NIS Slave Server To set up an NIS slave server, log on to the slave server and edit [.filename]#/etc/rc.conf# as for the master server. Do not generate any NIS maps, as these already exist on the master server. When running `ypinit` on the slave server, use `-s` (for slave) instead of `-m` (for master). This option requires the name of the NIS master in addition to the domain name, as seen in this example: [source,shell] .... coltrane# ypinit -s ellington test-domain Server Type: SLAVE Domain: test-domain Master: ellington Creating an YP server will require that you answer a few questions. Questions will all be asked at the beginning of the procedure. Do you want this procedure to quit on non-fatal errors? [y/n: n] n Ok, please remember to go back and redo manually whatever fails. If not, something might not work. There will be no further questions. The remainder of the procedure should take a few minutes, to copy the databases from ellington. Transferring netgroup... ypxfr: Exiting: Map successfully transferred Transferring netgroup.byuser... ypxfr: Exiting: Map successfully transferred Transferring netgroup.byhost... ypxfr: Exiting: Map successfully transferred Transferring master.passwd.byuid... ypxfr: Exiting: Map successfully transferred Transferring passwd.byuid... ypxfr: Exiting: Map successfully transferred Transferring passwd.byname... ypxfr: Exiting: Map successfully transferred Transferring group.bygid... ypxfr: Exiting: Map successfully transferred Transferring group.byname... ypxfr: Exiting: Map successfully transferred Transferring services.byname... ypxfr: Exiting: Map successfully transferred Transferring rpc.bynumber... ypxfr: Exiting: Map successfully transferred Transferring rpc.byname... ypxfr: Exiting: Map successfully transferred Transferring protocols.byname... ypxfr: Exiting: Map successfully transferred Transferring master.passwd.byname... ypxfr: Exiting: Map successfully transferred Transferring networks.byname... ypxfr: Exiting: Map successfully transferred Transferring networks.byaddr... ypxfr: Exiting: Map successfully transferred Transferring netid.byname... ypxfr: Exiting: Map successfully transferred Transferring hosts.byaddr... ypxfr: Exiting: Map successfully transferred Transferring protocols.bynumber... ypxfr: Exiting: Map successfully transferred Transferring ypservers... ypxfr: Exiting: Map successfully transferred Transferring hosts.byname... ypxfr: Exiting: Map successfully transferred coltrane has been setup as an YP slave server without any errors. Remember to update map ypservers on ellington. .... This will generate a directory on the slave server called [.filename]#/var/yp/test-domain# which contains copies of the NIS master server's maps. Adding these [.filename]#/etc/crontab# entries on each slave server will force the slaves to sync their maps with the maps on the master server: [.programlisting] .... 20 * * * * root /usr/libexec/ypxfr passwd.byname 21 * * * * root /usr/libexec/ypxfr passwd.byuid .... These entries are not mandatory because the master server automatically attempts to push any map changes to its slaves. However, since clients may depend upon the slave server to provide correct password information, it is recommended to force frequent password map updates. This is especially important on busy networks where map updates might not always complete. To finish the configuration, run `/etc/netstart` on the slave server in order to start the NIS services. === Setting Up an NIS Client An NIS client binds to an NIS server using man:ypbind[8]. This daemon broadcasts RPC requests on the local network. These requests specify the domain name configured on the client. If an NIS server in the same domain receives one of the broadcasts, it will respond to ypbind, which will record the server's address. If there are several servers available, the client will use the address of the first server to respond and will direct all of its NIS requests to that server. The client will automatically ping the server on a regular basis to make sure it is still available. If it fails to receive a reply within a reasonable amount of time, ypbind will mark the domain as unbound and begin broadcasting again in the hopes of locating another server. To configure a FreeBSD machine to be an NIS client: [.procedure] ==== . Edit [.filename]#/etc/rc.conf# and add the following lines in order to set the NIS domain name and start man:ypbind[8] during network startup: + [.programlisting] .... nisdomainname="test-domain" nis_client_enable="YES" .... . To import all possible password entries from the NIS server, use `vipw` to remove all user accounts except one from [.filename]#/etc/master.passwd#. When removing the accounts, keep in mind that at least one local account should remain and this account should be a member of `wheel`. If there is a problem with NIS, this local account can be used to log in remotely, become the superuser, and fix the problem. Before saving the edits, add the following line to the end of the file: + [.programlisting] .... +::::::::: .... + This line configures the client to provide anyone with a valid account in the NIS server's password maps an account on the client. There are many ways to configure the NIS client by modifying this line. -One method is described in crossref:network-servers[network-netgroups]. +One method is described in crossref:network-servers[network-netgroups, Using Netgroups]. For more detailed reading, refer to the book `Managing NFS and NIS`, published by O'Reilly Media. . To import all possible group entries from the NIS server, add this line to [.filename]#/etc/group#: + [.programlisting] .... +:*:: .... ==== To start the NIS client immediately, execute the following commands as the superuser: [source,shell] .... # /etc/netstart # service ypbind start .... After completing these steps, running `ypcat passwd` on the client should show the server's [.filename]#passwd# map. === NIS Security Since RPC is a broadcast-based service, any system running ypbind within the same domain can retrieve the contents of the NIS maps. To prevent unauthorized transactions, man:ypserv[8] supports a feature called "securenets" which can be used to restrict access to a given set of hosts. By default, this information is stored in [.filename]#/var/yp/securenets#, unless man:ypserv[8] is started with `-p` and an alternate path. This file contains entries that consist of a network specification and a network mask separated by white space. Lines starting with `+"#"+` are considered to be comments. A sample [.filename]#securenets# might look like this: [.programlisting] .... # allow connections from local host -- mandatory 127.0.0.1 255.255.255.255 # allow connections from any host # on the 192.168.128.0 network 192.168.128.0 255.255.255.0 # allow connections from any host # between 10.0.0.0 to 10.0.15.255 # this includes the machines in the testlab 10.0.0.0 255.255.240.0 .... If man:ypserv[8] receives a request from an address that matches one of these rules, it will process the request normally. If the address fails to match a rule, the request will be ignored and a warning message will be logged. If the [.filename]#securenets# does not exist, `ypserv` will allow connections from any host. crossref:security[tcpwrappers,"TCP Wrapper"] is an alternate mechanism for providing access control instead of [.filename]#securenets#. While either access control mechanism adds some security, they are both vulnerable to "IP spoofing" attacks. All NIS-related traffic should be blocked at the firewall. Servers using [.filename]#securenets# may fail to serve legitimate NIS clients with archaic TCP/IP implementations. Some of these implementations set all host bits to zero when doing broadcasts or fail to observe the subnet mask when calculating the broadcast address. While some of these problems can be fixed by changing the client configuration, other problems may force the retirement of these client systems or the abandonment of [.filename]#securenets#. The use of TCP Wrapper increases the latency of the NIS server. The additional delay may be long enough to cause timeouts in client programs, especially in busy networks with slow NIS servers. If one or more clients suffer from latency, convert those clients into NIS slave servers and force them to bind to themselves. ==== Barring Some Users In this example, the `basie` system is a faculty workstation within the NIS domain. The [.filename]#passwd# map on the master NIS server contains accounts for both faculty and students. This section demonstrates how to allow faculty logins on this system while refusing student logins. To prevent specified users from logging on to a system, even if they are present in the NIS database, use `vipw` to add `-_username_` with the correct number of colons towards the end of [.filename]#/etc/master.passwd# on the client, where _username_ is the username of a user to bar from logging in. The line with the blocked user must be before the `+` line that allows NIS users. In this example, `bill` is barred from logging on to `basie`: [source,shell] .... basie# cat /etc/master.passwd root:[password]:0:0::0:0:The super-user:/root:/bin/csh toor:[password]:0:0::0:0:The other super-user:/root:/bin/sh daemon:*:1:1::0:0:Owner of many system processes:/root:/usr/sbin/nologin operator:*:2:5::0:0:System &:/:/usr/sbin/nologin bin:*:3:7::0:0:Binaries Commands and Source,,,:/:/usr/sbin/nologin tty:*:4:65533::0:0:Tty Sandbox:/:/usr/sbin/nologin kmem:*:5:65533::0:0:KMem Sandbox:/:/usr/sbin/nologin games:*:7:13::0:0:Games pseudo-user:/usr/games:/usr/sbin/nologin news:*:8:8::0:0:News Subsystem:/:/usr/sbin/nologin man:*:9:9::0:0:Mister Man Pages:/usr/share/man:/usr/sbin/nologin bind:*:53:53::0:0:Bind Sandbox:/:/usr/sbin/nologin uucp:*:66:66::0:0:UUCP pseudo-user:/var/spool/uucppublic:/usr/libexec/uucp/uucico xten:*:67:67::0:0:X-10 daemon:/usr/local/xten:/usr/sbin/nologin pop:*:68:6::0:0:Post Office Owner:/nonexistent:/usr/sbin/nologin nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/usr/sbin/nologin -bill::::::::: +::::::::: basie# .... [[network-netgroups]] === Using Netgroups Barring specified users from logging on to individual systems becomes unscaleable on larger networks and quickly loses the main benefit of NIS: _centralized_ administration. Netgroups were developed to handle large, complex networks with hundreds of users and machines. Their use is comparable to UNIX(R) groups, where the main difference is the lack of a numeric ID and the ability to define a netgroup by including both user accounts and other netgroups. To expand on the example used in this chapter, the NIS domain will be extended to add the users and systems shown in Tables 28.2 and 28.3: .Additional Users [cols="1,1", frame="none", options="header"] |=== | User Name(s) | Description |`alpha`, `beta` |IT department employees |`charlie`, `delta` |IT department apprentices |`echo`, `foxtrott`, `golf`, ... |employees |`able`, `baker`, ... |interns |=== .Additional Systems [cols="1,1", frame="none", options="header"] |=== | Machine Name(s) | Description |`war`, `death`, `famine`, `pollution` |Only IT employees are allowed to log onto these servers. |`pride`, `greed`, `envy`, `wrath`, `lust`, `sloth` |All members of the IT department are allowed to login onto these servers. |`one`, `two`, `three`, `four`, ... |Ordinary workstations used by employees. |`trashcan` |A very old machine without any critical data. Even interns are allowed to use this system. |=== When using netgroups to configure this scenario, each user is assigned to one or more netgroups and logins are then allowed or forbidden for all members of the netgroup. When adding a new machine, login restrictions must be defined for all netgroups. When a new user is added, the account must be added to one or more netgroups. If the NIS setup is planned carefully, only one central configuration file needs modification to grant or deny access to machines. The first step is the initialization of the NIS `netgroup` map. In FreeBSD, this map is not created by default. On the NIS master server, use an editor to create a map named [.filename]#/var/yp/netgroup#. This example creates four netgroups to represent IT employees, IT apprentices, employees, and interns: [.programlisting] .... IT_EMP (,alpha,test-domain) (,beta,test-domain) IT_APP (,charlie,test-domain) (,delta,test-domain) USERS (,echo,test-domain) (,foxtrott,test-domain) \ (,golf,test-domain) INTERNS (,able,test-domain) (,baker,test-domain) .... Each entry configures a netgroup. The first column in an entry is the name of the netgroup. Each set of parentheses represents either a group of one or more users or the name of another netgroup. When specifying a user, the three comma-delimited fields inside each group represent: . The name of the host(s) where the other fields representing the user are valid. If a hostname is not specified, the entry is valid on all hosts. . The name of the account that belongs to this netgroup. . The NIS domain for the account. Accounts may be imported from other NIS domains into a netgroup. If a group contains multiple users, separate each user with whitespace. Additionally, each field may contain wildcards. See man:netgroup[5] for details. Netgroup names longer than 8 characters should not be used. The names are case sensitive and using capital letters for netgroup names is an easy way to distinguish between user, machine and netgroup names. Some non-FreeBSD NIS clients cannot handle netgroups containing more than 15 entries. This limit may be circumvented by creating several sub-netgroups with 15 users or fewer and a real netgroup consisting of the sub-netgroups, as seen in this example: [.programlisting] .... BIGGRP1 (,joe1,domain) (,joe2,domain) (,joe3,domain) [...] BIGGRP2 (,joe16,domain) (,joe17,domain) [...] BIGGRP3 (,joe31,domain) (,joe32,domain) BIGGROUP BIGGRP1 BIGGRP2 BIGGRP3 .... Repeat this process if more than 225 (15 times 15) users exist within a single netgroup. To activate and distribute the new NIS map: [source,shell] .... ellington# cd /var/yp ellington# make .... This will generate the three NIS maps [.filename]#netgroup#, [.filename]#netgroup.byhost# and [.filename]#netgroup.byuser#. Use the map key option of man:ypcat[1] to check if the new NIS maps are available: [source,shell] .... ellington% ypcat -k netgroup ellington% ypcat -k netgroup.byhost ellington% ypcat -k netgroup.byuser .... The output of the first command should resemble the contents of [.filename]#/var/yp/netgroup#. The second command only produces output if host-specific netgroups were created. The third command is used to get the list of netgroups for a user. To configure a client, use man:vipw[8] to specify the name of the netgroup. For example, on the server named `war`, replace this line: [.programlisting] .... +::::::::: .... with [.programlisting] .... +@IT_EMP::::::::: .... This specifies that only the users defined in the netgroup `IT_EMP` will be imported into this system's password database and only those users are allowed to login to this system. This configuration also applies to the `~` function of the shell and all routines which convert between user names and numerical user IDs. In other words, `cd ~_user_` will not work, `ls -l` will show the numerical ID instead of the username, and `find . -user joe -print` will fail with the message `No such user`. To fix this, import all user entries without allowing them to login into the servers. This can be achieved by adding an extra line: [.programlisting] .... +:::::::::/usr/sbin/nologin .... This line configures the client to import all entries but to replace the shell in those entries with [.filename]#/usr/sbin/nologin#. Make sure that extra line is placed _after_ `+@IT_EMP:::::::::`. Otherwise, all user accounts imported from NIS will have [.filename]#/usr/sbin/nologin# as their login shell and no one will be able to login to the system. To configure the less important servers, replace the old `+:::::::::` on the servers with these lines: [.programlisting] .... +@IT_EMP::::::::: +@IT_APP::::::::: +:::::::::/usr/sbin/nologin .... The corresponding lines for the workstations would be: [.programlisting] .... +@IT_EMP::::::::: +@USERS::::::::: +:::::::::/usr/sbin/nologin .... NIS supports the creation of netgroups from other netgroups which can be useful if the policy regarding user access changes. One possibility is the creation of role-based netgroups. For example, one might create a netgroup called `BIGSRV` to define the login restrictions for the important servers, another netgroup called `SMALLSRV` for the less important servers, and a third netgroup called `USERBOX` for the workstations. Each of these netgroups contains the netgroups that are allowed to login onto these machines. The new entries for the NIS`netgroup` map would look like this: [.programlisting] .... BIGSRV IT_EMP IT_APP SMALLSRV IT_EMP IT_APP ITINTERN USERBOX IT_EMP ITINTERN USERS .... This method of defining login restrictions works reasonably well when it is possible to define groups of machines with identical restrictions. Unfortunately, this is the exception and not the rule. Most of the time, the ability to define login restrictions on a per-machine basis is required. Machine-specific netgroup definitions are another possibility to deal with the policy changes. In this scenario, the [.filename]#/etc/master.passwd# of each system contains two lines starting with "+". The first line adds a netgroup with the accounts allowed to login onto this machine and the second line adds all other accounts with [.filename]#/usr/sbin/nologin# as shell. It is recommended to use the "ALL-CAPS" version of the hostname as the name of the netgroup: [.programlisting] .... +@BOXNAME::::::::: +:::::::::/usr/sbin/nologin .... Once this task is completed on all the machines, there is no longer a need to modify the local versions of [.filename]#/etc/master.passwd# ever again. All further changes can be handled by modifying the NIS map. Here is an example of a possible `netgroup` map for this scenario: [.programlisting] .... # Define groups of users first IT_EMP (,alpha,test-domain) (,beta,test-domain) IT_APP (,charlie,test-domain) (,delta,test-domain) DEPT1 (,echo,test-domain) (,foxtrott,test-domain) DEPT2 (,golf,test-domain) (,hotel,test-domain) DEPT3 (,india,test-domain) (,juliet,test-domain) ITINTERN (,kilo,test-domain) (,lima,test-domain) D_INTERNS (,able,test-domain) (,baker,test-domain) # # Now, define some groups based on roles USERS DEPT1 DEPT2 DEPT3 BIGSRV IT_EMP IT_APP SMALLSRV IT_EMP IT_APP ITINTERN USERBOX IT_EMP ITINTERN USERS # # And a groups for a special tasks # Allow echo and golf to access our anti-virus-machine SECURITY IT_EMP (,echo,test-domain) (,golf,test-domain) # # machine-based netgroups # Our main servers WAR BIGSRV FAMINE BIGSRV # User india needs access to this server POLLUTION BIGSRV (,india,test-domain) # # This one is really important and needs more access restrictions DEATH IT_EMP # # The anti-virus-machine mentioned above ONE SECURITY # # Restrict a machine to a single user TWO (,hotel,test-domain) # [...more groups to follow] .... It may not always be advisable to use machine-based netgroups. When deploying a couple of dozen or hundreds of systems, role-based netgroups instead of machine-based netgroups may be used to keep the size of the NIS map within reasonable limits. === Password Formats NIS requires that all hosts within an NIS domain use the same format for encrypting passwords. If users have trouble authenticating on an NIS client, it may be due to a differing password format. In a heterogeneous network, the format must be supported by all operating systems, where DES is the lowest common standard. To check which format a server or client is using, look at this section of [.filename]#/etc/login.conf#: [.programlisting] .... default:\ :passwd_format=des:\ :copyright=/etc/COPYRIGHT:\ [Further entries elided] .... In this example, the system is using the DES format for password hashing. Other possible values include `blf` for Blowfish, `md5` for MD5, `sha256` and `sha512` for SHA-256 and SHA-512 respectively. For more information and the up to date list of what is available on your system, consult the man:crypt[3] manpage. If the format on a host needs to be edited to match the one being used in the NIS domain, the login capability database must be rebuilt after saving the change: [source,shell] .... # cap_mkdb /etc/login.conf .... [NOTE] ==== The format of passwords for existing user accounts will not be updated until each user changes their password _after_ the login capability database is rebuilt. ==== [[network-ldap]] == Lightweight Directory Access Protocol (LDAP) The Lightweight Directory Access Protocol (LDAP) is an application layer protocol used to access, modify, and authenticate objects using a distributed directory information service. Think of it as a phone or record book which stores several levels of hierarchical, homogeneous information. It is used in Active Directory and OpenLDAP networks and allows users to access to several levels of internal information utilizing a single account. For example, email authentication, pulling employee contact information, and internal website authentication might all make use of a single user account in the LDAP server's record base. This section provides a quick start guide for configuring an LDAP server on a FreeBSD system. It assumes that the administrator already has a design plan which includes the type of information to store, what that information will be used for, which users should have access to that information, and how to secure this information from unauthorized access. === LDAP Terminology and Structure LDAP uses several terms which should be understood before starting the configuration. All directory entries consist of a group of _attributes_. Each of these attribute sets contains a unique identifier known as a _Distinguished Name_ (DN) which is normally built from several other attributes such as the common or _Relative Distinguished Name_ (RDN). Similar to how directories have absolute and relative paths, consider a DN as an absolute path and the RDN as the relative path. An example LDAP entry looks like the following. This example searches for the entry for the specified user account (`uid`), organizational unit (`ou`), and organization (`o`): [source,shell] .... % ldapsearch -xb "uid=trhodes,ou=users,o=example.com" # extended LDIF # # LDAPv3 # base with scope subtree # filter: (objectclass=*) # requesting: ALL # # trhodes, users, example.com dn: uid=trhodes,ou=users,o=example.com mail: trhodes@example.com cn: Tom Rhodes uid: trhodes telephoneNumber: (123) 456-7890 # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1 .... This example entry shows the values for the `dn`, `mail`, `cn`, `uid`, and `telephoneNumber` attributes. The cn attribute is the RDN. More information about LDAP and its terminology can be found at http://www.openldap.org/doc/admin24/intro.html[http://www.openldap.org/doc/admin24/intro.html]. [[ldap-config]] === Configuring an LDAP Server FreeBSD does not provide a built-in LDAP server. Begin the configuration by installing package:net/openldap-server[] package or port: [source,shell] .... # pkg install openldap-server .... There is a large set of default options enabled in the extref:{linux-users}[package, software]. Review them by running `pkg info openldap-server`. If they are not sufficient (for example if SQL support is needed), please consider recompiling the port using the appropriate crossref:ports[ports-using,framework]. The installation creates the directory [.filename]#/var/db/openldap-data# to hold the data. The directory to store the certificates must be created: [source,shell] .... # mkdir /usr/local/etc/openldap/private .... The next phase is to configure the Certificate Authority. The following commands must be executed from [.filename]#/usr/local/etc/openldap/private#. This is important as the file permissions need to be restrictive and users should not have access to these files. More detailed information about certificates and their parameters can be found in crossref:security[openssl,"OpenSSL"]. To create the Certificate Authority, start with this command and follow the prompts: [source,shell] .... # openssl req -days 365 -nodes -new -x509 -keyout ca.key -out ../ca.crt .... The entries for the prompts may be generic _except_ for the `Common Name`. This entry must be _different_ than the system hostname. If this will be a self signed certificate, prefix the hostname with `CA` for Certificate Authority. The next task is to create a certificate signing request and a private key. Input this command and follow the prompts: [source,shell] .... # openssl req -days 365 -nodes -new -keyout server.key -out server.csr .... During the certificate generation process, be sure to correctly set the `Common Name` attribute. The Certificate Signing Request must be signed with the Certificate Authority in order to be used as a valid certificate: [source,shell] .... # openssl x509 -req -days 365 -in server.csr -out ../server.crt -CA ../ca.crt -CAkey ca.key -CAcreateserial .... The final part of the certificate generation process is to generate and sign the client certificates: [source,shell] .... # openssl req -days 365 -nodes -new -keyout client.key -out client.csr # openssl x509 -req -days 3650 -in client.csr -out ../client.crt -CA ../ca.crt -CAkey ca.key .... Remember to use the same `Common Name` attribute when prompted. When finished, ensure that a total of eight (8) new files have been generated through the proceeding commands. The daemon running the OpenLDAP server is [.filename]#slapd#. Its configuration is performed through [.filename]#slapd.ldif#: the old [.filename]#slapd.conf# has been deprecated by OpenLDAP. http://www.openldap.org/doc/admin24/slapdconf2.html[Configuration examples] for [.filename]#slapd.ldif# are available and can also be found in [.filename]#/usr/local/etc/openldap/slapd.ldif.sample#. Options are documented in slapd-config(5). Each section of [.filename]#slapd.ldif#, like all the other LDAP attribute sets, is uniquely identified through a DN. Be sure that no blank lines are left between the `dn:` statement and the desired end of the section. In the following example, TLS will be used to implement a secure channel. The first section represents the global configuration: [.programlisting] .... # # See slapd-config(5) for details on configuration options. # This file should NOT be world readable. # dn: cn=config objectClass: olcGlobal cn: config # # # Define global ACLs to disable default read access. # olcArgsFile: /var/run/openldap/slapd.args olcPidFile: /var/run/openldap/slapd.pid olcTLSCertificateFile: /usr/local/etc/openldap/server.crt olcTLSCertificateKeyFile: /usr/local/etc/openldap/private/server.key olcTLSCACertificateFile: /usr/local/etc/openldap/ca.crt #olcTLSCipherSuite: HIGH olcTLSProtocolMin: 3.1 olcTLSVerifyClient: never .... The Certificate Authority, server certificate and server private key files must be specified here. It is recommended to let the clients choose the security cipher and omit option `olcTLSCipherSuite` (incompatible with TLS clients other than [.filename]#openssl#). Option `olcTLSProtocolMin` lets the server require a minimum security level: it is recommended. While verification is mandatory for the server, it is not for the client: `olcTLSVerifyClient: never`. The second section is about the backend modules and can be configured as follows: [.programlisting] .... # # Load dynamic backend modules: # dn: cn=module,cn=config objectClass: olcModuleList cn: module olcModulepath: /usr/local/libexec/openldap olcModuleload: back_mdb.la #olcModuleload: back_bdb.la #olcModuleload: back_hdb.la #olcModuleload: back_ldap.la #olcModuleload: back_passwd.la #olcModuleload: back_shell.la .... The third section is devoted to load the needed `ldif` schemas to be used by the databases: they are essential. [.programlisting] .... dn: cn=schema,cn=config objectClass: olcSchemaConfig cn: schema include: file:///usr/local/etc/openldap/schema/core.ldif include: file:///usr/local/etc/openldap/schema/cosine.ldif include: file:///usr/local/etc/openldap/schema/inetorgperson.ldif include: file:///usr/local/etc/openldap/schema/nis.ldif .... Next, the frontend configuration section: [.programlisting] .... # Frontend settings # dn: olcDatabase={-1}frontend,cn=config objectClass: olcDatabaseConfig objectClass: olcFrontendConfig olcDatabase: {-1}frontend olcAccess: to * by * read # # Sample global access control policy: # Root DSE: allow anyone to read it # Subschema (sub)entry DSE: allow anyone to read it # Other DSEs: # Allow self write access # Allow authenticated users read access # Allow anonymous users to authenticate # #olcAccess: to dn.base="" by * read #olcAccess: to dn.base="cn=Subschema" by * read #olcAccess: to * # by self write # by users read # by anonymous auth # # if no access controls are present, the default policy # allows anyone and everyone to read anything but restricts # updates to rootdn. (e.g., "access to * by * read") # # rootdn can always read and write EVERYTHING! # olcPasswordHash: {SSHA} # {SSHA} is already the default for olcPasswordHash .... Another section is devoted to the _configuration backend_, the only way to later access the OpenLDAP server configuration is as a global super-user. [.programlisting] .... dn: olcDatabase={0}config,cn=config objectClass: olcDatabaseConfig olcDatabase: {0}config olcAccess: to * by * none olcRootPW: {SSHA}iae+lrQZILpiUdf16Z9KmDmSwT77Dj4U .... The default administrator username is `cn=config`. Type [.filename]#slappasswd# in a shell, choose a password and use its hash in `olcRootPW`. If this option is not specified now, before [.filename]#slapd.ldif# is imported, no one will be later able to modify the _global configuration_ section. The last section is about the database backend: [.programlisting] .... ####################################################################### # LMDB database definitions ####################################################################### # dn: olcDatabase=mdb,cn=config objectClass: olcDatabaseConfig objectClass: olcMdbConfig olcDatabase: mdb olcDbMaxSize: 1073741824 olcSuffix: dc=domain,dc=example olcRootDN: cn=mdbadmin,dc=domain,dc=example # Cleartext passwords, especially for the rootdn, should # be avoided. See slappasswd(8) and slapd-config(5) for details. # Use of strong authentication encouraged. olcRootPW: {SSHA}X2wHvIWDk6G76CQyCMS1vDCvtICWgn0+ # The database directory MUST exist prior to running slapd AND # should only be accessible by the slapd and slap tools. # Mode 700 recommended. olcDbDirectory: /var/db/openldap-data # Indices to maintain olcDbIndex: objectClass eq .... This database hosts the _actual contents_ of the LDAP directory. Types other than `mdb` are available. Its super-user, not to be confused with the global one, is configured here: a (possibly custom) username in `olcRootDN` and the password hash in `olcRootPW`; [.filename]#slappasswd# can be used as before. This http://www.openldap.org/devel/gitweb.cgi?p=openldap.git;a=tree;f=tests/data/regressions/its8444;h=8a5e808e63b0de3d2bdaf2cf34fecca8577ca7fd;hb=HEAD[repository] contains four examples of [.filename]#slapd.ldif#. To convert an existing [.filename]#slapd.conf# into [.filename]#slapd.ldif#, refer to http://www.openldap.org/doc/admin24/slapdconf2.html[this page] (please note that this may introduce some unuseful options). When the configuration is completed, [.filename]#slapd.ldif# must be placed in an empty directory. It is recommended to create it as: [source,shell] .... # mkdir /usr/local/etc/openldap/slapd.d/ .... Import the configuration database: [source,shell] .... # /usr/local/sbin/slapadd -n0 -F /usr/local/etc/openldap/slapd.d/ -l /usr/local/etc/openldap/slapd.ldif .... Start the [.filename]#slapd# daemon: [source,shell] .... # /usr/local/libexec/slapd -F /usr/local/etc/openldap/slapd.d/ .... Option `-d` can be used for debugging, as specified in slapd(8). To verify that the server is running and working: [source,shell] .... # ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts # extended LDIF # # LDAPv3 # base <> with scope baseObject # filter: (objectclass=*) # requesting: namingContexts # # dn: namingContexts: dc=domain,dc=example # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1 .... The server must still be trusted. If that has never been done before, follow these instructions. Install the OpenSSL package or port: [source,shell] .... # pkg install openssl .... From the directory where [.filename]#ca.crt# is stored (in this example, [.filename]#/usr/local/etc/openldap#), run: [source,shell] .... # c_rehash . .... Both the CA and the server certificate are now correctly recognized in their respective roles. To verify this, run this command from the [.filename]#server.crt# directory: [source,shell] .... # openssl verify -verbose -CApath . server.crt .... If [.filename]#slapd# was running, restart it. As stated in [.filename]#/usr/local/etc/rc.d/slapd#, to properly run [.filename]#slapd# at boot the following lines must be added to [.filename]#/etc/rc.conf#: [.programlisting] .... slapd_enable="YES" slapd_flags='-h "ldapi://%2fvar%2frun%2fopenldap%2fldapi/ ldap://0.0.0.0/"' slapd_sockets="/var/run/openldap/ldapi" slapd_cn_config="YES" .... [.filename]#slapd# does not provide debugging at boot. Check [.filename]#/var/log/debug.log#, [.filename]#dmesg -a# and [.filename]#/var/log/messages# for this purpose. The following example adds the group `team` and the user `john` to the `domain.example` LDAP database, which is still empty. First, create the file [.filename]#domain.ldif#: [source,shell] .... # cat domain.ldif dn: dc=domain,dc=example objectClass: dcObject objectClass: organization o: domain.example dc: domain dn: ou=groups,dc=domain,dc=example objectClass: top objectClass: organizationalunit ou: groups dn: ou=users,dc=domain,dc=example objectClass: top objectClass: organizationalunit ou: users dn: cn=team,ou=groups,dc=domain,dc=example objectClass: top objectClass: posixGroup cn: team gidNumber: 10001 dn: uid=john,ou=users,dc=domain,dc=example objectClass: top objectClass: account objectClass: posixAccount objectClass: shadowAccount cn: John McUser uid: john uidNumber: 10001 gidNumber: 10001 homeDirectory: /home/john/ loginShell: /usr/bin/bash userPassword: secret .... See the OpenLDAP documentation for more details. Use [.filename]#slappasswd# to replace the plain text password `secret` with a hash in `userPassword`. The path specified as `loginShell` must exist in all the systems where `john` is allowed to login. Finally, use the `mdb` administrator to modify the database: [source,shell] .... # ldapadd -W -D "cn=mdbadmin,dc=domain,dc=example" -f domain.ldif .... Modifications to the _global configuration_ section can only be performed by the global super-user. For example, assume that the option `olcTLSCipherSuite: HIGH:MEDIUM:SSLv3` was initially specified and must now be deleted. First, create a file that contains the following: [source,shell] .... # cat global_mod dn: cn=config changetype: modify delete: olcTLSCipherSuite .... Then, apply the modifications: [source,shell] .... # ldapmodify -f global_mod -x -D "cn=config" -W .... When asked, provide the password chosen in the _configuration backend_ section. The username is not required: here, `cn=config` represents the DN of the database section to be modified. Alternatively, use `ldapmodify` to delete a single line of the database, `ldapdelete` to delete a whole entry. If something goes wrong, or if the global super-user cannot access the configuration backend, it is possible to delete and re-write the whole configuration: [source,shell] .... # rm -rf /usr/local/etc/openldap/slapd.d/ .... [.filename]#slapd.ldif# can then be edited and imported again. Please, follow this procedure only when no other solution is available. This is the configuration of the server only. The same machine can also host an LDAP client, with its own separate configuration. [[network-dhcp]] == Dynamic Host Configuration Protocol (DHCP) The Dynamic Host Configuration Protocol (DHCP) allows a system to connect to a network in order to be assigned the necessary addressing information for communication on that network. FreeBSD includes the OpenBSD version of `dhclient` which is used by the client to obtain the addressing information. FreeBSD does not install a DHCP server, but several servers are available in the FreeBSD Ports Collection. The DHCP protocol is fully described in http://www.freesoft.org/CIE/RFC/2131/[RFC 2131]. Informational resources are also available at http://www.isc.org/downloads/dhcp/[isc.org/downloads/dhcp/]. This section describes how to use the built-in DHCP client. It then describes how to install and configure a DHCP server. [NOTE] ==== In FreeBSD, the man:bpf[4] device is needed by both the DHCP server and DHCP client. This device is included in the [.filename]#GENERIC# kernel that is installed with FreeBSD. Users who prefer to create a custom kernel need to keep this device if DHCP is used. It should be noted that [.filename]#bpf# also allows privileged users to run network packet sniffers on that system. ==== === Configuring a DHCP Client DHCP client support is included in the FreeBSD installer, making it easy to configure a newly installed system to automatically receive its networking addressing information from an existing DHCP server. Refer to crossref:bsdinstall[bsdinstall-post,"Accounts, Time Zone, Services and Hardening"] for examples of network configuration. When `dhclient` is executed on the client machine, it begins broadcasting requests for configuration information. By default, these requests use UDP port 68. The server replies on UDP port 67, giving the client an IP address and other relevant network information such as a subnet mask, default gateway, and DNS server addresses. This information is in the form of a DHCP "lease" and is valid for a configurable time. This allows stale IP addresses for clients no longer connected to the network to automatically be reused. DHCP clients can obtain a great deal of information from the server. An exhaustive list may be found in man:dhcp-options[5]. By default, when a FreeBSD system boots, its DHCP client runs in the background, or _asynchronously_. Other startup scripts continue to run while the DHCP process completes, which speeds up system startup. Background DHCP works well when the DHCP server responds quickly to the client's requests. However, DHCP may take a long time to complete on some systems. If network services attempt to run before DHCP has assigned the network addressing information, they will fail. Using DHCP in _synchronous_ mode prevents this problem as it pauses startup until the DHCP configuration has completed. This line in [.filename]#/etc/rc.conf# is used to configure background or asynchronous mode: [.programlisting] .... ifconfig_fxp0="DHCP" .... This line may already exist if the system was configured to use DHCP during installation. Replace the _fxp0_ shown in these examples with the name of the interface to be dynamically configured, as described in crossref:config[config-network-setup,“Setting Up Network Interface Cards”]. To instead configure the system to use synchronous mode, and to pause during startup while DHCP completes, use "`SYNCDHCP`": [.programlisting] .... ifconfig_fxp0="SYNCDHCP" .... Additional client options are available. Search for `dhclient` in man:rc.conf[5] for details. The DHCP client uses the following files: * [.filename]#/etc/dhclient.conf# + The configuration file used by `dhclient`. Typically, this file contains only comments as the defaults are suitable for most clients. This configuration file is described in man:dhclient.conf[5]. * [.filename]#/sbin/dhclient# + More information about the command itself can be found in man:dhclient[8]. * [.filename]#/sbin/dhclient-script# + The FreeBSD-specific DHCP client configuration script. It is described in man:dhclient-script[8], but should not need any user modification to function properly. * [.filename]#/var/db/dhclient.leases.interface# + The DHCP client keeps a database of valid leases in this file, which is written as a log and is described in man:dhclient.leases[5]. [[network-dhcp-server]] === Installing and Configuring a DHCP Server This section demonstrates how to configure a FreeBSD system to act as a DHCP server using the Internet Systems Consortium (ISC) implementation of the DHCP server. This implementation and its documentation can be installed using the package:net/isc-dhcp44-server[] package or port. The installation of package:net/isc-dhcp44-server[] installs a sample configuration file. Copy [.filename]#/usr/local/etc/dhcpd.conf.example# to [.filename]#/usr/local/etc/dhcpd.conf# and make any edits to this new file. The configuration file is comprised of declarations for subnets and hosts which define the information that is provided to DHCP clients. For example, these lines configure the following: [.programlisting] .... option domain-name "example.org";<.> option domain-name-servers ns1.example.org;<.> option subnet-mask 255.255.255.0;<.> default-lease-time 600;<.> max-lease-time 72400;<.> ddns-update-style none;<.> subnet 10.254.239.0 netmask 255.255.255.224 { range 10.254.239.10 10.254.239.20;<.> option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;<.> } host fantasia { hardware ethernet 08:00:07:26:c0:a5;<.> fixed-address fantasia.fugue.com;<.> } .... <.> This option specifies the default search domain that will be provided to clients. Refer to man:resolv.conf[5] for more information. <.> This option specifies a comma separated list of DNS servers that the client should use. They can be listed by their Fully Qualified Domain Names (FQDN), as seen in the example, or by their IP addresses. <.> The subnet mask that will be provided to clients. <.> The default lease expiry time in seconds. A client can be configured to override this value. <.> The maximum allowed length of time, in seconds, for a lease. Should a client request a longer lease, a lease will still be issued, but it will only be valid for `max-lease-time`. <.> The default of `none` disables dynamic DNS updates. Changing this to `interim` configures the DHCP server to update a DNS server whenever it hands out a lease so that the DNS server knows which IP addresses are associated with which computers in the network. Do not change the default setting unless the DNS server has been configured to support dynamic DNS. <.> This line creates a pool of available IP addresses which are reserved for allocation to DHCP clients. The range of addresses must be valid for the network or subnet specified in the previous line. <.> Declares the default gateway that is valid for the network or subnet specified before the opening `{` bracket. <.> Specifies the hardware MAC address of a client so that the DHCP server can recognize the client when it makes a request. <.> Specifies that this host should always be given the same IP address. Using the hostname is correct, since the DHCP server will resolve the hostname before returning the lease information. This configuration file supports many more options. Refer to dhcpd.conf(5), installed with the server, for details and examples. Once the configuration of [.filename]#dhcpd.conf# is complete, enable the DHCP server in [.filename]#/etc/rc.conf#: [.programlisting] .... dhcpd_enable="YES" dhcpd_ifaces="dc0" .... Replace the `dc0` with the interface (or interfaces, separated by whitespace) that the DHCP server should listen on for DHCP client requests. Start the server by issuing the following command: [source,shell] .... # service isc-dhcpd start .... Any future changes to the configuration of the server will require the dhcpd service to be stopped and then started using man:service[8]. The DHCP server uses the following files. Note that the manual pages are installed with the server software. * [.filename]#/usr/local/sbin/dhcpd# + More information about the dhcpd server can be found in dhcpd(8). * [.filename]#/usr/local/etc/dhcpd.conf# + The server configuration file needs to contain all the information that should be provided to clients, along with information regarding the operation of the server. This configuration file is described in dhcpd.conf(5). * [.filename]#/var/db/dhcpd.leases# + The DHCP server keeps a database of leases it has issued in this file, which is written as a log. Refer to dhcpd.leases(5), which gives a slightly longer description. * [.filename]#/usr/local/sbin/dhcrelay# + This daemon is used in advanced environments where one DHCP server forwards a request from a client to another DHCP server on a separate network. If this functionality is required, install the package:net/isc-dhcp44-relay[] package or port. The installation includes dhcrelay(8) which provides more detail. [[network-dns]] == Domain Name System (DNS) Domain Name System (DNS) is the protocol through which domain names are mapped to IP addresses, and vice versa. DNS is coordinated across the Internet through a somewhat complex system of authoritative root, Top Level Domain (TLD), and other smaller-scale name servers, which host and cache individual domain information. It is not necessary to run a name server to perform DNS lookups on a system. The following table describes some of the terms associated with DNS: .DNS Terminology [cols="1,1", frame="none", options="header"] |=== | Term | Definition |Forward DNS |Mapping of hostnames to IP addresses. |Origin |Refers to the domain covered in a particular zone file. |Resolver |A system process through which a machine queries a name server for zone information. |Reverse DNS |Mapping of IP addresses to hostnames. |Root zone |The beginning of the Internet zone hierarchy. All zones fall under the root zone, similar to how all files in a file system fall under the root directory. |Zone |An individual domain, subdomain, or portion of the DNS administered by the same authority. |=== Examples of zones: * `.` is how the root zone is usually referred to in documentation. * `org.` is a Top Level Domain (TLD) under the root zone. * `example.org.` is a zone under the `org.`TLD. * `1.168.192.in-addr.arpa` is a zone referencing all IP addresses which fall under the `192.168.1.*`IP address space. As one can see, the more specific part of a hostname appears to its left. For example, `example.org.` is more specific than `org.`, as `org.` is more specific than the root zone. The layout of each part of a hostname is much like a file system: the [.filename]#/dev# directory falls within the root, and so on. === Reasons to Run a Name Server Name servers generally come in two forms: authoritative name servers, and caching (also known as resolving) name servers. An authoritative name server is needed when: * One wants to serve DNS information to the world, replying authoritatively to queries. * A domain, such as `example.org`, is registered and IP addresses need to be assigned to hostnames under it. * An IP address block requires reverse DNS entries (IP to hostname). * A backup or second name server, called a slave, will reply to queries. A caching name server is needed when: * A local DNS server may cache and respond more quickly than querying an outside name server. When one queries for `www.FreeBSD.org`, the resolver usually queries the uplink ISP's name server, and retrieves the reply. With a local, caching DNS server, the query only has to be made once to the outside world by the caching DNS server. Additional queries will not have to go outside the local network, since the information is cached locally. === DNS Server Configuration Unbound is provided in the FreeBSD base system. By default, it will provide DNS resolution to the local machine only. While the base system package can be configured to provide resolution services beyond the local machine, it is recommended that such requirements be addressed by installing Unbound from the FreeBSD Ports Collection. To enable Unbound, add the following to [.filename]#/etc/rc.conf#: [.programlisting] .... local_unbound_enable="YES" .... Any existing nameservers in [.filename]#/etc/resolv.conf# will be configured as forwarders in the new Unbound configuration. [NOTE] ==== If any of the listed nameservers do not support DNSSEC, local DNS resolution will fail. Be sure to test each nameserver and remove any that fail the test. The following command will show the trust tree or a failure for a nameserver running on `192.168.1.1`: [source,shell] .... % drill -S FreeBSD.org @192.168.1.1 .... ==== Once each nameserver is confirmed to support DNSSEC, start Unbound: [source,shell] .... # service local_unbound onestart .... This will take care of updating [.filename]#/etc/resolv.conf# so that queries for DNSSEC secured domains will now work. For example, run the following to validate the FreeBSD.org DNSSEC trust tree: [source,shell] .... % drill -S FreeBSD.org ;; Number of trusted keys: 1 ;; Chasing: freebsd.org. A DNSSEC Trust tree: freebsd.org. (A) |---freebsd.org. (DNSKEY keytag: 36786 alg: 8 flags: 256) |---freebsd.org. (DNSKEY keytag: 32659 alg: 8 flags: 257) |---freebsd.org. (DS keytag: 32659 digest type: 2) |---org. (DNSKEY keytag: 49587 alg: 7 flags: 256) |---org. (DNSKEY keytag: 9795 alg: 7 flags: 257) |---org. (DNSKEY keytag: 21366 alg: 7 flags: 257) |---org. (DS keytag: 21366 digest type: 1) | |---. (DNSKEY keytag: 40926 alg: 8 flags: 256) | |---. (DNSKEY keytag: 19036 alg: 8 flags: 257) |---org. (DS keytag: 21366 digest type: 2) |---. (DNSKEY keytag: 40926 alg: 8 flags: 256) |---. (DNSKEY keytag: 19036 alg: 8 flags: 257) ;; Chase successful .... === Authoritative Name Server Configuration FreeBSD does not provide authoritative name server software in the base system. Users are encouraged to install third party applications, like package:dns/nsd[] or package:dns/bind918[] package or port. [[network-zeroconf]] == Zero-configuration networking (mDNS/DNS-SD) https://en.wikipedia.org/wiki/Zero-configuration_networking[Zero-configuration networking] (sometimes referred to as zeroconf) is a set of technologies, which simplify network configuration by providing: * automatic assignment of numeric network addresses (mDNS), * automatic distribution and resolution of hostnames (mDNS), and * automatic discovery of service instances (DNS-SD). === Configuring and Starting Avahi One of the popular implementations of zeroconf is https://avahi.org/[Avahi]. Avahi can be installed and configured with the following commands: [source,shell] .... # pkg install avahi-app nss_mdns # grep -q '^hosts:.*\' /etc/nsswitch.conf || sed -i "" 's/^hosts: .*/& mdns/' /etc/nsswitch.conf # service dbus enable # service avahi-daemon enable # service dbus start # service avahi-daemon start .... [[network-apache]] == Apache HTTP Server The open source Apache HTTP Server is the most widely used web server. FreeBSD does not install this web server by default, but it can be installed from the package:www/apache24[] package or port. This section summarizes how to configure and start version 2._x_ of the Apache HTTP Server on FreeBSD. For more detailed information about Apache 2.X and its configuration directives, refer to http://httpd.apache.org/[httpd.apache.org]. === Configuring and Starting Apache In FreeBSD, the main Apache HTTP Server configuration file is installed as [.filename]#/usr/local/etc/apache2x/httpd.conf#, where _x_ represents the version number. This ASCII text file begins comment lines with a `+#+`. The most frequently modified directives are: `ServerRoot "/usr/local"`:: Specifies the default directory hierarchy for the Apache installation. Binaries are stored in the [.filename]#bin# and [.filename]#sbin# subdirectories of the server root and configuration files are stored in the [.filename]#etc/apache2x# subdirectory. `ServerAdmin \you@example.com`:: Change this to the email address to receive problems with the server. This address also appears on some server-generated pages, such as error documents. `ServerName www.example.com:80`:: Allows an administrator to set a hostname which is sent back to clients for the server. For example, `www` can be used instead of the actual hostname. If the system does not have a registered DNS name, enter its IP address instead. If the server will listen on an alternate report, change `80` to the alternate port number. `DocumentRoot "/usr/local/www/apache2_x_/data"`:: The directory where documents will be served from. By default, all requests are taken from this directory, but symbolic links and aliases may be used to point to other locations. It is always a good idea to make a backup copy of the default Apache configuration file before making changes. When the configuration of Apache is complete, save the file and verify the configuration using `apachectl`. Running `apachectl configtest` should return `Syntax OK`. To launch Apache at system startup, add the following line to [.filename]#/etc/rc.conf#: [.programlisting] .... apache24_enable="YES" .... If Apache should be started with non-default options, the following line may be added to [.filename]#/etc/rc.conf# to specify the needed flags: [.programlisting] .... apache24_flags="" .... If apachectl does not report configuration errors, start `httpd` now: [source,shell] .... # service apache24 start .... The `httpd` service can be tested by entering `http://_localhost_` in a web browser, replacing _localhost_ with the fully-qualified domain name of the machine running `httpd`. The default web page that is displayed is [.filename]#/usr/local/www/apache24/data/index.html#. The Apache configuration can be tested for errors after making subsequent configuration changes while `httpd` is running using the following command: [source,shell] .... # service apache24 configtest .... [NOTE] ==== It is important to note that `configtest` is not an man:rc[8] standard, and should not be expected to work for all startup scripts. ==== === Virtual Hosting Virtual hosting allows multiple websites to run on one Apache server. The virtual hosts can be _IP-based_ or _name-based_. IP-based virtual hosting uses a different IP address for each website. Name-based virtual hosting uses the clients HTTP/1.1 headers to figure out the hostname, which allows the websites to share the same IP address. To setup Apache to use name-based virtual hosting, add a `VirtualHost` block for each website. For example, for the webserver named `www.domain.tld` with a virtual domain of `www.someotherdomain.tld`, add the following entries to [.filename]#httpd.conf#: [.programlisting] .... ServerName www.domain.tld DocumentRoot /www/domain.tld ServerName www.someotherdomain.tld DocumentRoot /www/someotherdomain.tld .... For each virtual host, replace the values for `ServerName` and `DocumentRoot` with the values to be used. For more information about setting up virtual hosts, consult the official Apache documentation at: http://httpd.apache.org/docs/vhosts/[http://httpd.apache.org/docs/vhosts/]. === Apache Modules Apache uses modules to augment the functionality provided by the basic server. Refer to http://httpd.apache.org/docs/current/mod/[http://httpd.apache.org/docs/current/mod/] for a complete listing of and the configuration details for the available modules. In FreeBSD, some modules can be compiled with the package:www/apache24[] port. Type `make config` within [.filename]#/usr/ports/www/apache24# to see which modules are available and which are enabled by default. If the module is not compiled with the port, the FreeBSD Ports Collection provides an easy way to install many modules. This section describes three of the most commonly used modules. ==== SSL support At one point, support for SSL inside of Apache required a secondary module called [.filename]#mod_ssl#. This is no longer the case and the default install of Apache comes with SSL built into the web server. An example of how to enable support for SSL websites is available in the installed file, [.filename]#httpd-ssl.conf# inside of the [.filename]#/usr/local/etc/apache24/extra# directory Inside this directory is also a sample file called named [.filename]#ssl.conf-sample#. It is recommended that both files be evaluated to properly set up secure websites in the Apache web server. After the configuration of SSL is complete, the following line must be uncommented in the main [.filename]#http.conf# to activate the changes on the next restart or reload of Apache: [.programlisting] .... #Include etc/apache24/extra/httpd-ssl.conf .... [WARNING] ==== SSL version two and version three have known vulnerability issues. It is highly recommended TLS version 1.2 and 1.3 be enabled in place of the older SSL options. This can be accomplished by setting the following options in the [.filename]#ssl.conf#: ==== [.programlisting] .... SSLProtocol all -SSLv3 -SSLv2 +TLSv1.2 +TLSv1.3 SSLProxyProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 .... To complete the configuration of SSL in the web server, uncomment the following line to ensure that the configuration will be pulled into Apache during restart or reload: [.programlisting] .... # Secure (SSL/TLS) connections Include etc/apache24/extra/httpd-ssl.conf .... The following lines must also be uncommented in the [.filename]#httpd.conf# to fully support SSL in Apache: [.programlisting] .... LoadModule authn_socache_module libexec/apache24/mod_authn_socache.so LoadModule socache_shmcb_module libexec/apache24/mod_socache_shmcb.so LoadModule ssl_module libexec/apache24/mod_ssl.so .... The next step is to work with a certificate authority to have the appropriate certificates installed on the system. This will set up a chain of trust for the site and prevent any warnings of self-signed certificates. ==== [.filename]#mod_perl# The [.filename]#mod_perl# module makes it possible to write Apache modules in Perl. In addition, the persistent interpreter embedded in the server avoids the overhead of starting an external interpreter and the penalty of Perl start-up time. The [.filename]#mod_perl# can be installed using the package:www/mod_perl2[] package or port. Documentation for using this module can be found at http://perl.apache.org/docs/2.0/index.html[http://perl.apache.org/docs/2.0/index.html]. ==== [.filename]#mod_php# _PHP: Hypertext Preprocessor_ (PHP) is a general-purpose scripting language that is especially suited for web development. Capable of being embedded into HTML, its syntax draws upon C, Java(TM), and Perl with the intention of allowing web developers to write dynamically generated webpages quickly. Support for PHP for Apache and any other feature written in the language, can be added by installing the appropriate port. For all supported versions, search the package database using `pkg`: [source,shell] .... # pkg search php .... A list will be displayed including the versions and additional features they provide. The components are completely modular, meaning features are enabled by installing the appropriate port. To install PHP version 7.4 for Apache, issue the following command: [source,shell] .... # pkg install mod_php74 .... If any dependency packages need to be installed, they will be installed as well. By default, PHP will not be enabled. The following lines will need to be added to the Apache configuration file located in [.filename]#/usr/local/etc/apache24# to make it active: [.programlisting] .... SetHandler application/x-httpd-php SetHandler application/x-httpd-php-source .... In addition, the `DirectoryIndex` in the configuration file will also need to be updated and Apache will either need to be restarted or reloaded for the changes to take effect. Support for many of the PHP features may also be installed by using `pkg`. For example, to install support for XML or SSL, install their respective ports: [source,shell] .... # pkg install php74-xml php74-openssl .... As before, the Apache configuration will need to be reloaded for the changes to take effect, even in cases where it was just a module install. To perform a graceful restart to reload the configuration, issue the following command: [source,shell] .... # apachectl graceful .... Once the install is complete, there are two methods of obtaining the installed PHP support modules and the environmental information of the build. The first is to install the full PHP binary and running the command to gain the information: [source,shell] .... # pkg install php74 .... [source,shell] .... # php -i | less .... It is necessary to pass the output to a pager, such as the `more` or `less` to easier digest the amount of output. Finally, to make any changes to the global configuration of PHP there is a well documented file installed into [.filename]#/usr/local/etc/php.ini#. At the time of install, this file will not exist because there are two versions to choose from, one is [.filename]#php.ini-development# and the other is [.filename]#php.ini-production#. These are starting points to assist administrators in their deployment. ==== HTTP2 Support Apache support for the HTTP2 protocol is included by default when installing the port with `pkg`. The new version of HTTP includes many improvements over the previous version, including utilizing a single connection to a website, reducing overall roundtrips of TCP connections. Also, packet header data is compressed and HTTP2 requires encryption by default. When Apache is configured to only use HTTP2, web browsers will require secure, encrypted HTTPS connections. When Apache is configured to use both versions, HTTP1.1 will be considered a fall back option if any issues arise during the connection. While this change does require administrators to make changes, they are positive and equate to a more secure Internet for everyone. The changes are only required for sites not currently implementing SSL and TLS. [NOTE] ==== This configuration depends on the previous sections, including TLS support. It is recommended those instructions be followed before continuing with this configuration. ==== Start the process by enabling the http2 module by uncommenting the line in [.filename]#/usr/local/etc/apache24/httpd.conf# and replace the mpm_prefork module with mpm_event as the former does not support HTTP2. [.programlisting] .... LoadModule http2_module libexec/apache24/mod_http2.so LoadModule mpm_event_module libexec/apache24/mod_mpm_event.so .... [NOTE] ==== There is a separate [.filename]#mod_http2# port that is available. It exists to deliver security and bug fixes quicker than the module installed with the bundled [.filename]#apache24# port. It is not required for HTTP2 support but is available. When installed, the [.filename]#mod_h2.so# should be used in place of [.filename]#mod_http2.so# in the Apache configuration. ==== There are two methods to implement HTTP2 in Apache; one way is globally for all sites and each VirtualHost running on the system. To enable HTTP2 globally, add the following line under the ServerName directive: [.programlisting] .... Protocols h2 http/1.1 .... [NOTE] ==== To enable HTTP2 over plaintext, use h2h2chttp/1.1 in the [.filename]#httpd.conf#. ==== Having the h2c here will allow plaintext HTTP2 data to pass on the system but is not recommended. In addition, using the http/1.1 here will allow fallback to the HTTP1.1 version of the protocol should it be needed by the system. To enable HTTP2 for individual VirtualHosts, add the same line within the VirtualHost directive in either [.filename]#httpd.conf# or [.filename]#httpd-ssl.conf#. Reload the configuration using the `apachectl`[parameter]#reload# command and test the configuration either by using either of the following methods after visiting one of the hosted pages: [source,shell] .... # grep "HTTP/2.0" /var/log/httpd-access.log .... This should return something similar to the following: [.programlisting] .... 192.168.1.205 - - [18/Oct/2020:18:34:36 -0400] "GET / HTTP/2.0" 304 - 192.0.2.205 - - [18/Oct/2020:19:19:57 -0400] "GET / HTTP/2.0" 304 - 192.0.0.205 - - [18/Oct/2020:19:20:52 -0400] "GET / HTTP/2.0" 304 - 192.0.2.205 - - [18/Oct/2020:19:23:10 -0400] "GET / HTTP/2.0" 304 - .... The other method is using the web browser's built in site debugger or `tcpdump`; however, using either method is beyond the scope of this document. Support for HTTP2 reverse proxy connections by using the [.filename]#mod_proxy_http2.so# module. When configuring the ProxyPass or RewriteRules [P] statements, they should use h2:// for the connection. === Dynamic Websites In addition to mod_perl and mod_php, other languages are available for creating dynamic web content. These include Django and Ruby on Rails. ==== Django Django is a BSD-licensed framework designed to allow developers to write high performance, elegant web applications quickly. It provides an object-relational mapper so that data types are developed as Python objects. A rich dynamic database-access API is provided for those objects without the developer ever having to write SQL. It also provides an extensible template system so that the logic of the application is separated from the HTML presentation. Django depends on [.filename]#mod_python#, and an SQL database engine. In FreeBSD, the package:www/py-django[] port automatically installs [.filename]#mod_python# and supports the PostgreSQL, MySQL, or SQLite databases, with the default being SQLite. To change the database engine, type `make config` within [.filename]#/usr/ports/www/py-django#, then install the port. Once Django is installed, the application will need a project directory along with the Apache configuration in order to use the embedded Python interpreter. This interpreter is used to call the application for specific URLs on the site. To configure Apache to pass requests for certain URLs to the web application, add the following to [.filename]#httpd.conf#, specifying the full path to the project directory: [.programlisting] .... SetHandler python-program PythonPath "['/dir/to/the/django/packages/'] + sys.path" PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonAutoReload On PythonDebug On .... Refer to https://docs.djangoproject.com[https://docs.djangoproject.com] for more information on how to use Django. ==== Ruby on Rails Ruby on Rails is another open source web framework that provides a full development stack. It is optimized to make web developers more productive and capable of writing powerful applications quickly. On FreeBSD, it can be installed using the package:www/rubygem-rails[] package or port. Refer to http://guides.rubyonrails.org[http://guides.rubyonrails.org] for more information on how to use Ruby on Rails. [[network-ftp]] == File Transfer Protocol (FTP) The File Transfer Protocol (FTP) provides users with a simple way to transfer files to and from an FTP server. FreeBSD includes FTP server software, ftpd, in the base system. FreeBSD provides several configuration files for controlling access to the FTP server. This section summarizes these files. Refer to man:ftpd[8] for more details about the built-in FTP server. === Configuration The most important configuration step is deciding which accounts will be allowed access to the FTP server. A FreeBSD system has a number of system accounts which should not be allowed FTP access. The list of users disallowed any FTP access can be found in [.filename]#/etc/ftpusers#. By default, it includes system accounts. Additional users that should not be allowed access to FTP can be added. In some cases it may be desirable to restrict the access of some users without preventing them completely from using FTP. This can be accomplished be creating [.filename]#/etc/ftpchroot# as described in man:ftpchroot[5]. This file lists users and groups subject to FTP access restrictions. To enable anonymous FTP access to the server, create a user named `ftp` on the FreeBSD system. Users will then be able to log on to the FTP server with a username of `ftp` or `anonymous`. When prompted for the password, any input will be accepted, but by convention, an email address should be used as the password. The FTP server will call man:chroot[2] when an anonymous user logs in, to restrict access to only the home directory of the `ftp` user. There are two text files that can be created to specify welcome messages to be displayed to FTP clients. The contents of [.filename]#/etc/ftpwelcome# will be displayed to users before they reach the login prompt. After a successful login, the contents of [.filename]#/etc/ftpmotd# will be displayed. Note that the path to this file is relative to the login environment, so the contents of [.filename]#~ftp/etc/ftpmotd# would be displayed for anonymous users. Once the FTP server has been configured, set the appropriate variable in [.filename]#/etc/rc.conf# to start the service during boot: [.programlisting] .... ftpd_enable="YES" .... To start the service now: [source,shell] .... # service ftpd start .... Test the connection to the FTP server by typing: [source,shell] .... % ftp localhost .... The ftpd daemon uses man:syslog[3] to log messages. By default, the system log daemon will write messages related to FTP in [.filename]#/var/log/xferlog#. The location of the FTP log can be modified by changing the following line in [.filename]#/etc/syslog.conf#: [.programlisting] .... ftp.info /var/log/xferlog .... [NOTE] ==== Be aware of the potential problems involved with running an anonymous FTP server. In particular, think twice about allowing anonymous users to upload files. It may turn out that the FTP site becomes a forum for the trade of unlicensed commercial software or worse. If anonymous FTP uploads are required, then verify the permissions so that these files cannot be read by other anonymous users until they have been reviewed by an administrator. ==== [[network-samba]] == File and Print Services for Microsoft(R) Windows(R) Clients (Samba) Samba is a popular open source software package that provides file and print services using the SMB/CIFS protocol. This protocol is built into Microsoft(R) Windows(R) systems. It can be added to non-Microsoft(R) Windows(R) systems by installing the Samba client libraries. The protocol allows clients to access shared data and printers. These shares can be mapped as a local disk drive and shared printers can be used as if they were local printers. On FreeBSD, the Samba client libraries can be installed using the package:net/samba416[] port or package. The client provides the ability for a FreeBSD system to access SMB/CIFS shares in a Microsoft(R) Windows(R) network. A FreeBSD system can also be configured to act as a Samba server by installing the same package:net/samba416[] port or package. This allows the administrator to create SMB/CIFS shares on the FreeBSD system which can be accessed by clients running Microsoft(R) Windows(R) or the Samba client libraries. === Server Configuration Samba is configured in [.filename]#/usr/local/etc/smb4.conf#. This file must be created before Samba can be used. A simple [.filename]#smb4.conf# to share directories and printers with Windows(R) clients in a workgroup is shown here. For more complex setups involving LDAP or Active Directory, it is easier to use man:samba-tool[8] to create the initial [.filename]#smb4.conf#. [.programlisting] .... [global] workgroup = WORKGROUP server string = Samba Server Version %v netbios name = ExampleMachine wins support = Yes security = user passdb backend = tdbsam # Example: share /usr/src accessible only to 'developer' user [src] path = /usr/src valid users = developer writable = yes browsable = yes read only = no guest ok = no public = no create mask = 0666 directory mask = 0755 .... ==== Global Settings Settings that describe the network are added in [.filename]#/usr/local/etc/smb4.conf#: `workgroup`:: The name of the workgroup to be served. `netbios name`:: The NetBIOS name by which a Samba server is known. By default, it is the same as the first component of the host's DNS name. `server string`:: The string that will be displayed in the output of `net view` and some other networking tools that seek to display descriptive text about the server. `wins support`:: Whether Samba will act as a WINS server. Do not enable support for WINS on more than one server on the network. ==== Security Settings The most important settings in [.filename]#/usr/local/etc/smb4.conf# are the security model and the backend password format. These directives control the options: `security`:: If the clients use usernames that are the same as their usernames on the FreeBSD machine, user level security should be used. `security = user` is the default security policy and it requires clients to first log on before they can access shared resources. + Refer to man:smb.conf[5] to learn about other supported settings for the `security` option. `passdb backend`:: Samba has several different backend authentication models. Clients may be authenticated with LDAP, NIS+, an SQL database, or a modified password file. The recommended authentication method, `tdbsam`, is ideal for simple networks and is covered here. For larger or more complex networks, `ldapsam` is recommended. `smbpasswd` was the former default and is now obsolete. ==== Samba Users FreeBSD user accounts must be mapped to the `SambaSAMAccount` database for Windows(R) clients to access the share. Map existing FreeBSD user accounts using man:pdbedit[8]: [source,shell] .... # pdbedit -a -u username .... This section has only mentioned the most commonly used settings. Refer to the https://wiki.samba.org[Official Samba Wiki] for additional information about the available configuration options. === Starting Samba To enable Samba at boot time, add the following line to [.filename]#/etc/rc.conf#: [.programlisting] .... samba_server_enable="YES" .... To start Samba now: [source,shell] .... # service samba_server start Performing sanity check on Samba configuration: OK Starting nmbd. Starting smbd. .... Samba consists of three separate daemons. Both the nmbd and smbd daemons are started by `samba_enable`. If winbind name resolution is also required, set: [.programlisting] .... winbindd_enable="YES" .... Samba can be stopped at any time by typing: [source,shell] .... # service samba_server stop .... Samba is a complex software suite with functionality that allows broad integration with Microsoft(R) Windows(R) networks. For more information about functionality beyond the basic configuration described here, refer to https://www.samba.org[https://www.samba.org]. [[network-ntp]] == Clock Synchronization with NTP Over time, a computer's clock is prone to drift. This is problematic as many network services require the computers on a network to share the same accurate time. Accurate time is also needed to ensure that file timestamps stay consistent. The Network Time Protocol (NTP) is one way to provide clock accuracy in a network. FreeBSD includes man:ntpd[8] which can be configured to query other NTP servers to synchronize the clock on that machine or to provide time services to other computers in the network. This section describes how to configure ntpd on FreeBSD. Further documentation can be found in [.filename]#/usr/share/doc/ntp/# in HTML format. === NTP Configuration On FreeBSD, the built-in ntpd can be used to synchronize a system's clock. ntpd is configured using man:rc.conf[5] variables and [.filename]#/etc/ntp.conf#, as detailed in the following sections. ntpd communicates with its network peers using UDP packets. Any firewalls between your machine and its NTP peers must be configured to allow UDP packets in and out on port 123. ==== The [.filename]#/etc/ntp.conf# file ntpd reads [.filename]#/etc/ntp.conf# to determine which NTP servers to query. Choosing several NTP servers is recommended in case one of the servers becomes unreachable or its clock proves unreliable. As ntpd receives responses, it favors reliable servers over the less reliable ones. The servers which are queried can be local to the network, provided by an ISP, or selected from an http://support.ntp.org/bin/view/Servers/WebHome[ online list of publicly accessible NTP servers]. When choosing a public NTP server, select one that is geographically close and review its usage policy. The `pool` configuration keyword selects one or more servers from a pool of servers. An http://support.ntp.org/bin/view/Servers/NTPPoolServers[ online list of publicly accessible NTP pools] is available, organized by geographic area. In addition, FreeBSD provides a project-sponsored pool, `0.freebsd.pool.ntp.org`. .Sample [.filename]#/etc/ntp.conf# [example] ==== This is a simple example of an [.filename]#ntp.conf# file. It can safely be used as-is; it contains the recommended `restrict` options for operation on a publicly-accessible network connection. [.programlisting] .... # Disallow ntpq control/query access. Allow peers to be added only # based on pool and server statements in this file. restrict default limited kod nomodify notrap noquery nopeer restrict source limited kod nomodify notrap noquery # Allow unrestricted access from localhost for queries and control. restrict 127.0.0.1 restrict ::1 # Add a specific server. server ntplocal.example.com iburst # Add FreeBSD pool servers until 3-6 good servers are available. tos minclock 3 maxclock 6 pool 0.freebsd.pool.ntp.org iburst # Use a local leap-seconds file. leapfile "/var/db/ntpd.leap-seconds.list" .... ==== The format of this file is described in man:ntp.conf[5]. The descriptions below provide a quick overview of just the keywords used in the sample file above. By default, an NTP server is accessible to any network host. The `restrict` keyword controls which systems can access the server. Multiple `restrict` entries are supported, each one refining the restrictions given in previous statements. The values shown in the example grant the local system full query and control access, while allowing remote systems only the ability to query the time. For more details, refer to the `Access Control Support` subsection of man:ntp.conf[5]. The `server` keyword specifies a single server to query. The file can contain multiple server keywords, with one server listed on each line. The `pool` keyword specifies a pool of servers. ntpd will add one or more servers from this pool as needed to reach the number of peers specified using the `tos minclock` value. The `iburst` keyword directs ntpd to perform a burst of eight quick packet exchanges with a server when contact is first established, to help quickly synchronize system time. The `leapfile` keyword specifies the location of a file containing information about leap seconds. The file is updated automatically by man:periodic[8]. The file location specified by this keyword must match the location set in the `ntp_db_leapfile` variable in [.filename]#/etc/rc.conf#. ==== NTP entries in [.filename]#/etc/rc.conf# Set `ntpd_enable=YES` to start ntpd at boot time. Once `ntpd_enable=YES` has been added to [.filename]#/etc/rc.conf#, ntpd can be started immediately without rebooting the system by typing: [source,shell] .... # service ntpd start .... Only `ntpd_enable` must be set to use ntpd. The [.filename]#rc.conf# variables listed below may also be set as needed. Set `ntpd_sync_on_start=YES` to allow ntpd to step the clock any amount, one time at startup. Normally ntpd will log an error message and exit if the clock is off by more than 1000 seconds. This option is especially useful on systems without a battery-backed realtime clock. Set `ntpd_oomprotect=YES` to protect the ntpd daemon from being killed by the system attempting to recover from an Out Of Memory (OOM) condition. Set `ntpd_config=` to the location of an alternate [.filename]#ntp.conf# file. Set `ntpd_flags=` to contain any other ntpd flags as needed, but avoid using these flags which are managed internally by [.filename]#/etc/rc.d/ntpd#: * `-p` (pid file location) * `-c` (set `ntpd_config=` instead) ==== ntpd and the unpriveleged `ntpd` user ntpd on FreeBSD can start and run as an unpriveleged user. Doing so requires the man:mac_ntpd[4] policy module. The [.filename]#/etc/rc.d/ntpd# startup script first examines the NTP configuration. If possible, it loads the `mac_ntpd` module, then starts ntpd as unpriveleged user `ntpd` (user id 123). To avoid problems with file and directory access, the startup script will not automatically start ntpd as `ntpd` when the configuration contains any file-related options. The presence of any of the following in `ntpd_flags` requires manual configuration as described below to run as the `ntpd` user: * -f or --driftfile * -i or --jaildir * -k or --keyfile * -l or --logfile * -s or --statsdir The presence of any of the following keywords in [.filename]#ntp.conf# requires manual configuration as described below to run as the `ntpd` user: * crypto * driftfile * key * logdir * statsdir To manually configure ntpd to run as user `ntpd` you must: * Ensure that the `ntpd` user has access to all the files and directories specified in the configuration. * Arrange for the `mac_ntpd` module to be loaded or compiled into the kernel. See man:mac_ntpd[4] for details. * Set `ntpd_user="ntpd"` in [.filename]#/etc/rc.conf# === Using NTP with a PPP Connection ntpd does not need a permanent connection to the Internet to function properly. However, if a PPP connection is configured to dial out on demand, NTP traffic should be prevented from triggering a dial out or keeping the connection alive. This can be configured with `filter` directives in [.filename]#/etc/ppp/ppp.conf#. For example: [.programlisting] .... set filter dial 0 deny udp src eq 123 # Prevent NTP traffic from initiating dial out set filter dial 1 permit 0 0 set filter alive 0 deny udp src eq 123 # Prevent incoming NTP traffic from keeping the connection open set filter alive 1 deny udp dst eq 123 # Prevent outgoing NTP traffic from keeping the connection open set filter alive 2 permit 0/0 0/0 .... For more details, refer to the `PACKET FILTERING` section in man:ppp[8] and the examples in [.filename]#/usr/share/examples/ppp/#. [NOTE] ==== Some Internet access providers block low-numbered ports, preventing NTP from functioning since replies never reach the machine. ==== [[network-iscsi]] == iSCSI Initiator and Target Configuration iSCSI is a way to share storage over a network. Unlike NFS, which works at the file system level, iSCSI works at the block device level. In iSCSI terminology, the system that shares the storage is known as the _target_. The storage can be a physical disk, or an area representing multiple disks or a portion of a physical disk. For example, if the disk(s) are formatted with ZFS, a zvol can be created to use as the iSCSI storage. The clients which access the iSCSI storage are called _initiators_. To initiators, the storage available through iSCSI appears as a raw, unformatted disk known as a LUN. Device nodes for the disk appear in [.filename]#/dev/# and the device must be separately formatted and mounted. FreeBSD provides a native, kernel-based iSCSI target and initiator. This section describes how to configure a FreeBSD system as a target or an initiator. [[network-iscsi-target]] === Configuring an iSCSI Target To configure an iSCSI target, create the [.filename]#/etc/ctl.conf# configuration file, add a line to [.filename]#/etc/rc.conf# to make sure the man:ctld[8] daemon is automatically started at boot, and then start the daemon. The following is an example of a simple [.filename]#/etc/ctl.conf# configuration file. Refer to man:ctl.conf[5] for a complete description of this file's available options. [.programlisting] .... portal-group pg0 { discovery-auth-group no-authentication listen 0.0.0.0 listen [::] } target iqn.2012-06.com.example:target0 { auth-group no-authentication portal-group pg0 lun 0 { path /data/target0-0 size 4G } } .... The first entry defines the `pg0` portal group. Portal groups define which network addresses the man:ctld[8] daemon will listen on. The `discovery-auth-group no-authentication` entry indicates that any initiator is allowed to perform iSCSI target discovery without authentication. Lines three and four configure man:ctld[8] to listen on all IPv4 (`listen 0.0.0.0`) and IPv6 (`listen [::]`) addresses on the default port of 3260. It is not necessary to define a portal group as there is a built-in portal group called `default`. In this case, the difference between `default` and `pg0` is that with `default`, target discovery is always denied, while with `pg0`, it is always allowed. The second entry defines a single target. Target has two possible meanings: a machine serving iSCSI or a named group of LUNs. This example uses the latter meaning, where `iqn.2012-06.com.example:target0` is the target name. This target name is suitable for testing purposes. For actual use, change `com.example` to the real domain name, reversed. The `2012-06` represents the year and month of acquiring control of that domain name, and `target0` can be any value. Any number of targets can be defined in this configuration file. The `auth-group no-authentication` line allows all initiators to connect to the specified target and `portal-group pg0` makes the target reachable through the `pg0` portal group. The next section defines the LUN. To the initiator, each LUN will be visible as a separate disk device. Multiple LUNs can be defined for each target. Each LUN is identified by a number, where LUN 0 is mandatory. The `path /data/target0-0` line defines the full path to a file or zvol backing the LUN. That path must exist before starting man:ctld[8]. The second line is optional and specifies the size of the LUN. Next, to make sure the man:ctld[8] daemon is started at boot, add this line to [.filename]#/etc/rc.conf#: [.programlisting] .... ctld_enable="YES" .... To start man:ctld[8] now, run this command: [source,shell] .... # service ctld start .... As the man:ctld[8] daemon is started, it reads [.filename]#/etc/ctl.conf#. If this file is edited after the daemon starts, use this command so that the changes take effect immediately: [source,shell] .... # service ctld reload .... ==== Authentication The previous example is inherently insecure as it uses no authentication, granting anyone full access to all targets. To require a username and password to access targets, modify the configuration as follows: [.programlisting] .... auth-group ag0 { chap username1 secretsecret chap username2 anothersecret } portal-group pg0 { discovery-auth-group no-authentication listen 0.0.0.0 listen [::] } target iqn.2012-06.com.example:target0 { auth-group ag0 portal-group pg0 lun 0 { path /data/target0-0 size 4G } } .... The `auth-group` section defines username and password pairs. An initiator trying to connect to `iqn.2012-06.com.example:target0` must first specify a defined username and secret. However, target discovery is still permitted without authentication. To require target discovery authentication, set `discovery-auth-group` to a defined `auth-group` name instead of `no-authentication`. It is common to define a single exported target for every initiator. As a shorthand for the syntax above, the username and password can be specified directly in the target entry: [.programlisting] .... target iqn.2012-06.com.example:target0 { portal-group pg0 chap username1 secretsecret lun 0 { path /data/target0-0 size 4G } } .... [[network-iscsi-initiator]] === Configuring an iSCSI Initiator [NOTE] ==== The iSCSI initiator described in this section is supported starting with FreeBSD 10.0-RELEASE. To use the iSCSI initiator available in older versions, refer to man:iscontrol[8]. ==== The iSCSI initiator requires that the man:iscsid[8] daemon is running. This daemon does not use a configuration file. To start it automatically at boot, add this line to [.filename]#/etc/rc.conf#: [.programlisting] .... iscsid_enable="YES" .... To start man:iscsid[8] now, run this command: [source,shell] .... # service iscsid start .... Connecting to a target can be done with or without an [.filename]#/etc/iscsi.conf# configuration file. This section demonstrates both types of connections. ==== Connecting to a Target Without a Configuration File To connect an initiator to a single target, specify the IP address of the portal and the name of the target: [source,shell] .... # iscsictl -A -p 10.10.10.10 -t iqn.2012-06.com.example:target0 .... To verify if the connection succeeded, run `iscsictl` without any arguments. The output should look similar to this: [.programlisting] .... Target name Target portal State iqn.2012-06.com.example:target0 10.10.10.10 Connected: da0 .... In this example, the iSCSI session was successfully established, with [.filename]#/dev/da0# representing the attached LUN. If the `iqn.2012-06.com.example:target0` target exports more than one LUN, multiple device nodes will be shown in that section of the output: [source,shell] .... Connected: da0 da1 da2. .... Any errors will be reported in the output, as well as the system logs. For example, this message usually means that the man:iscsid[8] daemon is not running: [.programlisting] .... Target name Target portal State iqn.2012-06.com.example:target0 10.10.10.10 Waiting for iscsid(8) .... The following message suggests a networking problem, such as a wrong IP address or port: [.programlisting] .... Target name Target portal State iqn.2012-06.com.example:target0 10.10.10.11 Connection refused .... This message means that the specified target name is wrong: [.programlisting] .... Target name Target portal State iqn.2012-06.com.example:target0 10.10.10.10 Not found .... This message means that the target requires authentication: [.programlisting] .... Target name Target portal State iqn.2012-06.com.example:target0 10.10.10.10 Authentication failed .... To specify a CHAP username and secret, use this syntax: [source,shell] .... # iscsictl -A -p 10.10.10.10 -t iqn.2012-06.com.example:target0 -u user -s secretsecret .... ==== Connecting to a Target with a Configuration File To connect using a configuration file, create [.filename]#/etc/iscsi.conf# with contents like this: [.programlisting] .... t0 { TargetAddress = 10.10.10.10 TargetName = iqn.2012-06.com.example:target0 AuthMethod = CHAP chapIName = user chapSecret = secretsecret } .... The `t0` specifies a nickname for the configuration file section. It will be used by the initiator to specify which configuration to use. The other lines specify the parameters to use during connection. The `TargetAddress` and `TargetName` are mandatory, whereas the other options are optional. In this example, the CHAP username and secret are shown. To connect to the defined target, specify the nickname: [source,shell] .... # iscsictl -An t0 .... Alternately, to connect to all targets defined in the configuration file, use: [source,shell] .... # iscsictl -Aa .... To make the initiator automatically connect to all targets in [.filename]#/etc/iscsi.conf#, add the following to [.filename]#/etc/rc.conf#: [.programlisting] .... iscsictl_enable="YES" iscsictl_flags="-Aa" .... diff --git a/documentation/content/en/books/handbook/network/_index.adoc b/documentation/content/en/books/handbook/network/_index.adoc index c2b69cd54f..e25cc34640 100644 --- a/documentation/content/en/books/handbook/network/_index.adoc +++ b/documentation/content/en/books/handbook/network/_index.adoc @@ -1,951 +1,951 @@ --- title: Chapter 7. Network part: Part I. Getting Started prev: books/handbook/wayland next: books/handbook/partii description: This chapter delves into the topic of network configuration and performance, showcasing the robust networking capabilities of the FreeBSD operating system. tags: ["network", "ipv4", "ipv6", "wireless", "wpa_supplicant", "static ip", "dynamic ip"] showBookMenu: true weight: 9 path: "/books/handbook/network/" --- [[network]] = Network :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 7 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/network/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[network-synopsis]] == Synopsis This chapter delves into the topic of network configuration and performance, showcasing the robust networking capabilities of the FreeBSD operating system. Whether working with wired or wireless networks, this chapter provides a comprehensive guide to configuring and optimizing network connectivity in FreeBSD. Before diving into the details, it is beneficial for readers to have a basic understanding of networking concepts such as protocols, network interfaces, and addressing. This chapter covers: * The ability to configure wired networks in FreeBSD, including network interface setup, addressing, and customization options. * The skills to configure wireless networks in FreeBSD, encompassing wireless network interface setup, security protocols, and troubleshooting techniques. * FreeBSD's networking capabilities and its reputation for excellent network performance. * An understanding of various network services and protocols supported by FreeBSD, with configuration instructions for DNS, DHCP and more. More information about how to make advanced network configurations in crossref:advanced-networking[advanced-networking,Advanced Networking]. [[config-network-setup]] == Setting up the Network Setting up a wired or wireless connection is a common task for a FreeBSD user. This section will show how to identify the wired and wireless network adapters and how to configure them. Before starting with the configuration it is necessary to know the following network data: * If the network has DHCP * If the network does not have DHCP, the static IP to be used * The netmask * The IP address of the default gateway [TIP] ==== The network connection may have been configured at installation time by man:bsdinstall[8]. ==== [[config-identify-network-adapter]] === Identify Network Adapters FreeBSD supports a wide variety of network adapters for both wired and wireless networks. Check the Hardware Compatibility List for the used link:https://www.freebsd.org/releases/[FreeBSD release] to see if the network adapter is supported. To get the network adapters used by our system execute the following command: [source,shell] .... % pciconf -lv | grep -A1 -B3 network .... The output should be similar to the following: [.programlisting] .... em0@pci0:0:25:0: class=0x020000 rev=0x03 hdr=0x00 vendor=0x8086 device=0x10f5 subvendor=0x17aa subdevice=0x20ee vendor = 'Intel Corporation' <1> device = '82567LM Gigabit Network Connection' <2> class = network subclass = ethernet -- iwn0@pci0:3:0:0: class=0x028000 rev=0x00 hdr=0x00 vendor=0x8086 device=0x4237 subvendor=0x8086 subdevice=0x1211 vendor = 'Intel Corporation' <1> device = 'PRO/Wireless 5100 AGN [Shiloh] Network Connection' <2> class = networ .... The text before the '@' symbol is the name of the driver controlling the device. In this case these are man:em[4] and man:iwn[4]. <1> Shows the name of the vendor <2> Shows the name of the device [NOTE] ==== It is only necessary to load the network interface card module if FreeBSD has not detected it correctly. For example, to load the man:alc[4] module, execute the following command: [source,shell] .... # kldload if_alc .... Alternatively, to load the driver as a module at boot time, place the following line in [.filename]#/boot/loader.conf#: [.programlisting] .... if_alc_load="YES" .... ==== [[config-network-connection]] == Wired Networks Once the right driver is loaded the network adapter needs to be configured. FreeBSD uses the driver name followed by a unit number to name the network interface adapter. The unit number represents the order in which the adapter is detected at boot time, or is later discovered. For example, `em0` is the first network interface card (NIC) on the system using the man:em[4] driver. To display the network interface configuration, enter the following command: [source,shell] .... % ifconfig .... The output should be similar to the following: [.programlisting] .... em0: flags=8863 metric 0 mtu 1500 options=481249b ether 00:1f:16:0f:27:5a inet6 fe80::21f:16ff:fe0f:275a%em0 prefixlen 64 scopeid 0x1 inet 192.168.1.19 netmask 0xffffff00 broadcast 192.168.1.255 media: Ethernet autoselect (1000baseT ) status: active nd6 options=23 lo0: flags=8049 metric 0 mtu 16384 options=680003 inet6 ::1 prefixlen 128 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2 inet 127.0.0.1 netmask 0xff000000 groups: lo nd6 options=21 .... In this example, the following devices were displayed: * `em0`: The Ethernet interface. * `lo0`: The loop interface is a software loopback mechanism which may be used for performance analysis, software testing, and/or local communication. More information in man:lo[4]. The example shows that `em0` is up and running. The key indicators are: . `UP` means that the interface is configured and ready. . The interface has an IPv4 Internet (`inet`) address, `192.168.1.19`. . The interface has an IPv6 Internet (`inet6`) address, `fe80::21f:16ff:fe0f:275a%em0`. . It has a valid subnet mask (`netmask`), where `0xffffff00` is the same as `255.255.255.0`. . It has a valid broadcast address, `192.168.1.255`. . The MAC address of the interface (`ether`) is `00:1f:16:0f:27:5a`. . The physical media selection is on autoselection mode (`media: Ethernet autoselect (1000baseT )`). . The status of the link (`status`) is `active`, indicating that the carrier signal is detected. For `em0`, the `status: no carrier` status is normal when an Ethernet cable is not plugged into the interface. If the man:ifconfig[8] output had shown something similar to the next output it would indicate the interface has not been configured: [.programlisting] .... em0: flags=8822 metric 0 mtu 1500 options=481249b ether 00:1f:16:0f:27:5a media: Ethernet autoselect status: no carrier nd6 options=29 .... [[config-static-ip-v4]] === Configuring Static IPv4 Address This section provides a guide to configuring a static IPv4 address on a FreeBSD system. The network interface card configuration can be performed from the command line with man:ifconfig[8] but will not persist after a reboot unless the configuration is also added to [.filename]#/etc/rc.conf#. [NOTE] ==== If the network was configured during installation by man:bsdinstall[8], some entries for the network interface card (NICs) may be already present. Double check [.filename]#/etc/rc.conf# before executing man:sysrc[8]. ==== The IP address can be set executing the following command: [source,shell] .... # ifconfig em0 inet 192.168.1.150/24 .... To make the change persist across reboots execute the following command: [source,shell] .... # sysrc ifconfig_em0="inet 192.168.1.150 netmask 255.255.255.0" .... Add the default router executing the following command: [source,shell] .... # sysrc defaultrouter="192.168.1.1" .... Add the DNS records to [.filename]#/etc/resolv.conf#: [.programlisting] .... nameserver 8.8.8.8 nameserver 8.8.4.4 .... Then restart `netif` and `routing` executing the following command: [source,shell] .... # service netif restart && service routing restart .... The connection can be tested using man:ping[8]: [source,shell] .... % ping -c2 www.FreeBSD.org .... The output should be similar to the following: [.programlisting] .... PING web.geo.FreeBSD.org (147.28.184.45): 56 data bytes 64 bytes from 147.28.184.45: icmp_seq=0 ttl=51 time=55.173 ms 64 bytes from 147.28.184.45: icmp_seq=1 ttl=51 time=53.093 ms --- web.geo.FreeBSD.org ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 53.093/54.133/55.173/1.040 ms .... [[config-dynamic-ip-v4]] === Configuring Dynamic IPv4 Address If the network has a DHCP server, it is very easy to configure the network interface to use DHCP. FreeBSD uses man:dhclient[8] as the DHCP client. man:dhclient[8] will automatically provide the IP, the netmask and the default router. To make the interface work with DHCP execute the following command: [source,shell] .... # sysrc ifconfig_em0="DHCP" .... man:dhclient[8] can be used manually by running the following command: [source,shell] .... # dhclient em0 .... The output should be similar to the following: [.programlisting] .... DHCPREQUEST on em0 to 255.255.255.255 port 67 DHCPACK from 192.168.1.1 unknown dhcp option value 0x7d bound to 192.168.1.19 -- renewal in 43200 seconds. .... In this way it can be verified that the address assignment using DHCP works correctly. [TIP] ==== man:dhclient[8] client can be started in background. This can cause trouble with applications depending on a working network, but it will provide a faster startup in many cases. To execute man:dhclient[8] in background execute the following command: [source,shell] .... # sysrc background_dhclient="YES" .... ==== Then restart `netif` executing the following command: [source,shell] .... # service netif restart .... The connection can be tested using man:ping[8]: [source,shell] .... % ping -c2 www.FreeBSD.org .... The output should be similar to the following: [.programlisting] .... PING web.geo.FreeBSD.org (147.28.184.45): 56 data bytes 64 bytes from 147.28.184.45: icmp_seq=0 ttl=51 time=55.173 ms 64 bytes from 147.28.184.45: icmp_seq=1 ttl=51 time=53.093 ms --- web.geo.FreeBSD.org ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 53.093/54.133/55.173/1.040 ms .... [[network-ipv6]] === IPv6 IPv6 is the new version of the well-known IP protocol, also known as IPv4. IPv6 provides several advantages over IPv4 as well as many new features: * Its 128-bit address space allows for 340,282,366,920,938,463,463,374,607,431,768,211,456 addresses. This addresses the IPv4 address shortage and eventual IPv4 address exhaustion. * Routers only store network aggregation addresses in their routing tables, thus reducing the average space of a routing table to 8192 entries. This addresses the scalability issues associated with IPv4, which required every allocated block of IPv4 addresses to be exchanged between Internet routers, causing their routing tables to become too large to allow efficient routing. * Address autoconfiguration (http://www.ietf.org/rfc/rfc2462.txt[RFC2462]). * Mandatory multicast addresses. * Built-in IPsec (IP security). * Simplified header structure. * Support for mobile IP. * IPv6-to-IPv4 transition mechanisms. FreeBSD includes the http://www.kame.net/[KAME project] IPv6 reference implementation and comes with everything needed to use IPv6. This section focuses on getting IPv6 configured and running. There are three different types of IPv6 addresses: Unicast:: A packet sent to a unicast address arrives at the interface belonging to the address. Anycast:: These addresses are syntactically indistinguishable from unicast addresses but they address a group of interfaces. The packet destined for an anycast address will arrive at the nearest router interface. Anycast addresses are only used by routers. Multicast:: These addresses identify a group of interfaces. A packet destined for a multicast address will arrive at all interfaces belonging to the multicast group. The IPv4 broadcast address, usually `xxx.xxx.xxx.255`, is expressed by multicast addresses in IPv6. When reading an IPv6 address, the canonical form is represented as `x:x:x:x:x:x:x:x`, where each `x` represents a 16 bit hex value. An example is `FEBC:A574:382B:23C1:AA49:4592:4EFE:9982`. Often, an address will have long substrings of all zeros. A `::` (double colon) can be used to replace one substring per address. Also, up to three leading ``0``s per hex value can be omitted. For example, `fe80::1` corresponds to the canonical form `fe80:0000:0000:0000:0000:0000:0000:0001`. A third form is to write the last 32 bits using the well known IPv4 notation. For example, `2002::10.0.0.1` corresponds to the hexadecimal canonical representation `2002:0000:0000:0000:0000:0000:0a00:0001`, which in turn is equivalent to `2002::a00:1`. To view a FreeBSD system's IPv6 address execute the following command: [source,shell] .... # ifconfig .... The output should be similar to the following: [.programlisting] .... em0: flags=8863 metric 0 mtu 1500 options=481249b ether 00:1f:16:0f:27:5a inet 192.168.1.150 netmask 0xffffff00 broadcast 192.168.1.255 inet6 fe80::21f:16ff:fe0f:275a%em0 prefixlen 64 scopeid 0x1 media: Ethernet autoselect (1000baseT ) status: active nd6 options=23 .... In this example, the `em0` interface is using `fe80::21f:16ff:fe0f:275a%em0`, an auto-configured link-local address which was automatically generated from the MAC address. Some IPv6 addresses are reserved. A list of reserved addresses can be checked in the following table: [[reservedip6]] .Example IPv6 Reserved Addresses [cols="1,1,1,1", frame="none", options="header"] |=== | IPv6 address | Prefixlength (Bits) | Description | Notes |`::` |128 bits |unspecified |Equivalent to `0.0.0.0` in IPv4. |`::1` |128 bits |loopback address |Equivalent to `127.0.0.1` in IPv4. |`::00:xx:xx:xx:xx` |96 bits |embedded IPv4 |The lower 32 bits are the compatible IPv4 address. |`::ff:xx:xx:xx:xx` |96 bits |IPv4 mapped IPv6 address |The lower 32 bits are the IPv4 address for hosts which do not support IPv6. |`fe80::/10` |10 bits |link-local |Equivalent to 169.254.0.0/16 in IPv4. |`fc00::/7` |7 bits |unique-local |Unique local addresses are intended for local communication and are only routable within a set of cooperating sites. |`ff00::` |8 bits |multicast | |``2000::-3fff::`` |3 bits |global unicast |All global unicast addresses are assigned from this pool. The first 3 bits are `001`. |=== For further information on the structure of IPv6 addresses, refer to http://www.ietf.org/rfc/rfc3513.txt[RFC3513]. [[config-static-ip-v6]] === Configuring Static IPv6 Address To configure a FreeBSD system as an IPv6 client with a static IPv6 address it is necessary to set the IPv6 address. Execute the following commands to meet the requirements: [source,shell] .... # sysrc ifconfig_em0_ipv6="inet6 2001:db8:4672:6565:2026:5043:2d42:5344 prefixlen 64" .... To assign a default router, specify its address executing the following command: [source,shell] .... # sysrc ipv6_defaultrouter="2001:db8:4672:6565::1" .... [[config-dynamic-ip-v6]] === Configuring Dynamic IPv6 Address If the network has a DHCP server, it is very easy to configure the network interface to use DHCP. man:dhclient[8] will provide automatically the IP, the netmask and the default router. To make the interface work without DHCP, execute the following commands: [source,shell] .... # sysrc ifconfig_em0_ipv6="inet6 accept_rtadv" # sysrc rtsold_enable="YES" .... === Router Advertisement and Host Auto Configuration This section demonstrates how to setup man:rtadvd[8] on an IPv6 router to advertise the IPv6 network prefix and default route. To enable man:rtadvd[8], execute the following command: [source,shell] .... # sysrc rtadvd_enable="YES" .... It is important to specify the interface on which to do IPv6 router advertisement. For example, to tell man:rtadvd[8] to use `em0`: [source,shell] .... # sysrc rtadvd_interfaces="em0" .... Next, create the configuration file, [.filename]#/etc/rtadvd.conf# as seen in this example: [.programlisting] .... em0:\ :addrs#1:addr="2001:db8:1f11:246::":prefixlen#64:tc=ether: .... Replace `em0` with the interface to be used and `2001:db8:1f11:246::` with the prefix of the allocation. For a dedicated `/64` subnet, nothing else needs to be changed. Otherwise, change the `prefixlen#` to the correct value. === IPv6 and IPv4 Address mapping When IPv6 is enabled on a server, there may be a need to enable IPv4 mapped IPv6 address communication. This compatibility option allows for IPv4 addresses to be represented as IPv6 addresses. Permitting IPv6 applications to communicate with IPv4 and vice versa may be a security issue. This option may not be required in most cases and is available only for compatibility. This option will allow IPv6-only applications to work with IPv4 in a dual stack environment. This is most useful for third party applications which may not support an IPv6-only environment. To enable this feature execute the following command: [source,shell] .... # sysrc ipv6_ipv4mapping="YES" .... [[network-wireless]] == Wireless Networks Most wireless networks are based on the link:https://en.wikipedia.org/wiki/IEEE_802.11[IEEE(R) 802.11 standards]. FreeBSD supports networks that operate using link:https://en.wikipedia.org/wiki/IEEE_802.11a-1999[802.11a], link:https://en.wikipedia.org/wiki/IEEE_802.11b-1999[802.11b], link:https://en.wikipedia.org/wiki/IEEE_802.11g-2003[802.11g] and link:https://en.wikipedia.org/wiki/IEEE_802.11n-2009[802.11n]. [NOTE] ==== link:https://en.wikipedia.org/wiki/IEEE_802.11ac-2013[802.11ac] support on FreeBSD is currently under development. ==== A basic wireless network consists of multiple stations communicating with radios that broadcast in either the 2.4GHz or 5GHz band, though this varies according to the locale and is also changing to enable communication in the 2.3GHz and 4.9GHz ranges. There are three basic steps to configure a wireless network: 1. Scan and select an access point 2. Authenticate the station 3. Configure an IP address or use DHCP. The following sections discuss each step. [[network-wireless-quick-start]] === Quick Start to Connect to a Wireless Network Connecting FreeBSD to an existing wireless network is a very common situation. This procedure shows the steps required: * The first step will be to obtain the SSID (Service Set Identifier) and PSK (Pre-Shared Key) for the wireless network from the network administrator. * The second step will be to add an entry for this network to [.filename]#/etc/wpa_supplicant.conf#. If the file does not exist, create it: [.programlisting] .... network={ ssid="myssid" <.> psk="mypsk" <.> } .... <.> Is the SSID of the wireless network. Replace it with the name of the wireless network. <.> Is the PSK of the wireless network. Replace it with the password of the wireless network. * The third step will be to add the network entry to configure the network on startup: [source,shell] .... # sysrc wlans_iwn0="wlan0" # sysrc ifconfig_wlan0="WPA DHCP" .... * And the last step will be the restart `netif` service executing the following command: [source,shell] .... # service netif restart .... [[basic-wireless-configuration]] === Basic Wireless Configuration The first step will be to configure the wireless network card to an interface. To find out what wireless network cards are in the system check the section -crossref:network[config-identify-network-adapter]. +crossref:network[config-identify-network-adapter, Identify Network Adapters]. [source,shell] .... # ifconfig wlan0 create wlandev iwm0 .... To make the change persist across reboots execute the following command: [source,shell] .... # sysrc wlans_iwm0="wlan0" .... [NOTE] ==== Since the regulatory situation is different in various parts of the world, it is necessary to correctly set the domains that apply to your location to have the correct information about what channels can be used. The available region definitions can be found in [.filename]#/etc/regdomain.xml#. To set the data at runtime, use `ifconfig`: [source,shell] .... # ifconfig wlan0 regdomain etsi2 country AT .... To persist the settings, add it to [.filename]#/etc/rc.conf#: [source,shell] .... # sysrc create_args_wlan0="country AT regdomain etsi2" .... ==== [[scan-wireless-networks]] === Scan Wireless Networks Available wireless networks can be scanned using man:ifconfig[8]. To list the wireless networks execute the following command: [source,shell] .... # ifconfig wlan0 up list scan .... The output should be similar to the following: [.programlisting] .... SSID/MESH ID BSSID CHAN RATE S:N INT CAPS FreeBSD e8:d1:1b:1b:58:ae 1 54M -47:-96 100 EP RSN BSSLOAD HTCAP WPS WME NetBSD d4:b9:2f:35:fe:08 1 54M -80:-96 100 EP RSN BSSLOAD HTCAP WPS WME OpenBSD fc:40:09:c6:31:bd 36 54M -94:-96 100 EPS VHTPWRENV APCHANREP RSN WPS BSSLOAD HTCAP VHTCAP VHTOPMODE WME GNU-Linux dc:f8:b9:a0:a8:e0 44 54M -95:-96 100 EP WPA RSN WPS HTCAP VHTCAP VHTOPMODE WME VHTPWRENV Windows 44:48:b9:b3:c3:ff 44 54M -84:-96 100 EP BSSLOAD VHTPWRENV HTCAP WME RSN VHTCAP VHTOPMODE WPS MacOS 46:48:b9:b3:c3:ff 44 54M -84:-96 100 EP BSSLOAD VHTPWRENV HTCAP WME RSN VHTCAP VHTOPMODE WPS .... . SSID/MESH ID identifies the name of the network. . BSSID identifies the MAC address of the access point. . CAPS field identifies the type of each network and the capabilities of the stations operating there (see the definition of `list scan` in man:ifconfig[8] for more details). [[wireless-authentication]] === Connection and Authentication to a Wireless Network Once a wireless network has been selected from the list of scanned networks, it is necessary to perform the connection and the authentication. In the vast majority of wireless networks, authentication is done with a password configured in the router. Other schemes require cryptographic handshakes to be completed before data traffic can flow, either using pre-shared keys or secrets, or more complex schemes that involve backend services such as RADIUS. [[authenticate-wpa2-wpa-personal]] ==== Authenticate with WPA2/WPA/Personal The authentication process in a wireless network is managed by man:wpa_supplicant[8]. The man:wpa_supplicant[8] configuration will be made in the [.filename]#/etc/wpa_supplicant.conf# file. For more information, see man:wpa_supplicant.conf[5]. Once the scanning of the wireless networks has been carried out, a network has been chosen and have the password (PSK), that information will be added to the file [.filename]#/etc/wpa_supplicant.conf# as in the following example: [.programlisting] .... network={ scan_ssid=1 <.> ssid="FreeBSD" <.> psk="12345678" <.> } .... <.> SSID scan technique. Only need to use this option if the network is hidden. <.> Network name. <.> Password of the wireless network. The next step will be to configure the wireless connection in the file [.filename]#/etc/rc.conf#. To use a static address it will be necessary to execute the following command: [source,shell] .... # sysrc ifconfig_wlan0="inet 192.168.1.20 netmask 255.255.255.0" .... To use a dynamic address it will be necessary to execute the following command: [source,shell] .... # sysrc ifconfig_wlan0="WPA DHCP" .... Then restart the network executing the following command: [source,shell] .... # service netif restart .... [NOTE] ==== More information on how to perform more advanced methods of authentication can be obtained at crossref:advanced-networking[network-advanced-wireless,"Wireless Advanced Authentication"]. ==== [[authenticate-open-networks]] ==== Authenticate with Open Networks [TIP] ==== It is important that the user is *very* careful when connecting to open networks without any kind of authentication. ==== Once the wireless network scan is done and the SSID of the wireless network is selected, execute the following command: [source,shell] .... # ifconfig wlan0 ssid SSID .... And then execute man:dhclient[8] to get the address configured: [source,shell] .... # dhclient wlan0 .... === Using Both Wired and Wireless Connections A wired connection provides better performance and reliability, while a wireless connection provides flexibility and mobility. Laptop users typically want to roam seamlessly between the two types of connections. On FreeBSD, it is possible to combine two or even more network interfaces together in a "failover" fashion. This type of configuration uses the most preferred and available connection from a group of network interfaces, and the operating system switches automatically when the link state changes. Link aggregation and failover is covered in crossref:advanced-networking[network-aggregation,"Link Aggregation and Failover"] and an example for using both wired and wireless connections is provided at crossref:advanced-networking[networking-lagg-wired-and-wireless,"Failover Mode Between Ethernet and Wireless Interfaces"]. [[hostname]] == Hostname The hostname represents the fully qualified domain name (FQDN) of the host on the network. [TIP] ==== If no hostname has been set for the host FreeBSD will assign the value `Amnesiac`. ==== [[get-hostname]] === Check The Current Hostname man:hostname[1] can be used to check the current hostname: [source,shell] .... $ hostname .... The output should be similar to the following: [.programlisting] .... freebsdhostname.example.com .... [[change-hostname]] === Change Hostname To change the hostname of the host and persist it across reboots execute the following command: [source,shell] .... # sysrc hostname="freebsdhostname.example.com" .... [[dns]] == DNS The DNS could be understood as a link:https://en.wikipedia.org/wiki/Telephone_directory[telephone directory] in which an IP is identified to a hostname and vice versa. There are three files that handle how a FreeBSD system interact with the DNS. These three files are man:hosts[5], man:resolv.conf[5] and man:nsswitch.conf[5] Unless otherwise stated in the [.filename]#/etc/nsswitch.conf# file, FreeBSD will look at the addresses in the [.filename]#/etc/hosts# file and then the DNS information in the [.filename]#/etc/resolv.conf# file. [NOTE] ==== The man:nsswitch.conf[5] file specifies how the nsdispatch (name-service switch dispatcher) should operate. By default, the hosts section of the [.filename]#/etc/nsswitch.conf# file will be as follows: [.programlisting] .... hosts: files dns .... For example, in case of using the man:nscd[8] service. The order of preference could be changed by leaving the line as follows: [.programlisting] .... hosts: files cache dns .... ==== [[local-addresses]] === Local addresses The [.filename]#/etc/hosts# file is a simple text database who provide host name to IP address mappings. Entries for local computers connected via a LAN can be added to this file for simplistic naming purposes instead of setting up a DNS server. Additionally, [.filename]#/etc/hosts# can be used to provide a local record of Internet names, reducing the need to query external DNS servers for commonly accessed names. For example, in the case of having a local instance of package:www/gitlab-ce[] in a local environment, it could be added as follows to the file [.filename]#/etc/hosts#: [.programlisting] .... 192.168.1.150 git.example.com git .... [[configuring-nameserver]] === Configuring the Nameserver How a FreeBSD system accesses the Internet Domain Name System (DNS) is controlled by man:resolv.conf[5]. The most common entries to [.filename]#/etc/resolv.conf# are: [.informaltable] [cols="1,1", frame="none"] |=== |`nameserver` |The IP address of a name server the resolver should query. The servers are queried in the order listed with a maximum of three. |`search` |Search list for hostname lookup. This is normally determined by the domain of the local hostname. |`domain` |The local domain name. |=== A typical [.filename]#/etc/resolv.conf# looks like this: [.programlisting] .... search example.com nameserver 147.11.1.11 nameserver 147.11.100.30 .... [NOTE] ==== Only one of the `search` and `domain` options should be used. ==== When using DHCP, man:dhclient[8] usually rewrites [.filename]#/etc/resolv.conf# with information received from the DHCP server. [TIP] ==== If the machine in which the configuration is being made is *not* a DNS server, man:local-unbound[8] can be used to improve DNS lookup performance. To enable it at boot time execute the following command: [source,shell] .... # sysrc local_unbound_enable="YES" .... To start the man:local-unbound[8] service execute the following command: [source,shell] .... # service local_unbound start .... ==== [[troubleshooting]] == Troubleshooting When troubleshooting hardware and software configurations, check the simple things first. * Is the network cable plugged in? * Are the network services properly configured? * Is the firewall configured correctly? * Is the NIC supported by FreeBSD? * Is the router working correctly? [TIP] ==== Before sending a bug report, always check the Hardware Notes in the link:https://www.freebsd.org/releases/[FreeBSD release page], update the version of FreeBSD to the latest STABLE version, check the mailing list archives, and search the Internet. ==== [[wired-troubleshooting]] === Troubleshooting in Wired Networks If the card works, yet performance is poor, read through man:tuning[7]. Also, check the network configuration as incorrect network settings can cause slow connections. `No route to host` messages occur if the system is unable to route a packet to the destination host. This can happen if no default route is specified or if a cable is unplugged. Check the output of `netstat -rn` and make sure there is a valid route to the host. If there is not, read crossref:advanced-networking[network-routing,"Gateways and Routes"]. `ping: sendto: Permission denied` error messages are often caused by a misconfigured firewall. If a firewall is enabled on FreeBSD but no rules have been defined, the default policy is to deny all traffic, even man:ping[8]. Refer to crossref:firewalls[firewalls,Firewalls] for more information. [[wireless-troubleshooting]] === Troubleshooting in Wireless Networks This section describes a number of steps to help troubleshoot common wireless networking problems. * If the access point is not listed when scanning, check that the configuration has not limited the wireless device to a limited set of channels. * If the device cannot associate with an access point, verify that the configuration matches the settings on the access point. This includes the authentication scheme and any security protocols. Simplify the configuration as much as possible. If using a security protocol such as WPA2 or WPA, configure the access point for open authentication and no security to see if traffic will pass. * Once the system can associate with the access point, diagnose the network configuration using tools like man:ping[8]. * There are many lower-level debugging tools. Debugging messages can be enabled in the 802.11 protocol support layer using man:wlandebug[8]. diff --git a/documentation/content/en/books/handbook/ports/_index.adoc b/documentation/content/en/books/handbook/ports/_index.adoc index dcfb26e308..8797672f9b 100644 --- a/documentation/content/en/books/handbook/ports/_index.adoc +++ b/documentation/content/en/books/handbook/ports/_index.adoc @@ -1,1310 +1,1310 @@ --- title: "Chapter 4. Installing Applications: Packages and Ports" part: Part I. Getting Started prev: books/handbook/basics next: books/handbook/x11 description: "FreeBSD provides two complementary technologies for installing third-party software: the FreeBSD Ports Collection, for installing from source, and packages, for installing from pre-built binaries" tags: ["ports", "collection", "pkg", "poudriere", "management"] showBookMenu: true weight: 6 path: "/books/handbook/ports/" --- [[ports]] = Installing Applications: Packages and Ports :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 4 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/ports/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[ports-synopsis]] == Synopsis FreeBSD is bundled with a rich collection of system tools as part of the base system. In addition, FreeBSD provides two complementary technologies for installing third-party software: the FreeBSD Ports Collection, for installing from source, and packages, for installing from pre-built binaries. Either method may be used to install software from local media or from the network. After reading this chapter, you will know: * The difference between binary packages and ports. * How to find third-party software that has been ported to FreeBSD. * How to manage binary packages using pkg. * How to build third-party software from source using the Ports Collection. * How to find the files installed with the application for post-installation configuration. * What to do if a software installation fails. [[ports-overview]] == Overview of Software Installation A FreeBSD _port_ is a collection of files designed to automate the process of compiling an application from source code. The files that comprise a port contain all the necessary information to automatically download, extract, patch, compile, and install the application. If the software has not already been adapted and tested on FreeBSD, the source code might need editing in order for it to install and run properly. However, over link:https://ports.FreeBSD.org[{numports}] third-party applications have already been ported to FreeBSD. When feasible, these applications are made available for download as pre-compiled _packages_. Packages can be manipulated with the FreeBSD package management commands. Both packages and ports understand dependencies. If a package or port is used to install an application and a dependent library is not already installed, the library will automatically be installed first. A FreeBSD package contains pre-compiled copies of all the commands for an application, as well as any configuration files and documentation. A package can be manipulated with the man:pkg[8] commands, such as `pkg install`. While the two technologies are similar, packages and ports each have their own strengths. Select the technology that meets your requirements for installing a particular application. .Package Benefits * A compressed package tarball is typically smaller than the compressed tarball containing the source code for the application. * Packages do not require compilation time. For large applications, such as Firefox, KDE Plasma, or GNOME, this can be important on a slow system. * Packages do not require any understanding of the process involved in compiling software on FreeBSD. .Port Benefits * Packages are normally compiled with conservative options because they have to run on the maximum number of systems. By compiling from the port, one can change the compilation options. * Some applications have compile-time options relating to which features are installed. For example, NGINX(R) can be configured with a wide variety of different built-in options. + In some cases, multiple packages will exist for the same application to specify certain settings. For example, NGINX(R) is available as a `nginx` package and a `nginx-lite` package, depending on whether or not Xorg is installed. Creating multiple packages rapidly becomes impossible if an application has more than one or two different compile-time options. * The licensing conditions of some software forbid binary distribution. Such software must be distributed as source code which must be compiled by the end-user. * Some people do not trust binary distributions or prefer to read through source code in order to look for potential problems. * Source code is needed in order to apply custom patches. To keep track of updated ports, subscribe to the {freebsd-ports} and the {freebsd-ports-bugs}. [WARNING] ==== Before installing an application, check https://vuxml.freebsd.org/[] for related security issues. To audit installed packages against known vulnerabilities, run `pkg audit -F`. ==== The remainder of this chapter explains how to use packages and ports to install and manage third-party software on FreeBSD. [[ports-finding-applications]] == Finding Software FreeBSD's list of available applications is growing all the time. There are a number of ways to find software to install: * The FreeBSD web site maintains an up-to-date searchable list of all the available applications, at link:https://ports.FreeBSD.org[Ports Portal]. The ports can be searched by application name or by software category. * Dan Langille maintains https://www.freshports.org/[FreshPorts] which provides a comprehensive search utility and also tracks changes to the applications in the Ports Collection. Registered users can create a customized watch list in order to receive an automated email when their watched ports are updated. * If finding a particular application becomes challenging, try searching a site like https://sourceforge.net/[SourceForge] or https://github.com/[GitHub] then check back at the link:https://ports.FreeBSD.org[Ports Portal] to see if the application has been ported. * Search the binary package repository for an application using the man:pkg[8] command [[pkgng-intro]] == Using pkg for Binary Package Management man:pkg[8] provides an interface for manipulating packages: registering, adding, removing and upgrading packages. For sites wishing to only use prebuilt binary packages from the FreeBSD mirrors, managing packages with man:pkg[8] can be sufficient. However, for those sites building from source a separate crossref:ports[ports-upgrading-tools, port management tool] will be needed. Since man:pkg[8] only works with binary packages, it is not a replacement for such tools. Those tools can be used to install software from both binary packages and the Ports Collection, while man:pkg[8] installs only binary packages. [[pkgng-initial-setup]] === Getting Started with pkg All supported versions of FreeBSD now contain `/usr/sbin/pkg` a.k.a man:pkg[7]. This is a small placeholder that has just the minimum functionality required to install the real man:pkg[8]. [NOTE] ==== An Internet working connection is required for the bootstrap process to succeed. ==== Run man:pkg[8] command line: [source,shell] .... # pkg .... The output should be similar to the following: [.programlisting] .... The package management tool is not yet installed on your system. Do you want to fetch and install it now? [y/N] .... man:pkg[7] will intercept the command, and if you confirm that is your intention, download the man:pkg[8] tarball, install man:pkg[8] from it, bootstrap the local package database and then proceed to run the command you originally requested. More recent versions of man:pkg[7] understand `pkg -N` as a test to see if man:pkg[8] is installed without triggering the installation, and conversely, pkg bootstrap[-f] to install man:pkg[8] (or force it to be reinstalled) without performing any other actions. Usage information for pkg is available in the man:pkg[8] manual page or by running `pkg` without additional arguments. Additional pkg configuration options are described in man:pkg.conf[5]. Each pkg command argument is documented in a command-specific manual page. To read the manual page for `pkg install`, for example, run this command: [source,shell] .... # pkg help install .... The rest of this section demonstrates common binary package management tasks which can be performed using man:pkg[8]. Each demonstrated command provides many switches to customize its use. Refer to a command's help or man page for details and more examples. [[quarterly-latest-branch]] === Quarterly and Latest Ports Branches The `Quarterly` branch provides users with a more predictable and stable experience for port and package installation and upgrades. This is done essentially by only allowing non-feature updates. Quarterly branches aim to receive security fixes (that may be version updates, or backports of commits), bug fixes and ports compliance or framework changes. The Quarterly branch is cut from HEAD at the beginning of every (yearly) quarter in January, April, July, and October. Branches are named according to the year (YYYY) and quarter (Q1-4) they are created in. For example, the quarterly branch created in January 2023, is named 2023Q1. And the `Latest` branch provides the latest versions of the packages to the users. To switch man:pkg[8] from Quarterly to Latest run the following commands: [source,shell] .... # mkdir -p /usr/local/etc/pkg/repos # echo 'FreeBSD: { url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest" }' > /usr/local/etc/pkg/repos/FreeBSD.conf .... Then run this command to update the local package repositories catalogues for the Latest branch: [source,shell] .... # pkg update -f .... [[pkg-configuration]] === Configure pkg man:pkg.conf[5] is the system-wide configuration file used by the man:pkg[8] tools. The default location of this file is `/usr/local/etc/pkg.conf`. [NOTE] ==== FreeBSD does not need to have a `pkg.conf` file. Many installations will work well with no `pkg.conf` at all or with an empty `pkg.conf` (other than comment lines). ==== Lines in the file beginning with a "#" are comments and are ignored. The file is in UCL format. For more information on the syntax of man:libucl[3], please visit the link:https://github.com/vstakhov/libucl[official UCL website]. The following types of options are recognized - boolean, string and list options. A boolean option is marked as enabled if one of the following values is specified in the configuration file - YES, TRUE and ON. [[pkg-search]] === Searching Packages To search a package man:pkg-search[8] can be used: [source,shell] .... # pkg search nginx .... The output should be similar to the following: [.programlisting] .... modsecurity3-nginx-1.0.3 Instruction detection and prevention engine / nginx Wrapper nginx-1.22.1_2,3 Robust and small WWW server nginx-devel-1.23.2_4 Robust and small WWW server nginx-full-1.22.1_1,3 Robust and small WWW server (full package) nginx-lite-1.22.1,3 Robust and small WWW server (lite package) nginx-naxsi-1.22.1,3 Robust and small WWW server (plus NAXSI) nginx-prometheus-exporter-0.10.0_7 Prometheus exporter for NGINX and NGINX Plus stats nginx-ultimate-bad-bot-blocker-4.2020.03.2005_1 Nginx bad bot and other things blocker nginx-vts-exporter-0.10.7_7 Server that scraps NGINX vts stats and export them via HTTP p5-Nginx-ReadBody-0.07_1 Nginx embeded perl module to read and evaluate a request body p5-Nginx-Simple-0.07_1 Perl 5 module for easy to use interface for Nginx Perl Module p5-Test-Nginx-0.30 Testing modules for Nginx C module development py39-certbot-nginx-2.0.0 NGINX plugin for Certbot rubygem-passenger-nginx-6.0.15 Modules for running Ruby on Rails and Rack applications .... [[pkg-installing-fetching]] === Installing and Fetching Packages To install a binary package man:pkg-install[8] can be used. This command uses repository data to determine which version of the software to install and if it has any uninstalled dependencies. For example, to install curl: [source,shell] .... # pkg install curl .... The output should be similar to the following: [.programlisting] .... Updating FreeBSD repository catalogue... FreeBSD repository is up to date. All repositories are up to date. The following 9 package(s) will be affected (of 0 checked): New packages to be INSTALLED: ca_root_nss: 3.83 curl: 7.86.0 gettext-runtime: 0.21 indexinfo: 0.3.1 libidn2: 2.3.3 libnghttp2: 1.48.0 libpsl: 0.21.1_4 libssh2: 1.10.0.3 libunistring: 1.0 Number of packages to be installed: 9 The process will require 11 MiB more space. 3 MiB to be downloaded Proceed with this action? [y/N] .... The new package and any additional packages that were installed as dependencies can be seen in the installed packages list: [source,shell] .... # pkg info .... The output should be similar to the following: [.programlisting] .... ca_root_nss-3.83 Root certificate bundle from the Mozilla Project curl-7.86.0 Command line tool and library for transferring data with URLs gettext-runtime-0.21.1 GNU gettext runtime libraries and programs indexinfo-0.3.1 Utility to regenerate the GNU info page index libidn2-2.3.3 Implementation of IDNA2008 internationalized domain names libnghttp2-1.48.0 HTTP/2.0 C Library libpsl-0.21.1_6 C library to handle the Public Suffix List libssh2-1.10.0.3 Library implementing the SSH2 protocol libunistring-1.0 Unicode string library pkg-1.18.4 Package manager .... To fetch a package and install it later or in another place use man:pkg-fetch[8]. For example, to download `nginx-lite`: [source,shell] .... # pkg fetch -d -o /usr/home/user/packages/ nginx-lite .... * `-d`: used to fetch all the dependencies * `-o`: used to specify the download directory The output should be similar to the following: [.programlisting] .... Updating FreeBSD repository catalogue... FreeBSD repository is up to date. All repositories are up to date. The following packages will be fetched: New packages to be FETCHED: nginx-lite: 1.22.1,3 (342 KiB: 22.20% of the 2 MiB to download) pcre: 8.45_3 (1 MiB: 77.80% of the 2 MiB to download) Number of packages to be fetched: 2 The process will require 2 MiB more space. 2 MiB to be downloaded. Proceed with fetching packages? [y/N]: .... To install the downloaded packages man:pkg-install[8] can be used as follows: [source,shell] .... # cd /usr/home/user/packages/ .... [source,shell] .... # pkg install nginx-lite-1.22.1,3.pkg .... [[pkgng-pkg-info]] === Obtaining Information About Installed Packages Information about the packages installed on a system can be viewed by running man:pkg-info[8] which, when run without any switches, will list the package version for either all installed packages or the specified package. For example, to see which version of pkg is installed, run: [source,shell] .... # pkg info pkg .... The output should be similar to the following: [.programlisting] .... pkg-1.19.0 Name : pkg Version : 1.19.0 Installed on : Sat Dec 17 11:05:28 2022 CET Origin : ports-mgmt/pkg Architecture : FreeBSD:13:amd64 Prefix : /usr/local Categories : ports-mgmt Licenses : BSD2CLAUSE Maintainer : pkg@FreeBSD.org WWW : https://github.com/freebsd/pkg Comment : Package manager Options : DOCS : on Shared Libs provided: libpkg.so.4 Annotations : FreeBSD_version: 1301000 repo_type : binary repository : FreeBSD Flat size : 33.2MiB Description : Package management tool WWW: https://github.com/freebsd/pkg .... [[pkgng-upgrading]] === Upgrading Installed Packages Installed packages can be upgraded to their latest versions using man:pkg-upgrade[8]: [source,shell] .... # pkg upgrade .... This command will compare the installed versions with those available in the repository catalogue and upgrade them from the repository. [[pkgng-auditing]] === Auditing Installed Packages Software vulnerabilities are regularly discovered in third-party applications. To address this, pkg includes a built-in auditing mechanism. To determine if there are any known vulnerabilities for the software installed on the system, use man:pkg-audit[8]: [source,shell] .... # pkg audit -F .... The output should be similar to the following: [.programlisting] .... Fetching vuln.xml.xz: 100% 976 KiB 499.5kB/s 00:02 chromium-108.0.5359.98 is vulnerable: chromium -- multiple vulnerabilities CVE: CVE-2022-4440 CVE: CVE-2022-4439 CVE: CVE-2022-4438 CVE: CVE-2022-4437 CVE: CVE-2022-4436 WWW: https://vuxml.FreeBSD.org/freebsd/83eb9374-7b97-11ed-be8f-3065ec8fd3ec.html .... [[pkg-delete]] === Removing Packages Packages that are no longer needed can be removed with man:pkg-delete[8]. For example: [source,shell] .... # pkg delete curl .... The output should be similar to the following: [.programlisting] .... Checking integrity... done (0 conflicting) Deinstallation has been requested for the following 1 packages (of 0 packages in the universe): Installed packages to be REMOVED: curl :7.86.0 Number of packages to be removed: 1 The operation will free 4 MiB. Proceed with deinstallation packages? [y/N]: y [1/1] Deinstalling curl-7.86.0... [1/1] Deleting files for curl-7.86.0: 100% .... [[pkgng-autoremove]] === Automatically Removing Unused Packages Removing a package may leave behind dependencies which are no longer required. Unneeded packages that were installed as dependencies (leaf packages) can be automatically detected and removed using man:pkg-autoremove[8]: [source,shell] .... # pkg autoremove .... The output should be similar to the following: [.programlisting] .... Checking integrity... done (0 conflicting) Deinstallation has been requested for the following 1 packages: Installed packages to be REMOVED: ca_root_nss-3.83 Number of packages to be removed: 1 The operation will free 723 KiB. Proceed with deinstalling packages? [y/N]: .... Packages installed as dependencies are called _automatic_ packages. Non-automatic packages, i.e the packages that were explicitly installed not as a dependency to another package, can be listed using: [source,shell] .... # pkg prime-list .... The output should be similar to the following: [.programlisting] .... nginx openvpn sudo .... `pkg prime-list` is an alias command declared in `/usr/local/etc/pkg.conf`. There are many others that can be used to query the package database of the system. For instance, command `pkg prime-origins` can be used to get the origin port directory of the list mentioned above: [source,shell] .... # pkg prime-origins .... The output should be similar to the following: [.programlisting] .... www/nginx security/openvpn security/sudo .... This list can be used to rebuild all packages installed on a system using build tools such as package:ports-mgmt/poudriere[] or package:ports-mgmt/synth[]. Marking an installed package as automatic can be done using: [source,shell] .... # pkg set -A 1 devel/cmake .... Once a package is a leaf package and is marked as automatic, it gets selected by `pkg autoremove`. Marking an installed package as _not_ automatic can be done using: [source,shell] .... # pkg set -A 0 devel/cmake .... [[pkgng-clean]] === Removing Stale Packages By default, pkg stores binary packages in a cache directory defined by `PKG_CACHEDIR` in man:pkg.conf[5]. Only copies of the latest installed packages are kept. Older versions of pkg kept all previous packages. To remove these outdated binary packages, run: [source,shell] .... # pkg clean .... The entire cache may be cleared by running: [source,shell] .... # pkg clean -a .... [[pkg-locking-unlocking]] === Locking and Unlocking Packages man:pkg-lock[8] is used to lock packages against reinstallation, modification or deletion. man:pkg-unlock[8] unlocks the named packages. Either variant only has an effect on currently installed packages. Consequently it is impossible to block installation of a new package by using this mechanism, unless such an installation implies updating a locked package. For example, to lock `nginx-lite`: [source,shell] .... # pkg lock nginx-lite .... And to unlock `nginx-lite`: [source,shell] .... # pkg unlock nginx-lite .... [[pkgng-set]] === Modifying Package Metadata Software within the FreeBSD Ports Collection can undergo major version number changes. To address this, pkg has a built-in command to update package origins. This can be useful, for example, if package:lang/python3[] is renamed to package:lang/python311[] so that package:lang/python3[] can now represent version `3.11`. To change the package origin for the above example, run: [source,shell] .... # pkg set -o lang/python3:lang/python311 .... As another example, to update package:lang/ruby31[] to package:lang/ruby32[], run: [source,shell] .... # pkg set -o lang/ruby31:lang/ruby32 .... [NOTE] ==== When changing package origins, it is important to reinstall packages that are dependent on the package with the modified origin. To force a reinstallation of dependent packages, run: [source,shell] .... # pkg install -Rf lang/ruby32 .... ==== [[ports-using]] == Using the Ports Collection The Ports Collection is a set of `Makefiles`, patches, and description files. Each set of these files is used to compile and install an individual application on FreeBSD, and is called a _port_. By default, the Ports Collection itself is stored as a subdirectory of `/usr/ports`. [WARNING] ==== Before installing and using the Ports Collection, please be aware that it is generally ill-advised to use the Ports Collection in conjunction with the binary packages provided via pkg to install software. pkg, by default, tracks quarterly branch-releases of the ports tree and not HEAD. Dependencies could be different for a port in HEAD compared to its counterpart in a quarterly branch release and this could result in conflicts between dependencies installed by pkg and those from the Ports Collection. If the Ports Collection and pkg must be used in conjunction, then be sure that your Ports Collection and pkg are on the same branch release of the ports tree. ==== The Ports Collection contains directories for software categories. Inside each category are subdirectories for individual applications. Each application subdirectory contains a set of files that tells FreeBSD how to compile and install that program, called a _ports skeleton_. Each port skeleton includes these files and directories: * *Makefile*: contains statements that specify how the application should be compiled and where its components should be installed. * *distinfo*: contains the names and checksums of the files that must be downloaded to build the port. * *files/*: this directory contains any patches needed for the program to compile and install on FreeBSD. This directory may also contain other files used to build the port. * *pkg-descr*: provides a more detailed description of the program. * *pkg-plist*: a list of all the files that will be installed by the port. It also tells the ports system which files to remove upon deinstallation. Some ports include `pkg-message` or other files to handle special situations. For more details on these files, and on ports in general, refer to the extref:{porters-handbook}[FreeBSD Porter's Handbook]. The port does not include the actual source code, also known as a `distfile`. The extract portion of building a port will automatically save the downloaded source to `/usr/ports/distfiles`. [[ports-using-installation-methods]] === Installing the Ports Collection Before an application can be compiled using a port, the Ports Collection must first be installed. If it was not installed during the installation of FreeBSD, use the following method to install it: [[ports-using-git-method]] [.procedure] **** *Procedure: Git Method* If more control over the ports tree is needed or if local changes need to be maintained, or if running FreeBSD-CURRENT, Git can be used to obtain the Ports Collection. Refer to extref:{committers-guide}[the Git Primer, git-primer] for a detailed description of Git. We add --depth 1 to the git command line to clone the tree without obtaining the commit history, which saves time and is acceptable for most users. If you have your own changes to the ports tree, or need the history for any reason, omit the --depth 1 argument below. . Git must be installed before it can be used to check out the ports tree. If a copy of the ports tree is already present, install Git like this: + [source,shell] .... # cd /usr/ports/devel/git # make install clean .... + If the ports tree is not available, or pkg is being used to manage packages, Git can be installed as a package: + [source,shell] .... # pkg install git .... + . Check out a copy of the HEAD branch of the ports tree: + [source,shell] .... # git clone --depth 1 https://git.FreeBSD.org/ports.git /usr/ports .... + . Or, check out a copy of a quarterly branch: + [source,shell] .... # git clone --depth 1 https://git.FreeBSD.org/ports.git -b 2023Q1 /usr/ports .... + . As needed, update `/usr/ports` after the initial Git checkout: + [source,shell] .... # git -C /usr/ports pull .... + . As needed, switch `/usr/ports` to a different quarterly branch: + [source,shell] .... # git -C /usr/ports switch 2023Q1 .... **** === Installing Ports This section provides basic instructions on using the Ports Collection to install or remove software. The detailed description of available `make` targets and environment variables is available in man:ports[7]. [WARNING] ==== Before compiling any port, be sure to update the Ports Collection as described in the previous section. Since the installation of any third-party software can introduce security vulnerabilities, it is recommended to first check https://vuxml.freebsd.org/[] for known security issues related to the port. Alternatively, run `pkg audit -F` before installing a new port. This command can be configured to automatically perform a security audit and an update of the vulnerability database during the daily security system check. For more information, refer to man:pkg-audit[8] and man:periodic[8]. ==== Using the Ports Collection assumes a working Internet connection. It also requires superuser privilege. To compile and install the port, change to the directory of the port to be installed, then type `make install` at the prompt. Messages will indicate the progress: [source,shell] .... # cd /usr/ports/sysutils/lsof # make install >> lsof_4.88D.freebsd.tar.gz doesn't seem to exist in /usr/ports/distfiles/. >> Attempting to fetch from ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/. ===> Extracting for lsof-4.88 ... [extraction output snipped] ... >> Checksum OK for lsof_4.88D.freebsd.tar.gz. ===> Patching for lsof-4.88.d,8 ===> Applying FreeBSD patches for lsof-4.88.d,8 ===> Configuring for lsof-4.88.d,8 ... [configure output snipped] ... ===> Building for lsof-4.88.d,8 ... [compilation output snipped] ... ===> Installing for lsof-4.88.d,8 ... [installation output snipped] ... ===> Generating temporary packing list ===> Compressing manual pages for lsof-4.88.d,8 ===> Registering installation for lsof-4.88.d,8 ===> SECURITY NOTE: This port has installed the following binaries which execute with increased privileges. /usr/local/sbin/lsof # .... Since `lsof` is a program that runs with increased privileges, a security warning is displayed as it is installed. Once the installation is complete, the prompt will be returned. Some shells keep a cache of the commands that are available in the directories listed in the `PATH` environment variable, to speed up lookup operations for the executable file of these commands. Users of the `tcsh` shell should type `rehash` so that a newly installed command can be used without specifying its full path. Use `hash -r` instead for the `sh` shell. Refer to the documentation for the shell for more information. During installation, a working subdirectory is created which contains all the temporary files used during compilation. Removing this directory saves disk space and minimizes the chance of problems later when upgrading to the newer version of the port: [source,shell] .... # make clean ===> Cleaning for lsof-88.d,8 # .... [NOTE] ==== To save this extra step, instead use `make install clean` when compiling the port. ==== ==== Customizing Ports Installation Some ports provide build options which can be used to enable or disable application components, provide security options, or allow for other customizations. Examples include package:www/firefox[] and package:security/gpgme[]. If the port depends upon other ports which have configurable options, it may pause several times for user interaction as the default behavior is to prompt the user to select options from a menu. To avoid this and do all of the configuration in one batch, run `make config-recursive` within the port skeleton. Then, run `make install [clean]` to compile and install the port. [TIP] ==== When using `config-recursive`, the list of ports to configure are gathered by the `all-depends-list` target. It is recommended to run `make config-recursive` until all dependent ports options have been defined, and ports options screens no longer appear, to be certain that all dependency options have been configured. ==== There are several ways to revisit a port's build options menu in order to add, remove, or change these options after a port has been built. One method is to `cd` into the directory containing the port and type `make config`. Another option is to use `make showconfig`. Another option is to execute `make rmconfig` which will remove all selected options and allow you to start over. All of these options, and others, are explained in great detail in man:ports[7]. The ports system uses man:fetch[1] to download the source files, which supports various environment variables. The `FTP_PASSIVE_MODE`, `FTP_PROXY`, and `FTP_PASSWORD` variables may need to be set if the FreeBSD system is behind a firewall or FTP/HTTP proxy. See man:fetch[3] for the complete list of supported variables. For users who cannot be connected to the Internet all the time, `make fetch` can be run within `/usr/ports`, to fetch all distfiles, or within a category, such as `/usr/ports/net`, or within the specific port skeleton. Note that if a port has any dependencies, running this command in a category or ports skeleton will _not_ fetch the distfiles of ports from another category. Instead, use `make fetch-recursive` to also fetch the distfiles for all the dependencies of a port. In rare cases, such as when an organization has a local distfiles repository, the `MASTER_SITES` variable can be used to override the download locations specified in the `Makefile`. When using, specify the alternate location: [source,shell] .... # cd /usr/ports/directory # make MASTER_SITE_OVERRIDE= \ ftp://ftp.organization.org/pub/FreeBSD/ports/distfiles/ fetch .... The `WRKDIRPREFIX` and `PREFIX` variables can override the default working and target directories. For example: [source,shell] .... # make WRKDIRPREFIX=/usr/home/example/ports install .... will compile the port in `/usr/home/example/ports` and install everything under `/usr/local`. [source,shell] .... # make PREFIX=/usr/home/example/local install .... will compile the port in `/usr/ports` and install it in `/usr/home/example/local`. And: [source,shell] .... # make WRKDIRPREFIX=../ports PREFIX=../local install .... will combine the two. These can also be set as environmental variables. Refer to the manual page for your shell for instructions on how to set an environmental variable. [[ports-removing]] === Removing Installed Ports Installed ports can be uninstalled using `pkg delete`. Examples for using this command can be found in the man:pkg-delete[8] manual page. Alternately, `make deinstall` can be run in the port\'s directory: [source,shell] .... # cd /usr/ports/sysutils/lsof # make deinstall ===> Deinstalling for sysutils/lsof ===> Deinstalling Deinstallation has been requested for the following 1 packages: lsof-4.88.d,8 The deinstallation will free 229 kB [1/1] Deleting lsof-4.88.d,8... done .... It is recommended to read the messages as the port is uninstalled. If the port has any applications that depend upon it, this information will be displayed but the uninstallation will proceed. In such cases, it may be better to reinstall the application in order to prevent broken dependencies. [[ports-upgrading]] === Upgrading Ports Over time, newer versions of software become available in the Ports Collection. This section describes how to determine which software can be upgraded and how to perform the upgrade. To determine if newer versions of installed ports are available, ensure that the latest version of the ports tree is installed, using the updating command described in crossref:ports[ports-using-git-method, "Git Method"]. The following command will list the installed ports which are out of date: [source,shell] .... # pkg version -l "<" .... [IMPORTANT] ==== Before attempting an upgrade, read `/usr/ports/UPDATING` from the top of the file to the date closest to the last time ports were upgraded or the system was installed. This file describes various issues and additional steps users may encounter and need to perform when updating a port, including such things as file format changes, changes in locations of configuration files, or any incompatibilities with previous versions. Make note of any instructions which match any of the ports that need upgrading and follow these instructions when performing the upgrade. ==== [[ports-upgrading-tools]] ==== Tools to Upgrade and Manage Ports The Ports Collection contains several utilities to perform the actual upgrade. Each has its strengths and weaknesses. Historically, most installations used either Portmaster or Portupgrade. Synth is a newer alternative. [NOTE] ==== The choice of which tool is best for a particular system is up to the system administrator. It is recommended practice to back up your data before using any of these tools. ==== [[portmaster]] ==== Upgrading Ports Using Portmaster package:ports-mgmt/portmaster[] is a very small utility for upgrading installed ports. It is designed to use the tools installed with the FreeBSD base system without depending on other ports or databases. To install this utility as a port: [source,shell] .... # cd /usr/ports/ports-mgmt/portmaster # make install clean .... Portmaster defines four categories of ports: * Root port: has no dependencies and is not a dependency of any other ports. * Trunk port: has no dependencies, but other ports depend upon it. * Branch port: has dependencies and other ports depend upon it. * Leaf port: has dependencies but no other ports depend upon it. To list these categories and search for updates: [source,shell] .... # portmaster -L ===>>> Root ports (No dependencies, not depended on) ===>>> ispell-3.2.06_18 ===>>> screen-4.0.3 ===>>> New version available: screen-4.0.3_1 ===>>> tcpflow-0.21_1 ===>>> 7 root ports ... ===>>> Branch ports (Have dependencies, are depended on) ===>>> apache22-2.2.3 ===>>> New version available: apache22-2.2.8 ... ===>>> Leaf ports (Have dependencies, not depended on) ===>>> automake-1.9.6_2 ===>>> bash-3.1.17 ===>>> New version available: bash-3.2.33 ... ===>>> 32 leaf ports ===>>> 137 total installed ports ===>>> 83 have new versions available .... This command is used to upgrade all outdated ports: [source,shell] .... # portmaster -a .... [NOTE] ==== By default, Portmaster makes a backup package before deleting the existing port. If the installation of the new version is successful, Portmaster deletes the backup. Using `-b` instructs Portmaster not to automatically delete the backup. Adding `-i` starts Portmaster in interactive mode, prompting for confirmation before upgrading each port. Many other options are available. Read through the manual page for man:portmaster[8] for details regarding their usage. ==== If errors are encountered during the upgrade process, add `-f` to upgrade and rebuild all ports: [source,shell] .... # portmaster -af .... Portmaster can also be used to install new ports on the system, upgrading all dependencies before building and installing the new port. To use this function, specify the location of the port in the Ports Collection: [source,shell] .... # portmaster shells/bash .... More information about package:ports-mgmt/portmaster[] may be found in its `pkg-descr`. [[portupgrade]] ==== Upgrading Ports Using Portupgrade package:ports-mgmt/portupgrade[] is another utility that can be used to upgrade ports. It installs a suite of applications which can be used to manage ports. However, it is dependent upon Ruby. To install the port: [source,shell] .... # cd /usr/ports/ports-mgmt/portupgrade # make install clean .... Before performing an upgrade using this utility, it is recommended to scan the list of installed ports using `pkgdb -F` and to fix all the inconsistencies it reports. To upgrade all the outdated ports installed on the system, use `portupgrade -a`. Alternately, include `-i` to be asked for confirmation of every individual upgrade: [source,shell] .... # portupgrade -ai .... To upgrade only a specified application instead of all available ports, use `portupgrade _pkgname_`. It is very important to include `-R` to first upgrade all the ports required by the given application: [source,shell] .... # portupgrade -R firefox .... If `-P` is included, Portupgrade searches for available packages in the local directories listed in `PKG_PATH`. If none are available locally, it then fetches packages from a remote site. If packages can not be found locally or fetched remotely, Portupgrade will use ports. To avoid using ports entirely, specify `-PP`. This last set of options tells Portupgrade to abort if no packages are available: [source,shell] .... # portupgrade -PP gnome3 .... To just fetch the port distfiles, or packages, if `-P` is specified, without building or installing anything, use `-F`. For further information on all of the available switches, refer to the manual page for `portupgrade`. More information about package:ports-mgmt/portupgrade[] may be found in its `pkg-descr`. [[ports-disk-space]] === Ports and Disk Space Using the Ports Collection will use up disk space over time. After building and installing a port, running `make clean` within the ports skeleton will clean up the temporary `work` directory. If Portmaster is used to install a port, it will automatically remove this directory unless `-K` is specified. If Portupgrade is installed, this command will remove all `work` directories found within the local copy of the Ports Collection: [source,shell] .... # portsclean -C .... In addition, outdated source distribution files accumulate in `/usr/ports/distfiles` over time. To use Portupgrade to delete all the distfiles that are no longer referenced by any ports: [source,shell] .... # portsclean -D .... Portupgrade can remove all distfiles not referenced by any port currently installed on the system: [source,shell] .... # portsclean -DD .... If Portmaster is installed, use: [source,shell] .... # portmaster --clean-distfiles .... By default, this command is interactive and prompts the user to confirm if a distfile should be deleted. In addition to these commands, package:ports-mgmt/pkg_cutleaves[] automates the task of removing installed ports that are no longer needed. [[ports-poudriere]] == Building Packages with poudriere poudriere is a `BSD`-licensed utility for creating and testing FreeBSD packages. It uses FreeBSD jails to set up isolated compilation environments. These jails can be used to build packages for versions of FreeBSD that are different from the system on which it is installed, and also to build packages for i386 if the host is an amd64 system. Once the packages are built, they are in a layout identical to the official mirrors. These packages are usable by man:pkg[8] and other package management tools. poudriere is installed using the package:ports-mgmt/poudriere[] package or port. The installation includes a sample configuration file `/usr/local/etc/poudriere.conf.sample`. Copy this file to `/usr/local/etc/poudriere.conf`. Edit the copied file to suit the local configuration. While `ZFS` is not required on the system running poudriere, it is beneficial. When `ZFS` is used, `ZPOOL` must be specified in `/usr/local/etc/poudriere.conf` and `FREEBSD_HOST` should be set to a nearby mirror. Defining `CCACHE_DIR` enables the use of package:devel/ccache[] to cache compilation and reduce build times for frequently-compiled code. It may be convenient to put poudriere datasets in an isolated tree mounted at `/poudriere`. Defaults for the other configuration values are adequate. The number of processor cores detected is used to define how many builds will run in parallel. Supply enough virtual memory, either with `RAM` or swap space. If virtual memory runs out, the compilation jails will stop and be torn down, resulting in weird error messages. [[poudriere-initialization]] === Initialize Jails and Port Trees After configuration, initialize poudriere so that it installs a jail with the required FreeBSD tree and a ports tree. Specify a name for the jail using `-j` and the FreeBSD version with `-v`. On systems running FreeBSD/amd64, the architecture can be set with `-a` to either `i386` or `amd64`. The default is the architecture shown by `uname`. [source,shell] .... # poudriere jail -c -j 13amd64 -v 13.1-RELEASE [00:00:00] Creating 13amd64 fs at /poudriere/jails/13amd64... done [00:00:00] Using pre-distributed MANIFEST for FreeBSD 13.1-RELEASE amd64 [00:00:00] Fetching base for FreeBSD 13.1-RELEASE amd64 /poudriere/jails/13amd64/fromftp/base.txz 125 MB 4110 kBps 31s [00:00:33] Extracting base... done [00:00:54] Fetching src for FreeBSD 13.1-RELEASE amd64 /poudriere/jails/13amd64/fromftp/src.txz 154 MB 4178 kBps 38s [00:01:33] Extracting src... done [00:02:31] Fetching lib32 for FreeBSD 13.1-RELEASE amd64 /poudriere/jails/13amd64/fromftp/lib32.txz 24 MB 3969 kBps 06s [00:02:38] Extracting lib32... done [00:02:42] Cleaning up... done [00:02:42] Recording filesystem state for clean... done [00:02:42] Upgrading using ftp /etc/resolv.conf -> /poudriere/jails/13amd64/etc/resolv.conf Looking up update.FreeBSD.org mirrors... 3 mirrors found. Fetching public key from update4.freebsd.org... done. Fetching metadata signature for 13.1-RELEASE from update4.freebsd.org... done. Fetching metadata index... done. Fetching 2 metadata files... done. Inspecting system... done. Preparing to download files... done. Fetching 124 patches.....10....20....30....40....50....60....70....80....90....100....110....120.. done. Applying patches... done. Fetching 6 files... done. The following files will be added as part of updating to 13.1-RELEASE-p1: /usr/src/contrib/unbound/.github /usr/src/contrib/unbound/.github/FUNDING.yml /usr/src/contrib/unbound/contrib/drop2rpz /usr/src/contrib/unbound/contrib/unbound_portable.service.in /usr/src/contrib/unbound/services/rpz.c /usr/src/contrib/unbound/services/rpz.h /usr/src/lib/libc/tests/gen/spawnp_enoexec.sh The following files will be updated as part of updating to 13.1-RELEASE-p1: […] Installing updates...Scanning //usr/share/certs/blacklisted for certificates... Scanning //usr/share/certs/trusted for certificates... done. 13.1-RELEASE-p1 [00:04:06] Recording filesystem state for clean... done [00:04:07] Jail 13amd64 13.1-RELEASE-p1 amd64 is ready to be used .... [source,shell] .... # poudriere ports -c -p local -m git+https [00:00:00] Creating local fs at /poudriere/ports/local... done [00:00:00] Checking out the ports tree... done .... On a single computer, poudriere can build ports with multiple configurations, in multiple jails, and from different port trees. Custom configurations for these combinations are called _sets_. See the CUSTOMIZATION section of man:poudriere[8] for details after package:ports-mgmt/poudriere[] or package:ports-mgmt/poudriere-devel[] is installed. The basic configuration shown here puts a single jail-, port-, and set-specific `make.conf` in `/usr/local/etc/poudriere.d`. The filename in this example is created by combining the jail name, port name, and set name: `13amd64-local-workstation-make.conf`. The system `make.conf` and this new file are combined at build time to create the `make.conf` used by the build jail. Packages to be built are entered in `13amd64-local-workstation-pkglist` (ports with extref:{porters-handbook}flavors[FLAVORS] can be defined with @FLAVOR): [.programlisting] .... editors/emacs devel/git devel/php-composer2@php82 ports-mgmt/pkg ... .... Options and dependencies for the specified ports are configured: [source,shell] .... # poudriere options -j 13amd64 -p local -z workstation -f 13amd64-local-workstation-pkglist .... Finally, packages are built and a package repository is created: [source,shell] .... # poudriere bulk -j 13amd64 -p local -z workstation -f 13amd64-local-workstation-pkglist .... While running, pressing kbd:[Ctrl+t] displays the current state of the build. poudriere also builds files in `/poudriere/logs/bulk/jailname` that can be used with a web server to display build information. After completion, the new packages are now available for installation from the poudriere repository. For more information on using poudriere, see man:poudriere[8] and the main web site, https://github.com/freebsd/poudriere/wiki[]. === Configuring pkg Clients to Use a poudriere Repository While it is possible to use both a custom repository along side of the official repository, sometimes it is useful to disable the official repository. This is done by creating a configuration file that overrides and disables the official configuration file. Create `/usr/local/etc/pkg/repos/FreeBSD.conf` that contains the following: [.programlisting] .... FreeBSD: { enabled: no } .... Usually it is easiest to serve a poudriere repository to the client machines via HTTP. Set up a webserver to serve up the package directory, for instance: `/usr/local/poudriere/data/packages/13amd64`, where `13amd64` is the name of the build. If the URL to the package repository is: `http://pkg.example.com/13amd64`, then the repository configuration file in `/usr/local/etc/pkg/repos/custom.conf` would look like: [.programlisting] .... custom: { url: "http://pkg.example.com/13amd64", enabled: yes, } .... If exposing the package repository to the internet is not desired, the `file://` protocol can be used to point to the repository directly: [.programlisting] .... custom: { url: "file:///usr/local/poudriere/data/packages/11amd64", enabled: yes, } .... [[ports-nextsteps]] == Post-Installation Considerations Regardless of whether the software was installed from a binary package or port, most third-party applications require some level of configuration after installation. The following commands and locations can be used to help determine what was installed with the application. * Most applications install at least one default configuration file in `/usr/local/etc`. In cases where an application has a large number of configuration files, a subdirectory will be created to hold them. Often, sample configuration files are installed which end with a suffix such as `.sample`. The configuration files should be reviewed and possibly edited to meet the system's needs. To edit a sample file, first copy it without the `.sample` extension. * Applications which provide documentation will install it into `/usr/local/share/doc` and many applications also install manual pages. This documentation should be consulted before continuing. * Some applications run services which must be added to `/etc/rc.conf` before starting the application. These applications usually install a startup script in `/usr/local/etc/rc.d`. See crossref:config[configtuning-starting-services,Starting Services] for more information. + [NOTE] ==== By design, applications do not run their startup script upon installation, nor do they run their stop script upon deinstallation or upgrade. This decision is left to the individual system administrator. ==== * Users of man:csh[1] should run `rehash` to rebuild the known binary list in the shells `PATH`. * Use `pkg info` to determine which files, man pages, and binaries were installed with the application. [[ports-broken]] == Dealing with Broken Ports When a port does not build or install, try the following: . Search to see if there is a fix pending for the port in the link:https://www.FreeBSD.org/support/[Problem Report database]. If so, implementing the proposed fix may fix the issue. . Ask the maintainer of the port for help. Type `make maintainer` in the ports skeleton or read the port's `Makefile` to find the maintainer's email address. Remember to include the output leading up to the error in the email to the maintainer. + [NOTE] ==== Some ports are not maintained by an individual but instead by a group maintainer represented by a extref:{mailing-list-faq}[mailing list]. Many, but not all, of these addresses look like mailto:freebsd-listname@FreeBSD.org[freebsd-listname@FreeBSD.org]. Please take this into account when sending an email. In particular, ports maintained by mailto:ports@FreeBSD.org[ports@FreeBSD.org] are not maintained by a specific individual. Instead, any fixes and support come from the general community who subscribe to that mailing list. More volunteers are always needed! ==== + If there is no response to the email, use Bugzilla to submit a bug report using the instructions in extref:{problem-reports}[Writing FreeBSD Problem Reports]. . Fix it! The extref:{porters-handbook}[Porter's Handbook] includes detailed information on the ports infrastructure so that you can fix the occasional broken port or even submit your own! -. Install the package instead of the port using the instructions in crossref:ports[pkgng-intro]. +. Install the package instead of the port using the instructions in crossref:ports[pkgng-intro, Using pkg for Binary Package Management]. diff --git a/documentation/content/en/books/handbook/printing/_index.adoc b/documentation/content/en/books/handbook/printing/_index.adoc index 5ef36c1b83..40482444e2 100644 --- a/documentation/content/en/books/handbook/printing/_index.adoc +++ b/documentation/content/en/books/handbook/printing/_index.adoc @@ -1,897 +1,897 @@ --- title: Chapter 11. Printing part: Part II. Common Tasks prev: books/handbook/kernelconfig next: books/handbook/linuxemu description: This chapter covers the printing system in FreeBSD tags: ["printing", "CUPS", "LPD", "PostScript", "PDLs", "HPLIP", "LPRng"] showBookMenu: true weight: 14 path: "/books/handbook/printing/" --- [[printing]] = Printing :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 11 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/printing/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] Putting information on paper is a vital function, despite many attempts to eliminate it. Printing has two basic components. The data must be delivered to the printer, and must be in a form that the printer can understand. [[printing-quick-start]] == Quick Start Basic printing can be set up quickly. The printer must be capable of printing plain `ASCII` text. -For printing to other types of files, see crossref:printing[printing-lpd-filters]. +For printing to other types of files, see crossref:printing[printing-lpd-filters, Filters]. [.procedure] **** . Create a directory to store files while they are being printed: + [source,shell] .... # mkdir -p /var/spool/lpd/lp # chown daemon:daemon /var/spool/lpd/lp # chmod 770 /var/spool/lpd/lp .... + . As `root`, create [.filename]#/etc/printcap# with these contents: + [.programlisting] .... lp:\ lp=/dev/unlpt0:\ <.> sh:\ mx#0:\ sd=/var/spool/lpd/lp:\ lf=/var/log/lpd-errs: .... + <.> This line is for a printer connected to a `USB` port. + For a printer connected to a parallel or "printer" port, use: + [.programlisting] .... :lp=/dev/lpt0:\ .... + For a printer connected directly to a network, use: + [.programlisting] .... :lp=:rm=network-printer-name:rp=raw:\ .... + Replace _network-printer-name_ with the `DNS` host name of the network printer. + . Enable LPD by editing [.filename]#/etc/rc.conf#, adding this line: + [.programlisting] .... lpd_enable="YES" .... + Start the service: + [source,shell] .... # service lpd start Starting lpd. .... + . Print a test: + [source,shell] .... # printf "1. This printer can print.\n2. This is the second line.\n" | lpr .... + [TIP] ==== If both lines do not start at the left border, but "stairstep" instead, see -crossref:printing[printing-lpd-filters-stairstep]. +crossref:printing[printing-lpd-filters-stairstep, Preventing Stairstepping on Plain Text Printers]. ==== + Text files can now be printed with `lpr`. Give the filename on the command line, or pipe output directly into `lpr`. + [source,shell] .... % lpr textfile.txt % ls -lh | lpr .... **** [[printing-connections]] == Printer Connections Printers are connected to computer systems in a variety of ways. Small desktop printers are usually connected directly to a computer's `USB` port. Older printers are connected to a parallel or "printer" port. Some printers are directly connected to a network, making it easy for multiple computers to share them. A few printers use a rare serial port connection. FreeBSD can communicate with all of these types of printers. [[printing-connections-usb]] `USB`:: `USB` printers can be connected to any available `USB` port on the computer. + When FreeBSD detects a `USB` printer, two device entries are created: [.filename]#/dev/ulpt0# and [.filename]#/dev/unlpt0#. Data sent to either device will be relayed to the printer. After each print job, [.filename]#ulpt0# resets the `USB` port. Resetting the port can cause problems with some printers, so the [.filename]#unlpt0# device is usually used instead. [.filename]#unlpt0# does not reset the USB port at all. [[printing-connections-parallel]] Parallel (`IEEE`-1284):: The parallel port device is [.filename]#/dev/lpt0#. This device appears whether a printer is attached or not, it is not autodetected. + Vendors have largely moved away from these "legacy" ports, and many computers no longer have them. Adapters can be used to connect a parallel printer to a `USB` port. With such an adapter, the printer can be treated as if it were actually a `USB` printer. Devices called _print servers_ can also be used to connect parallel printers directly to a network. [[printing-connections-serial]] Serial (RS-232):: Serial ports are another legacy port, rarely used for printers except in certain niche applications. Cables, connectors, and required wiring vary widely. + For serial ports built into a motherboard, the serial device name is [.filename]#/dev/cuau0# or [.filename]#/dev/cuau1#. Serial `USB` adapters can also be used, and these will appear as [.filename]#/dev/cuaU0#. + Several communication parameters must be known to communicate with a serial printer. The most important are _baud rate_ or `BPS` (Bits Per Second) and _parity_. Values vary, but typical serial printers use a baud rate of 9600 and no parity. [[printing-connections-network]] Network:: Network printers are connected directly to the local computer network. + The `DNS` hostname of the printer must be known. If the printer is assigned a dynamic address by `DHCP`, `DNS` should be dynamically updated so that the host name always has the correct `IP` address. Network printers are often given static `IP` addresses to avoid this problem. + Most network printers understand print jobs sent with the LPD protocol. A print queue name can also be specified. Some printers process data differently depending on which queue is used. For example, a `raw` queue prints the data unchanged, while the `text` queue adds carriage returns to plain text. + Many network printers can also print data sent directly to port 9100. [[printing-connections-summary]] === Summary Wired network connections are usually the easiest to set up and give the fastest printing. For direct connection to the computer, `USB` is preferred for speed and simplicity. Parallel connections work but have limitations on cable length and speed. Serial connections are more difficult to configure. Cable wiring differs between models, and communication parameters like baud rate and parity bits must add to the complexity. Fortunately, serial printers are rare. [[printing-pdls]] == Common Page Description Languages Data sent to a printer must be in a language that the printer can understand. These languages are called Page Description Languages, or PDLs. [[print-pdls-ascii]] `ASCII`:: Plain `ASCII` text is the simplest way to send data to a printer. Characters correspond one to one with what will be printed: an `A` in the data prints an `A` on the page. Very little formatting is available. There is no way to select a font or proportional spacing. The forced simplicity of plain `ASCII` means that text can be printed straight from the computer with little or no encoding or translation. The printed output corresponds directly with what was sent. + Some inexpensive printers cannot print plain `ASCII` text. This makes them more difficult to set up, but it is usually still possible. [[print-pdls-postscript]] PostScript(R):: PostScript(R) is almost the opposite of `ASCII`. Rather than simple text, a PostScript(R) program is a set of instructions that draw the final document. Different fonts and graphics can be used. However, this power comes at a price. The program that draws the page must be written. Usually this program is generated by application software, so the process is invisible to the user. + Inexpensive printers sometimes leave out PostScript(R) compatibility as a cost-saving measure. [[print-pdls-pcl]] `PCL` (Printer Command Language):: `PCL` is an extension of `ASCII`, adding escape sequences for formatting, font selection, and printing graphics. Many printers provide `PCL5` support. Some support the newer `PCL6` or `PCLXL`. These later versions are supersets of `PCL5` and can provide faster printing. [[print-pdls-host-based]] Host-Based:: Manufacturers can reduce the cost of a printer by giving it a simple processor and very little memory. These printers are not capable of printing plain text. Instead, bitmaps of text and graphics are drawn by a driver on the host computer and then sent to the printer. These are called _host-based_ printers. + Communication between the driver and a host-based printer is often through proprietary or undocumented protocols, making them functional only on the most common operating systems. [[print-pdls-table]] === Converting PostScript(R) to Other PDLs Many applications from the Ports Collection and FreeBSD utilities produce PostScript(R) output. This table shows the utilities available to convert that into other common PDLs: [[print-pdls-ps-to-other-tbl]] .Output PDLs [cols="1,1,1", frame="none", options="header"] |=== <| Output PDL <| Generated By <| Notes |`PCL` or `PCL5` |package:print/ghostscript9-base[] |`-sDEVICE=ljet4` for monochrome, `-sDEVICE=cljet5` for color |`PCLXL` or `PCL6` |package:print/ghostscript9-base[] |`-sDEVICE=pxlmono` for monochrome, `-sDEVICE=pxlcolor` for color |`ESC/P2` |package:print/ghostscript9-base[] |`-sDEVICE=uniprint` |`XQX` |package:print/foo2zjs[] | |=== [[print-pdls-summary]] === Summary For the easiest printing, choose a printer that supports PostScript(R). Printers that support `PCL` are the next preferred. With package:print/ghostscript9-base[], these printers can be used as if they understood PostScript(R) natively. Printers that support PostScript(R) or `PCL` directly almost always support direct printing of plain `ASCII` text files also. Line-based printers like typical inkjets usually do not support PostScript(R) or `PCL`. They often can print plain `ASCII` text files. package:print/ghostscript9-base[] supports the PDLs used by some of these printers. However, printing an entire graphic-based page on these printers is often very slow due to the large amount of data to be transferred and printed. Host-based printers are often more difficult to set up. Some cannot be used at all because of proprietary PDLs. Avoid these printers when possible. The particular `PDL` used by various models of printers can be found at http://www.openprinting.org/printers[]. [[printing-direct]] == Direct Printing For occasional printing, files can be sent directly to a printer device without any setup. For example, a file called [.filename]#sample.txt# can be sent to a `USB` printer: [source,shell] .... # cp sample.txt /dev/unlpt0 .... Direct printing to network printers depends on the abilities of the printer, but most accept print jobs on port 9100, and man:nc[1] can be used with them. To print the same file to a printer with the `DNS` hostname of _netlaser_: [source,shell] .... # nc netlaser 9100 < sample.txt .... [[printing-lpd]] == LPD (Line Printer Daemon) Printing a file in the background is called _spooling_. A spooler allows the user to continue with other programs on the computer without waiting for the printer to slowly complete the print job. FreeBSD includes a spooler called man:lpd[8]. Print jobs are submitted with man:lpr[1]. [[printing-lpd-setup]] === Initial Setup A directory for storing print jobs is created, ownership is set, and the permissions are set to prevent other users from viewing the contents of those files: [source,shell] .... # mkdir -p /var/spool/lpd/lp # chown daemon:daemon /var/spool/lpd/lp # chmod 770 /var/spool/lpd/lp .... Printers are defined in [.filename]#/etc/printcap#. An entry for each printer includes details like a name, the port where it is attached, and various other settings. Create [.filename]#/etc/printcap# with these contents: [.programlisting] .... lp:\ <.> :lp=/dev/unlpt0:\ <.> :sh:\ <.> :mx#0:\ <.> :sd=/var/spool/lpd/lp:\ <.> :lf=/var/log/lpd-errs: <.> .... <.> The name of this printer. man:lpr[1] sends print jobs to the `lp` printer unless another printer is specified with `-P`, so the default printer should be named `lp`. <.> The device where the printer is connected. Replace this line with the appropriate one for the connection type shown here. <.> Suppress the printing of a header page at the start of a print job. <.> Do not limit the maximum size of a print job. <.> The path to the spooling directory for this printer. Each printer uses its own spooling directory. <.> The log file where errors on this printer will be reported. After creating [.filename]#/etc/printcap#, use man:chkprintcap[8] to test it for errors: [source,shell] .... # chkprintcap .... Fix any reported problems before continuing. Enable man:lpd[8] in [.filename]#/etc/rc.conf#: [.programlisting] .... lpd_enable="YES" .... Start the service: [source,shell] .... # service lpd start .... [[printing-lpd-lpr]] === Printing with man:lpr[1] Documents are sent to the printer with `lpr`. A file to be printed can be named on the command line or piped into `lpr`. These two commands are equivalent, sending the contents of [.filename]#doc.txt# to the default printer: [source,shell] .... % lpr doc.txt % cat doc.txt | lpr .... Printers can be selected with `-P`. To print to a printer called _laser_: [source,shell] .... % lpr -Plaser doc.txt .... [[printing-lpd-filters]] === Filters The examples shown so far have sent the contents of a text file directly to the printer. As long as the printer understands the content of those files, output will be printed correctly. Some printers are not capable of printing plain text, and the input file might not even be plain text. _Filters_ allow files to be translated or processed. The typical use is to translate one type of input, like plain text, into a form that the printer can understand, like PostScript(R) or `PCL`. Filters can also be used to provide additional features, like adding page numbers or highlighting source code to make it easier to read. The filters discussed here are _input filters_ or _text filters_. These filters convert the incoming file into different forms. Use man:su[1] to become `root` before creating the files. Filters are specified in [.filename]#/etc/printcap# with the `if=` identifier. To use [.filename]#/usr/local/libexec/lf2crlf# as a filter, modify [.filename]#/etc/printcap# like this: [.programlisting] .... lp:\ :lp=/dev/unlpt0:\ :sh:\ :mx#0:\ :sd=/var/spool/lpd/lp:\ :if=/usr/local/libexec/lf2crlf:\ <.> :lf=/var/log/lpd-errs: .... <.> `if=` identifies the _input filter_ that will be used on incoming text. [TIP] ==== The backslash _line continuation_ characters at the end of the lines in [.filename]#printcap# entries reveal that an entry for a printer is really just one long line with entries delimited by colon characters. An earlier example can be rewritten as a single less-readable line: [.programlisting] .... lp:lp=/dev/unlpt0:sh:mx#0:sd=/var/spool/lpd/lp:if=/usr/local/libexec/lf2crlf:lf=/var/log/lpd-errs: .... ==== [[printing-lpd-filters-stairstep]] ==== Preventing Stairstepping on Plain Text Printers Typical FreeBSD text files contain only a single line feed character at the end of each line. These lines will "stairstep" on a standard printer: [.programlisting] .... A printed file looks like the steps of a staircase scattered by the wind .... A filter can convert the newline characters into carriage returns and newlines. The carriage returns make the printer return to the left after each line. Create [.filename]#/usr/local/libexec/lf2crlf# with these contents: [.programlisting] .... #!/bin/sh CR=$'\r' /usr/bin/sed -e "s/$/${CR}/g" .... Set the permissions and make it executable: [source,shell] .... # chmod 555 /usr/local/libexec/lf2crlf .... Modify [.filename]#/etc/printcap# to use the new filter: [.programlisting] .... :if=/usr/local/libexec/lf2crlf:\ .... Test the filter by printing the same plain text file. The carriage returns will cause each line to start at the left side of the page. [[printing-lpd-filters-enscript]] ==== Fancy Plain Text on PostScript(R) Printers with package:print/enscript[] GNUEnscript converts plain text files into nicely-formatted PostScript(R) for printing on PostScript(R) printers. It adds page numbers, wraps long lines, and provides numerous other features to make printed text files easier to read. Depending on the local paper size, install either package:print/enscript-letter[] or package:print/enscript-a4[] from the Ports Collection. Create [.filename]#/usr/local/libexec/enscript# with these contents: [.programlisting] .... #!/bin/sh /usr/local/bin/enscript -o - .... Set the permissions and make it executable: [source,shell] .... # chmod 555 /usr/local/libexec/enscript .... Modify [.filename]#/etc/printcap# to use the new filter: [.programlisting] .... :if=/usr/local/libexec/enscript:\ .... Test the filter by printing a plain text file. [[printing-lpd-filters-ps2pcl]] ==== Printing PostScript(R) to `PCL` Printers Many programs produce PostScript(R) documents. However, inexpensive printers often only understand plain text or `PCL`. This filter converts PostScript(R) files to `PCL` before sending them to the printer. Install the Ghostscript PostScript(R) interpreter, package:print/ghostscript9-base[], from the Ports Collection. Create [.filename]#/usr/local/libexec/ps2pcl# with these contents: [.programlisting] .... #!/bin/sh /usr/local/bin/gs -dSAFER -dNOPAUSE -dBATCH -q -sDEVICE=ljet4 -sOutputFile=- - .... Set the permissions and make it executable: [source,shell] .... # chmod 555 /usr/local/libexec/ps2pcl .... PostScript(R) input sent to this script will be rendered and converted to `PCL` before being sent on to the printer. Modify [.filename]#/etc/printcap# to use this new input filter: [.programlisting] .... :if=/usr/local/libexec/ps2pcl:\ .... Test the filter by sending a small PostScript(R) program to it: [source,shell] .... % printf "%%\!PS \n /Helvetica findfont 18 scalefont setfont \ 72 432 moveto (PostScript printing successful.) show showpage \004" | lpr .... [[printing-lpd-filters-smart]] ==== Smart Filters A filter that detects the type of input and automatically converts it to the correct format for the printer can be very convenient. The first two characters of a PostScript(R) file are usually `%!`. A filter can detect those two characters. PostScript(R) files can be sent on to a PostScript(R) printer unchanged. Text files can be converted to PostScript(R) with Enscript as shown earlier. Create [.filename]#/usr/local/libexec/psif# with these contents: [.programlisting] .... #!/bin/sh # # psif - Print PostScript or plain text on a PostScript printer # IFS="" read -r first_line first_two_chars=`expr "$first_line" : '\(..\)'` case "$first_two_chars" in %!) # %! : PostScript job, print it. echo "$first_line" && cat && exit 0 exit 2 ;; *) # otherwise, format with enscript ( echo "$first_line"; cat ) | /usr/local/bin/enscript -o - && exit 0 exit 2 ;; esac .... Set the permissions and make it executable: [source,shell] .... # chmod 555 /usr/local/libexec/psif .... Modify [.filename]#/etc/printcap# to use this new input filter: [.programlisting] .... :if=/usr/local/libexec/psif:\ .... Test the filter by printing PostScript(R) and plain text files. [[printing-lpd-queues]] === Multiple Queues The entries in [.filename]#/etc/printcap# are really definitions of _queues_. There can be more than one queue for a single printer. When combined with filters, multiple queues provide users more control over how their jobs are printed. As an example, consider a networked PostScript(R) laser printer in an office. Most users want to print plain text, but a few advanced users want to be able to print PostScript(R) files directly. Two entries can be created for the same printer in [.filename]#/etc/printcap#: [.programlisting] .... textprinter:\ :lp=9100@officelaser:\ :sh:\ :mx#0:\ :sd=/var/spool/lpd/textprinter:\ :if=/usr/local/libexec/enscript:\ :lf=/var/log/lpd-errs: psprinter:\ :lp=9100@officelaser:\ :sh:\ :mx#0:\ :sd=/var/spool/lpd/psprinter:\ :lf=/var/log/lpd-errs: .... Documents sent to `textprinter` will be formatted by the [.filename]#/usr/local/libexec/enscript# filter shown in an earlier example. Advanced users can print PostScript(R) files on `psprinter`, where no filtering is done. This multiple queue technique can be used to provide direct access to all kinds of printer features. A printer with a duplexer could use two queues, one for ordinary single-sided printing, and one with a filter that sends the command sequence to enable double-sided printing and then sends the incoming file. [[printing-lpd-monitor]] === Monitoring and Controlling Printing Several utilities are available to monitor print jobs and check and control printer operation. [[printing-lpd-monitor-lpq]] ==== man:lpq[1] man:lpq[1] shows the status of a user's print jobs. Print jobs from other users are not shown. Show the current user's pending jobs on a single printer: [source,shell] .... % lpq -Plp Rank Owner Job Files Total Size 1st jsmith 0 (standard input) 12792 bytes .... Show the current user's pending jobs on all printers: [source,shell] .... % lpq -a lp: Rank Owner Job Files Total Size 1st jsmith 1 (standard input) 27320 bytes laser: Rank Owner Job Files Total Size 1st jsmith 287 (standard input) 22443 bytes .... [[printing-lpd-monitor-lprm]] ==== man:lprm[1] man:lprm[1] is used to remove print jobs. Normal users are only allowed to remove their own jobs. `root` can remove any or all jobs. Remove all pending jobs from a printer: [source,shell] .... # lprm -Plp - dfA002smithy dequeued cfA002smithy dequeued dfA003smithy dequeued cfA003smithy dequeued dfA004smithy dequeued cfA004smithy dequeued .... Remove a single job from a printer. man:lpq[1] is used to find the job number. [source,shell] .... % lpq Rank Owner Job Files Total Size 1st jsmith 5 (standard input) 12188 bytes % lprm -Plp 5 dfA005smithy dequeued cfA005smithy dequeued .... [[printing-lpd-monitor-lpc]] ==== man:lpc[8] man:lpc[8] is used to check and modify printer status. `lpc` is followed by a command and an optional printer name. `all` can be used instead of a specific printer name, and the command will be applied to all printers. Normal users can view status with man:lpc[8]. Only `root` can use commands which modify printer status. Show the status of all printers: [source,shell] .... % lpc status all lp: queuing is enabled printing is enabled 1 entry in spool area printer idle laser: queuing is enabled printing is enabled 1 entry in spool area waiting for laser to come up .... Prevent a printer from accepting new jobs, then begin accepting new jobs again: [source,shell] .... # lpc disable lp lp: queuing disabled # lpc enable lp lp: queuing enabled .... Stop printing, but continue to accept new jobs. Then begin printing again: [source,shell] .... # lpc stop lp lp: printing disabled # lpc start lp lp: printing enabled daemon started .... Restart a printer after some error condition: [source,shell] .... # lpc restart lp lp: no daemon to abort printing enabled daemon restarted .... Turn the print queue off and disable printing, with a message to explain the problem to users: [source,shell] .... # lpc down lp Repair parts will arrive on Monday lp: printer and queuing disabled status message is now: Repair parts will arrive on Monday .... Re-enable a printer that is down: [source,shell] .... # lpc up lp lp: printing enabled daemon started .... See man:lpc[8] for more commands and options. [[printing-lpd-shared]] === Shared Printers Printers are often shared by multiple users in businesses and schools. Additional features are provided to make sharing printers more convenient. [[printing-shared-aliases]] ==== Aliases The printer name is set in the first line of the entry in [.filename]#/etc/printcap#. Additional names, or _aliases_, can be added after that name. Aliases are separated from the name and each other by vertical bars: [.programlisting] .... lp|repairsprinter|salesprinter:\ .... Aliases can be used in place of the printer name. For example, users in the Sales department print to their printer with [source,shell] .... % lpr -Psalesprinter sales-report.txt .... Users in the Repairs department print to _their_ printer with [source,shell] .... % lpr -Prepairsprinter repairs-report.txt .... All of the documents print on that single printer. When the Sales department grows enough to need their own printer, the alias can be removed from the shared printer entry and used as the name of a new printer. Users in both departments continue to use the same commands, but the Sales documents are sent to the new printer. [[printing-shared-headers]] ==== Header Pages It can be difficult for users to locate their documents in the stack of pages produced by a busy shared printer. _Header pages_ were created to solve this problem. A header page with the user name and document name is printed before each print job. These pages are also sometimes called _banner_ or _separator_ pages. Enabling header pages differs depending on whether the printer is connected directly to the computer with a `USB`, parallel, or serial cable, or is connected remotely over a network. Header pages on directly-connected printers are enabled by removing the `:sh:\` (Suppress Header) line from the entry in [.filename]#/etc/printcap#. These header pages only use line feed characters for new lines. Some printers will need the [.filename]#/usr/share/examples/printing/hpif# filter to prevent stairstepped text. The filter configures `PCL` printers to print both carriage returns and line feeds when a line feed is received. Header pages for network printers must be configured on the printer itself. Header page entries in [.filename]#/etc/printcap# are ignored. Settings are usually available from the printer front panel or a configuration web page accessible with a web browser. [[printing-lpd-references]] === References Example files: [.filename]#/usr/share/examples/printing/#. The _4.3BSD Line Printer Spooler Manual_, [.filename]#/usr/share/doc/smm/07.lpd/paper.ascii.gz#. Manual pages: man:printcap[5], man:lpd[8], man:lpr[1], man:lpc[8], man:lprm[1], man:lpq[1]. [[printing-other]] == Other Printing Systems Several other printing systems are available in addition to the built-in man:lpd[8]. These systems offer support for other protocols or additional features. [[printing-other-cups]] === CUPS (Common UNIX(R) Printing System) CUPS is a popular printing system available on many operating systems. Using CUPS on FreeBSD is documented in a separate article: extref:{cups}[CUPS] [[printing-other-hplip]] === HPLIP Hewlett Packard provides a printing system that supports many of their inkjet and laser printers. The port is package:print/hplip[]. The main web page is at https://developers.hp.com/hp-linux-imaging-and-printing[]. The port handles all the installation details on FreeBSD. Configuration information is shown at https://developers.hp.com/hp-linux-imaging-and-printing/install[]. [[printing-other-lprng]] === LPRng LPRng was developed as an enhanced alternative to man:lpd[8]. The port is package:sysutils/LPRng[]. For details and documentation, see https://lprng.sourceforge.net/[]. diff --git a/documentation/content/en/books/handbook/security/_index.adoc b/documentation/content/en/books/handbook/security/_index.adoc index 8332e314f9..e2bba4caf3 100644 --- a/documentation/content/en/books/handbook/security/_index.adoc +++ b/documentation/content/en/books/handbook/security/_index.adoc @@ -1,2183 +1,2183 @@ --- title: Chapter 16. Security part: Part III. System Administration prev: books/handbook/boot next: books/handbook/jails description: Hundreds of standard practices have been authored about how to secure systems and networks, and as a user of FreeBSD, understanding how to protect against attacks and intruders is a must tags: ["security", "TCP Wrappers", "Kerberos", "OpenSSL", "OpenSSH", "ACL", "NFSv4 ACLs", "advisories", "sudo", "doas", "capsicum", "monitoring"] showBookMenu: true weight: 20 path: "/books/handbook/security/" --- [[security]] = Security :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 16 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/security/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[security-synopsis]] == Synopsis Hundreds of standard practices have been authored about how to secure systems and networks, and as a user of FreeBSD, understanding how to protect against attacks and intruders is a must. In this chapter, several fundamentals and techniques will be discussed. The FreeBSD system comes with multiple layers of security, and many more third party utilities may be added to enhance security. This chapter covers: * Basic FreeBSD system security concepts. * The various crypt mechanisms available in FreeBSD. * How to configure TCP Wrappers for use with man:inetd[8]. * How to set up Kerberos on FreeBSD. * How to configure and use OpenSSH on FreeBSD. * How to use OpenSSL on FreeBSD. * How to use file system ACLs. * How to use pkg to audit third party software packages installed from the Ports Collection. * How to utilize FreeBSD security advisories. * What Process Accounting is and how to enable it on FreeBSD. * How to control user resources using login classes or the resource limits database. * What is Capsicum and a basic example. Certain topics due to their complexity are found in dedicated chapters such as crossref:firewalls[firewalls,Firewalls], crossref:mac[mac,Mandatory Access Control] and articles like extref:{vpn-ipsec}[VPN over IPsec]. [[security-intro]] == Introduction Security is everyone's responsibility. A weak entry point in any system could allow intruders to gain access to critical information and cause havoc on an entire network. One of the core principles of information security is the CIA triad, which stands for the Confidentiality, Integrity, and Availability of information systems. The CIA triad is a bedrock concept of computer security as customers and users expect their data to be protected. For example, a customer expects that their credit card information is securely stored (confidentiality), that their orders are not changed behind the scenes (integrity), and that they have access to their order information at all times (availability). To provide CIA, security professionals apply a defense in depth strategy. The idea of defense in depth is to add several layers of security to prevent one single layer failing and the entire security system collapsing. For example, a system administrator cannot simply turn on a firewall and consider the network or system secure. One must also audit accounts, check the integrity of binaries, and ensure malicious tools are not installed. To implement an effective security strategy, one must understand threats and how to defend against them. What is a threat as it pertains to computer security? Threats are not limited to remote attackers who attempt to access a system without permission from a remote location. Threats also include employees, malicious software, unauthorized network devices, natural disasters, security vulnerabilities, and even competing corporations. Systems and networks can be accessed without permission, sometimes by accident, or by remote attackers, and in some cases, via corporate espionage or former employees. As a user, it is important to prepare for and admit when a mistake has led to a security breach and report possible issues to the security team. As an administrator, it is important to know of the threats and be prepared to mitigate them. When applying security to systems, it is recommended to start by securing the basic accounts and system configuration, and then to secure the network layer so that it adheres to the system policy and the organization's security procedures. Many organizations already have a security policy that covers the configuration of technology devices. The policy should include the security configuration of workstations, desktops, mobile devices, phones, production servers, and development servers. In many cases, standard operating procedures (SOPs) already exist. When in doubt, ask the security team. [[sec-accounts]] == Securing Accounts Maintaining secure accounts in FreeBSD is crucial for data confidentiality, system integrity, and privilege separation, as it prevents unauthorized access, malware, and data breaches while ensuring compliance and protecting an organization's reputation. [[security-accounts]] === Preventing Logins In securing a system, a good starting point is an audit of accounts. Disable any accounts that do not need login access. [TIP] ==== Ensure that `root` has a strong password and that this password is not shared. ==== To deny login access to accounts, two methods exist. The first is to lock the account, this example shows how to lock the `imani` account: [source,shell] .... # pw lock imani .... The second method is to prevent login access by changing the shell to [.filename]#/usr/sbin/nologin#. The man:nologin[8] shell prevents the system from assigning a shell to the user when they attempt to login. Only the superuser can change the shell for other users: [source,shell] .... # chsh -s /usr/sbin/nologin imani .... [[security-passwords]] === Password Hashes Passwords are a necessary evil of technology. When they must be used, they should be complex and a powerful hash mechanism should be used to encrypt the version that is stored in the password database. FreeBSD supports several algorithms, including SHA256, SHA512 and Blowfish hash algorithms in its `crypt()` library, see man:crypt[3] for details. The default of SHA512 should not be changed to a less secure hashing algorithm, but can be changed to the more secure Blowfish algorithm. [NOTE] ==== Blowfish is not part of AES and is not considered compliant with any Federal Information Processing Standards (FIPS). Its use may not be permitted in some environments. ==== To determine which hash algorithm is used to encrypt a user's password, the superuser can view the hash for the user in the FreeBSD password database. Each hash starts with a symbol which indicates the type of hash mechanism used to encrypt the password. If DES is used, there is no beginning symbol. For MD5, the symbol is `$`. For SHA256 and SHA512, the symbol is `$6$`. For Blowfish, the symbol is `$2a$`. In this example, the password for `imani` is hashed using the default SHA512 algorithm as the hash starts with `$6$`. Note that the encrypted hash, not the password itself, is stored in the password database: [source,shell] .... # grep imani /etc/master.passwd .... The output should be similar to the following: [.programlisting] .... imani:$6$pzIjSvCAn.PBYQBA$PXpSeWPx3g5kscj3IMiM7tUEUSPmGexxta.8Lt9TGSi2lNQqYGKszsBPuGME0:1001:1001::0:0:imani:/usr/home/imani:/bin/sh .... The hash mechanism is set in the user's login class. The following command can be run to check which hash mechanism is currently being used: [source,shell] .... # grep user /etc/master.passwd .... The output should be similar to the following: [.programlisting] .... :passwd_format=sha512:\ .... For example, to change the algorithm to Blowfish, modify that line to look like this: [.programlisting] .... :passwd_format=blf:\ .... Then, man:cap_mkdb[1] must be executed to upgrade the login.conf database: [source,shell] .... # cap_mkdb /etc/login.conf .... Note that this change will not affect any existing password hashes. This means that all passwords should be re-hashed by asking users to run `passwd` in order to change their password. [[security-pwpolicy]] === Password Policy Enforcement Enforcing a strong password policy for local accounts is a fundamental aspect of system security. In FreeBSD, password length, password strength, and password complexity can be implemented using built-in Pluggable Authentication Modules (PAM). This section demonstrates how to configure the minimum and maximum password length and the enforcement of mixed characters using the man:pam_passwdqc[8] module. This module is enforced when a user changes their password. To configure this module, become the superuser and uncomment the line containing `pam_passwdqc.so` in [.filename]#/etc/pam.d/passwd#. Then, edit that line to match the password policy: [.programlisting] .... password requisite pam_passwdqc.so min=disabled,disabled,disabled,12,10 similar=deny retry=3 enforce=users .... The explanation of the parameters can be found in man:pam_passwdqc[8]. Once this file is saved, a user changing their password will see a message similar to the following: [source,shell] .... % passwd .... The output should be similar to the following: [.programlisting] .... Changing local password for user Old Password: You can now choose the new password. A valid password should be a mix of upper and lower case letters, digits and other characters. You can use a 12 character long password with characters from at least 3 of these 4 classes, or a 10 character long password containing characters from all the classes. Characters that form a common pattern are discarded by the check. Alternatively, if no one else can see your terminal now, you can pick this as your password: "trait-useful&knob". Enter new password: .... If a password that does not match the policy is entered, it will be rejected with a warning and the user will have an opportunity to try again, up to the configured number of retries. If your organization's policy requires passwords to expire, FreeBSD supports the `passwordtime` in the user's login class in [.filename]#/etc/login.conf# The `default` login class contains an example: [.programlisting] .... # :passwordtime=90d:\ .... So, to set an expiry of 90 days for this login class, remove the comment symbol (#), save the edit, and execute the following command: [source,shell] .... # cap_mkdb /etc/login.conf .... To set the expiration on individual users, pass an expiration date or the number of days to expiry and a username to `pw`: [source,shell] .... # pw usermod -p 30-apr-2025 -n user .... As seen here, an expiration date is set in the form of day, month, and year. For more information, see man:pw[8]. [[security-sudo]] === Shared Administration with sudo System administrators often need the ability to grant enhanced permissions to users so they may perform privileged tasks. The idea that team members are provided access to a FreeBSD system to perform their specific tasks opens up unique challenges to every administrator. These team members only need a subset of access beyond normal end user levels; however, they almost always tell management they are unable to perform their tasks without superuser access. Thankfully, there is no reason to provide such access to end users because tools exist to manage this exact requirement. [TIP] ==== Even administrators should limit their privileges when not needed. ==== Up to this point, the security chapter has covered permitting access to authorized users and attempting to prevent unauthorized access. Another problem arises once authorized users have access to the system resources. In many cases, some users may need access to application startup scripts, or a team of administrators need to maintain the system. Traditionally, the standard users and groups, file permissions, and even the man:su[1] command would manage this access. And as applications required more access, as more users needed to use system resources, a better solution was required. The most used application is currently Sudo. Sudo allows administrators to configure more rigid access to system commands and provide for some advanced logging features. As a tool, it is available from the Ports Collection as package:security/sudo[] or by use of the man:pkg[8] utility. Execute the following command to install it: [source,shell] .... # pkg install sudo .... After the installation is complete, the installed `visudo` will open the configuration file with a text editor. Using `visudo` is highly recommended as it comes with a built in syntax checker to verify there are no errors before the file is saved. The configuration file is made up of several small sections which allow for extensive configuration. In the following example, web application maintainer, user1, needs to start, stop, and restart the web application known as _webservice_. To grant this user permission to perform these tasks, add this line to the end of [.filename]#/usr/local/etc/sudoers#: [.programlisting] .... user1 ALL=(ALL) /usr/sbin/service webservice * .... The user may now start _webservice_ using this command: [source,shell] .... % sudo /usr/sbin/service webservice start .... While this configuration allows a single user access to the webservice service; however, in most organizations, there is an entire web team in charge of managing the service. A single line can also give access to an entire group. These steps will create a web group, add a user to this group, and allow all members of the group to manage the service: [source,shell] .... # pw groupadd -g 6001 -n webteam .... Using the same man:pw[8] command, the user is added to the webteam group: [source,shell] .... # pw groupmod -m user1 -n webteam .... Finally, this line in [.filename]#/usr/local/etc/sudoers# allows any member of the webteam group to manage _webservice_: [.programlisting] .... %webteam ALL=(ALL) /usr/sbin/service webservice * .... Unlike man:su[1], man:sudo[8] only requires the end user password. This avoids sharing passwords, which is a poor practice. Users permitted to run applications with man:sudo[8] only enter their own passwords. This is more secure and gives better control than man:su[1], where the `root` password is entered and the user acquires all `root` permissions. [TIP] ==== Most organizations are moving or have moved toward a two factor authentication model. In these cases, the user may not have a password to enter. man:sudo[8] can be configured to permit two factor authentication model by using the `NOPASSWD` variable. Adding it to the configuration above will allow all members of the _webteam_ group to manage the service without the password requirement: [.programlisting] .... %webteam ALL=(ALL) NOPASSWD: /usr/sbin/service webservice * .... ==== [[security-doas]] === Shared Administration with Doas man:doas[1] is a command-line utility ported from OpenBSD. It serves as an alternative to the widely used man:sudo[8] command in Unix-like systems. With doas, users can execute commands with elevated privileges, typically as the root user, while maintaining a simplified and security-conscious approach. Unlike man:sudo[8], doas emphasizes simplicity and minimalism, focusing on streamlined privilege delegation without an overwhelming array of configuration options. Execute the following command to install it: [source,shell] .... # pkg install doas .... After the installation [.filename]#/usr/local/etc/doas.conf# must be configured to grant access for users for specific commands, or roles. The simplest entry could be the following, which grants the user `local_user` with `root` permissions without asking for its password when executing the doas command. [.programlisting] .... permit nopass local_user as root .... After the installation and configuration of the `doas` utility, a command can now be executed with enhanced privileges, for example: [source,shell] .... $ doas vi /etc/rc.conf .... For more configuration examples, please read man:doas.conf[5]. [[security-ids]] == Intrusion Detection System (IDS) Verification of system files and binaries is important because it provides the system administration and security teams information about system changes. A software application that monitors the system for changes is called an Intrusion Detection System (IDS). FreeBSD provides native support for a basic IDS system called man:mtree[8]. While the nightly security emails will notify an administrator of changes, the information is stored locally and there is a chance that a malicious user could modify this information in order to hide their changes to the system. As such, it is recommended to create a separate set of binary signatures and store them on a read-only, root-owned directory or, preferably, on a removable USB disk or remote server. It is also recommended to run `freebsd-update IDS` after each update. [[security-ids-generate-spec-file]] === Generating the Specification File The built-in man:mtree[8] utility can be used to generate a specification of the contents of a directory. A seed, or a numeric constant, is used to generate the specification and is required to check that the specification has not changed. This makes it possible to determine if a file or binary has been modified. Since the seed value is unknown by an attacker, faking or checking the checksum values of files will be difficult to impossible. [TIP] ==== It is recommended to create specifications for the directories which contain binaries and configuration files, as well as any directories containing sensitive data. Typically, specifications are created for [.filename]#/bin#, [.filename]#/sbin#, [.filename]#/usr/bin#, [.filename]#/usr/sbin#, [.filename]#/usr/local/bin#, [.filename]#/etc#, and [.filename]#/usr/local/etc#. ==== The following example generates a set of `sha512` hashes, one for each system binary in [.filename]#/bin#, and saves those values to a hidden file in user's home directory, [.filename]#/home/user/.bin_chksum_mtree#: [source,shell] .... # mtree -s 123456789 -c -K cksum,sha512 -p /bin > /home/user/.bin_chksum_mtree .... The output should be similar to the following: [.programlisting] .... mtree: /bin checksum: 3427012225 .... [WARNING] ==== The `123456789` value represents the seed, and should be chosen randomly. This value should be remembered, *but not shared*. It is important to keep the seed value and the checksum output hidden from malicious users. ==== [[security-ids-spec-file-structure]] === The Specification File Structure The mtree format is a textual format that describes a collection of filesystem objects. Such files are typically used to create or verify directory hierarchies. An mtree file consists of a series of lines, each providing information about a single filesystem object. Leading whitespace is always ignored. The specification file created above will be used to explain the format and content: [.programlisting] .... # user: root <.> # machine: machinename <.> # tree: /bin <.> # date: Thu Aug 24 21:58:37 2023 <.> # . /set type=file uid=0 gid=0 mode=0555 nlink=1 flags=uarch <.> . type=dir mode=0755 nlink=2 time=1681388848.239523000 <.> \133 nlink=2 size=12520 time=1685991378.688509000 \ cksum=520880818 \ sha512=5c1374ce0e2ba1b3bc5a41b23f4bbdc1ec89ae82fa01237f376a5eeef41822e68f1d8f75ec46b7bceb65396c122a9d837d692740fdebdcc376a05275adbd3471 cat size=14600 time=1685991378.694601000 cksum=3672531848 \ <.> sha512=b30b96d155fdc4795432b523989a6581d71cdf69ba5f0ccb45d9b9e354b55a665899b16aee21982fffe20c4680d11da4e3ed9611232a775c69f926e5385d53a2 chflags size=8920 time=1685991378.700385000 cksum=1629328991 \ sha512=289a088cbbcbeb436dd9c1f74521a89b66643976abda696b99b9cc1fbfe8b76107c5b54d4a6a9b65332386ada73fc1bbb10e43c4e3065fa2161e7be269eaf86a chio size=20720 time=1685991378.706095000 cksum=1948751604 \ sha512=46f58277ff16c3495ea51e74129c73617f31351e250315c2b878a88708c2b8a7bb060e2dc8ff92f606450dbc7dd2816da4853e465ec61ee411723e8bf52709ee chmod size=9616 time=1685991378.712546000 cksum=4244658911 \ sha512=1769313ce08cba84ecdc2b9c07ef86d2b70a4206420dd71343867be7ab59659956f6f5a458c64e2531a1c736277a8e419c633a31a8d3c7ccc43e99dd4d71d630 .... <.> User who created the specification. <.> Machine's hostname. <.> Directory path. <.> The Date and time when the specification was created. <.> `/set` special commands, defines some settings obtained from the files analyzed. <.> Refers to the parsed directory and indicates things like what type it is, its mode, the number of hard links, and the time in UNIX format since it was modified. <.> Refers to the file and shows the size, time and a list of hashes to verify the integrity. [[security-ids-verify-specification-file]] === Verify the Specification file To verify that the binary signatures have not changed, compare the current contents of the directory to the previously generated specification, and save the results to a file. This command requires the seed that was used to generate the original specification: [source,shell] .... # mtree -s 123456789 -p /bin < /home/user/.bin_chksum_mtree >> /home/user/.bin_chksum_output .... This should produce the same checksum for [.filename]#/bin# that was produced when the specification was created. If no changes have occurred to the binaries in this directory, the [.filename]#/home/user/.bin_chksum_output# output file will be empty. To simulate a change, change the date on [.filename]#/bin/cat# using man:touch[1] and run the verification command again: [source,shell] .... # touch /bin/cat .... Run the verification command again: [source,shell] .... # mtree -s 123456789 -p /bin < /home/user/.bin_chksum_mtree >> /home/user/.bin_chksum_output .... And then check the content of the output file: [source,shell] .... # cat /root/.bin_chksum_output .... The output should be similar to the following: [.programlisting] .... cat: modification time (Fri Aug 25 13:30:17 2023, Fri Aug 25 13:34:20 2023) .... [WARNING] ==== This is just an example of what would be displayed when executing the command, to show the changes that would occur in the metadata. ==== [[security-secure-levels]] == Secure levels securelevel is a security mechanism implemented in the kernel. When the securelevel is positive, the kernel restricts certain tasks; not even the superuser (root) is allowed to do them. The securelevel mechanism limits the ability to: * Unset certain file flags, such as `schg` (the system immutable flag). * Write to kernel memory via [.filename]#/dev/mem# and [.filename]#/dev/kmem#. * Load kernel modules. * Alter firewall rules. [[security-secure-levels-definitions]] === Secure Levels Definitions The kernel runs with five different security levels. Any super-user process can raise the level, but no process can lower it. The security definitions are: -1:: *Permanently insecure mode* - always run the system in insecure mode. This is the default initial value. 0:: *Insecure mode* - immutable and append-only flags may be turned off. All devices may be read or written subject to their permissions. 1:: *Secure mode* - the system immutable and system append-only flags may not be turned off; disks for mounted file systems, [.filename]#/dev/mem# and [.filename]#/dev/kmem# may not be opened for writing; [.filename]#/dev/io# (if your platform has it) may not be opened at all; kernel modules (see man:kld[4]) may not be loaded or unloaded. The kernel debugger may not be entered using the debug.kdb.enter sysctl. A panic or trap cannot be forced using the debug.kdb.panic, debug.kdb.panic_str and other sysctl's. 2:: *Highly secure mode* - same as secure mode, plus disks may not be opened for writing (except by man:mount[2]) whether mounted or not. This level precludes tampering with file systems by unmounting them, but also inhibits running man:newfs[8] while the system is multiuser. 3:: *Network secure mode* - same as highly secure mode, plus IP packet filter rules (see man:ipfw[8], man:ipfirewall[4] and man:pfctl[8]) cannot be changed and man:dummynet[4] or man:pf[4] configuration cannot be adjusted. [TIP] ==== In summary, the key difference between `Permanently Insecure Mode` and `Insecure Mode` in FreeBSD secure levels is the degree of security they provide. `Permanently Insecure Mode` completely lifts all security restrictions, while `Insecure Mode` relaxes some restrictions but still maintains a level of control and security. ==== [[security-modify-secure-levels]] === Modify Secure Levels In order to change the securelevel of the system it is necessary to activate `kern_securelevel_enable` by executing the following command: [source,shell] .... # sysrc kern_securelevel_enable="YES" .... And set the value of `kern_securelevel` to the desired security level: [source,shell] .... # sysrc kern_securelevel=2 .... To check the status of the securelevel on a running system execute the following command: [source,shell] .... # sysctl -n kern.securelevel .... The output contains the current value of the securelevel. If it is greater than 0, at least some of the securelevel's protections are enabled. [[security-file-flags]] == File flags File flags allow users to attach additional metadata or attributes to files and directories beyond basic permissions and ownership. These flags provide a way to control various behaviors and properties of files without needing to resort to creating special directories or using extended attributes. File flags can be used to achieve different goals, such as preventing file deletion, making files append-only, synchronizing file updates, and more. Some commonly used file flags in FreeBSD include the "immutable" flag, which prevents modification or deletion of a file, and the "append-only" flag, which allows only data to be added to the end of a file but not modified or removed. These flags can be managed using the man:chflags[1] command in FreeBSD, providing administrators and users with greater control over the behavior and characteristics of their files and directories. It is important to note that file flags are typically managed by root or users with appropriate privileges, as they can influence how files are accessed and manipulated. Some flags are available for the use of the file's owner, as described in man:chflags[1]. [[security-work-file-flag]] === Work with File Flags In this example, a file named [.filename]#~/important.txt# in user's home directory want to be protected against deletions. Execute the following command to set the `schg` file flag: [source,shell] .... # chflags schg ~/important.txt .... When any user, including the `root` user, tries to delete the file, the system will display the message: [.programlisting] .... rm: important.txt: Operation not permitted .... To delete the file, it will be necessary to delete the file flags of that file by executing the following command: [source,shell] .... # chflags noschg ~/important.txt .... A list of supported file flags and their functionality can be found in man:chflags[1]. [[openssh]] == OpenSSH OpenSSH is a set of network connectivity tools used to provide secure access to remote machines. Additionally, TCP/IP connections can be tunneled or forwarded securely through SSH connections. OpenSSH encrypts all traffic to eliminate eavesdropping, connection hijacking, and other network-level attacks. OpenSSH is maintained by the OpenBSD project and is installed by default in FreeBSD. When data is sent over the network in an unencrypted form, network sniffers anywhere in between the client and server can steal user/password information or data transferred during the session. OpenSSH offers a variety of authentication and encryption methods to prevent this from happening. More information about OpenSSH is available in the link:https://www.openssh.com/[web page]. This section provides an overview of the built-in client utilities to securely access other systems and securely transfer files from a FreeBSD system. It then describes how to configure a SSH server on a FreeBSD system. [TIP] ==== As stated, this chapter will cover the base system version of OpenSSH. A version of OpenSSH is also available in the package:security/openssh-portable[], which provides additional configuration options and is updated with new features more regularly. ==== === Using the SSH Client Utilities To log into a SSH server, use man:ssh[1] and specify a username that exists on that server and the IP address or hostname of the server. If this is the first time a connection has been made to the specified server, the user will be prompted to first verify the server's fingerprint: [source,shell] .... # ssh user@example.com .... The output should be similar to the following: [.programlisting] .... The authenticity of host 'example.com (10.0.0.1)' can't be established. ECDSA key fingerprint is 25:cc:73:b5:b3:96:75:3d:56:19:49:d2:5c:1f:91:3b. Are you sure you want to continue connecting (yes/no)? yes Permanently added 'example.com' (ECDSA) to the list of known hosts. Password for user@example.com: user_password .... SSH utilizes a key fingerprint system to verify the authenticity of the server when the client connects. When the user accepts the key's fingerprint by typing `yes` when connecting for the first time, a copy of the key is saved to [.filename]#~/.ssh/known_hosts# in the user's home directory. Future attempts to login are verified against the saved key and man:ssh[1] will display an alert if the server's key does not match the saved key. If this occurs, the user should first verify why the key has changed before continuing with the connection. [NOTE] ==== How to perform this check is outside the scope of this chapter. ==== Use man:scp[1] to securely copy a file to or from a remote machine. This example copies `COPYRIGHT` on the remote system to a file of the same name in the current directory of the local system: [source,shell] .... # scp user@example.com:/COPYRIGHT COPYRIGHT .... The output should be similar to the following: [.programlisting] .... Password for user@example.com: ******* COPYRIGHT 100% |*****************************| 4735 .... Since the fingerprint was already verified for this host, the server's key is automatically checked before prompting for the user's password. The arguments passed to man:scp[1] are similar to man:cp[1]. The file or files to copy is the first argument and the destination to copy to is the second. Since the file is fetched over the network, one or more of the file arguments takes the form `user@host:`. Be aware when copying directories recursively that man:scp[1] uses `-r`, whereas man:cp[1] uses `-R`. To open an interactive session for copying files, use man:sftp[1]. Refer to man:sftp[1] for a list of available commands while in an man:sftp[1] session. [[security-ssh-keygen]] === Key-based Authentication Instead of using passwords, a client can be configured to connect to the remote machine using keys. For security reasons, this is the preferred method. man:ssh-keygen[1] can be used to generate the authentication keys. To generate a public and private key pair, specify the type of key and follow the prompts. It is recommended to protect the keys with a memorable, but hard to guess passphrase. [source,shell] .... % ssh-keygen -t rsa -b 4096 .... The output should be similar to the following: [.programlisting] .... Generating public/private rsa key pair. Enter file in which to save the key (/home/user/.ssh/id_rsa): Created directory '/home/user/.ssh/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/user/.ssh/id_rsa. Your public key has been saved in /home/user/.ssh/id_rsa.pub. The key fingerprint is: SHA256:54Xm9Uvtv6H4NOo6yjP/YCfODryvUU7yWHzMqeXwhq8 user@host.example.com The key's randomart image is: +---[RSA 2048]----+ | | | | | | | . o.. | | .S*+*o | | . O=Oo . . | | = Oo= oo..| | .oB.* +.oo.| | =OE**.o..=| +----[SHA256]-----+ .... The private key is stored in [.filename]#~/.ssh/id_rsa# and the public key is stored in [.filename]#~/.ssh/id_rsa.pub#. The _public_ key must be copied to [.filename]#~/.ssh/authorized_keys# on the remote machine for key-based authentication to work. [WARNING] ==== Utilizing a passphrase for OpenSSH keys is a key security practice, providing an extra layer of protection against unauthorized access and enhancing overall cybersecurity. In case of loss or theft, this adds another layer of security. ==== [[security-ssh-tunneling]] === SSH Tunneling OpenSSH has the ability to create a tunnel to encapsulate another protocol in an encrypted session. The following command tells man:ssh[1] to create a tunnel: [source,shell] .... % ssh -D 8080 user@example.com .... This example uses the following options: -D:: Specifies a local "dynamic" application-level port forwarding. user@foo.example.com:: The login name to use on the specified remote SSH server. An SSH tunnel works by creating a listen socket on `localhost` on the specified `localport`. This method can be used to wrap any number of insecure TCP protocols such as SMTP, POP3, and FTP. === Enabling the SSH Server In addition to providing built-in SSH client utilities, a FreeBSD system can be configured as an SSH server, accepting connections from other SSH clients. [TIP] ==== As stated, this chapter will cover the base system version of OpenSSH. Please *not* confuse with package:security/openssh-portable[], the version of OpenSSH that ships with the FreeBSD ports. ==== In order to have the SSH Server enabled across reboots execute the following command: [source,shell] .... # sysrc sshd_enable="YES" .... Then execute the following command to enable the service: [source,shell] .... # service sshd start .... The first time sshd starts on a FreeBSD system, the system's host keys will be automatically created and the fingerprint will be displayed on the console. Provide users with the fingerprint so that they can verify it the first time they connect to the server. Refer to man:sshd[8] for the list of available options when starting sshd and a complete discussion about authentication, the login process, and the various configuration files. At this point, the sshd should be available to all users with a username and password on the system. [[config-publickey-auth]] === Configuring publickey auth method Configuring OpenSSH to use public key authentication enhances security by leveraging asymmetric cryptography for authentication. This method eliminates password-related risks, such as weak passwords or interception during transmission, while thwarting various password-based attacks. However, it's vital to ensure the private keys are well-protected to prevent unauthorized access. The first step will be to configure man:sshd[8] to use the required authentication method. Edit [.filename]#/etc/ssh/sshd_config# and uncomment the following configuration: [.programlisting] .... PubkeyAuthentication yes .... Once the configuration is done, the users will have to send the system administrator their *public key* and these keys will be added in [.filename]#.ssh/authorized_keys#. The process for generating the keys is described in crossref:security[Key-based Authentication]. Then restart the server executing the following command: [source,shell] .... # service sshd reload .... It is strongly recommended to follow the security improvements indicated in -crossref:security[security-sshd-security-options]. +crossref:security[security-sshd-security-options, SSH Server Security Options]. [[security-sshd-security-options]] === SSH Server Security Options While sshd is the most widely used remote administration facility for FreeBSD, brute force and drive by attacks are common to any system exposed to public networks. Several additional parameters are available to prevent the success of these attacks and will be described in this section. All configurations will be done in [.filename]#/etc/ssh/sshd_config# [TIP] ==== Do not confuse [.filename]#/etc/ssh/sshd_config# with [.filename]#/etc/ssh/ssh_config# (note the extra `d` in the first filename). The first file configures the server and the second file configures the client. Refer to man:ssh_config[5] for a listing of the available client settings. ==== By default, authentication can be done with both pubkey and password. To allow *only* pubkey authentication, *which is strongly recommended*, change the variable: [.programlisting] .... PasswordAuthentication no .... It is a good idea to limit which users can log into the SSH server and from where using the `AllowUsers` keyword in the OpenSSH server configuration file. For example, to only allow `user` to log in from `192.168.1.32`, add this line to [.filename]#/etc/ssh/sshd_config#: [.programlisting] .... AllowUsers user@192.168.1.32 .... To allow `user` to log in from anywhere, list that user without specifying an IP address: [.programlisting] .... AllowUsers user .... Multiple users should be listed on the same line, like so: [.programlisting] .... AllowUsers root@192.168.1.32 user .... After making all the changes, and before restarting the service, it is recommended to verify that the configuration made is correct by executing the following command: [source,shell] .... # sshd -t .... If the configuration file is correct, no output will be shown. In case the configuration file is incorrect, it will show something like this: [.programlisting] .... /etc/ssh/sshd_config: line 3: Bad configuration option: sdadasdasdasads /etc/ssh/sshd_config: terminating, 1 bad configuration options .... After making the changes and checking that the configuration file is correct, tell sshd to reload its configuration file by running: [source,shell] .... # service sshd reload .... [[openssl]] == OpenSSL OpenSSL is a cryptography toolkit implementing the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) network protocols and many cryptography routines. The openssl program is a command line tool for using the various cryptography functions of OpenSSL's crypto library from the shell. It can be used for * Creation and management of private keys, public keys and parameters * Public key cryptographic operations * Creation of X.509 certificates, CSRs and CRLs * Calculation of Message Digests * Encryption and Decryption with Ciphers * SSL/TLS Client and Server Tests * Handling of S/MIME signed or encrypted mail * Time Stamp requests, generation and verification * Benchmarking the crypto routines For more information about OpenSSL, read the free https://www.feistyduck.com/books/openssl-cookbook/[OpenSSL Cookbook]. [[generating-certificates]] === Generating Certificates OpenSSL supports the generation of certificates both to be validated by a link:https://en.wikipedia.org/wiki/Certificate_authority[CA] and for own use. Run the command man:openssl[1] to generate a valid certificate for a link:https://en.wikipedia.org/wiki/Certificate_authority[CA] with the following arguments. This command will create two files in the current directory. The certificate request, [.filename]#req.pem#, can be sent to a link:https://en.wikipedia.org/wiki/Certificate_authority[CA] which, will validate the entered credentials, sign the request, and return the signed certificate. The second file, [.filename]#cert.key#, is the private key for the certificate and should be stored in a secure location. If this falls in the hands of others, it can be used to impersonate the user or the server. Execute the following command to generate the certificate: [source,shell] .... # openssl req -new -nodes -out req.pem -keyout cert.key -sha3-512 -newkey rsa:4096 .... The output should be similar to the following: [.programlisting] .... Generating a RSA private key ..................................................................................................................................+++++ ......................................+++++ writing new private key to 'cert.key' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:ES State or Province Name (full name) [Some-State]:Valencian Community Locality Name (eg, city) []:Valencia Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Organizational Unit Name (eg, section) []:Systems Administrator Common Name (e.g. server FQDN or YOUR name) []:localhost.example.org Email Address []:user@FreeBSD.org Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:123456789 An optional company name []:Another name .... Alternately, if a signature from a link:https://en.wikipedia.org/wiki/Certificate_authority[CA] is not required, a self-signed certificate can be created. This will create two new files in the current directory: a private key file [.filename]#cert.key#, and the certificate itself, [.filename]#cert.crt#. These should be placed in a directory, preferably under [.filename]#/etc/ssl/#, which is readable only by `root`. Permissions of `0700` are appropriate for these files and can be set using `chmod`. Execute the following command to generate the certificate: [source,shell] .... # openssl req -new -x509 -days 365 -sha3-512 -keyout /etc/ssl/private/cert.key -out /etc/ssl/certs/cert.crt .... The output should be similar to the following: [.programlisting] .... Generating a RSA private key ........................................+++++ ...........+++++ writing new private key to '/etc/ssl/private/cert.key' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:ES State or Province Name (full name) [Some-State]:Valencian Community Locality Name (eg, city) []:Valencia Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Organizational Unit Name (eg, section) []:Systems Administrator Common Name (e.g. server FQDN or YOUR name) []:localhost.example.org Email Address []:user@FreeBSD.org .... [[fips-provider]] === Configuring the FIPS Provider With the import of OpenSSL 3 into the base system (on FreeBSD 14 and later), its new concept of provider modules was introduced in the system. Besides the default provider module built-in to the library, the _legacy_ module implements the now optional deprecated cryptography algorithms, while the _fips_ module restricts the OpenSSL implementation to the cryptography algorithms present in the link:https://en.wikipedia.org/wiki/Federal_Information_Processing_Standards[FIPS] set of standards. This part of OpenSSL receives link:https://www.openssl.org/docs/fips.html[particular care], including a link:https://www.openssl.org/news/fips-cve.html[list of relevant security issues], and is subject to the link:https://github.com/openssl/openssl/blob/master/README-FIPS.md[FIPS 140 validation process] on a regular basis. The link:https://www.openssl.org/source/[list of FIPS validated versions] is also available. This allows users to ensure FIPS compliance in their use of OpenSSL. Importantly, the man:fips_module[7] is protected by an additional security measure, preventing its use without passing an integrity check. This check can be setup by the local system administrator, allowing every user of OpenSSL 3 to load this module. When not configured correctly, the FIPS module is expected to fail as follows: [source,shell] .... # echo test | openssl aes-128-cbc -a -provider fips -pbkdf2 .... The output should be similar to the following: [.programlisting] .... aes-128-cbc: unable to load provider fips Hint: use -provider-path option or OPENSSL_MODULES environment variable. 00206124D94D0000:error:1C8000D5:Provider routines:SELF_TEST_post:missing config data:crypto/openssl/providers/fips/self_test.c:275: 00206124D94D0000:error:1C8000E0:Provider routines:ossl_set_error_state:fips module entering error state:crypto/openssl/providers/fips/self_test.c:373: 00206124D94D0000:error:1C8000D8:Provider routines:OSSL_provider_init_int:self test post failure:crypto/openssl/providers/fips/fipsprov.c:707: 00206124D94D0000:error:078C0105:common libcrypto routines:provider_init:init fail:crypto/openssl/crypto/provider_core.c:932:name=fips .... The check can be configured through the creation of a file in [.filename]#/etc/ssl/fipsmodule.cnf#, which will then be referenced in OpenSSL's main configuration file [.filename]#/etc/ssl/openssl.cnf#. OpenSSL provides the man:openssl-fipsinstall[1] utility to help with this process, which can be used as follows: [source,shell] .... # openssl fipsinstall -module /usr/lib/ossl-modules/fips.so -out /etc/ssl/fipsmodule.cnf .... The output should be similar to the following: [.programlisting] .... INSTALL PASSED .... The [.filename]#/etc/ssl/openssl.cnf# should then be modified, in order to: * Include the [.filename]#/etc/ssl/fipsmodule.cnf# file generated above, * Expose the FIPS module for possible use, * And explicitly activate the default module. [.programlisting] .... [...] # For FIPS # Optionally include a file that is generated by the OpenSSL fipsinstall # application. This file contains configuration data required by the OpenSSL # fips provider. It contains a named section e.g. [fips_sect] which is # referenced from the [provider_sect] below. # Refer to the OpenSSL security policy for more information. .include /etc/ssl/fipsmodule.cnf [...] # List of providers to load [provider_sect] default = default_sect # The fips section name should match the section name inside the # included fipsmodule.cnf. fips = fips_sect # If no providers are activated explicitly, the default one is activated implicitly. # See man 7 OSSL_PROVIDER-default for more details. # # If you add a section explicitly activating any other provider(s), you most # probably need to explicitly activate the default provider, otherwise it # becomes unavailable in openssl. As a consequence applications depending on # OpenSSL may not work correctly which could lead to significant system # problems including inability to remotely access the system. [default_sect] activate = 1 .... With this done, it should be possible to confirm that the FIPS module is effectively available and working: [source,shell] .... # echo test | openssl aes-128-cbc -a -provider fips -pbkdf2 .... The output should be similar to the following: [.programlisting] .... enter AES-128-CBC encryption password: Verifying - enter AES-128-CBC encryption password: U2FsdGVkX18idooW6e3LqWeeiKP76kufcOUClh57j8U= .... This procedure has to be repeated every time the FIPS module is modified, e.g., after performing system updates, or after applying security fixes affecting OpenSSL in the base system. [[kerberos5]] == Kerberos Kerberos is a network authentication protocol which was originally created by the Massachusetts Institute of Technology (MIT) as a way to securely provide authentication across a potentially hostile network. The Kerberos protocol uses strong cryptography so that both a client and server can prove their identity without sending any unencrypted secrets over the network. Kerberos can be described as an identity-verifying proxy system and as a trusted third-party authentication system. After a user authenticates with Kerberos, their communications can be encrypted to assure privacy and data integrity. The only function of Kerberos is to provide the secure authentication of users and servers on the network. It does not provide authorization or auditing functions. It is recommended that Kerberos be used with other security methods which provide authorization and audit services. The current version of the protocol is version 5, described in RFC 4120. Several free implementations of this protocol are available, covering a wide range of operating systems. MIT continues to develop their Kerberos package. It is commonly used in the US as a cryptography product, and has historically been subject to US export regulations. In FreeBSD, MITKerberos is available as the package:security/krb5[] package or port. The Heimdal Kerberos implementation was explicitly developed outside of the US to avoid export regulations. The Heimdal Kerberos distribution is included in the base FreeBSD installation, and another distribution with more configurable options is available as package:security/heimdal[] in the Ports Collection. In Kerberos users and services are identified as "principals" which are contained within an administrative grouping, called a "realm". A typical user principal would be of the form `_user_@_REALM_` (realms are traditionally uppercase). This section provides a guide on how to set up Kerberos using the Heimdal distribution included in FreeBSD. For purposes of demonstrating a Kerberos installation, the name spaces will be as follows: * The DNS domain (zone) will be `example.org`. * The Kerberos realm will be `EXAMPLE.ORG`. [NOTE] ==== Use real domain names when setting up Kerberos, even if it will run internally. This avoids DNS problems and assures inter-operation with other Kerberos realms. ==== === Setting up a Heimdal KDC The Key Distribution Center (KDC) is the centralized authentication service that Kerberos provides, the "trusted third party" of the system. It is the computer that issues Kerberos tickets, which are used for clients to authenticate to servers. As the KDC is considered trusted by all other computers in the Kerberos realm, it has heightened security concerns. Direct access to the KDC should be limited. While running a KDC requires few computing resources, a dedicated machine acting only as a KDC is recommended for security reasons. To begin, install the package:security/heimdal[] package as follows: [source,shell] .... # pkg install heimdal .... Next, update [.filename]#/etc/rc.conf# using `sysrc` as follows: [source,shell] .... # sysrc kdc_enable=yes # sysrc kadmind_enable=yes .... Next, edit [.filename]#/etc/krb5.conf# as follows: [.programlisting] .... [libdefaults] default_realm = EXAMPLE.ORG [realms] EXAMPLE.ORG = { kdc = kerberos.example.org admin_server = kerberos.example.org } [domain_realm] .example.org = EXAMPLE.ORG .... In this example, the KDC will use the fully-qualified hostname `kerberos.example.org`. The hostname of the KDC must be resolvable in the DNS. Kerberos can also use the DNS to locate KDCs, instead of a `[realms]` section in [.filename]#/etc/krb5.conf#. For large organizations that have their own DNS servers, the above example could be trimmed to: [.programlisting] .... [libdefaults] default_realm = EXAMPLE.ORG [domain_realm] .example.org = EXAMPLE.ORG .... With the following lines being included in the `example.org` zone file: [.programlisting] .... _kerberos._udp IN SRV 01 00 88 kerberos.example.org. _kerberos._tcp IN SRV 01 00 88 kerberos.example.org. _kpasswd._udp IN SRV 01 00 464 kerberos.example.org. _kerberos-adm._tcp IN SRV 01 00 749 kerberos.example.org. _kerberos IN TXT EXAMPLE.ORG .... [NOTE] ==== In order for clients to be able to find the Kerberos services, they _must_ have either a fully configured [.filename]#/etc/krb5.conf# or a minimally configured [.filename]#/etc/krb5.conf# _and_ a properly configured DNS server. ==== Next, create the Kerberos database which contains the keys of all principals (users and hosts) encrypted with a master password. It is not required to remember this password as it will be stored in [.filename]#/var/heimdal/m-key#; it would be reasonable to use a 45-character random password for this purpose. To create the master key, run `kstash` and enter a password: [source,shell] .... # kstash .... The output should be similar to the following: [.programlisting] .... Master key: xxxxxxxxxxxxxxxxxxxxxxx Verifying password - Master key: xxxxxxxxxxxxxxxxxxxxxxx .... Once the master key has been created, the database should be initialized. The Kerberos administrative tool man:kadmin[8] can be used on the KDC in a mode that operates directly on the database, without using the man:kadmind[8] network service, as `kadmin -l`. This resolves the chicken-and-egg problem of trying to connect to the database before it is created. At the `kadmin` prompt, use `init` to create the realm's initial database: [source,shell] .... # kadmin -l kadmin> init EXAMPLE.ORG Realm max ticket life [unlimited]: .... Lastly, while still in `kadmin`, create the first principal using `add`. Stick to the default options for the principal for now, as these can be changed later with `modify`. Type `?` at the prompt to see the available options. [source,shell] .... kadmin> add tillman .... The output should be similar to the following: [.programlisting] .... Max ticket life [unlimited]: Max renewable life [unlimited]: Principal expiration time [never]: Password expiration time [never]: Attributes []: Password: xxxxxxxx Verifying password - Password: xxxxxxxx .... Next, start the KDC services by running: [source,shell] .... # service kdc start # service kadmind start .... While there will not be any kerberized daemons running at this point, it is possible to confirm that the KDC is functioning by obtaining a ticket for the principal that was just created: [source,shell] .... % kinit tillman .... The output should be similar to the following: [.programlisting] .... tillman@EXAMPLE.ORG's Password: .... Confirm that a ticket was successfully obtained using `klist`: [source,shell] .... % klist .... The output should be similar to the following: [.programlisting] .... Credentials cache: FILE:/tmp/krb5cc_1001 Principal: tillman@EXAMPLE.ORG Issued Expires Principal Aug 27 15:37:58 2013 Aug 28 01:37:58 2013 krbtgt/EXAMPLE.ORG@EXAMPLE.ORG .... The temporary ticket can be destroyed when the test is finished: [source,shell] .... % kdestroy .... === Configuring a Server to Use Kerberos The first step in configuring a server to use Kerberos authentication is to ensure that it has the correct configuration in [.filename]#/etc/krb5.conf#. The version from the KDC can be used as-is, or it can be regenerated on the new system. Next, create [.filename]#/etc/krb5.keytab# on the server. This is the main part of "Kerberizing" a service - it corresponds to generating a secret shared between the service and the KDC. The secret is a cryptographic key, stored in a "keytab". The keytab contains the server's host key, which allows it and the KDC to verify each others' identity. It must be transmitted to the server in a secure fashion, as the security of the server can be broken if the key is made public. Typically, the [.filename]#keytab# is generated on an administrator's trusted machine using `kadmin`, then securely transferred to the server, e.g., with man:scp[1]; it can also be created directly on the server if that is consistent with the desired security policy. It is very important that the keytab is transmitted to the server in a secure fashion: if the key is known by some other party, that party can impersonate any user to the server! Using `kadmin` on the server directly is convenient, because the entry for the host principal in the KDC database is also created using `kadmin`. Of course, `kadmin` is a kerberized service; a Kerberos ticket is needed to authenticate to the network service, but to ensure that the user running `kadmin` is actually present (and their session has not been hijacked), `kadmin` will prompt for the password to get a fresh ticket. The principal authenticating to the kadmin service must be permitted to use the `kadmin` interface, as specified in [.filename]#/var/heimdal/kadmind.acl#. See the section titled "Remote administration" in `info heimdal` for details on designing access control lists. Instead of enabling remote `kadmin` access, the administrator could securely connect to the KDC via the local console or man:ssh[1], and perform administration locally using `kadmin -l`. After installing [.filename]#/etc/krb5.conf#, use `add --random-key` in `kadmin`. This adds the server's host principal to the database, but does not extract a copy of the host principal key to a keytab. To generate the keytab, use `ext` to extract the server's host principal key to its own keytab: [source,shell] .... # kadmin .... The output should be similar to the following: [.programlisting] .... kadmin> add --random-key host/myserver.example.org Max ticket life [unlimited]: Max renewable life [unlimited]: Principal expiration time [never]: Password expiration time [never]: Attributes []: kadmin> ext_keytab host/myserver.example.org kadmin> exit .... Note that `ext_keytab` stores the extracted key in [.filename]#/etc/krb5.keytab# by default. This is good when being run on the server being kerberized, but the `--keytab _path/to/file_` argument should be used when the keytab is being extracted elsewhere: [source,shell] .... # kadmin .... The output should be similar to the following: [.programlisting] .... kadmin> ext_keytab --keytab=/tmp/example.keytab host/myserver.example.org kadmin> exit .... The keytab can then be securely copied to the server using man:scp[1] or a removable media. Be sure to specify a non-default keytab name to avoid inserting unneeded keys into the system's keytab. At this point, the server can read encrypted messages from the KDC using its shared key, stored in [.filename]#krb5.keytab#. It is now ready for the Kerberos-using services to be enabled. One of the most common such services is man:sshd[8], which supports Kerberos via the GSS-API. In [.filename]#/etc/ssh/sshd_config#, add the line: [.programlisting] .... GSSAPIAuthentication yes .... After making this change, man:sshd[8] must be restarted for the new configuration to take effect: `service sshd restart`. === Configuring a Client to Use Kerberos As it was for the server, the client requires configuration in [.filename]#/etc/krb5.conf#. Copy the file in place (securely) or re-enter it as needed. Test the client by using `kinit`, `klist`, and `kdestroy` from the client to obtain, show, and then delete a ticket for an existing principal. Kerberos applications should also be able to connect to Kerberos enabled servers. If that does not work but obtaining a ticket does, the problem is likely with the server and not with the client or the KDC. In the case of kerberized man:ssh[1], GSS-API is disabled by default, so test using `ssh -o GSSAPIAuthentication=yes _hostname_`. When testing a Kerberized application, try using a packet sniffer such as `tcpdump` to confirm that no sensitive information is sent in the clear. Various Kerberos client applications are available. With the advent of a bridge so that applications using SASL for authentication can use GSS-API mechanisms as well, large classes of client applications can use Kerberos for authentication, from Jabber clients to IMAP clients. Users within a realm typically have their Kerberos principal mapped to a local user account. Occasionally, one needs to grant access to a local user account to someone who does not have a matching Kerberos principal. For example, `tillman@EXAMPLE.ORG` may need access to the local user account `webdevelopers`. Other principals may also need access to that local account. The [.filename]#.k5login# and [.filename]#.k5users# files, placed in a user's home directory, can be used to solve this problem. For example, if the following [.filename]#.k5login# is placed in the home directory of `webdevelopers`, both principals listed will have access to that account without requiring a shared password: [.programlisting] .... tillman@example.org jdoe@example.org .... Refer to man:ksu[1] for more information about [.filename]#.k5users#. === MIT Differences The major difference between the MIT and Heimdal implementations is that `kadmin` has a different, but equivalent, set of commands and uses a different protocol. If the KDC is MIT, the Heimdal version of `kadmin` cannot be used to administer the KDC remotely, and vice versa. Client applications may also use slightly different command line options to accomplish the same tasks. Following the instructions at http://web.mit.edu/Kerberos/www/[http://web.mit.edu/Kerberos/www/] is recommended. Be careful of path issues: the MIT port installs into [.filename]#/usr/local/# by default, and the FreeBSD system applications run instead of the MIT versions if `PATH` lists the system directories first. When using MIT Kerberos as a KDC on FreeBSD, execute the following commands to add the required configurations to [.filename]#/etc/rc.conf#: [source,shell] .... # sysrc kdc_program="/usr/local/sbin/krb5kdc" # sysrc kadmind_program="/usr/local/sbin/kadmind" # sysrc kdc_flags="" # sysrc kdc_enable="YES" # sysrc kadmind_enable="YES" .... === Kerberos Tips, Tricks, and Troubleshooting When configuring and troubleshooting Kerberos, keep the following points in mind: * When using either Heimdal or MITKerberos from ports, ensure that the `PATH` lists the port's versions of the client applications before the system versions. * If all the computers in the realm do not have synchronized time settings, authentication may fail. crossref:network-servers[network-ntp,“Clock Synchronization with NTP”] describes how to synchronize clocks using NTP. * If the hostname is changed, the `host/` principal must be changed and the keytab updated. This also applies to special keytab entries like the `HTTP/` principal used for Apache's package:www/mod_auth_kerb[]. * All hosts in the realm must be both forward and reverse resolvable in DNS or, at a minimum, exist in [.filename]#/etc/hosts#. CNAMEs will work, but the A and PTR records must be correct and in place. The error message for unresolvable hosts is not intuitive: `Kerberos5 refuses authentication because Read req failed: Key table entry not found`. * Some operating systems that act as clients to the KDC do not set the permissions for `ksu` to be setuid `root`. This means that `ksu` does not work. This is a permissions problem, not a KDC error. * With MITKerberos, to allow a principal to have a ticket life longer than the default lifetime of ten hours, use `modify_principal` at the man:kadmin[8] prompt to change the `maxlife` of both the principal in question and the `krbtgt` principal. The principal can then use `kinit -l` to request a ticket with a longer lifetime. * When running a packet sniffer on the KDC to aid in troubleshooting while running `kinit` from a workstation, the Ticket Granting Ticket (TGT) is sent immediately, even before the password is typed. This is because the Kerberos server freely transmits a TGT to any unauthorized request. However, every TGT is encrypted in a key derived from the user's password. When a user types their password, it is not sent to the KDC, it is instead used to decrypt the TGT that `kinit` already obtained. If the decryption process results in a valid ticket with a valid time stamp, the user has valid Kerberos credentials. These credentials include a session key for establishing secure communications with the Kerberos server in the future, as well as the actual TGT, which is encrypted with the Kerberos server's own key. This second layer of encryption allows the Kerberos server to verify the authenticity of each TGT. * Host principals can have a longer ticket lifetime. If the user principal has a lifetime of a week but the host being connected to has a lifetime of nine hours, the user cache will have an expired host principal and the ticket cache will not work as expected. * When setting up [.filename]#krb5.dict# to prevent specific bad passwords from being used as described in man:kadmind[8], remember that it only applies to principals that have a password policy assigned to them. The format used in [.filename]#krb5.dict# is one string per line. Creating a symbolic link to [.filename]#/usr/share/dict/words# might be useful. === Mitigating Kerberos Limitations Since Kerberos is an all or nothing approach, every service enabled on the network must either be modified to work with Kerberos or be otherwise secured against network attacks. This is to prevent user credentials from being stolen and re-used. An example is when Kerberos is enabled on all remote shells but the non-Kerberized POP3 mail server sends passwords in plain text. The KDC is a single point of failure. By design, the KDC must be as secure as its master password database. The KDC should have absolutely no other services running on it and should be physically secure. The danger is high because Kerberos stores all passwords encrypted with the same master key which is stored as a file on the KDC. A compromised master key is not quite as bad as one might fear. The master key is only used to encrypt the Kerberos database and as a seed for the random number generator. As long as access to the KDC is secure, an attacker cannot do much with the master key. If the KDC is unavailable, network services are unusable as authentication cannot be performed. This can be alleviated with a single master KDC and one or more slaves, and with careful implementation of secondary or fall-back authentication using PAM. Kerberos allows users, hosts and services to authenticate between themselves. It does not have a mechanism to authenticate the KDC to the users, hosts, or services. This means that a trojaned `kinit` could record all user names and passwords. File system integrity checking tools like package:security/tripwire[] can alleviate this. === Resources and Further Information * http://www.faqs.org/faqs/Kerberos-faq/general/preamble.html[The Kerberos FAQ] * http://web.mit.edu/Kerberos/www/dialogue.html[Designing an Authentication System: a Dialog in Four Scenes] * https://www.ietf.org/rfc/rfc4120.txt[RFC 4120, The Kerberos Network Authentication Service (V5)] * http://web.mit.edu/Kerberos/www/[MIT Kerberos home page] * https://github.com/heimdal/heimdal/wiki[Heimdal Kerberos project wiki page] [[tcpwrappers]] == TCP Wrappers TCP Wrappers is a host-based network access control system. By intercepting incoming network requests before they reach the actual network service, TCP Wrappers assess whether the source IP address is permitted or denied access based on predefined rules in configuration files. However, while TCP Wrappers provide basic access control, they should not be considered a substitute for more robust security measures. For comprehensive protection, it's recommended to use advanced technologies like firewalls, along with proper user authentication practices and intrusion detection systems. [[tcpwrappers-initial-configuration]] === Initial Configuration TCP Wrappers are enabled by default in man:inetd[8]. So the first step will be to enable man:inetd[8] executing the following commands: [source,shell] .... # sysrc inetd_enable="YES" # service inetd start .... Then, properly configure [.filename]#/etc/hosts.allow#. [WARNING] ==== Unlike other implementations of TCP Wrappers, the use of [.filename]#hosts.deny# is deprecated in FreeBSD. All configuration options should be placed in [.filename]#/etc/hosts.allow#. ==== In the simplest configuration, daemon connection policies are set to either permit or block, depending on the options in [.filename]#/etc/hosts.allow#. The default configuration in FreeBSD is to allow all connections to the daemons started with inetd. Basic configuration usually takes the form of `daemon : address : action`, where `daemon` is the daemon which inetd started, `address` is a valid hostname, IP address, or an IPv6 address enclosed in brackets ([ ]), and `action` is either `allow` or `deny`. TCP Wrappers uses a first rule match semantic, meaning that the configuration file is scanned from the beginning for a matching rule. When a match is found, the rule is applied and the search process stops. For example, to allow POP3 connections via the package:mail/qpopper[] daemon, the following lines should be appended to [.filename]#/etc/hosts.allow#: [.programlisting] .... # This line is required for POP3 connections: qpopper : ALL : allow .... Whenever this file is edited, restart inetd: [source,shell] .... # service inetd restart .... [[tcpwrappers-advanced-config]] === Advanced Configuration TCP Wrappers provides advanced options to allow more control over the way connections are handled. In some cases, it may be appropriate to return a comment to certain hosts or daemon connections. In other cases, a log entry should be recorded or an email sent to the administrator. Other situations may require the use of a service for local connections only. This is all possible through the use of configuration options known as wildcards, expansion characters, and external command execution. To learn more about wildcards and their associated functionality, refer to man:hosts_access[5]. [[fs-acl]] == Access Control Lists Access Control Lists (ACLs) extend traditional UNIX(R) file permissions by allowing fine-grained access control for users and groups on a per-file or per-directory basis. Each ACL entry defines a user or group and the associated permissions, such as read, write, and execute. FreeBSD provides commands like man:getfacl[1] and man:setfacl[1] to manage ACLs. ACLs are useful in scenarios requiring more specific access control than standard permissions, commonly used in multi-user environments or shared hosting. However, complexity may be unavoidable, but careful planning is required to ensure that the desired security properties are being provided [NOTE] ==== FreeBSD supports the implementation of NFSv4 ACLs in both UFS and OpenZFS. Please note that some arguments to the man:setfacl[1] command only work with POSIX ACLs and others in NFSv4 ACLs. ==== [[acl-enabling-support-ufs]] === Enabling ACL Support in UFS ACLs are enabled by the mount-time administrative flag, `acls`, which may be added to [.filename]#/etc/fstab#. Therefore it will be necessary to access [.filename]#/etc/fstab# and in the options section add the `acls` flag as follows: [.programlisting] .... # Device Mountpoint FStype Options Dump Pass# /dev/ada0s1a / ufs rw,acls 1 1 .... [[security-acl-info]] === Get ACLs information It is possible to check the ACLs of a file or a directory using man:getfacl[1]. For example, to view the ACL settings on [.filename]#~/test# file execute the following command: [source,shell] .... % getfacl test .... The output should be similar to the following in case of using NFSv4 ACLs: [.programlisting] .... # file: test # owner: freebsduser # group: freebsduser owner@:rw-p--aARWcCos:-------:allow group@:r-----a-R-c--s:-------:allow everyone@:r-----a-R-c--s:-------:allow .... And the output should be similar to the following in case of using POSIX.1e ACLs: [.programlisting] .... # file: test # owner: freebsduser # group: freebsduser user::rw- group::r-- other::r-- .... [[security-working-acls]] === Working with ACLs man:setfacl[1] can be used to add, modify or remove ACLs from a file or directory. As noted above, some arguments to man:setfacl[1] do not work with NFSv4 ACLs, and vice versa. This section covers how to execute the commands for POSIX ACLs and for NFSv4 ACLs and shows examples of both. For example, to set the mandatory elements of the POSIX.1e default ACL: [source,shell] .... % setfacl -d -m u::rwx,g::rx,o::rx,mask::rwx directory .... This other example sets read, write, and execute permissions for the file owner's POSIX.1e ACL entry and read and write permissions for group mail on file: [source,shell] .... % setfacl -m u::rwx,g:mail:rw file .... To do the same as in the previous example but in NFSv4 ACL: [source,shell] .... % setfacl -m owner@:rwxp::allow,g:mail:rwp::allow file .... To remove all ACL entries except for the three required from file in POSIX.1e ACL: [source,shell] .... % setfacl -bn file .... To remove all ACL entries in NFSv4 ACL: [source,shell] .... % setfacl -b file .... Refer to man:getfacl[1] and man:setfacl[1] for more information about the options available for these commands. [[capsicum]] == Capsicum Capsicum is a lightweight OS capability and sandbox framework implementing a hybrid capability system model. Capabilities are unforgeable tokens of authority that can be delegated and must be presented to perform an action. Capsicum makes file descriptors into capabilities. Capsicum can be used for application and library compartmentalisation, the decomposition of larger bodies of software into isolated (sandboxed) components in order to implement security policies and limit the impact of software vulnerabilities. [[security-accounting]] == Process Accounting Process accounting is a security method in which an administrator may keep track of system resources used and their allocation among users, provide for system monitoring, and minimally track a user's commands. Process accounting has both positive and negative points. One of the positives is that an intrusion may be narrowed down to the point of entry. A negative is the amount of logs generated by process accounting, and the disk space they may require. This section walks an administrator through the basics of process accounting. [NOTE] ==== If more fine-grained accounting is needed, refer to crossref:audit[audit,Security Event Auditing]. ==== === Enabling and Utilizing Process Accounting Before using process accounting, it must be enabled using the following commands: [source,shell] .... # sysrc accounting_enable=yes # service accounting start .... The accounting information is stored in files located in [.filename]#/var/account#, which is automatically created, if necessary, the first time the accounting service starts. These files contain sensitive information, including all the commands issued by all users. Write access to the files is limited to `root`, and read access is limited to `root` and members of the `wheel` group. To also prevent members of `wheel` from reading the files, change the mode of the [.filename]#/var/account# directory to allow access only by `root`. Once enabled, accounting will begin to track information such as CPU statistics and executed commands. All accounting logs are in a non-human readable format which can be viewed using man:sa[8]. If issued without any options, man:sa[8] prints information relating to the number of per-user calls, the total elapsed time in minutes, total CPU and user time in minutes, and the average number of I/O operations. Refer to man:sa[8] for the list of available options which control the output. To display the commands issued by users, use `lastcomm`. For example, this command prints out all usage of `ls` by `trhodes` on the `ttyp1` terminal: [source,shell] .... # lastcomm ls trhodes ttyp1 .... Many other useful options exist and are explained in man:lastcomm[1], man:acct[5], and man:sa[8]. [[security-resourcelimits]] == Resource Limits In FreeBSD, resource limits refer to the mechanisms that control and manage the allocation of various system resources to processes and users. These limits are designed to prevent a single process or user from consuming an excessive amount of resources, which could lead to performance degradation or system instability. Resource limits help ensure fair resource distribution among all active processes and users on the system. FreeBSD provides several methods for an administrator to limit the amount of system resources an individual may use. The traditional method defines login classes by editing [.filename]#/etc/login.conf#. While this method is still supported, any changes require a multi-step process of editing this file, rebuilding the resource database, making necessary changes to [.filename]#/etc/master.passwd#, and rebuilding the password database. This can become time consuming, depending upon the number of users to configure. man:rctl[8] can be used to provide a more fine-grained method for controlling resource limits. This command supports more than user limits as it can also be used to set resource constraints on processes and jails. This section demonstrates both methods for controlling resources, beginning with the traditional method. [[security-resource-limits-types]] === Types of Resources FreeBSD provides limits for various types of resources, including: .Resource types [options="header", cols="1,1"] |=== | Type | Description | CPU Time | Limits the amount of CPU time a process can consume | Memory | Controls the amount of physical memory a process can use | Open Files | Limits the number of files a process can have open simultaneously | Processes | Controls the number of processes a user or a process can create | File Size | Limits the maximum size of files that a process can create | Core Dumps | Controls whether processes are allowed to generate core dump files | Network Resources | Limits the amount of network resources (e.g., sockets) a process can use |=== For a full listing of types see man:login.conf[5] and man:rctl[8]. [[users-limiting]] === Configuring Login Classes In the traditional method, login classes and the resource limits to apply to a login class are defined in [.filename]#/etc/login.conf#. Each user account can be assigned to a login class, where `default` is the default login class. Each login class has a set of login capabilities associated with it. A login capability is a `_name_=_value_` pair, where _name_ is a well-known identifier and _value_ is an arbitrary string which is processed accordingly depending on the _name_. The first step to configure a resource limit will be to open [.filename]#/etc/login.conf# by executing the following command: [source,shell] .... # ee /etc/login.conf .... Then locate the section for the user class to be modified. In this example, let's assume the user class is named `limited`, create it in case it does not exist. [.programlisting] .... limited:\ <.> :maxproc=50:\ <.> :tc=default: <.> .... <.> Name of the user class. <.> Sets the maximum number of processes (maxproc) to 50 for users in the `limited` class. <.> Indicates that this user class inherits the default settings from the "default" class. After modifying the [.filename]#/etc/login.conf# file, run man:cap_mkdb[1] to generate the database that FreeBSD uses to apply these settings: [source,shell] .... # cap_mkdb /etc/login.conf .... man:chpass[1] can be used to change the class to the desired user by executing the following command: [source,shell] .... # chpass username .... This will open a text editor, add the new `limited` class there as follows: [.programlisting] .... #Changing user information for username. Login: username Password: $6$2H.419USdGaiJeqK$6kgcTnDadasdasd3YnlNZsOni5AMymibkAfRCPirc7ZFjjv DVsKyXx26daabdfqSdasdsmL/ZMUpdHiO0 Uid [#]: 1001 Gid [# or name]: 1001 Change [month day year]: Expire [month day year]: Class: limited Home directory: /home/username Shell: /bin/sh Full Name: User & Office Location: Office Phone: Home Phone: Other information: .... Now, the user assigned to the `limited` class will have a maximum process limit of 50. Remember that this is just one example of setting a resource limit using the [.filename]#/etc/login.conf# file. Keep in mind that after making changes to the [.filename]#/etc/login.conf# file, the user needs to log out and log back in for the changes to take effect. Additionally, always exercise caution when editing system configuration files, especially when using privileged access. [[security-rctl]] === Enabling and Configuring Resource Limits The man:rctl[8] system provides a more fine-grained way to set and manage resource limits for individual processes and users. It allows you to dynamically assign resource limits to specific processes or users, regardless of their user class. The first step to use man:rctl[8] will be to enable it adding the following line to [.filename]#/boot/loader.conf# and reboot the system: [.programlisting] .... kern.racct.enable=1 .... Then enable and start the man:rctl[8] service by executing the following commands: [source,shell] .... # sysrc rctl_enable="YES" # service rctl start .... Then man:rctl[8] may be used to set rules for the system. Rule syntax (man:rctl.conf[5]) is controlled through the use of a subject, subject-id, resource, and action, as seen in this example rule: [.programlisting] .... subject:subject-id:resource:action=amount/per .... For example to constrained the user to add no more than 10 processes execute the following command: [source,shell] .... # rctl -a user:username:maxproc:deny=10/user .... To check the applied resource limits the man:rctl[8] command can be executed: [source,shell] .... # rctl .... The output should be similar to the following: [.programlisting] .... user:username:maxproc:deny=10 .... Rules will persist across reboots if they have been added to [.filename]#/etc/rctl.conf#. The format is a rule, without the preceding command. For example, the previous rule could be added as: [.programlisting] .... user:username:maxproc:deny=10 .... [[security-pkg]] == Monitoring Third Party Security Issues In recent years, the security world has made many improvements to how vulnerability assessment is handled. The threat of system intrusion increases as third party utilities are installed and configured for virtually any operating system available today. Vulnerability assessment is a key factor in security. While FreeBSD releases advisories for the base system, doing so for every third party utility is beyond the FreeBSD Project's capability. There is a way to mitigate third party vulnerabilities and warn administrators of known security issues. A FreeBSD add on utility known as pkg includes options explicitly for this purpose. pkg polls a database for security issues. The database is updated and maintained by the FreeBSD Security Team and ports developers. Installation provides man:periodic[8] configuration files for maintaining the pkg audit database, and provides a programmatic method of keeping it updated. After installation, and to audit third party utilities as part of the Ports Collection at any time, an administrator may choose to update the database and view known vulnerabilities of installed packages by invoking: [source,shell] .... % pkg audit -F .... The output should be similar to the following: [.programlisting] .... vulnxml file up-to-date chromium-116.0.5845.96_1 is vulnerable: chromium -- multiple vulnerabilities CVE: CVE-2023-4431 CVE: CVE-2023-4427 CVE: CVE-2023-4428 CVE: CVE-2023-4429 CVE: CVE-2023-4430 WWW: https://vuxml.FreeBSD.org/freebsd/5fa332b9-4269-11ee-8290-a8a1599412c6.html samba413-4.13.17_5 is vulnerable: samba -- multiple vulnerabilities CVE: CVE-2023-3347 CVE: CVE-2023-34966 CVE: CVE-2023-34968 CVE: CVE-2022-2127 CVE: CVE-2023-34967 WWW: https://vuxml.FreeBSD.org/freebsd/441e1e1a-27a5-11ee-a156-080027f5fec9.html 2 problem(s) in 2 installed package(s) found. .... By pointing a web browser to the displayed URL, an administrator may obtain more information about the vulnerability. This will include the versions affected, by FreeBSD port version, along with other web sites which may contain security advisories. [[security-advisories]] == FreeBSD Security Advisories Like many producers of quality operating systems, the FreeBSD Project has a security team which is responsible for determining the End-of-Life (EoL) date for each FreeBSD release and to provide security updates for supported releases which have not yet reached their EoL. More information about the FreeBSD security team and the supported releases is available on the link:https://www.FreeBSD.org/security[FreeBSD security page]. One task of the security team is to respond to reported security vulnerabilities in the FreeBSD operating system. Once a vulnerability is confirmed, the security team verifies the steps necessary to fix the vulnerability and updates the source code with the fix. It then publishes the details as a "Security Advisory". Security advisories are published on the link:https://www.FreeBSD.org/security/advisories/[FreeBSD website] and mailed to the {freebsd-security-notifications}, {freebsd-security}, and {freebsd-announce}. === Format of a Security Advisory Here is an example of a FreeBSD security advisory: [.programlisting] .... -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 ============================================================================= FreeBSD-SA-23:07.bhyve Security Advisory The FreeBSD Project Topic: bhyve privileged guest escape via fwctl Category: core Module: bhyve Announced: 2023-08-01 Credits: Omri Ben Bassat and Vladimir Eli Tokarev from Microsoft Affects: FreeBSD 13.1 and 13.2 Corrected: 2023-08-01 19:48:53 UTC (stable/13, 13.2-STABLE) 2023-08-01 19:50:47 UTC (releng/13.2, 13.2-RELEASE-p2) 2023-08-01 19:48:26 UTC (releng/13.1, 13.1-RELEASE-p9) CVE Name: CVE-2023-3494 For general information regarding FreeBSD Security Advisories, including descriptions of the fields above, security branches, and the following sections, please visit . I. Background bhyve(8)'s fwctl interface provides a mechanism through which guest firmware can query the hypervisor for information about the virtual machine. The fwctl interface is available to guests when bhyve is run with the "-l bootrom" option, used for example when booting guests in UEFI mode. bhyve is currently only supported on the amd64 platform. II. Problem Description The fwctl driver implements a state machine which is executed when the guest accesses certain x86 I/O ports. The interface lets the guest copy a string into a buffer resident in the bhyve process' memory. A bug in the state machine implementation can result in a buffer overflowing when copying this string. III. Impact A malicious, privileged software running in a guest VM can exploit the buffer overflow to achieve code execution on the host in the bhyve userspace process, which typically runs as root. Note that bhyve runs in a Capsicum sandbox, so malicious code is constrained by the capabilities available to the bhyve process. IV. Workaround No workaround is available. bhyve guests that are executed without the "-l bootrom" option are unaffected. V. Solution Upgrade your vulnerable system to a supported FreeBSD stable or release / security branch (releng) dated after the correction date. Perform one of the following: 1) To update your vulnerable system via a binary patch: Systems running a RELEASE version of FreeBSD on the amd64, i386, or (on FreeBSD 13 and later) arm64 platforms can be updated via the freebsd-update(8) utility: # freebsd-update fetch # freebsd-update install Restart all affected virtual machines. 2) To update your vulnerable system via a source code patch: The following patches have been verified to apply to the applicable FreeBSD release branches. a) Download the relevant patch from the location below, and verify the detached PGP signature using your PGP utility. [FreeBSD 13.2] # fetch https://security.FreeBSD.org/patches/SA-23:07/bhyve.13.2.patch # fetch https://security.FreeBSD.org/patches/SA-23:07/bhyve.13.2.patch.asc # gpg --verify bhyve.13.2.patch.asc [FreeBSD 13.1] # fetch https://security.FreeBSD.org/patches/SA-23:07/bhyve.13.1.patch # fetch https://security.FreeBSD.org/patches/SA-23:07/bhyve.13.1.patch.asc # gpg --verify bhyve.13.1.patch.asc b) Apply the patch. Execute the following commands as root: # cd /usr/src # patch < /path/to/patch c) Recompile the operating system using buildworld and installworld as described in . Restart all affected virtual machines. VI. Correction details This issue is corrected by the corresponding Git commit hash or Subversion revision number in the following stable and release branches: Branch/path Hash Revision - ------------------------------------------------------------------------- stable/13/ 9fe302d78109 stable/13-n255918 releng/13.2/ 2bae613e0da3 releng/13.2-n254625 releng/13.1/ 87702e38a4b4 releng/13.1-n250190 - ------------------------------------------------------------------------- Run the following command to see which files were modified by a particular commit: # git show --stat Or visit the following URL, replacing NNNNNN with the hash: To determine the commit count in a working tree (for comparison against nNNNNNN in the table above), run: # git rev-list --count --first-parent HEAD VII. References The latest revision of this advisory is available at -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEthUnfoEIffdcgYM7bljekB8AGu8FAmTJdsIACgkQbljekB8A Gu8Q1Q/7BFw5Aa0cFxBzbdz+O5NAImj58MvKS6xw61bXcYr12jchyT6ENC7yiR+K qCqbe5TssRbtZ1gg/94gSGEXccz5OcJGxW+qozhcdPUh2L2nzBPkMCrclrYJfTtM cnmQKjg/wFZLUVr71GEM95ZFaktlZdXyXx9Z8eBzow5rXexpl1TTHQQ2kZZ41K4K KFhup91dzGCIj02cqbl+1h5BrXJe3s/oNJt5JKIh/GBh5THQu9n6AywQYl18HtjV fMb1qRTAS9WbiEP5QV2eEuOG86ucuhytqnEN5MnXJ2rLSjfb9izs9HzLo3ggy7yb hN3tlbfIPjMEwYexieuoyP3rzKkLeYfLXqJU4zKCRnIbBIkMRy4mcFkfcYmI+MhF NPh2R9kccemppKXeDhKJurH0vsetr8ti+AwOZ3pgO21+9w+mjE+EfaedIi+JWhip hwqeFv03bAQHJdacNYGV47NsJ91CY4ZgWC3ZOzBZ2Y5SDtKFjyc0bf83WTfU9A/0 drC0z3xaJribah9e6k5d7lmZ7L6aHCbQ70+aayuAEZQLr/N1doB0smNi0IHdrtY0 JdIqmVX+d1ihVhJ05prC460AS/Kolqiaysun1igxR+ZnctE9Xdo1BlLEbYu2KjT4 LpWvSuhRMSQaYkJU72SodQc0FM5mqqNN42Vx+X4EutOfvQuRGlI= =MlAY -----END PGP SIGNATURE----- .... Every security advisory uses the following format: * Each security advisory is signed by the PGP key of the Security Officer. The public key for the Security Officer can be verified at crossref:pgpkeys[pgpkeys,OpenPGP Keys]. * The name of the security advisory always begins with `FreeBSD-SA-` (for FreeBSD Security Advisory), followed by the year in two digit format (`23:`), followed by the advisory number for that year (`07.`), followed by the name of the affected application or subsystem (`bhyve`). * The `Topic` field summarizes the vulnerability. * The `Category` refers to the affected part of the system which may be one of `core`, `contrib`, or `ports`. The `core` category means that the vulnerability affects a core component of the FreeBSD operating system. The `contrib` category means that the vulnerability affects software included with FreeBSD, such as BIND. The `ports` category indicates that the vulnerability affects software available through the Ports Collection. * The `Module` field refers to the component location. In this example, the `bhyve` module is affected; therefore, this vulnerability affects an application installed with the operating system. * The `Announced` field reflects the date the security advisory was published. This means that the security team has verified that the problem exists and that a patch has been committed to the FreeBSD source code repository. * The `Credits` field gives credit to the individual or organization who noticed the vulnerability and reported it. * The `Affects` field explains which releases of FreeBSD are affected by this vulnerability. * The `Corrected` field indicates the date, time, time offset, and releases that were corrected. The section in parentheses shows each branch for which the fix has been merged, and the version number of the corresponding release from that branch. The release identifier itself includes the version number and, if appropriate, the patch level. The patch level is the letter `p` followed by a number, indicating the sequence number of the patch, allowing users to track which patches have already been applied to the system. * The `CVE Name` field lists the advisory number, if one exists, in the public http://cve.mitre.org[cve.mitre.org] security vulnerabilities database. * The `Background` field provides a description of the affected module. * The `Problem Description` field explains the vulnerability. This can include information about the flawed code and how the utility could be maliciously used. * The `Impact` field describes what type of impact the problem could have on a system. * The `Workaround` field indicates if a workaround is available to system administrators who cannot immediately patch the system. * The `Solution` field provides the instructions for patching the affected system. This is a step by step tested and verified method for getting a system patched and working securely. * The `Correction Details` field displays each affected Subversion or Git branch with the revision number that contains the corrected code. * The `References` field offers sources of additional information regarding the vulnerability. diff --git a/documentation/content/en/books/handbook/serialcomms/_index.adoc b/documentation/content/en/books/handbook/serialcomms/_index.adoc index 05717f6302..7ecebe9e0d 100644 --- a/documentation/content/en/books/handbook/serialcomms/_index.adoc +++ b/documentation/content/en/books/handbook/serialcomms/_index.adoc @@ -1,1219 +1,1219 @@ --- title: Chapter 29. Serial Communications part: Part IV. Network Communication prev: books/handbook/partiv next: books/handbook/ppp-and-slip description: This chapter covers some of the ways serial communications can be used on FreeBSD tags: ["serial", "communications", "terminal", "modem", "console"] showBookMenu: true weight: 34 path: "/books/handbook/serialcomms/" --- [[serialcomms]] = Serial Communications :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 29 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/serialcomms/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[serial-synopsis]] == Synopsis UNIX(R) has always had support for serial communications as the very first UNIX(R) machines relied on serial lines for user input and output. Things have changed a lot from the days when the average terminal consisted of a 10-character-per-second serial printer and a keyboard. This chapter covers some of the ways serial communications can be used on FreeBSD. After reading this chapter, you will know: * How to connect terminals to a FreeBSD system. * How to use a modem to dial out to remote hosts. * How to allow remote users to login to a FreeBSD system with a modem. * How to boot a FreeBSD system from a serial console. Before reading this chapter, you should: * Know how to crossref:kernelconfig[kernelconfig, configure and install a custom kernel]. * Understand crossref:basics[basics, FreeBSD permissions and processes]. * Have access to the technical manual for the serial hardware to be used with FreeBSD. [[serial]] == Serial Terminology and Hardware The following terms are often used in serial communications: bps:: Bits per Second (bps) is the rate at which data is transmitted. DTE:: Data Terminal Equipment (DTE) is one of two endpoints in a serial communication. An example would be a computer. DCE:: Data Communications Equipment (DCE) is the other endpoint in a serial communication. Typically, it is a modem or serial terminal. RS-232:: The original standard which defined hardware serial communications. It has since been renamed to TIA-232. When referring to communication data rates, this section does not use the term _baud_. Baud refers to the number of electrical state transitions made in a period of time, while bps is the correct term to use. To connect a serial terminal to a FreeBSD system, a serial port on the computer and the proper cable to connect to the serial device are needed. Users who are already familiar with serial hardware and cabling can safely skip this section. [[term-cables-null]] === Serial Cables and Ports There are several different kinds of serial cables. The two most common types are null-modem cables and standard RS-232 cables. The documentation for the hardware should describe the type of cable required. These two types of cables differ in how the wires are connected to the connector. Each wire represents a signal, with the defined signals summarized in -crossref:serialcomms[serialcomms-signal-names]. +crossref:serialcomms[serialcomms-signal-names,.RS-232C Signal Names]. A standard serial cable passes all of the RS-232C signals straight through. For example, the "Transmitted Data" pin on one end of the cable goes to the "Transmitted Data" pin on the other end. This is the type of cable used to connect a modem to the FreeBSD system, and is also appropriate for some terminals. A null-modem cable switches the "Transmitted Data" pin of the connector on one end with the "Received Data" pin on the other end. The connector can be either a DB-25 or a DB-9. A null-modem cable can be constructed using the pin connections summarized in crossref:serialcomms[nullmodem-db25], crossref:serialcomms[nullmodem-db9], and -crossref:serialcomms[nullmodem-db9-25]. +crossref:serialcomms[nullmodem-db9-25,.DB-9 to DB-25 Null-Modem Cable]. While the standard calls for a straight-through pin 1 to pin 1 "Protective Ground" line, it is often omitted. Some terminals work using only pins 2, 3, and 7, while others require different configurations. When in doubt, refer to the documentation for the hardware. [[serialcomms-signal-names]] .RS-232C Signal Names [cols="1,1", frame="none", options="header"] |=== <| Acronyms <| Names |RD |Received Data |TD |Transmitted Data |DTR |Data Terminal Ready |DSR |Data Set Ready |DCD |Data Carrier Detect |SG |Signal Ground |RTS |Request to Send |CTS |Clear to Send |=== [[nullmodem-db25]] .DB-25 to DB-25 Null-Modem Cable [cols="1,1,1,1,1", frame="none", options="header"] |=== <| Signal <| Pin # | <| Pin # <| Signal |SG |7 |connects to |7 |SG |TD |2 |connects to |3 |RD |RD |3 |connects to |2 |TD |RTS |4 |connects to |5 |CTS |CTS |5 |connects to |4 |RTS |DTR |20 |connects to |6 |DSR |DTR |20 |connects to |8 |DCD |DSR |6 |connects to |20 |DTR |DCD |8 |connects to |20 |DTR |=== [[nullmodem-db9]] .DB-9 to DB-9 Null-Modem Cable [cols="1,1,1,1,1", frame="none", options="header"] |=== <| Signal <| Pin # | <| Pin # <| Signal |RD |2 |connects to |3 |TD |TD |3 |connects to |2 |RD |DTR |4 |connects to |6 |DSR |DTR |4 |connects to |1 |DCD |SG |5 |connects to |5 |SG |DSR |6 |connects to |4 |DTR |DCD |1 |connects to |4 |DTR |RTS |7 |connects to |8 |CTS |CTS |8 |connects to |7 |RTS |=== [[nullmodem-db9-25]] .DB-9 to DB-25 Null-Modem Cable [cols="1,1,1,1,1", frame="none", options="header"] |=== <| Signal <| Pin # | <| Pin # <| Signal |RD |2 |connects to |2 |TD |TD |3 |connects to |3 |RD |DTR |4 |connects to |6 |DSR |DTR |4 |connects to |8 |DCD |SG |5 |connects to |7 |SG |DSR |6 |connects to |20 |DTR |DCD |1 |connects to |20 |DTR |RTS |7 |connects to |5 |CTS |CTS |8 |connects to |4 |RTS |=== [NOTE] ==== When one pin at one end connects to a pair of pins at the other end, it is usually implemented with one short wire between the pair of pins in their connector and a long wire to the other single pin. ==== Serial ports are the devices through which data is transferred between the FreeBSD host computer and the terminal. Several kinds of serial ports exist. Before purchasing or constructing a cable, make sure it will fit the ports on the terminal and on the FreeBSD system. Most terminals have DB-25 ports. Personal computers may have DB-25 or DB-9 ports. A multiport serial card may have RJ-12 or RJ-45/ ports. See the documentation that accompanied the hardware for specifications on the kind of port or visually verify the type of port. In FreeBSD, each serial port is accessed through an entry in [.filename]#/dev#. There are two different kinds of entries: * Call-in ports are named [.filename]#/dev/ttyuN# where _N_ is the port number, starting from zero. If a terminal is connected to the first serial port ([.filename]#COM1#), use [.filename]#/dev/ttyu0# to refer to the terminal. If the terminal is on the second serial port ([.filename]#COM2#), use [.filename]#/dev/ttyu1#, and so forth. Generally, the call-in port is used for terminals. Call-in ports require that the serial line assert the "Data Carrier Detect" signal to work correctly. * Call-out ports are named [.filename]#/dev/cuauN# on FreeBSD versions 8.X and higher and [.filename]#/dev/cuadN# on FreeBSD versions 7.X and lower. Call-out ports are usually not used for terminals, but are used for modems. The call-out port can be used if the serial cable or the terminal does not support the "Data Carrier Detect" signal. FreeBSD also provides initialization devices ([.filename]#/dev/ttyuN.init# and [.filename]#/dev/cuauN.init# or [.filename]#/dev/cuadN.init#) and locking devices ([.filename]#/dev/ttyuN.lock# and [.filename]#/dev/cuauN.lock# or [.filename]#/dev/cuadN.lock#). The initialization devices are used to initialize communications port parameters each time a port is opened, such as `crtscts` for modems which use `RTS/CTS` signaling for flow control. The locking devices are used to lock flags on ports to prevent users or programs changing certain parameters. Refer to man:termios[4], man:uart[4], and man:stty[1] for information on terminal settings, locking and initializing devices, and setting terminal options, respectively. [[serial-hw-config]] === Serial Port Configuration By default, FreeBSD supports four serial ports which are commonly known as [.filename]#COM1#, [.filename]#COM2#, [.filename]#COM3#, and [.filename]#COM4#. FreeBSD also supports dumb multi-port serial interface cards, such as the BocaBoard 1008 and 2016, as well as more intelligent multi-port cards such as those made by Digiboard. However, the default kernel only looks for the standard [.filename]#COM# ports. To see if the system recognizes the serial ports, look for system boot messages that start with `uart`: [source,shell] .... # grep uart /var/run/dmesg.boot .... If the system does not recognize all of the needed serial ports, additional entries can be added to [.filename]#/boot/device.hints#. This file already contains `hint.uart.0.\*` entries for [.filename]#COM1# and `hint.uart.1.*` entries for [.filename]#COM2#. When adding a port entry for [.filename]#COM3# use `0x3E8`, and for [.filename]#COM4# use `0x2E8`. Common IRQ addresses are `5` for [.filename]#COM3# and `9` for [.filename]#COM4#. To determine the default set of terminal I/O settings used by the port, specify its device name. This example determines the settings for the call-in port on [.filename]#COM2#: [source,shell] .... # stty -a -f /dev/ttyu1 .... System-wide initialization of serial devices is controlled by [.filename]#/etc/rc.d/serial#. This file affects the default settings of serial devices. To change the settings for a device, use `stty`. By default, the changed settings are in effect until the device is closed and when the device is reopened, it goes back to the default set. To permanently change the default set, open and adjust the settings of the initialization device. For example, to turn on `CLOCAL` mode, 8 bit communication, and `XON/XOFF` flow control for [.filename]#ttyu5#, type: [source,shell] .... # stty -f /dev/ttyu5.init clocal cs8 ixon ixoff .... To prevent certain settings from being changed by an application, make adjustments to the locking device. For example, to lock the speed of [.filename]#ttyu5# to 57600 bps, type: [source,shell] .... # stty -f /dev/ttyu5.lock 57600 .... Now, any application that opens [.filename]#ttyu5# and tries to change the speed of the port will be stuck with 57600 bps. [[term]] == Terminals Terminals provide a convenient and low-cost way to access a FreeBSD system when not at the computer's console or on a connected network. This section describes how to use terminals with FreeBSD. The original UNIX(R) systems did not have consoles. Instead, users logged in and ran programs through terminals that were connected to the computer's serial ports. The ability to establish a login session on a serial port still exists in nearly every UNIX(R)-like operating system today, including FreeBSD. By using a terminal attached to an unused serial port, a user can log in and run any text program that can normally be run on the console or in an `xterm` window. Many terminals can be attached to a FreeBSD system. An older spare computer can be used as a terminal wired into a more powerful computer running FreeBSD. This can turn what might otherwise be a single-user computer into a powerful multiple-user system. FreeBSD supports three types of terminals: Dumb terminals:: Dumb terminals are specialized hardware that connect to computers over serial lines. They are called "dumb" because they have only enough computational power to display, send, and receive text. No programs can be run on these devices. Instead, dumb terminals connect to a computer that runs the needed programs. + There are hundreds of kinds of dumb terminals made by many manufacturers, and just about any kind will work with FreeBSD. Some high-end terminals can even display graphics, but only certain software packages can take advantage of these advanced features. + Dumb terminals are popular in work environments where workers do not need access to graphical applications. Computers Acting as Terminals:: Since a dumb terminal has just enough ability to display, send, and receive text, any spare computer can be a dumb terminal. All that is needed is the proper cable and some _terminal emulation_ software to run on the computer. + This configuration can be useful. For example, if one user is busy working at the FreeBSD system's console, another user can do some text-only work at the same time from a less powerful personal computer hooked up as a terminal to the FreeBSD system. + There are at least two utilities in the base-system of FreeBSD that can be used to work through a serial connection: man:cu[1] and man:tip[1]. + For example, to connect from a client system that runs FreeBSD to the serial connection of another system: + [source,shell] .... # cu -l /dev/cuauN .... + Ports are numbered starting from zero. This means that [.filename]#COM1# is [.filename]#/dev/cuau0#. + Additional programs are available through the Ports Collection, such as package:comms/minicom[]. X Terminals:: X terminals are the most sophisticated kind of terminal available. Instead of connecting to a serial port, they usually connect to a network like Ethernet. Instead of being relegated to text-only applications, they can display any Xorg application. + This chapter does not cover the setup, configuration, or use of X terminals. [[term-config]] === Terminal Configuration This section describes how to configure a FreeBSD system to enable a login session on a serial terminal. It assumes that the system recognizes the serial port to which the terminal is connected and that the terminal is connected with the correct cable. In FreeBSD, `init` reads [.filename]#/etc/ttys# and starts a `getty` process on the available terminals. The `getty` process is responsible for reading a login name and starting the `login` program. The ports on the FreeBSD system which allow logins are listed in [.filename]#/etc/ttys#. For example, the first virtual console, [.filename]#ttyv0#, has an entry in this file, allowing logins on the console. This file also contains entries for the other virtual consoles, serial ports, and pseudo-ttys. For a hardwired terminal, the serial port's [.filename]#/dev# entry is listed without the `/dev` part. For example, [.filename]#/dev/ttyv0# is listed as `ttyv0`. The default [.filename]#/etc/ttys# configures support for the first four serial ports, [.filename]#ttyu0# through [.filename]#ttyu3#: [.programlisting] .... ttyu0 "/usr/libexec/getty std.115200" dialup off secure ttyu1 "/usr/libexec/getty std.115200" dialup off secure ttyu2 "/usr/libexec/getty std.115200" dialup off secure ttyu3 "/usr/libexec/getty std.115200" dialup off secure .... When attaching a terminal to one of those ports, modify the default entry to set the required speed and terminal type, to turn the device `on` and, if needed, to change the port's `secure` setting. If the terminal is connected to another port, add an entry for the port. -crossref:serialcomms[ex-etc-ttys] configures two terminals in [.filename]#/etc/ttys#. +crossref:serialcomms[ex-etc-ttys,.Configuring Terminal Entries] configures two terminals in [.filename]#/etc/ttys#. The first entry configures a Wyse-50 connected to [.filename]#COM2#. The second entry configures an old computer running Procomm terminal software emulating a VT-100 terminal. The computer is connected to the sixth serial port on a multi-port serial card. [example] [[ex-etc-ttys]] .Configuring Terminal Entries ==== [.programlisting] .... ttyu1 "/usr/libexec/getty std.38400" wy50 on insecure ttyu5 "/usr/libexec/getty std.19200" vt100 on insecure .... The first field specifies the device name of the serial terminal. The second field tells `getty` to initialize and open the line, set the line speed, prompt for a user name, and then execute the `login` program. The optional _getty type_ configures characteristics on the terminal line, like bps rate and parity. The available getty types are listed in [.filename]#/etc/gettytab#. In almost all cases, the getty types that start with `std` will work for hardwired terminals as these entries ignore parity. There is a `std` entry for each bps rate from 110 to 115200. Refer to man:gettytab[5] for more information. When setting the getty type, make sure to match the communications settings used by the terminal. For this example, the Wyse-50 uses no parity and connects at 38400 bps. The computer uses no parity and connects at 19200 bps. The third field is the type of terminal. For dial-up ports, `unknown` or `dialup` is typically used since users may dial up with practically any type of terminal or software. Since the terminal type does not change for hardwired terminals, a real terminal type from [.filename]#/etc/termcap# can be specified. For this example, the Wyse-50 uses the real terminal type while the computer running Procomm is set to emulate a VT-100. The fourth field specifies if the port should be enabled. To enable logins on this port, this field must be set to `on`. The final field is used to specify whether the port is secure. Marking a port as `secure` means that it is trusted enough to allow `root` to login from that port. Insecure ports do not allow `root` logins. On an insecure port, users must login from unprivileged accounts and then use `su` or a similar mechanism to gain superuser privileges, as described in crossref:basics[users-superuser,“The Superuser Account”]. For security reasons, it is recommended to change this setting to `insecure`. ==== After making any changes to [.filename]#/etc/ttys#, send a SIGHUP (hangup) signal to the `init` process to force it to re-read its configuration file: [source,shell] .... # kill -HUP 1 .... Since `init` is always the first process run on a system, it always has a process ID of `1`. If everything is set up correctly, all cables are in place, and the terminals are powered up, a `getty` process should now be running on each terminal and login prompts should be available on each terminal. [[term-debug]] === Troubleshooting the Connection Even with the most meticulous attention to detail, something could still go wrong while setting up a terminal. Here is a list of common symptoms and some suggested fixes. If no login prompt appears, make sure the terminal is plugged in and powered up. If it is a personal computer acting as a terminal, make sure it is running terminal emulation software on the correct serial port. Make sure the cable is connected firmly to both the terminal and the FreeBSD computer. Make sure it is the right kind of cable. Make sure the terminal and FreeBSD agree on the bps rate and parity settings. For a video display terminal, make sure the contrast and brightness controls are turned up. If it is a printing terminal, make sure paper and ink are in good supply. Use `ps` to make sure that a `getty` process is running and serving the terminal. For example, the following listing shows that a `getty` is running on the second serial port, [.filename]#ttyu1#, and is using the `std.38400` entry in [.filename]#/etc/gettytab#: [source,shell] .... # ps -axww|grep ttyu 22189 d1 Is+ 0:00.03 /usr/libexec/getty std.38400 ttyu1 .... If no `getty` process is running, make sure the port is enabled in [.filename]#/etc/ttys#. Remember to run `kill -HUP 1` after modifying [.filename]#/etc/ttys#. If the `getty` process is running but the terminal still does not display a login prompt, or if it displays a prompt but will not accept typed input, the terminal or cable may not support hardware handshaking. Try changing the entry in [.filename]#/etc/ttys# from `std.38400` to `3wire.38400`, then run `kill -HUP 1` after modifying [.filename]#/etc/ttys#. The `3wire` entry is similar to `std`, but ignores hardware handshaking. The bps may also need to be reduced or software flow control enabled when using `3wire` to prevent buffer overflows. If garbage appears instead of a login prompt, make sure the terminal and FreeBSD agree on the bps rate and parity settings. Check the `getty` processes to make sure the correct _getty_ type is in use. If not, edit [.filename]#/etc/ttys# and run `kill -HUP 1`. If characters appear doubled and the password appears when typed, switch the terminal, or the terminal emulation software, from "half duplex" or "local echo" to "full duplex." [[dialup]] == Dial-in Service Configuring a FreeBSD system for dial-in service is similar to configuring terminals, except that modems are used instead of terminal devices. FreeBSD supports both external and internal modems. External modems are more convenient because they often can be configured via parameters stored in non-volatile RAM and they usually provide lighted indicators that display the state of important RS-232 signals, indicating whether the modem is operating properly. Internal modems usually lack non-volatile RAM, so their configuration may be limited to setting DIP switches. If the internal modem has any signal indicator lights, they are difficult to view when the system's cover is in place. When using an external modem, a proper cable is needed. A standard RS-232C serial cable should suffice. FreeBSD needs the RTS and CTS signals for flow control at speeds above 2400 bps, the CD signal to detect when a call has been answered or the line has been hung up, and the DTR signal to reset the modem after a session is complete. Some cables are wired without all of the needed signals, so if a login session does not go away when the line hangs up, there may be a problem with the cable. -Refer to crossref:serialcomms[term-cables-null] for more information about these signals. +Refer to crossref:serialcomms[term-cables-null, Serial Cables and Ports] for more information about these signals. Like other UNIX(R)-like operating systems, FreeBSD uses the hardware signals to find out when a call has been answered or a line has been hung up and to hangup and reset the modem after a call. FreeBSD avoids sending commands to the modem or watching for status reports from the modem. FreeBSD supports the NS8250, NS16450, NS16550, and NS16550A-based RS-232C (CCITT V.24) communications interfaces. The 8250 and 16450 devices have single-character buffers. The 16550 device provides a 16-character buffer, which allows for better system performance. Bugs in plain 16550 devices prevent the use of the 16-character buffer, so use 16550A devices if possible. As single-character-buffer devices require more work by the operating system than the 16-character-buffer devices, 16550A-based serial interface cards are preferred. If the system has many active serial ports or will have a heavy load, 16550A-based cards are better for low-error-rate communications. The rest of this section demonstrates how to configure a modem to receive incoming connections, how to communicate with the modem, and offers some troubleshooting tips. [[dialup-ttys]] === Modem Configuration As with terminals, `init` spawns a `getty` process for each configured serial port used for dial-in connections. When a user dials the modem's line and the modems connect, the "Carrier Detect" signal is reported by the modem. The kernel notices that the carrier has been detected and instructs `getty` to open the port and display a `login:` prompt at the specified initial line speed. In a typical configuration, if garbage characters are received, usually due to the modem's connection speed being different than the configured speed, `getty` tries adjusting the line speeds until it receives reasonable characters. After the user enters their login name, `getty` executes `login`, which completes the login process by asking for the user's password and then starting the user's shell. There are two schools of thought regarding dial-up modems. One configuration method is to set the modems and systems so that no matter at what speed a remote user dials in, the dial-in RS-232 interface runs at a locked speed. The benefit of this configuration is that the remote user always sees a system login prompt immediately. The downside is that the system does not know what a user's true data rate is, so full-screen programs like Emacs will not adjust their screen-painting methods to make their response better for slower connections. The second method is to configure the RS-232 interface to vary its speed based on the remote user's connection speed. As `getty` does not understand any particular modem's connection speed reporting, it gives a `login:` message at an initial speed and watches the characters that come back in response. If the user sees junk, they should press kbd:[Enter] until they see a recognizable prompt. If the data rates do not match, `getty` sees anything the user types as junk, tries the next speed, and gives the `login:` prompt again. This procedure normally only takes a keystroke or two before the user sees a good prompt. This login sequence does not look as clean as the locked-speed method, but a user on a low-speed connection should receive better interactive response from full-screen programs. When locking a modem's data communications rate at a particular speed, no changes to [.filename]#/etc/gettytab# should be needed. However, for a matching-speed configuration, additional entries may be required in order to define the speeds to use for the modem. This example configures a 14.4 Kbps modem with a top interface speed of 19.2 Kbps using 8-bit, no parity connections. It configures `getty` to start the communications rate for a V.32bis connection at 19.2 Kbps, then cycles through 9600 bps, 2400 bps, 1200 bps, 300 bps, and back to 19.2 Kbps. Communications rate cycling is implemented with the `nx=` (next table) capability. Each line uses a `tc=` (table continuation) entry to pick up the rest of the settings for a particular data rate. [.programlisting] .... # # Additions for a V.32bis Modem # um|V300|High Speed Modem at 300,8-bit:\ :nx=V19200:tc=std.300: un|V1200|High Speed Modem at 1200,8-bit:\ :nx=V300:tc=std.1200: uo|V2400|High Speed Modem at 2400,8-bit:\ :nx=V1200:tc=std.2400: up|V9600|High Speed Modem at 9600,8-bit:\ :nx=V2400:tc=std.9600: uq|V19200|High Speed Modem at 19200,8-bit:\ :nx=V9600:tc=std.19200: .... For a 28.8 Kbps modem, or to take advantage of compression on a 14.4 Kbps modem, use a higher communications rate, as seen in this example: [.programlisting] .... # # Additions for a V.32bis or V.34 Modem # Starting at 57.6 Kbps # vm|VH300|Very High Speed Modem at 300,8-bit:\ :nx=VH57600:tc=std.300: vn|VH1200|Very High Speed Modem at 1200,8-bit:\ :nx=VH300:tc=std.1200: vo|VH2400|Very High Speed Modem at 2400,8-bit:\ :nx=VH1200:tc=std.2400: vp|VH9600|Very High Speed Modem at 9600,8-bit:\ :nx=VH2400:tc=std.9600: vq|VH57600|Very High Speed Modem at 57600,8-bit:\ :nx=VH9600:tc=std.57600: .... For a slow CPU or a heavily loaded system without 16550A-based serial ports, this configuration may produce `uart` "silo" errors at 57.6 Kbps. The configuration of [.filename]#/etc/ttys# is similar to -crossref:serialcomms[ex-etc-ttys], but a different argument is passed to `getty` and `dialup` is used for the terminal type. +crossref:serialcomms[ex-etc-ttys,.Configuring Terminal Entries], but a different argument is passed to `getty` and `dialup` is used for the terminal type. Replace _xxx_ with the process `init` will run on the device: [.programlisting] .... ttyu0 "/usr/libexec/getty xxx" dialup on .... The `dialup` terminal type can be changed. For example, setting `vt102` as the default terminal type allows users to use VT102 emulation on their remote systems. For a locked-speed configuration, specify the speed with a valid type listed in [.filename]#/etc/gettytab#. This example is for a modem whose port speed is locked at 19.2 Kbps: [.programlisting] .... ttyu0 "/usr/libexec/getty std.19200" dialup on .... In a matching-speed configuration, the entry needs to reference the appropriate beginning "auto-baud" entry in [.filename]#/etc/gettytab#. To continue the example for a matching-speed modem that starts at 19.2 Kbps, use this entry: [.programlisting] .... ttyu0 "/usr/libexec/getty V19200" dialup on .... After editing [.filename]#/etc/ttys#, wait until the modem is properly configured and connected before signaling `init`: [source,shell] .... # kill -HUP 1 .... High-speed modems, like V.32, V.32bis, and V.34 modems, use hardware (`RTS/CTS`) flow control. Use `stty` to set the hardware flow control flag for the modem port. This example sets the `crtscts` flag on [.filename]#COM2#'s dial-in and dial-out initialization devices: [source,shell] .... # stty -f /dev/ttyu1.init crtscts # stty -f /dev/cuau1.init crtscts .... === Troubleshooting This section provides a few tips for troubleshooting a dial-up modem that will not connect to a FreeBSD system. Hook up the modem to the FreeBSD system and boot the system. If the modem has status indication lights, watch to see whether the modem's DTR indicator lights when the `login:` prompt appears on the system's console. If it lights up, that should mean that FreeBSD has started a `getty` process on the appropriate communications port and is waiting for the modem to accept a call. If the DTR indicator does not light, login to the FreeBSD system through the console and type `ps ax` to see if FreeBSD is running a `getty` process on the correct port: [source,shell] .... 114 ?? I 0:00.10 /usr/libexec/getty V19200 ttyu0 .... If the second column contains a `d0` instead of a `??` and the modem has not accepted a call yet, this means that `getty` has completed its open on the communications port. This could indicate a problem with the cabling or a misconfigured modem because `getty` should not be able to open the communications port until the carrier detect signal has been asserted by the modem. If no `getty` processes are waiting to open the port, double-check that the entry for the port is correct in [.filename]#/etc/ttys#. Also, check [.filename]#/var/log/messages# to see if there are any log messages from `init` or `getty`. Next, try dialing into the system. Be sure to use 8 bits, no parity, and 1 stop bit on the remote system. If a prompt does not appear right away, or the prompt shows garbage, try pressing kbd:[Enter] about once per second. If there is still no `login:` prompt, try sending a `BREAK`. When using a high-speed modem, try dialing again after locking the dialing modem's interface speed. If there is still no `login:` prompt, check [.filename]#/etc/gettytab# again and double-check that: * The initial capability name specified in the entry in [.filename]#/etc/ttys# matches the name of a capability in [.filename]#/etc/gettytab#. * Each `nx=` entry matches another [.filename]#gettytab# capability name. * Each `tc=` entry matches another [.filename]#gettytab# capability name. If the modem on the FreeBSD system will not answer, make sure that the modem is configured to answer the phone when DTR is asserted. If the modem seems to be configured correctly, verify that the DTR line is asserted by checking the modem's indicator lights. If it still does not work, try sending an email to the {freebsd-questions} describing the modem and the problem. [[dialout]] == Dial-out Service The following are tips for getting the host to connect over the modem to another computer. This is appropriate for establishing a terminal session with a remote host. This kind of connection can be helpful to get a file on the Internet if there are problems using PPP. If PPP is not working, use the terminal session to FTP the needed file. Then use zmodem to transfer it to the machine. [[hayes-unsupported]] === Using a Stock Hayes Modem A generic Hayes dialer is built into `tip`. Use `at=hayes` in [.filename]#/etc/remote#. The Hayes driver is not smart enough to recognize some of the advanced features of newer modems messages like `BUSY`, `NO DIALTONE`, or `CONNECT 115200`. Turn those messages off when using `tip` with `ATX0&W`. The dial timeout for `tip` is 60 seconds. The modem should use something less, or else `tip` will think there is a communication problem. Try `ATS7=45&W`. [[direct-at]] === Using `AT` Commands Create a "direct" entry in [.filename]#/etc/remote#. For example, if the modem is hooked up to the first serial port, [.filename]#/dev/cuau0#, use the following line: [.programlisting] .... cuau0:dv=/dev/cuau0:br#19200:pa=none .... Use the highest bps rate the modem supports in the `br` capability. Then, type `tip cuau0` to connect to the modem. Or, use `cu` as `root` with the following command: [source,shell] .... # cu -lline -sspeed .... _line_ is the serial port, such as [.filename]#/dev/cuau0#, and _speed_ is the speed, such as `57600`. When finished entering the AT commands, type `~.` to exit. [[gt-failure]] === The `@` Sign Does Not Work The `@` sign in the phone number capability tells `tip` to look in [.filename]#/etc/phones# for a phone number. But, the `@` sign is also a special character in capability files like [.filename]#/etc/remote#, so it needs to be escaped with a backslash: [.programlisting] .... pn=\@ .... [[dial-command-line]] === Dialing from the Command Line Put a "generic" entry in [.filename]#/etc/remote#. For example: [.programlisting] .... tip115200|Dial any phone number at 115200 bps:\ :dv=/dev/cuau0:br#115200:at=hayes:pa=none:du: tip57600|Dial any phone number at 57600 bps:\ :dv=/dev/cuau0:br#57600:at=hayes:pa=none:du: .... This should now work: [source,shell] .... # tip -115200 5551234 .... Users who prefer `cu` over `tip`, can use a generic `cu` entry: [.programlisting] .... cu115200|Use cu to dial any number at 115200bps:\ :dv=/dev/cuau1:br#57600:at=hayes:pa=none:du: .... and type: [source,shell] .... # cu 5551234 -s 115200 .... [[set-bps]] === Setting the bps Rate Put in an entry for `tip1200` or `cu1200`, but go ahead and use whatever bps rate is appropriate with the `br` capability. `tip` thinks a good default is 1200 bps which is why it looks for a `tip1200` entry. 1200 bps does not have to be used, though. [[terminal-server]] === Accessing a Number of Hosts Through a Terminal Server Rather than waiting until connected and typing `CONNECT _host_` each time, use ``tip``'s `cm` capability. For example, these entries in [.filename]#/etc/remote# will let you type `tip pain` or `tip muffin` to connect to the hosts `pain` or `muffin`, and `tip deep13` to connect to the terminal server. [.programlisting] .... pain|pain.deep13.com|Forrester's machine:\ :cm=CONNECT pain\n:tc=deep13: muffin|muffin.deep13.com|Frank's machine:\ :cm=CONNECT muffin\n:tc=deep13: deep13:Gizmonics Institute terminal server:\ :dv=/dev/cuau2:br#38400:at=hayes:du:pa=none:pn=5551234: .... [[tip-multiline]] === Using More Than One Line with `tip` This is often a problem where a university has several modem lines and several thousand students trying to use them. Make an entry in [.filename]#/etc/remote# and use `@` for the `pn` capability: [.programlisting] .... big-university:\ :pn=\@:tc=dialout dialout:\ :dv=/dev/cuau3:br#9600:at=courier:du:pa=none: .... Then, list the phone numbers in [.filename]#/etc/phones#: [.programlisting] .... big-university 5551111 big-university 5551112 big-university 5551113 big-university 5551114 .... `tip` will try each number in the listed order, then give up. To keep retrying, run `tip` in a `while` loop. [[multi-controlp]] === Using the Force Character kbd:[Ctrl+P] is the default "force" character, used to tell `tip` that the next character is literal data. The force character can be set to any other character with the `~s` escape, which means "set a variable." Type `~sforce=_single-char_` followed by a newline. _single-char_ is any single character. If _single-char_ is left out, then the force character is the null character, which is accessed by typing kbd:[Ctrl+2] or kbd:[Ctrl+Space]. A pretty good value for _single-char_ is kbd:[Shift+Ctrl+6], which is only used on some terminal servers. To change the force character, specify the following in [.filename]#~/.tiprc#: [.programlisting] .... force=single-char .... [[uppercase]] === Upper Case Characters This happens when kbd:[Ctrl+A] is pressed, which is ``tip``'s "raise character", specially designed for people with broken caps-lock keys. Use `~s` to set `raisechar` to something reasonable. It can be set to be the same as the force character, if neither feature is used. Here is a sample [.filename]#~/.tiprc# for Emacs users who need to type kbd:[Ctrl+2] and kbd:[Ctrl+A]: [.programlisting] .... force=^^ raisechar=^^ .... The `^^` is kbd:[Shift+Ctrl+6]. [[tip-filetransfer]] === File Transfers with `tip` When talking to another UNIX(R)-like operating system, files can be sent and received using `~p` (put) and `~t` (take). These commands run `cat` and `echo` on the remote system to accept and send files. The syntax is: `~p` local-file [ remote-file ] `~t` remote-file [ local-file ] There is no error checking, so another protocol, like zmodem, should probably be used. [[zmodem-tip]] === Using zmodem with `tip`? To receive files, start the sending program on the remote end. Then, type `~C rz` to begin receiving them locally. To send files, start the receiving program on the remote end. Then, type `~C sz _files_` to send them to the remote system. [[serialconsole-setup]] == Setting Up the Serial Console FreeBSD has the ability to boot a system with a dumb terminal on a serial port as a console. This configuration is useful for system administrators who wish to install FreeBSD on machines that have no keyboard or monitor attached, and developers who want to debug the kernel or device drivers. As described in crossref:boot[boot,The FreeBSD Booting Process], FreeBSD employs a three stage bootstrap. The first two stages are in the boot block code which is stored at the beginning of the FreeBSD slice on the boot disk. The boot block then loads and runs the boot loader as the third stage code. In order to set up booting from a serial console, the boot block code, the boot loader code, and the kernel need to be configured. [[serialconsole-howto-fast]] === Quick Serial Console Configuration This section provides a fast overview of setting up the serial console. This procedure can be used when the dumb terminal is connected to [.filename]#COM1#. [.procedure] .Procedure: Configuring a Serial Console on [.filename]#COM1# . Connect the serial cable to [.filename]#COM1# and the controlling terminal. . To configure boot messages to display on the serial console, issue the following command as the superuser: + [source,shell] .... # echo 'console="comconsole"' >> /boot/loader.conf .... . Edit [.filename]#/etc/ttys# and change `off` to `on` and `dialup` to `vt100` for the [.filename]#ttyu0# entry. Otherwise, a password will not be required to connect via the serial console, resulting in a potential security hole. . Reboot the system to see if the changes took effect. If a different configuration is required, see the next section for a more in-depth configuration explanation. [[serialconsole-howto]] === In-Depth Serial Console Configuration This section provides a more detailed explanation of the steps needed to setup a serial console in FreeBSD. [.procedure] .Procedure: Configuring a Serial Console . Prepare a serial cable. + Use either a null-modem cable or a standard serial cable and a null-modem adapter. -See crossref:serialcomms[term-cables-null] for a discussion on serial cables. +See crossref:serialcomms[term-cables-null, Serial Cables and Ports] for a discussion on serial cables. . Unplug the keyboard. + Many systems probe for the keyboard during the Power-On Self-Test (POST) and will generate an error if the keyboard is not detected. Some machines will refuse to boot until the keyboard is plugged in. + If the computer complains about the error, but boots anyway, no further configuration is needed. + If the computer refuses to boot without a keyboard attached, configure the BIOS so that it ignores this error. Consult the motherboard's manual for details on how to do this. + [TIP] ==== Try setting the keyboard to "Not installed" in the BIOS. This setting tells the BIOS not to probe for a keyboard at power-on so it should not complain if the keyboard is absent. If that option is not present in the BIOS, look for an "Halt on Error" option instead. Setting this to "All but Keyboard" or to "No Errors" will have the same effect. ==== + If the system has a PS/2(R) mouse, unplug it as well. PS/2(R) mice share some hardware with the keyboard and leaving the mouse plugged in can fool the keyboard probe into thinking the keyboard is still there. + [NOTE] ==== While most systems will boot without a keyboard, quite a few will not boot without a graphics adapter. Some systems can be configured to boot with no graphics adapter by changing the "graphics adapter" setting in the BIOS configuration to "Not installed". Other systems do not support this option and will refuse to boot if there is no display hardware in the system. With these machines, leave some kind of graphics card plugged in, even if it is just a junky mono board. A monitor does not need to be attached. ==== . Plug a dumb terminal, an old computer with a modem program, or the serial port on another UNIX(R) box into the serial port. . Add the appropriate `hint.uart.*` entries to [.filename]#/boot/device.hints# for the serial port. Some multi-port cards also require kernel configuration options. Refer to man:uart[4] for the required options and device hints for each supported serial port. . Create [.filename]#boot.config# in the root directory of the `a` partition on the boot drive. + This file instructs the boot block code how to boot the system. In order to activate the serial console, one or more of the following options are needed. When using multiple options, include them all on the same line: + `-h`::: Toggles between the internal and serial consoles. Use this to switch console devices. For instance, to boot from the internal (video) console, use `-h` to direct the boot loader and the kernel to use the serial port as its console device. Alternatively, to boot from the serial port, use `-h` to tell the boot loader and the kernel to use the video display as the console instead. `-D`::: Toggles between the single and dual console configurations. In the single configuration, the console will be either the internal console (video display) or the serial port, depending on the state of `-h`. In the dual console configuration, both the video display and the serial port will become the console at the same time, regardless of the state of `-h`. However, the dual console configuration takes effect only while the boot block is running. Once the boot loader gets control, the console specified by `-h` becomes the only console. `-P`::: Makes the boot block probe the keyboard. If no keyboard is found, the `-D` and `-h` options are automatically set. + [NOTE] ==== Due to space constraints in the current version of the boot blocks, `-P` is capable of detecting extended keyboards only. Keyboards with less than 101 keys and without F11 and F12 keys may not be detected. Keyboards on some laptops may not be properly found because of this limitation. If this is the case, do not use `-P`. ==== + Use either `-P` to select the console automatically or `-h` to activate the serial console. Refer to man:boot[8] and man:boot.config[5] for more details. + The options, except for `-P`, are passed to the boot loader. The boot loader will determine whether the internal video or the serial port should become the console by examining the state of `-h`. This means that if `-D` is specified but `-h` is not specified in [.filename]#/boot.config#, the serial port can be used as the console only during the boot block as the boot loader will use the internal video display as the console. . Boot the machine. + When FreeBSD starts, the boot blocks echo the contents of [.filename]#/boot.config# to the console. For example: + [source,shell] .... /boot.config: -P Keyboard: no .... + The second line appears only if `-P` is in [.filename]#/boot.config# and indicates the presence or absence of the keyboard. These messages go to either the serial or internal console, or both, depending on the option in [.filename]#/boot.config#: + [.informaltable] [cols="1,1", frame="none", options="header"] |=== <| Options <| Message goes to |none |internal console |`-h` |serial console |`-D` |serial and internal consoles |`-Dh` |serial and internal consoles |`-P`, keyboard present |internal console |`-P`, keyboard absent |serial console |=== + After the message, there will be a small pause before the boot blocks continue loading the boot loader and before any further messages are printed to the console. Under normal circumstances, there is no need to interrupt the boot blocks, but one can do so in order to make sure things are set up correctly. + Press any key, other than kbd:[Enter], at the console to interrupt the boot process. The boot blocks will then prompt for further action: + [source,shell] .... >> FreeBSD/i386 BOOT Default: 0:ad(0,a)/boot/loader boot: .... + Verify that the above message appears on either the serial or internal console, or both, according to the options in [.filename]#/boot.config#. If the message appears in the correct console, press kbd:[Enter] to continue the boot process. + If there is no prompt on the serial terminal, something is wrong with the settings. Enter `-h` then kbd:[Enter] or kbd:[Return] to tell the boot block (and then the boot loader and the kernel) to choose the serial port for the console. Once the system is up, go back and check what went wrong. During the third stage of the boot process, one can still switch between the internal console and the serial console by setting appropriate environment variables in the boot loader. See man:loader[8] for more information. [NOTE] ==== This line in [.filename]#/boot/loader.conf# or [.filename]#/boot/loader.conf.local# configures the boot loader and the kernel to send their boot messages to the serial console, regardless of the options in [.filename]#/boot.config#: [.programlisting] .... console="comconsole" .... That line should be the first line of [.filename]#/boot/loader.conf# so that boot messages are displayed on the serial console as early as possible. If that line does not exist, or if it is set to `console="vidconsole"`, the boot loader and the kernel will use whichever console is indicated by `-h` in the boot block. See man:loader.conf[5] for more information. At the moment, the boot loader has no option equivalent to `-P` in the boot block, and there is no provision to automatically select the internal console and the serial console based on the presence of the keyboard. ==== [TIP] ==== While it is not required, it is possible to provide a `login` prompt over the serial line. To configure this, edit the entry for the serial port in [.filename]#/etc/ttys# -using the instructions in crossref:serialcomms[term-config]. +using the instructions in crossref:serialcomms[term-config, Terminal Configuration]. If the speed of the serial port has been changed, change `std.115200` to match the new setting. ==== === Setting a Faster Serial Port Speed By default, the serial port settings are 115200 baud, 8 bits, no parity, and 1 stop bit. To change the default console speed, use one of the following options: * Edit [.filename]#/etc/make.conf# and set `BOOT_COMCONSOLE_SPEED` to the new console speed. Then, recompile and install the boot blocks and the boot loader: + [source,shell] .... # cd /sys/boot # make clean # make # make install .... + If the serial console is configured in some other way than by booting with `-h`, or if the serial console used by the kernel is different from the one used by the boot blocks, add the following option, with the desired speed, to a custom kernel configuration file and compile a new kernel: + [.programlisting] .... options CONSPEED=19200 .... * Add the `-S__19200__` boot option to [.filename]#/boot.config#, replacing `_19200_` with the speed to use. * Add the following options to [.filename]#/boot/loader.conf#. Replace `_115200_` with the speed to use. + [.programlisting] .... boot_multicons="YES" boot_serial="YES" comconsole_speed="115200" console="comconsole,vidconsole" .... [[serialconsole-ddb]] === Entering the DDB Debugger from the Serial Line To configure the ability to drop into the kernel debugger from the serial console, add the following options to a custom kernel configuration file and compile the kernel using the instructions in crossref:kernelconfig[kernelconfig,Configuring the FreeBSD Kernel]. Note that while this is useful for remote diagnostics, it is also dangerous if a spurious BREAK is generated on the serial port. Refer to man:ddb[4] and man:ddb[8] for more information about the kernel debugger. [.programlisting] .... options BREAK_TO_DEBUGGER options DDB .... diff --git a/documentation/content/en/books/handbook/x11/_index.adoc b/documentation/content/en/books/handbook/x11/_index.adoc index eba545b496..8bad3e2d7d 100644 --- a/documentation/content/en/books/handbook/x11/_index.adoc +++ b/documentation/content/en/books/handbook/x11/_index.adoc @@ -1,828 +1,828 @@ --- title: Chapter 5. The X Window System part: Part I. Getting Started prev: books/handbook/ports next: books/handbook/wayland description: This chapter describes how to install and configure Xorg on FreeBSD, which provides the open source X Window System used to provide a graphical environment tags: ["X11", "Xorg", "TrueType", "Intel", "AMD", "NVIDIA", "Anti-Aliased", "VESA", "SCFB"] showBookMenu: true weight: 7 path: "/books/handbook/x11/" --- [[x11]] = The X Window System :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 5 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/x11/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[x11-synopsis]] == Synopsis An installation of FreeBSD using bsdinstall does not automatically install a graphical user interface. This chapter describes how to install and configure Xorg, which provides the open source X Window System used to provide a graphical environment. It then describes how to find and install a desktop environment or window manager. Before reading this chapter, you should: * Know how to install additional third-party software as described in crossref:ports[ports,Installing Applications: Packages and Ports]. After reading this chapter, you will know: * The various components of the X Window System, and how they interoperate. * How to install and configure Xorg. * How to use TrueType(R) fonts in Xorg. * How to set up your system for graphical logins (XDM). [[x-install]] == Installing Xorg On FreeBSD, Xorg can be installed as a package or port. The binary meta package can be installed quickly but with fewer options for customization: [source,shell] .... # pkg install xorg .... Either of these installations results in the complete Xorg system being installed. The current user must be a member of the `video` group. To add a user to `video` group, execute the following command: [source,shell] .... # pw groupmod video -m username .... [TIP] ==== A smaller version of the X system suitable for experienced users is available in package:x11/xorg-minimal[]. Most of the documents, libraries, and applications will not be installed. Some applications require these additional components to function. ==== [TIP] ==== Video cards, monitors, and input devices are automatically detected and do not require any manual configuration. Do not create `xorg.conf` or run a `-configure` step unless automatic configuration fails. ==== [[x-graphic-card-drivers]] == Graphic card drivers The following table shows the different graphics cards supported by FreeBSD, which package should be installed and its corresponding module. .Graphic card packages [options="header", cols="1,1,1,1"] |=== | Brand | Type | Package | Module | Intel(R) | Open Source | drm-kmod | `i915kms` | AMD(R) | Open Source | drm-kmod | `amdgpu` and `radeonkms` | NVIDIA(R) | Proprietary | nvidia-driver | `nvidia` or `nvidia-modeset` | VESA | Open Source | xf86-video-vesa | vesa | SCFB | Open Source | xf86-video-scfb | scfb | VirtualBox(R) | Open Source | virtualbox-ose-additions | VirtualBox(R) OSE additions include the `vboxvideo` driver. | VMware(R) | Open Source | xf86-video-vmware | vmwgfx |=== The following command can be used to identify which graphics card is installed in the system: [source,shell] .... % pciconf -lv|grep -B4 VGA .... The output should be similar to the following: [.programlisting] .... vgapci0@pci0:0:2:0: class=0x030000 rev=0x07 hdr=0x00 vendor=0x8086 device=0x2a42 subvendor=0x17aa subdevice=0x20e4 vendor = 'Intel Corporation' device = 'Mobile 4 Series Chipset Integrated Graphics Controller' class = display subclass = VGA .... [WARNING] ==== If the graphics card is not supported by Intel(R), AMD(R) or NVIDIA(R) drivers, then VESA or SCFB modules should be used. VESA module must be used when booting in BIOS mode and SCFB module must be used when booting in UEFI mode. This command can be used to check the booting mode: [source,shell] .... % sysctl machdep.bootmethod .... The output should be similar to the following: [.programlisting] .... machdep.bootmethod: BIOS .... ==== [[x-configuration-intel]] === Intel(R) Intel(R) Graphics refers to the class of graphics chips that are integrated on the same die as an Intel(R) CPU. Wikipedia offers link:https://en.wikipedia.org/wiki/List_of_Intel_graphics_processing_units[a good overview of the variations and names used for generations of Intel HD Graphics]. The package:graphics/drm-kmod[] package indirectly provides a range of kernel modules for use with Intel(R) Graphics cards. The Intel(R) driver can be installed by executing the following command: [source,shell] .... # pkg install drm-kmod .... Then add the module to `/etc/rc.conf` file, executing the following command: [source,shell] .... # sysrc kld_list+=i915kms .... [TIP] ==== If a high CPU usage is noticed or excessive tearing with HD video, the installation of package:multimedia/libva-intel-driver[] may help. To install the package execute the following command: [source,shell] .... # pkg install libva-intel-driver mesa-libs mesa-dri .... ==== [[x-configuration-amd]] === AMD(R) The package:graphics/drm-kmod[] package indirectly provides a range of kernel modules for use with AMD(R) Graphics cards. The modules `amdgpu` and `radeonkms` can be used depending the generation of the hardware. The FreeBSD project maintains an link:https://wiki.freebsd.org/Graphics/AMD-GPU-Matrix[AMD graphics support matrix to determine which driver must be used]. AMD(R) driver can be installed by executing the following command: [source,shell] .... # pkg install drm-kmod .... For post-HD7000 or Tahiti graphic cards add the module to `/etc/rc.conf` file, executing the following command: [source,shell] .... # sysrc kld_list+=amdgpu .... For older graphic cards (pre-HD7000 or pre-Tahiti) add the module to `/etc/rc.conf` file, executing the following command: [source,shell] .... # sysrc kld_list+=radeonkms .... [[x-configuration-nvidia]] === NVIDIA(R) FreeBSD supports different versions of the proprietary NVIDIA(R) driver. Users of newer graphics cards should install the package:x11/nvidia-driver[] package. Those with older cards will have to check below which version supports them. .Supported versions of NVIDIA(R) drivers [options="header", cols="1,1"] |=== | Package | Supported hardware | x11/nvidia-driver-304 | link:https://www.nvidia.com/Download/driverResults.aspx/123712/en-us/[supported hardware] | x11/nvidia-driver-340 | link:https://www.nvidia.com/Download/driverResults.aspx/156167/en-us/[supported hardware] | x11/nvidia-driver-390 | link:https://www.nvidia.com/Download/driverResults.aspx/191122/en-us/[supported hardware] | x11/nvidia-driver-470 | link:https://www.nvidia.com/Download/driverResults.aspx/194639/en-us/[supported hardware] | x11/nvidia-driver | link:https://www.nvidia.com/Download/driverResults.aspx/210651/en-us/[supported hardware] |=== [WARNING] ==== Version 304 of the NVIDIA(R) graphics driver (nvidia-driver-304) does not support xorg-server 1.20 or later. ==== The latest NVIDIA(R) driver can be installed by running the following command: [source,shell] .... # pkg install nvidia-driver .... Then add the module to `/etc/rc.conf` file, executing the following command: [source,shell] .... # sysrc kld_list+=nvidia-modeset .... [WARNING] ==== The `nvidia` driver must be used if the packages x11/nvidia-driver-304 or x11/nvidia-driver-340 have been installed. [source,shell] .... # sysrc kld_list+=nvidia .... ==== [[x-config]] == Xorg Configuration Xorg supports most common video cards, keyboards, and pointing devices. [WARNING] ==== Video cards, monitors, and input devices are automatically detected and do not require any manual configuration. Do not create [.filename]#xorg.conf# or run a `Xorg -configure` step unless automatic configuration fails. ==== [[x-config-files]] === Configuration Files Xorg looks in several directories for configuration files. [.filename]#/usr/local/etc/X11/# is the *recommended* directory for these files on FreeBSD. Using this directory helps keep application files separate from operating system files. [[x-config-files-single-or-multi]] === Single or Multiple Files It is easier to use multiple files that each configure a specific setting than the traditional single [.filename]#xorg.conf#. These files are stored in the [.filename]#/usr/local/etc/X11/xorg.conf.d/# subdirectory. [TIP] ==== The traditional single [.filename]#xorg.conf# still works, but is neither as clear nor as flexible as multiple files in the [.filename]#/usr/local/etc/X11/xorg.conf.d/# subdirectory. ==== [[x-config-video-cards]] === Video Cards The driver for the graphics card can be specified in the [.filename]#/usr/local/etc/X11/xorg.conf.d/# directory. To configure the Intel(R) driver in a configuration file: [[x-config-video-cards-file-intel]] .Select Intel(R) Video Driver in a File [example] ==== [.filename]#/usr/local/etc/X11/xorg.conf.d/20-intel.conf# [.programlisting] .... Section "Device" Identifier "Card0" Driver "intel" EndSection .... ==== To configure the AMD(R) driver in a configuration file: [[x-config-video-cards-file-amd]] .Select AMD(R) Video Driver in a File [example] ==== [.filename]#/usr/local/etc/X11/xorg.conf.d/20-radeon.conf# [.programlisting] .... Section "Device" Identifier "Card0" Driver "radeon" EndSection .... ==== To configure the NVIDIA(R) driver in a configuration file: [[x-config-video-cards-file-nvidia]] .Select NVIDIA(R) Video Driver in a File [example] ==== [.filename]#/usr/local/etc/X11/xorg.conf.d/20-nvidia.conf# [.programlisting] .... Section "Device" Identifier "Card0" Driver "nvidia" EndSection .... ==== [TIP] ==== package:x11/nvidia-xconfig[] can also be used to perform basic control over configuration options available in the NVIDIA driver. ==== To configure the VESA driver in a configuration file: [[x-config-video-cards-file-vesa]] .Select VESA Video Driver in a File [example] ==== [.filename]#/usr/local/etc/X11/xorg.conf.d/20-vesa.conf# [.programlisting] .... Section "Device" Identifier "Card0" Driver "vesa" EndSection .... ==== To configure the SCFB driver in a configuration file: [[x-config-video-cards-file-sfcb]] .Select SCFB Video Driver in a File [example] ==== [.filename]#/usr/local/etc/X11/xorg.conf.d/20-scfb.conf# [.programlisting] .... Section "Device" Identifier "Card0" Driver "scfb" EndSection .... ==== To configure multiple video cards, the `BusID` can be added. A list of video card bus ``ID``s can be displayed by executing: [source,shell] .... % pciconf -lv | grep -B3 display .... The output should be similar to the following: [.programlisting] .... vgapci0@pci0:0:2:0: class=0x030000 rev=0x07 hdr=0x00 vendor=0x8086 device=0x2a42 subvendor=0x17aa subdevice=0x20e4 vendor = 'Intel Corporation' device = 'Mobile 4 Series Chipset Integrated Graphics Controller' class = display -- vgapci1@pci0:0:2:1: class=0x038000 rev=0x07 hdr=0x00 vendor=0x8086 device=0x2a43 subvendor=0x17aa subdevice=0x20e4 vendor = 'Intel Corporation' device = 'Mobile 4 Series Chipset Integrated Graphics Controller' class = display .... [[x-config-video-cards-file-multiple]] .Select Intel(R) Video Driver and NVIDIA(R) Video Driver in a File [example] ==== [.filename]#/usr/local/etc/X11/xorg.conf.d/20-drivers.conf# [.programlisting] .... Section "Device" Identifier "Card0" Driver "intel" BusID "pci0:0:2:0" EndSection Section "Device" Identifier "Card0" Driver "nvidia" BusID "pci0:0:2:1" EndSection .... ==== [[x-config-monitors]] === Monitors Almost all monitors support the Extended Display Identification Data standard (`EDID`). Xorg uses `EDID` to communicate with the monitor and detect the supported resolutions and refresh rates. Then it selects the most appropriate combination of settings to use with that monitor. Other resolutions supported by the monitor can be chosen by setting the desired resolution in configuration files, or after the X server has been started with man:xrandr[1]. [[x-config-monitors-xrandr]] ==== Using RandR (Resize and Rotate) Run man:xrandr[1] without any parameters to see a list of video outputs and detected monitor modes: [source,shell] .... % xrandr .... The output should be similar to the following: [.programlisting] .... Screen 0: minimum 320 x 200, current 2560 x 960, maximum 8192 x 8192 LVDS-1 connected 1280x800+0+0 (normal left inverted right x axis y axis) 261mm x 163mm 1280x800 59.99*+ 59.81 59.91 50.00 1280x720 59.86 59.74 1024x768 60.00 1024x576 59.90 59.82 960x540 59.63 59.82 800x600 60.32 56.25 864x486 59.92 59.57 640x480 59.94 720x405 59.51 58.99 640x360 59.84 59.32 VGA-1 connected primary 1280x960+1280+0 (normal left inverted right x axis y axis) 410mm x 257mm 1280x1024 75.02 60.02 1440x900 74.98 60.07 1280x960 60.00* 1280x800 74.93 59.81 1152x864 75.00 1024x768 75.03 70.07 60.00 832x624 74.55 800x600 72.19 75.00 60.32 56.25 640x480 75.00 72.81 66.67 59.94 720x400 70.08 HDMI-1 disconnected (normal left inverted right x axis y axis) DP-1 disconnected (normal left inverted right x axis y axis) HDMI-2 disconnected (normal left inverted right x axis y axis) DP-2 disconnected (normal left inverted right x axis y axis) DP-3 disconnected (normal left inverted right x axis y axis) .... This shows that the `VGA-1` output is being used to display a screen resolution of 1280x960 pixels at a refresh rate of about 60 Hz. The `LVDS-1` is being used as a secondary monitor to display a screen resolution of 1280x800 pixels at a refresh rate of about 60 Hz. Monitors are not attached to the `HDMI-1`, `HDMI-2`, `DP-1`, `DP-2` and `DP-3` connectors. Any of the other display modes can be selected with man:xrandr[1]. For example, to switch to 1280x1024 at 60 Hz: [source,shell] .... % xrandr --output LVDS-1 --mode 1280x720 --rate 60 .... [[x-config-monitors-files]] ==== Using the Xorg configuration file The monitor configuration can also be set in a configuration file. To set a screen resolution of 1024x768 in a configuration file: .Set Screen Resolution in a File [example] ==== [.filename]#/usr/local/etc/X11/xorg.conf.d/10-monitor.conf# [.programlisting] .... Section "Screen" Identifier "Screen0" Device "Card0" SubSection "Display" Modes "1024x768" EndSubSection EndSection .... ==== [[x-config-input]] === Input Devices Xorg supports the vast majority of input devices via package:x11/libinput[]. [TIP] ==== Some desktop environments (such as KDE Plasma) provide a graphical UI for setting these parameters. Check if this is the case before resorting to manual configuration editing. ==== [[x-config-input-keyboard-layout]] For example, to configure the keyboard layout: .Setting a Keyboard Layout [example] ==== [.filename]#/usr/local/etc/X11/xorg.conf.d/00-keyboard.conf# [.programlisting] .... Section "InputClass" Identifier "Keyboard1" MatchIsKeyboard "on" Option "XkbLayout" "es, fr" Option "XkbModel" "pc104" Option "XkbVariant" ",qwerty" Option "XkbOptions" "grp:win_space_toggle" EndSection .... ==== [[x-fonts]] == Using Fonts in Xorg The default fonts that ship with Xorg are less than ideal for typical desktop publishing applications. Large presentation fonts show up jagged and unprofessional looking, and small fonts are almost completely unintelligible. However, there are several free, high quality Type1 (PostScript(R)) fonts available which can be readily used with Xorg. [[type1]] === Type1 Fonts The URW font collection (package:x11-fonts/urwfonts[]) includes high quality versions of standard type1 fonts (Times Roman(TM), Helvetica(TM), Palatino(TM) and others). The Freefonts collection (package:x11-fonts/freefonts[]) includes many more fonts, but most of them are intended for use in graphics software such as the Gimp, and are not complete enough to serve as screen fonts. In addition, Xorg can be configured to use TrueType(R) fonts with a minimum of effort. -For more details on this, see the man:X[7] manual page or crossref:x11[truetype]. +For more details on this, see the man:X[7] manual page or crossref:x11[truetype, TrueType(R) Fonts]. To install the above Type1 font collections from binary packages, run the following commands: [source,shell] .... # pkg install urwfonts .... And likewise with the freefont or other collections. To have the X server detect these fonts, add an appropriate line to the X server configuration file ([.filename]#/usr/local/etc/X11/xorg.conf.d/90-fonts.conf#), which reads: [.programlisting] .... Section "Files" FontPath "/usr/local/share/fonts/urwfonts/" EndSection .... Alternatively, at the command line in the X session run: [source,shell] .... % xset fp+ /usr/local/share/fonts/urwfonts % xset fp rehash .... This will work but will be lost when the X session is closed, unless it is added to the startup file ([.filename]#~/.xinitrc# for a normal `startx` session, or [.filename]#~/.xsession# when logging in through a graphical login manager like XDM). A third way is to use the new [.filename]#/usr/local/etc/fonts/local.conf# as -demonstrated in crossref:x11[antialias]. +demonstrated in crossref:x11[antialias, Anti-Aliased Fonts]. [[truetype]] === TrueType(R) Fonts Xorg has built in support for rendering TrueType(R) fonts. There are two different modules that can enable this functionality. The freetype module is used in this example because it is more consistent with the other font rendering back-ends. To enable the freetype module just add the following line to the `"Module"` section of [.filename]#/usr/local/etc/X11/xorg.conf.d/90-fonts.conf#. [.programlisting] .... Load "freetype" .... Now make a directory for the TrueType(R) fonts (for example, [.filename]#/usr/local/share/fonts/TrueType#) and copy all of the TrueType(R) fonts into this directory. Keep in mind that TrueType(R) fonts cannot be directly taken from an Apple(R) Mac(R); they must be in UNIX(R)/MS-DOS(R)/Windows(R) format for use by Xorg. Once the files have been copied into this directory, use mkfontscale to create a [.filename]#fonts.dir#, so that the X font renderer knows that these new files have been installed. `mkfontscale` can be installed as a package: [source,shell] .... # pkg install mkfontscale .... Then create an index of X font files in a directory: [source,shell] .... # cd /usr/local/share/fonts/TrueType # mkfontscale .... Now add the TrueType(R) directory to the font path. -This is just the same as described in crossref:x11[type1]: +This is just the same as described in crossref:x11[type1, Type1 Fonts]: [source,shell] .... % xset fp+ /usr/local/share/fonts/TrueType % xset fp rehash .... or add a `FontPath` line to [.filename]#xorg.conf#. Now Gimp, LibreOffice, and all of the other X applications should now recognize the installed TrueType(R) fonts. Extremely small fonts (as with text in a high resolution display on a web page) and extremely large fonts (within LibreOffice) will look much better now. [[antialias]] === Anti-Aliased Fonts All fonts in Xorg that are found in [.filename]#/usr/local/share/fonts/# and [.filename]#~/.fonts/# are automatically made available for anti-aliasing to Xft-aware applications. Most recent applications are Xft-aware, including KDE, GNOME, and Firefox. To control which fonts are anti-aliased, or to configure anti-aliasing properties, create (or edit, if it already exists) the file [.filename]#/usr/local/etc/fonts/local.conf#. Several advanced features of the Xft font system can be tuned using this file; this section describes only some simple possibilities. For more details, please see man:fonts-conf[5]. This file must be in XML format. Pay careful attention to case, and make sure all tags are properly closed. The file begins with the usual XML header followed by a DOCTYPE definition, and then the `` tag: [.programlisting] .... .... As previously stated, all fonts in [.filename]#/usr/local/share/fonts/# as well as [.filename]#~/.fonts/# are already made available to Xft-aware applications. To add another directory outside of these two directory trees, add a line like this to [.filename]#/usr/local/etc/fonts/local.conf#: [.programlisting] .... /path/to/my/fonts .... After adding new fonts, and especially new font directories, rebuild the font caches: [source,shell] .... # fc-cache -f .... Anti-aliasing makes borders slightly fuzzy, which makes very small text more readable and removes "staircases" from large text, but can cause eyestrain if applied to normal text. To exclude font sizes smaller than 14 point from anti-aliasing, include these lines: [.programlisting] .... 14 false 14 false .... Spacing for some monospaced fonts might also be inappropriate with anti-aliasing. This seems to be an issue with KDE, in particular. One possible fix is to force the spacing for such fonts to be 100. Add these lines: [.programlisting] .... fixed mono console mono .... (this aliases the other common names for fixed fonts as `"mono"`), and then add: [.programlisting] .... mono 100 .... Certain fonts, such as Helvetica, may have a problem when anti-aliased. Usually this manifests itself as a font that seems cut in half vertically. At worst, it may cause applications to crash. To avoid this, consider adding the following to [.filename]#local.conf#: [.programlisting] .... Helvetica sans-serif .... After editing [.filename]#local.conf#, make certain to end the file with the `` tag. Not doing this will cause changes to be ignored. Users can add personalized settings by creating their own [.filename]#~/.config/fontconfig/fonts.conf#. This file uses the same `XML` format described above. One last point: with an LCD screen, sub-pixel sampling may be desired. This basically treats the (horizontally separated) red, green and blue components separately to improve the horizontal resolution; the results can be dramatic. To enable this, add the line somewhere in [.filename]#local.conf#: [.programlisting] .... unknown rgb .... [NOTE] ==== Depending on the sort of display, `rgb` may need to be changed to `bgr`, `vrgb` or `vbgr`: experiment and see which works best. ==== For more information about how to install and configure fonts on FreeBSD, please read the article link:{fonts}[Fonts and FreeBSD]. diff --git a/documentation/content/en/books/handbook/zfs/_index.adoc b/documentation/content/en/books/handbook/zfs/_index.adoc index ae95e8797c..e8215f18e2 100644 --- a/documentation/content/en/books/handbook/zfs/_index.adoc +++ b/documentation/content/en/books/handbook/zfs/_index.adoc @@ -1,3033 +1,3033 @@ --- title: Chapter 22. The Z File System (ZFS) part: Part III. System Administration prev: books/handbook/geom next: books/handbook/filesystems description: ZFS is an advanced file system designed to solve major problems found in previous storage subsystem software tags: ["ZFS", "filesystem", "administration", "zpool", "features", "terminology", "RAID-Z"] showBookMenu: true weight: 26 path: "/books/handbook/zfs/" --- [[zfs]] = The Z File System (ZFS) :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 22 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/zfs/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] ZFS is an advanced file system designed to solve major problems found in previous storage subsystem software. Originally developed at Sun(TM), ongoing open source ZFS development has moved to the http://open-zfs.org[OpenZFS Project]. ZFS has three major design goals: * Data integrity: All data includes a crossref:zfs[zfs-term-checksum,checksum] of the data. ZFS calculates checksums and writes them along with the data. When reading that data later, ZFS recalculates the checksums. If the checksums do not match, meaning detecting one or more data errors, ZFS will attempt to automatically correct errors when ditto-, mirror-, or parity-blocks are available. * Pooled storage: adding physical storage devices to a pool, and allocating storage space from that shared pool. Space is available to all file systems and volumes, and increases by adding new storage devices to the pool. * Performance: caching mechanisms provide increased performance. crossref:zfs[zfs-term-arc,ARC] is an advanced memory-based read cache. ZFS provides a second level disk-based read cache with crossref:zfs[zfs-term-l2arc,L2ARC], and a disk-based synchronous write cache named crossref:zfs[zfs-term-zil,ZIL]. -A complete list of features and terminology is in crossref:zfs[zfs-term]. +A complete list of features and terminology is in crossref:zfs[zfs-term, ZFS Features and Terminology]. [[zfs-differences]] == What Makes ZFS Different More than a file system, ZFS is fundamentally different from traditional file systems. Combining the traditionally separate roles of volume manager and file system provides ZFS with unique advantages. The file system is now aware of the underlying structure of the disks. Traditional file systems could exist on a single disk alone at a time. If there were two disks then creating two separate file systems was necessary. A traditional hardware RAID configuration avoided this problem by presenting the operating system with a single logical disk made up of the space provided by physical disks on top of which the operating system placed a file system. Even with software RAID solutions like those provided by GEOM, the UFS file system living on top of the RAID believes it's dealing with a single device. ZFS' combination of the volume manager and the file system solves this and allows the creation of file systems that all share a pool of available storage. One big advantage of ZFS' awareness of the physical disk layout is that existing file systems grow automatically when adding extra disks to the pool. This new space then becomes available to the file systems. ZFS can also apply different properties to each file system. This makes it useful to create separate file systems and datasets instead of a single monolithic file system. [[zfs-quickstart]] == Quick Start Guide FreeBSD can mount ZFS pools and datasets during system initialization. To enable it, add this line to [.filename]#/etc/rc.conf#: [.programlisting] .... zfs_enable="YES" .... Then start the service: [source,shell] .... # service zfs start .... The examples in this section assume three SCSI disks with the device names [.filename]#da0#, [.filename]#da1#, and [.filename]#da2#. Users of SATA hardware should instead use [.filename]#ada# device names. [[zfs-quickstart-single-disk-pool]] === Single Disk Pool To create a simple, non-redundant pool using a single disk device: [source,shell] .... # zpool create example /dev/da0 .... To view the new pool, review the output of `df`: [source,shell] .... # df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235230 1628718 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032846 48737598 2% /usr example 17547136 0 17547136 0% /example .... This output shows creating and mounting of the `example` pool, and that is now accessible as a file system. Create files for users to browse: [source,shell] .... # cd /example # ls # touch testfile # ls -al total 4 drwxr-xr-x 2 root wheel 3 Aug 29 23:15 . drwxr-xr-x 21 root wheel 512 Aug 29 23:12 .. -rw-r--r-- 1 root wheel 0 Aug 29 23:15 testfile .... This pool is not using any advanced ZFS features and properties yet. To create a dataset on this pool with compression enabled: [source,shell] .... # zfs create example/compressed # zfs set compression=gzip example/compressed .... The `example/compressed` dataset is now a ZFS compressed file system. Try copying some large files to [.filename]#/example/compressed#. Disable compression with: [source,shell] .... # zfs set compression=off example/compressed .... To unmount a file system, use `zfs umount` and then verify with `df`: [source,shell] .... # zfs umount example/compressed # df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235232 1628716 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032864 48737580 2% /usr example 17547008 0 17547008 0% /example .... To re-mount the file system to make it accessible again, use `zfs mount` and verify with `df`: [source,shell] .... # zfs mount example/compressed # df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235234 1628714 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032864 48737580 2% /usr example 17547008 0 17547008 0% /example example/compressed 17547008 0 17547008 0% /example/compressed .... Running `mount` shows the pool and file systems: [source,shell] .... # mount /dev/ad0s1a on / (ufs, local) devfs on /dev (devfs, local) /dev/ad0s1d on /usr (ufs, local, soft-updates) example on /example (zfs, local) example/compressed on /example/compressed (zfs, local) .... Use ZFS datasets like any file system after creation. Set other available features on a per-dataset basis when needed. The example below creates a new file system called `data`. It assumes the file system contains important files and configures it to store two copies of each data block. [source,shell] .... # zfs create example/data # zfs set copies=2 example/data .... Use `df` to see the data and space usage: [source,shell] .... # df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235234 1628714 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032864 48737580 2% /usr example 17547008 0 17547008 0% /example example/compressed 17547008 0 17547008 0% /example/compressed example/data 17547008 0 17547008 0% /example/data .... Notice that all file systems in the pool have the same available space. Using `df` in these examples shows that the file systems use the space they need and all draw from the same pool. ZFS gets rid of concepts such as volumes and partitions, and allows several file systems to share the same pool. To destroy the file systems and then the pool that is no longer needed: [source,shell] .... # zfs destroy example/compressed # zfs destroy example/data # zpool destroy example .... [[zfs-quickstart-raid-z]] === RAID-Z Disks fail. One way to avoid data loss from disk failure is to use RAID. ZFS supports this feature in its pool design. RAID-Z pools require three or more disks but provide more usable space than mirrored pools. This example creates a RAID-Z pool, specifying the disks to add to the pool: [source,shell] .... # zpool create storage raidz da0 da1 da2 .... [NOTE] ==== Sun(TM) recommends that the number of devices used in a RAID-Z configuration be between three and nine. For environments requiring a single pool consisting of 10 disks or more, consider breaking it up into smaller RAID-Z groups. If two disks are available, ZFS mirroring provides redundancy if required. Refer to man:zpool[8] for more details. ==== The previous example created the `storage` zpool. This example makes a new file system called `home` in that pool: [source,shell] .... # zfs create storage/home .... Enable compression and store an extra copy of directories and files: [source,shell] .... # zfs set copies=2 storage/home # zfs set compression=gzip storage/home .... To make this the new home directory for users, copy the user data to this directory and create the appropriate symbolic links: [source,shell] .... # cp -rp /home/* /storage/home # rm -rf /home /usr/home # ln -s /storage/home /home # ln -s /storage/home /usr/home .... Users data is now stored on the freshly-created [.filename]#/storage/home#. Test by adding a new user and logging in as that user. Create a file system snapshot to roll back to later: [source,shell] .... # zfs snapshot storage/home@08-30-08 .... ZFS creates snapshots of a dataset, not a single directory or file. The `@` character is a delimiter between the file system name or the volume name. Before deleting an important directory, back up the file system, then roll back to an earlier snapshot in which the directory still exists: [source,shell] .... # zfs rollback storage/home@08-30-08 .... To list all available snapshots, run `ls` in the file system's [.filename]#.zfs/snapshot# directory. For example, to see the snapshot taken: [source,shell] .... # ls /storage/home/.zfs/snapshot .... Write a script to take regular snapshots of user data. Over time, snapshots can use up a lot of disk space. Remove the previous snapshot using the command: [source,shell] .... # zfs destroy storage/home@08-30-08 .... After testing, make [.filename]#/storage/home# the real [.filename]#/home# with this command: [source,shell] .... # zfs set mountpoint=/home storage/home .... Run `df` and `mount` to confirm that the system now treats the file system as the real [.filename]#/home#: [source,shell] .... # mount /dev/ad0s1a on / (ufs, local) devfs on /dev (devfs, local) /dev/ad0s1d on /usr (ufs, local, soft-updates) storage on /storage (zfs, local) storage/home on /home (zfs, local) # df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235240 1628708 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032826 48737618 2% /usr storage 26320512 0 26320512 0% /storage storage/home 26320512 0 26320512 0% /home .... This completes the RAID-Z configuration. Add daily status updates about the created file systems to the nightly man:periodic[8] runs by adding this line to [.filename]#/etc/periodic.conf#: [.programlisting] .... daily_status_zfs_enable="YES" .... [[zfs-quickstart-recovering-raid-z]] === Recovering RAID-Z Every software RAID has a method of monitoring its `state`. View the status of RAID-Z devices using: [source,shell] .... # zpool status -x .... If all pools are crossref:zfs[zfs-term-online,Online] and everything is normal, the message shows: [source,shell] .... all pools are healthy .... If there is a problem, perhaps a disk being in the crossref:zfs[zfs-term-offline,Offline] state, the pool state will look like this: [source,shell] .... pool: storage state: DEGRADED status: One or more devices has been taken offline by the administrator. Sufficient replicas exist for the pool to continue functioning in a degraded state. action: Online the device using 'zpool online' or replace the device with 'zpool replace'. scrub: none requested config: NAME STATE READ WRITE CKSUM storage DEGRADED 0 0 0 raidz1 DEGRADED 0 0 0 da0 ONLINE 0 0 0 da1 OFFLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors .... "OFFLINE" shows the administrator took [.filename]#da1# offline using: [source,shell] .... # zpool offline storage da1 .... Power down the computer now and replace [.filename]#da1#. Power up the computer and return [.filename]#da1# to the pool: [source,shell] .... # zpool replace storage da1 .... Next, check the status again, this time without `-x` to display all pools: [source,shell] .... # zpool status storage pool: storage state: ONLINE scrub: resilver completed with 0 errors on Sat Aug 30 19:44:11 2008 config: NAME STATE READ WRITE CKSUM storage ONLINE 0 0 0 raidz1 ONLINE 0 0 0 da0 ONLINE 0 0 0 da1 ONLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors .... In this example, everything is normal. [[zfs-quickstart-data-verification]] === Data Verification ZFS uses checksums to verify the integrity of stored data. Creating file systems automatically enables them. [WARNING] ==== Disabling Checksums is possible but _not_ recommended! Checksums take little storage space and provide data integrity. Most ZFS features will not work properly with checksums disabled. Disabling these checksums will not increase performance noticeably. ==== Verifying the data checksums (called _scrubbing_) ensures integrity of the `storage` pool with: [source,shell] .... # zpool scrub storage .... The duration of a scrub depends on the amount of data stored. Larger amounts of data will take proportionally longer to verify. Since scrubbing is I/O intensive, ZFS allows a single scrub to run at a time. After scrubbing completes, view the status with `zpool status`: [source,shell] .... # zpool status storage pool: storage state: ONLINE scrub: scrub completed with 0 errors on Sat Jan 26 19:57:37 2013 config: NAME STATE READ WRITE CKSUM storage ONLINE 0 0 0 raidz1 ONLINE 0 0 0 da0 ONLINE 0 0 0 da1 ONLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors .... Displaying the completion date of the last scrubbing helps decide when to start another. Routine scrubs help protect data from silent corruption and ensure the integrity of the pool. Refer to man:zfs[8] and man:zpool[8] for other ZFS options. [[zfs-zpool]] == `zpool` Administration ZFS administration uses two main utilities. The `zpool` utility controls the operation of the pool and allows adding, removing, replacing, and managing disks. The crossref:zfs[zfs-zfs,`zfs`] utility allows creating, destroying, and managing datasets, both crossref:zfs[zfs-term-filesystem,file systems] and crossref:zfs[zfs-term-volume,volumes]. [[zfs-zpool-create]] === Creating and Destroying Storage Pools Creating a ZFS storage pool requires permanent decisions, as the pool structure cannot change after creation. The most important decision is which types of vdevs to group the physical disks into. See the list of crossref:zfs[zfs-term-vdev,vdev types] for details about the possible options. After creating the pool, most vdev types do not allow adding disks to the vdev. The exceptions are mirrors, which allow adding new disks to the vdev, and stripes, which upgrade to mirrors by attaching a new disk to the vdev. Although adding new vdevs expands a pool, the pool layout cannot change after pool creation. Instead, back up the data, destroy the pool, and recreate it. Create a simple mirror pool: [source,shell] .... # zpool create mypool mirror /dev/ada1 /dev/ada2 # zpool status pool: mypool state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada1 ONLINE 0 0 0 ada2 ONLINE 0 0 0 errors: No known data errors .... To create more than one vdev with a single command, specify groups of disks separated by the vdev type keyword, `mirror` in this example: [source,shell] .... # zpool create mypool mirror /dev/ada1 /dev/ada2 mirror /dev/ada3 /dev/ada4 # zpool status pool: mypool state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada1 ONLINE 0 0 0 ada2 ONLINE 0 0 0 mirror-1 ONLINE 0 0 0 ada3 ONLINE 0 0 0 ada4 ONLINE 0 0 0 errors: No known data errors .... Pools can also use partitions rather than whole disks. Putting ZFS in a separate partition allows the same disk to have other partitions for other purposes. In particular, it allows adding partitions with bootcode and file systems needed for booting. This allows booting from disks that are also members of a pool. ZFS adds no performance penalty on FreeBSD when using a partition rather than a whole disk. Using partitions also allows the administrator to _under-provision_ the disks, using less than the full capacity. If a future replacement disk of the same nominal size as the original actually has a slightly smaller capacity, the smaller partition will still fit, using the replacement disk. Create a crossref:zfs[zfs-term-vdev-raidz,RAID-Z2] pool using partitions: [source,shell] .... # zpool create mypool raidz2 /dev/ada0p3 /dev/ada1p3 /dev/ada2p3 /dev/ada3p3 /dev/ada4p3 /dev/ada5p3 # zpool status pool: mypool state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 raidz2-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 ada2p3 ONLINE 0 0 0 ada3p3 ONLINE 0 0 0 ada4p3 ONLINE 0 0 0 ada5p3 ONLINE 0 0 0 errors: No known data errors .... Destroy a pool that is no longer needed to reuse the disks. Destroying a pool requires unmounting the file systems in that pool first. If any dataset is in use, the unmount operation fails without destroying the pool. Force the pool destruction with `-f`. This can cause undefined behavior in applications which had open files on those datasets. [[zfs-zpool-attach]] === Adding and Removing Devices Two ways exist for adding disks to a pool: attaching a disk to an existing vdev with `zpool attach`, or adding vdevs to the pool with `zpool add`. Some crossref:zfs[zfs-term-vdev,vdev types] allow adding disks to the vdev after creation. A pool created with a single disk lacks redundancy. It can detect corruption but can not repair it, because there is no other copy of the data. The crossref:zfs[zfs-term-copies,copies] property may be able to recover from a small failure such as a bad sector, but does not provide the same level of protection as mirroring or RAID-Z. Starting with a pool consisting of a single disk vdev, use `zpool attach` to add a new disk to the vdev, creating a mirror. Also use `zpool attach` to add new disks to a mirror group, increasing redundancy and read performance. When partitioning the disks used for the pool, replicate the layout of the first disk on to the second. Use `gpart backup` and `gpart restore` to make this process easier. Upgrade the single disk (stripe) vdev [.filename]#ada0p3# to a mirror by attaching [.filename]#ada1p3#: [source,shell] .... # zpool status pool: mypool state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 errors: No known data errors # zpool attach mypool ada0p3 ada1p3 Make sure to wait until resilvering finishes before rebooting. If you boot from pool 'mypool', you may need to update boot code on newly attached disk _ada1p3_. Assuming you use GPT partitioning and _da0_ is your new boot disk you may use the following command: gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0 # gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1 bootcode written to ada1 # zpool status pool: mypool state: ONLINE status: One or more devices is currently being resilvered. The pool will continue to function, possibly in a degraded state. action: Wait for the resilver to complete. scan: resilver in progress since Fri May 30 08:19:19 2014 527M scanned out of 781M at 47.9M/s, 0h0m to go 527M resilvered, 67.53% done config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 (resilvering) errors: No known data errors # zpool status pool: mypool state: ONLINE scan: resilvered 781M in 0h0m with 0 errors on Fri May 30 08:15:58 2014 config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 errors: No known data errors .... When adding disks to the existing vdev is not an option, as for RAID-Z, an alternative method is to add another vdev to the pool. Adding vdevs provides higher performance by distributing writes across the vdevs. Each vdev provides its own redundancy. Mixing vdev types like `mirror` and `RAID-Z` is possible but discouraged. Adding a non-redundant vdev to a pool containing mirror or RAID-Z vdevs risks the data on the entire pool. Distributing writes means a failure of the non-redundant disk will result in the loss of a fraction of every block written to the pool. ZFS stripes data across each of the vdevs. For example, with two mirror vdevs, this is effectively a RAID 10 that stripes writes across two sets of mirrors. ZFS allocates space so that each vdev reaches 100% full at the same time. Having vdevs with different amounts of free space will lower performance, as more data writes go to the less full vdev. When attaching new devices to a boot pool, remember to update the bootcode. Attach a second mirror group ([.filename]#ada2p3# and [.filename]#ada3p3#) to the existing mirror: [source,shell] .... # zpool status pool: mypool state: ONLINE scan: resilvered 781M in 0h0m with 0 errors on Fri May 30 08:19:35 2014 config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 errors: No known data errors # zpool add mypool mirror ada2p3 ada3p3 # gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada2 bootcode written to ada2 # gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada3 bootcode written to ada3 # zpool status pool: mypool state: ONLINE scan: scrub repaired 0 in 0h0m with 0 errors on Fri May 30 08:29:51 2014 config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 mirror-1 ONLINE 0 0 0 ada2p3 ONLINE 0 0 0 ada3p3 ONLINE 0 0 0 errors: No known data errors .... Removing vdevs from a pool is impossible and removal of disks from a mirror is exclusive if there is enough remaining redundancy. If a single disk remains in a mirror group, that group ceases to be a mirror and becomes a stripe, risking the entire pool if that remaining disk fails. Remove a disk from a three-way mirror group: [source,shell] .... # zpool status pool: mypool state: ONLINE scan: scrub repaired 0 in 0h0m with 0 errors on Fri May 30 08:29:51 2014 config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 ada2p3 ONLINE 0 0 0 errors: No known data errors # zpool detach mypool ada2p3 # zpool status pool: mypool state: ONLINE scan: scrub repaired 0 in 0h0m with 0 errors on Fri May 30 08:29:51 2014 config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 errors: No known data errors .... [[zfs-zpool-status]] === Checking the Status of a Pool Pool status is important. If a drive goes offline or ZFS detects a read, write, or checksum error, the corresponding error count increases. The `status` output shows the configuration and status of each device in the pool and the status of the entire pool. Actions to take and details about the last crossref:zfs[zfs-zpool-scrub,`scrub`] are also shown. [source,shell] .... # zpool status pool: mypool state: ONLINE scan: scrub repaired 0 in 2h25m with 0 errors on Sat Sep 14 04:25:50 2013 config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 raidz2-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 ada2p3 ONLINE 0 0 0 ada3p3 ONLINE 0 0 0 ada4p3 ONLINE 0 0 0 ada5p3 ONLINE 0 0 0 errors: No known data errors .... [[zfs-zpool-clear]] === Clearing Errors When detecting an error, ZFS increases the read, write, or checksum error counts. Clear the error message and reset the counts with `zpool clear _mypool_`. Clearing the error state can be important for automated scripts that alert the administrator when the pool encounters an error. Without clearing old errors, the scripts may fail to report further errors. [[zfs-zpool-replace]] === Replacing a Functioning Device It may be desirable to replace one disk with a different disk. When replacing a working disk, the process keeps the old disk online during the replacement. The pool never enters a crossref:zfs[zfs-term-degraded,degraded] state, reducing the risk of data loss. Running `zpool replace` copies the data from the old disk to the new one. After the operation completes, ZFS disconnects the old disk from the vdev. If the new disk is larger than the old disk, it may be possible to grow the zpool, using the new space. See crossref:zfs[zfs-zpool-online,Growing a Pool]. Replace a functioning device in the pool: [source,shell] .... # zpool status pool: mypool state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 errors: No known data errors # zpool replace mypool ada1p3 ada2p3 Make sure to wait until resilvering finishes before rebooting. When booting from the pool 'zroot', update the boot code on the newly attached disk 'ada2p3'. Assuming GPT partitioning is used and [.filename]#da0# is the new boot disk, use the following command: gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0 # gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada2 # zpool status pool: mypool state: ONLINE status: One or more devices is currently being resilvered. The pool will continue to function, possibly in a degraded state. action: Wait for the resilver to complete. scan: resilver in progress since Mon Jun 2 14:21:35 2014 604M scanned out of 781M at 46.5M/s, 0h0m to go 604M resilvered, 77.39% done config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 replacing-1 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 ada2p3 ONLINE 0 0 0 (resilvering) errors: No known data errors # zpool status pool: mypool state: ONLINE scan: resilvered 781M in 0h0m with 0 errors on Mon Jun 2 14:21:52 2014 config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada2p3 ONLINE 0 0 0 errors: No known data errors .... [[zfs-zpool-resilver]] === Dealing with Failed Devices When a disk in a pool fails, the vdev to which the disk belongs enters the crossref:zfs[zfs-term-degraded,degraded] state. The data is still available, but with reduced performance because ZFS computes missing data from the available redundancy. To restore the vdev to a fully functional state, replace the failed physical device. ZFS is then instructed to begin the crossref:zfs[zfs-term-resilver,resilver] operation. ZFS recomputes data on the failed device from available redundancy and writes it to the replacement device. After completion, the vdev returns to crossref:zfs[zfs-term-online,online] status. If the vdev does not have any redundancy, or if devices have failed and there is not enough redundancy to compensate, the pool enters the crossref:zfs[zfs-term-faulted,faulted] state. Unless enough devices can reconnect the pool becomes inoperative requiring a data restore from backups. When replacing a failed disk, the name of the failed disk changes to the GUID of the new disk. A new device name parameter for `zpool replace` is not required if the replacement device has the same device name. Replace a failed disk using `zpool replace`: [source,shell] .... # zpool status pool: mypool state: DEGRADED status: One or more devices could not be opened. Sufficient replicas exist for the pool to continue functioning in a degraded state. action: Attach the missing device and online it using 'zpool online'. see: http://illumos.org/msg/ZFS-8000-2Q scan: none requested config: NAME STATE READ WRITE CKSUM mypool DEGRADED 0 0 0 mirror-0 DEGRADED 0 0 0 ada0p3 ONLINE 0 0 0 316502962686821739 UNAVAIL 0 0 0 was /dev/ada1p3 errors: No known data errors # zpool replace mypool 316502962686821739 ada2p3 # zpool status pool: mypool state: DEGRADED status: One or more devices is currently being resilvered. The pool will continue to function, possibly in a degraded state. action: Wait for the resilver to complete. scan: resilver in progress since Mon Jun 2 14:52:21 2014 641M scanned out of 781M at 49.3M/s, 0h0m to go 640M resilvered, 82.04% done config: NAME STATE READ WRITE CKSUM mypool DEGRADED 0 0 0 mirror-0 DEGRADED 0 0 0 ada0p3 ONLINE 0 0 0 replacing-1 UNAVAIL 0 0 0 15732067398082357289 UNAVAIL 0 0 0 was /dev/ada1p3/old ada2p3 ONLINE 0 0 0 (resilvering) errors: No known data errors # zpool status pool: mypool state: ONLINE scan: resilvered 781M in 0h0m with 0 errors on Mon Jun 2 14:52:38 2014 config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada2p3 ONLINE 0 0 0 errors: No known data errors .... [[zfs-zpool-scrub]] === Scrubbing a Pool Routinely crossref:zfs[zfs-term-scrub,scrub] pools, ideally at least once every month. The `scrub` operation is disk-intensive and will reduce performance while running. Avoid high-demand periods when scheduling `scrub` or use crossref:zfs[zfs-advanced-tuning-scrub_delay,`vfs.zfs.scrub_delay`] to adjust the relative priority of the `scrub` to keep it from slowing down other workloads. [source,shell] .... # zpool scrub mypool # zpool status pool: mypool state: ONLINE scan: scrub in progress since Wed Feb 19 20:52:54 2014 116G scanned out of 8.60T at 649M/s, 3h48m to go 0 repaired, 1.32% done config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 raidz2-0 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 ada2p3 ONLINE 0 0 0 ada3p3 ONLINE 0 0 0 ada4p3 ONLINE 0 0 0 ada5p3 ONLINE 0 0 0 errors: No known data errors .... To cancel a scrub operation if needed, run `zpool scrub -s _mypool_`. [[zfs-zpool-selfheal]] === Self-Healing The checksums stored with data blocks enable the file system to _self-heal_. This feature will automatically repair data whose checksum does not match the one recorded on another device that is part of the storage pool. For example, a mirror configuration with two disks where one drive is starting to malfunction and cannot properly store the data any more. This is worse when the data was not accessed for a long time, as with long term archive storage. Traditional file systems need to run commands that check and repair the data like man:fsck[8]. These commands take time, and in severe cases, an administrator has to decide which repair operation to perform. When ZFS detects a data block with a mismatched checksum, it tries to read the data from the mirror disk. If that disk can provide the correct data, ZFS will give that to the application and correct the data on the disk with the wrong checksum. This happens without any interaction from a system administrator during normal pool operation. The next example shows this self-healing behavior by creating a mirrored pool of disks [.filename]#/dev/ada0# and [.filename]#/dev/ada1#. [source,shell] .... # zpool create healer mirror /dev/ada0 /dev/ada1 # zpool status healer pool: healer state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM healer ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0 ONLINE 0 0 0 ada1 ONLINE 0 0 0 errors: No known data errors # zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT healer 960M 92.5K 960M - - 0% 0% 1.00x ONLINE - .... Copy some important data to the pool to protect from data errors using the self-healing feature and create a checksum of the pool for later comparison. [source,shell] .... # cp /some/important/data /healer # zfs list NAME SIZE ALLOC FREE CAP DEDUP HEALTH ALTROOT healer 960M 67.7M 892M 7% 1.00x ONLINE - # sha1 /healer > checksum.txt # cat checksum.txt SHA1 (/healer) = 2753eff56d77d9a536ece6694bf0a82740344d1f .... Simulate data corruption by writing random data to the beginning of one of the disks in the mirror. To keep ZFS from healing the data when detected, export the pool before the corruption and import it again afterwards. [WARNING] ==== This is a dangerous operation that can destroy vital data, shown here for demonstration alone. *Do not try* it during normal operation of a storage pool. Nor should this intentional corruption example run on any disk with a file system not using ZFS on another partition in it. Do not use any other disk device names other than the ones that are part of the pool. Ensure proper backups of the pool exist and test them before running the command! ==== [source,shell] .... # zpool export healer # dd if=/dev/random of=/dev/ada1 bs=1m count=200 200+0 records in 200+0 records out 209715200 bytes transferred in 62.992162 secs (3329227 bytes/sec) # zpool import healer .... The pool status shows that one device has experienced an error. Note that applications reading data from the pool did not receive any incorrect data. ZFS provided data from the [.filename]#ada0# device with the correct checksums. To find the device with the wrong checksum, look for one whose `CKSUM` column contains a nonzero value. [source,shell] .... # zpool status healer pool: healer state: ONLINE status: One or more devices has experienced an unrecoverable error. An attempt was made to correct the error. Applications are unaffected. action: Determine if the device needs to be replaced, and clear the errors using 'zpool clear' or replace the device with 'zpool replace'. see: http://illumos.org/msg/ZFS-8000-4J scan: none requested config: NAME STATE READ WRITE CKSUM healer ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0 ONLINE 0 0 0 ada1 ONLINE 0 0 1 errors: No known data errors .... ZFS detected the error and handled it by using the redundancy present in the unaffected [.filename]#ada0# mirror disk. A checksum comparison with the original one will reveal whether the pool is consistent again. [source,shell] .... # sha1 /healer >> checksum.txt # cat checksum.txt SHA1 (/healer) = 2753eff56d77d9a536ece6694bf0a82740344d1f SHA1 (/healer) = 2753eff56d77d9a536ece6694bf0a82740344d1f .... Generate checksums before and after the intentional tampering while the pool data still matches. This shows how ZFS is capable of detecting and correcting any errors automatically when the checksums differ. Note this is possible with enough redundancy present in the pool. A pool consisting of a single device has no self-healing capabilities. That is also the reason why checksums are so important in ZFS; do not disable them for any reason. ZFS requires no man:fsck[8] or similar file system consistency check program to detect and correct this, and keeps the pool available while there is a problem. A scrub operation is now required to overwrite the corrupted data on [.filename]#ada1#. [source,shell] .... # zpool scrub healer # zpool status healer pool: healer state: ONLINE status: One or more devices has experienced an unrecoverable error. An attempt was made to correct the error. Applications are unaffected. action: Determine if the device needs to be replaced, and clear the errors using 'zpool clear' or replace the device with 'zpool replace'. see: http://illumos.org/msg/ZFS-8000-4J scan: scrub in progress since Mon Dec 10 12:23:30 2012 10.4M scanned out of 67.0M at 267K/s, 0h3m to go 9.63M repaired, 15.56% done config: NAME STATE READ WRITE CKSUM healer ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0 ONLINE 0 0 0 ada1 ONLINE 0 0 627 (repairing) errors: No known data errors .... The scrub operation reads data from [.filename]#ada0# and rewrites any data with a wrong checksum on [.filename]#ada1#, shown by the `(repairing)` output from `zpool status`. After the operation is complete, the pool status changes to: [source,shell] .... # zpool status healer pool: healer state: ONLINE status: One or more devices has experienced an unrecoverable error. An attempt was made to correct the error. Applications are unaffected. action: Determine if the device needs to be replaced, and clear the errors using 'zpool clear' or replace the device with 'zpool replace'. see: http://illumos.org/msg/ZFS-8000-4J scan: scrub repaired 66.5M in 0h2m with 0 errors on Mon Dec 10 12:26:25 2012 config: NAME STATE READ WRITE CKSUM healer ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0 ONLINE 0 0 0 ada1 ONLINE 0 0 2.72K errors: No known data errors .... After the scrubbing operation completes with all the data synchronized from [.filename]#ada0# to [.filename]#ada1#, crossref:zfs[zfs-zpool-clear,clear] the error messages from the pool status by running `zpool clear`. [source,shell] .... # zpool clear healer # zpool status healer pool: healer state: ONLINE scan: scrub repaired 66.5M in 0h2m with 0 errors on Mon Dec 10 12:26:25 2012 config: NAME STATE READ WRITE CKSUM healer ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0 ONLINE 0 0 0 ada1 ONLINE 0 0 0 errors: No known data errors .... The pool is now back to a fully working state, with all error counts now zero. [[zfs-zpool-online]] === Growing a Pool The smallest device in each vdev limits the usable size of a redundant pool. Replace the smallest device with a larger device. After completing a crossref:zfs[zfs-zpool-replace,replace] or crossref:zfs[zfs-term-resilver,resilver] operation, the pool can grow to use the capacity of the new device. For example, consider a mirror of a 1 TB drive and a 2 TB drive. The usable space is 1 TB. When replacing the 1 TB drive with another 2 TB drive, the resilvering process copies the existing data onto the new drive. As both of the devices now have 2 TB capacity, the mirror's available space grows to 2 TB. Start expansion by using `zpool online -e` on each device. After expanding all devices, the extra space becomes available to the pool. [[zfs-zpool-import]] === Importing and Exporting Pools _Export_ pools before moving them to another system. ZFS unmounts all datasets, marking each device as exported but still locked to prevent use by other disks. This allows pools to be _imported_ on other machines, other operating systems that support ZFS, and even different hardware architectures (with some caveats, see man:zpool[8]). When a dataset has open files, use `zpool export -f` to force exporting the pool. Use this with caution. The datasets are forcibly unmounted, potentially resulting in unexpected behavior by the applications which had open files on those datasets. Export a pool that is not in use: [source,shell] .... # zpool export mypool .... Importing a pool automatically mounts the datasets. If this is undesired behavior, use `zpool import -N` to prevent it. `zpool import -o` sets temporary properties for this specific import. `zpool import altroot=` allows importing a pool with a base mount point instead of the root of the file system. If the pool was last used on a different system and was not properly exported, force the import using `zpool import -f`. `zpool import -a` imports all pools that do not appear to be in use by another system. List all available pools for import: [source,shell] .... # zpool import pool: mypool id: 9930174748043525076 state: ONLINE action: The pool can be imported using its name or numeric identifier. config: mypool ONLINE ada2p3 ONLINE .... Import the pool with an alternative root directory: [source,shell] .... # zpool import -o altroot=/mnt mypool # zfs list zfs list NAME USED AVAIL REFER MOUNTPOINT mypool 110K 47.0G 31K /mnt/mypool .... [[zfs-zpool-upgrade]] === Upgrading a Storage Pool After upgrading FreeBSD, or if importing a pool from a system using an older version, manually upgrade the pool to the latest ZFS version to support newer features. Consider whether the pool may ever need importing on an older system before upgrading. Upgrading is a one-way process. Upgrade older pools is possible, but downgrading pools with newer features is not. Upgrade a v28 pool to support `Feature Flags`: [source,shell] .... # zpool status pool: mypool state: ONLINE status: The pool is formatted using a legacy on-disk format. The pool can still be used, but some features are unavailable. action: Upgrade the pool using 'zpool upgrade'. Once this is done, the pool will no longer be accessible on software that does not support feat flags. scan: none requested config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0 ONLINE 0 0 0 ada1 ONLINE 0 0 0 errors: No known data errors # zpool upgrade This system supports ZFS pool feature flags. The following pools are formatted with legacy version numbers and are upgraded to use feature flags. After being upgraded, these pools will no longer be accessible by software that does not support feature flags. VER POOL --- ------------ 28 mypool Use 'zpool upgrade -v' for a list of available legacy versions. Every feature flags pool has all supported features enabled. # zpool upgrade mypool This system supports ZFS pool feature flags. Successfully upgraded 'mypool' from version 28 to feature flags. Enabled the following features on 'mypool': async_destroy empty_bpobj lz4_compress multi_vdev_crash_dump .... The newer features of ZFS will not be available until `zpool upgrade` has completed. Use `zpool upgrade -v` to see what new features the upgrade provides, as well as which features are already supported. Upgrade a pool to support new feature flags: [source,shell] .... # zpool status pool: mypool state: ONLINE status: Some supported features are not enabled on the pool. The pool can still be used, but some features are unavailable. action: Enable all features using 'zpool upgrade'. Once this is done, the pool may no longer be accessible by software that does not support the features. See zpool-features(7) for details. scan: none requested config: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada0 ONLINE 0 0 0 ada1 ONLINE 0 0 0 errors: No known data errors # zpool upgrade This system supports ZFS pool feature flags. All pools are formatted using feature flags. Some supported features are not enabled on the following pools. Once a feature is enabled the pool may become incompatible with software that does not support the feature. See zpool-features(7) for details. POOL FEATURE --------------- zstore multi_vdev_crash_dump spacemap_histogram enabled_txg hole_birth extensible_dataset bookmarks filesystem_limits # zpool upgrade mypool This system supports ZFS pool feature flags. Enabled the following features on 'mypool': spacemap_histogram enabled_txg hole_birth extensible_dataset bookmarks filesystem_limits .... [WARNING] ==== Update the boot code on systems that boot from a pool to support the new pool version. Use `gpart bootcode` on the partition that contains the boot code. Two types of bootcode are available, depending on way the system boots: GPT (the most common option) and EFI (for more modern systems). For legacy boot using GPT, use the following command: [source,shell] .... # gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1 .... For systems using EFI to boot, execute the following command: [source,shell] .... # gpart bootcode -p /boot/boot1.efifat -i 1 ada1 .... Apply the bootcode to all bootable disks in the pool. See man:gpart[8] for more information. ==== [[zfs-zpool-history]] === Displaying Recorded Pool History ZFS records commands that change the pool, including creating datasets, changing properties, or replacing a disk. Reviewing history about a pool's creation is useful, as is checking which user performed a specific action and when. History is not kept in a log file, but is part of the pool itself. The command to review this history is aptly named `zpool history`: [source,shell] .... # zpool history History for 'tank': 2013-02-26.23:02:35 zpool create tank mirror /dev/ada0 /dev/ada1 2013-02-27.18:50:58 zfs set atime=off tank 2013-02-27.18:51:09 zfs set checksum=fletcher4 tank 2013-02-27.18:51:18 zfs create tank/backup .... The output shows `zpool` and `zfs` commands altering the pool in some way along with a timestamp. Commands like `zfs list` are not included. When specifying no pool name, ZFS displays history of all pools. `zpool history` can show even more information when providing the options `-i` or `-l`. `-i` displays user-initiated events as well as internally logged ZFS events. [source,shell] .... # zpool history -i History for 'tank': 2013-02-26.23:02:35 [internal pool create txg:5] pool spa 28; zfs spa 28; zpl 5;uts 9.1-RELEASE 901000 amd64 2013-02-27.18:50:53 [internal property set txg:50] atime=0 dataset = 21 2013-02-27.18:50:58 zfs set atime=off tank 2013-02-27.18:51:04 [internal property set txg:53] checksum=7 dataset = 21 2013-02-27.18:51:09 zfs set checksum=fletcher4 tank 2013-02-27.18:51:13 [internal create txg:55] dataset = 39 2013-02-27.18:51:18 zfs create tank/backup .... Show more details by adding `-l`. Showing history records in a long format, including information like the name of the user who issued the command and the hostname on which the change happened. [source,shell] .... # zpool history -l History for 'tank': 2013-02-26.23:02:35 zpool create tank mirror /dev/ada0 /dev/ada1 [user 0 (root) on :global] 2013-02-27.18:50:58 zfs set atime=off tank [user 0 (root) on myzfsbox:global] 2013-02-27.18:51:09 zfs set checksum=fletcher4 tank [user 0 (root) on myzfsbox:global] 2013-02-27.18:51:18 zfs create tank/backup [user 0 (root) on myzfsbox:global] .... The output shows that the `root` user created the mirrored pool with disks [.filename]#/dev/ada0# and [.filename]#/dev/ada1#. The hostname `myzfsbox` is also shown in the commands after the pool's creation. The hostname display becomes important when exporting the pool from one system and importing on another. It's possible to distinguish the commands issued on the other system by the hostname recorded for each command. Combine both options to `zpool history` to give the most detailed information possible for any given pool. Pool history provides valuable information when tracking down the actions performed or when needing more detailed output for debugging. [[zfs-zpool-iostat]] === Performance Monitoring A built-in monitoring system can display pool I/O statistics in real time. It shows the amount of free and used space on the pool, read and write operations performed per second, and I/O bandwidth used. By default, ZFS monitors and displays all pools in the system. Provide a pool name to limit monitoring to that pool. A basic example: [source,shell] .... # zpool iostat capacity operations bandwidth pool alloc free read write read write ---------- ----- ----- ----- ----- ----- ----- data 288G 1.53T 2 11 11.3K 57.1K .... To continuously see I/O activity, specify a number as the last parameter, indicating an interval in seconds to wait between updates. The next statistic line prints after each interval. Press kbd:[Ctrl+C] to stop this continuous monitoring. Give a second number on the command line after the interval to specify the total number of statistics to display. Display even more detailed I/O statistics with `-v`. Each device in the pool appears with a statistics line. This is useful for seeing read and write operations performed on each device, and can help determine if any individual device is slowing down the pool. This example shows a mirrored pool with two devices: [source,shell] .... # zpool iostat -v capacity operations bandwidth pool alloc free read write read write ----------------------- ----- ----- ----- ----- ----- ----- data 288G 1.53T 2 12 9.23K 61.5K mirror 288G 1.53T 2 12 9.23K 61.5K ada1 - - 0 4 5.61K 61.7K ada2 - - 1 4 5.04K 61.7K ----------------------- ----- ----- ----- ----- ----- ----- .... [[zfs-zpool-split]] === Splitting a Storage Pool ZFS can split a pool consisting of one or more mirror vdevs into two pools. Unless otherwise specified, ZFS detaches the last member of each mirror and creates a new pool containing the same data. Be sure to make a dry run of the operation with `-n` first. This displays the details of the requested operation without actually performing it. This helps confirm that the operation will do what the user intends. [[zfs-zfs]] == `zfs` Administration The `zfs` utility can create, destroy, and manage all existing ZFS datasets within a pool. To manage the pool itself, use crossref:zfs[zfs-zpool,`zpool`]. [[zfs-zfs-create]] === Creating and Destroying Datasets Unlike traditional disks and volume managers, space in ZFS is _not_ preallocated. With traditional file systems, after partitioning and assigning the space, there is no way to add a new file system without adding a new disk. With ZFS, creating new file systems is possible at any time. Each crossref:zfs[zfs-term-dataset,_dataset_] has properties including features like compression, deduplication, caching, and quotas, as well as other useful properties like readonly, case sensitivity, network file sharing, and a mount point. Nesting datasets within each other is possible and child datasets will inherit properties from their ancestors. crossref:zfs[zfs-zfs-allow,Delegate], crossref:zfs[zfs-zfs-send,replicate], crossref:zfs[zfs-zfs-snapshot,snapshot], crossref:zfs[zfs-zfs-jail,jail] allows administering and destroying each dataset as a unit. Creating a separate dataset for each different type or set of files has advantages. The drawbacks to having a large number of datasets are that some commands like `zfs list` will be slower, and that mounting of hundreds or even thousands of datasets will slow the FreeBSD boot process. Create a new dataset and enable crossref:zfs[zfs-term-compression-lz4,LZ4 compression] on it: [source,shell] .... # zfs list NAME USED AVAIL REFER MOUNTPOINT mypool 781M 93.2G 144K none mypool/ROOT 777M 93.2G 144K none mypool/ROOT/default 777M 93.2G 777M / mypool/tmp 176K 93.2G 176K /tmp mypool/usr 616K 93.2G 144K /usr mypool/usr/home 184K 93.2G 184K /usr/home mypool/usr/ports 144K 93.2G 144K /usr/ports mypool/usr/src 144K 93.2G 144K /usr/src mypool/var 1.20M 93.2G 608K /var mypool/var/crash 148K 93.2G 148K /var/crash mypool/var/log 178K 93.2G 178K /var/log mypool/var/mail 144K 93.2G 144K /var/mail mypool/var/tmp 152K 93.2G 152K /var/tmp # zfs create -o compress=lz4 mypool/usr/mydataset # zfs list NAME USED AVAIL REFER MOUNTPOINT mypool 781M 93.2G 144K none mypool/ROOT 777M 93.2G 144K none mypool/ROOT/default 777M 93.2G 777M / mypool/tmp 176K 93.2G 176K /tmp mypool/usr 704K 93.2G 144K /usr mypool/usr/home 184K 93.2G 184K /usr/home mypool/usr/mydataset 87.5K 93.2G 87.5K /usr/mydataset mypool/usr/ports 144K 93.2G 144K /usr/ports mypool/usr/src 144K 93.2G 144K /usr/src mypool/var 1.20M 93.2G 610K /var mypool/var/crash 148K 93.2G 148K /var/crash mypool/var/log 178K 93.2G 178K /var/log mypool/var/mail 144K 93.2G 144K /var/mail mypool/var/tmp 152K 93.2G 152K /var/tmp .... Destroying a dataset is much quicker than deleting the files on the dataset, as it does not involve scanning the files and updating the corresponding metadata. Destroy the created dataset: [source,shell] .... # zfs list NAME USED AVAIL REFER MOUNTPOINT mypool 880M 93.1G 144K none mypool/ROOT 777M 93.1G 144K none mypool/ROOT/default 777M 93.1G 777M / mypool/tmp 176K 93.1G 176K /tmp mypool/usr 101M 93.1G 144K /usr mypool/usr/home 184K 93.1G 184K /usr/home mypool/usr/mydataset 100M 93.1G 100M /usr/mydataset mypool/usr/ports 144K 93.1G 144K /usr/ports mypool/usr/src 144K 93.1G 144K /usr/src mypool/var 1.20M 93.1G 610K /var mypool/var/crash 148K 93.1G 148K /var/crash mypool/var/log 178K 93.1G 178K /var/log mypool/var/mail 144K 93.1G 144K /var/mail mypool/var/tmp 152K 93.1G 152K /var/tmp # zfs destroy mypool/usr/mydataset # zfs list NAME USED AVAIL REFER MOUNTPOINT mypool 781M 93.2G 144K none mypool/ROOT 777M 93.2G 144K none mypool/ROOT/default 777M 93.2G 777M / mypool/tmp 176K 93.2G 176K /tmp mypool/usr 616K 93.2G 144K /usr mypool/usr/home 184K 93.2G 184K /usr/home mypool/usr/ports 144K 93.2G 144K /usr/ports mypool/usr/src 144K 93.2G 144K /usr/src mypool/var 1.21M 93.2G 612K /var mypool/var/crash 148K 93.2G 148K /var/crash mypool/var/log 178K 93.2G 178K /var/log mypool/var/mail 144K 93.2G 144K /var/mail mypool/var/tmp 152K 93.2G 152K /var/tmp .... In modern versions of ZFS, `zfs destroy` is asynchronous, and the free space might take minutes to appear in the pool. Use `zpool get freeing _poolname_` to see the `freeing` property, that shows which datasets are having their blocks freed in the background. If there are child datasets, like crossref:zfs[zfs-term-snapshot,snapshots] or other datasets, destroying the parent is impossible. To destroy a dataset and its children, use `-r` to recursively destroy the dataset and its children. Use `-n -v` to list datasets and snapshots destroyed by this operation, without actually destroy anything. Space reclaimed by destroying snapshots is also shown. [[zfs-zfs-volume]] === Creating and Destroying Volumes A volume is a special dataset type. Rather than mounting as a file system, expose it as a block device under [.filename]#/dev/zvol/poolname/dataset#. This allows using the volume for other file systems, to back the disks of a virtual machine, or to make it available to other network hosts using protocols like iSCSI or HAST. Format a volume with any file system or without a file system to store raw data. To the user, a volume appears to be a regular disk. Putting ordinary file systems on these _zvols_ provides features that ordinary disks or file systems do not have. For example, using the compression property on a 250 MB volume allows creation of a compressed FAT file system. [source,shell] .... # zfs create -V 250m -o compression=on tank/fat32 # zfs list tank NAME USED AVAIL REFER MOUNTPOINT tank 258M 670M 31K /tank # newfs_msdos -F32 /dev/zvol/tank/fat32 # mount -t msdosfs /dev/zvol/tank/fat32 /mnt # df -h /mnt | grep fat32 Filesystem Size Used Avail Capacity Mounted on /dev/zvol/tank/fat32 249M 24k 249M 0% /mnt # mount | grep fat32 /dev/zvol/tank/fat32 on /mnt (msdosfs, local) .... Destroying a volume is much the same as destroying a regular file system dataset. The operation is nearly instantaneous, but it may take minutes to reclaim the free space in the background. [[zfs-zfs-rename]] === Renaming a Dataset To change the name of a dataset, use `zfs rename`. To change the parent of a dataset, use this command as well. Renaming a dataset to have a different parent dataset will change the value of those properties inherited from the parent dataset. Renaming a dataset unmounts then remounts it in the new location (inherited from the new parent dataset). To prevent this behavior, use `-u`. Rename a dataset and move it to be under a different parent dataset: [source,shell] .... # zfs list NAME USED AVAIL REFER MOUNTPOINT mypool 780M 93.2G 144K none mypool/ROOT 777M 93.2G 144K none mypool/ROOT/default 777M 93.2G 777M / mypool/tmp 176K 93.2G 176K /tmp mypool/usr 704K 93.2G 144K /usr mypool/usr/home 184K 93.2G 184K /usr/home mypool/usr/mydataset 87.5K 93.2G 87.5K /usr/mydataset mypool/usr/ports 144K 93.2G 144K /usr/ports mypool/usr/src 144K 93.2G 144K /usr/src mypool/var 1.21M 93.2G 614K /var mypool/var/crash 148K 93.2G 148K /var/crash mypool/var/log 178K 93.2G 178K /var/log mypool/var/mail 144K 93.2G 144K /var/mail mypool/var/tmp 152K 93.2G 152K /var/tmp # zfs rename mypool/usr/mydataset mypool/var/newname # zfs list NAME USED AVAIL REFER MOUNTPOINT mypool 780M 93.2G 144K none mypool/ROOT 777M 93.2G 144K none mypool/ROOT/default 777M 93.2G 777M / mypool/tmp 176K 93.2G 176K /tmp mypool/usr 616K 93.2G 144K /usr mypool/usr/home 184K 93.2G 184K /usr/home mypool/usr/ports 144K 93.2G 144K /usr/ports mypool/usr/src 144K 93.2G 144K /usr/src mypool/var 1.29M 93.2G 614K /var mypool/var/crash 148K 93.2G 148K /var/crash mypool/var/log 178K 93.2G 178K /var/log mypool/var/mail 144K 93.2G 144K /var/mail mypool/var/newname 87.5K 93.2G 87.5K /var/newname mypool/var/tmp 152K 93.2G 152K /var/tmp .... Renaming snapshots uses the same command. Due to the nature of snapshots, rename cannot change their parent dataset. To rename a recursive snapshot, specify `-r`; this will also rename all snapshots with the same name in child datasets. [source,shell] .... # zfs list -t snapshot NAME USED AVAIL REFER MOUNTPOINT mypool/var/newname@first_snapshot 0 - 87.5K - # zfs rename mypool/var/newname@first_snapshot new_snapshot_name # zfs list -t snapshot NAME USED AVAIL REFER MOUNTPOINT mypool/var/newname@new_snapshot_name 0 - 87.5K - .... [[zfs-zfs-set]] === Setting Dataset Properties Each ZFS dataset has properties that control its behavior. Most properties are automatically inherited from the parent dataset, but can be overridden locally. Set a property on a dataset with `zfs set _property=value dataset_`. Most properties have a limited set of valid values, `zfs get` will display each possible property and valid values. Using `zfs inherit` reverts most properties to their inherited values. User-defined properties are also possible. They become part of the dataset configuration and provide further information about the dataset or its contents. To distinguish these custom properties from the ones supplied as part of ZFS, use a colon (`:`) to create a custom namespace for the property. [source,shell] .... # zfs set custom:costcenter=1234 tank # zfs get custom:costcenter tank NAME PROPERTY VALUE SOURCE tank custom:costcenter 1234 local .... To remove a custom property, use `zfs inherit` with `-r`. If the custom property is not defined in any of the parent datasets, this option removes it (but the pool's history still records the change). [source,shell] .... # zfs inherit -r custom:costcenter tank # zfs get custom:costcenter tank NAME PROPERTY VALUE SOURCE tank custom:costcenter - - # zfs get all tank | grep custom:costcenter # .... [[zfs-zfs-set-share]] ==== Getting and Setting Share Properties Two commonly used and useful dataset properties are the NFS and SMB share options. Setting these defines if and how ZFS shares datasets on the network. At present, FreeBSD supports setting NFS sharing alone. To get the current status of a share, enter: [source,shell] .... # zfs get sharenfs mypool/usr/home NAME PROPERTY VALUE SOURCE mypool/usr/home sharenfs on local # zfs get sharesmb mypool/usr/home NAME PROPERTY VALUE SOURCE mypool/usr/home sharesmb off local .... To enable sharing of a dataset, enter: [source,shell] .... # zfs set sharenfs=on mypool/usr/home .... Set other options for sharing datasets through NFS, such as `-alldirs`, `-maproot` and `-network`. To set options on a dataset shared through NFS, enter: [source,shell] .... # zfs set sharenfs="-alldirs,-maproot=root,-network=192.168.1.0/24" mypool/usr/home .... [[zfs-zfs-snapshot]] === Managing Snapshots crossref:zfs[zfs-term-snapshot,Snapshots] are one of the most powerful features of ZFS. A snapshot provides a read-only, point-in-time copy of the dataset. With Copy-On-Write (COW), ZFS creates snapshots fast by preserving older versions of the data on disk. If no snapshots exist, ZFS reclaims space for future use when data is rewritten or deleted. Snapshots preserve disk space by recording just the differences between the current dataset and a previous version. Allowing snapshots on whole datasets, not on individual files or directories. A snapshot from a dataset duplicates everything contained in it. This includes the file system properties, files, directories, permissions, and so on. Snapshots use no extra space when first created, but consume space as the blocks they reference change. Recursive snapshots taken with `-r` create snapshots with the same name on the dataset and its children, providing a consistent moment-in-time snapshot of the file systems. This can be important when an application has files on related datasets or that depend upon each other. Without snapshots, a backup would have copies of the files from different points in time. Snapshots in ZFS provide a variety of features that even other file systems with snapshot functionality lack. A typical example of snapshot use is as a quick way of backing up the current state of the file system when performing a risky action like a software installation or a system upgrade. If the action fails, rolling back to the snapshot returns the system to the same state when creating the snapshot. If the upgrade was successful, delete the snapshot to free up space. Without snapshots, a failed upgrade often requires restoring backups, which is tedious, time consuming, and may require downtime during which the system is unusable. Rolling back to snapshots is fast, even while the system is running in normal operation, with little or no downtime. The time savings are enormous with multi-terabyte storage systems considering the time required to copy the data from backup. Snapshots are not a replacement for a complete backup of a pool, but offer a quick and easy way to store a dataset copy at a specific time. [[zfs-zfs-snapshot-creation]] ==== Creating Snapshots To create snapshots, use `zfs snapshot _dataset_@_snapshotname_`. Adding `-r` creates a snapshot recursively, with the same name on all child datasets. Create a recursive snapshot of the entire pool: [source,shell] .... # zfs list -t all NAME USED AVAIL REFER MOUNTPOINT mypool 780M 93.2G 144K none mypool/ROOT 777M 93.2G 144K none mypool/ROOT/default 777M 93.2G 777M / mypool/tmp 176K 93.2G 176K /tmp mypool/usr 616K 93.2G 144K /usr mypool/usr/home 184K 93.2G 184K /usr/home mypool/usr/ports 144K 93.2G 144K /usr/ports mypool/usr/src 144K 93.2G 144K /usr/src mypool/var 1.29M 93.2G 616K /var mypool/var/crash 148K 93.2G 148K /var/crash mypool/var/log 178K 93.2G 178K /var/log mypool/var/mail 144K 93.2G 144K /var/mail mypool/var/newname 87.5K 93.2G 87.5K /var/newname mypool/var/newname@new_snapshot_name 0 - 87.5K - mypool/var/tmp 152K 93.2G 152K /var/tmp # zfs snapshot -r mypool@my_recursive_snapshot # zfs list -t snapshot NAME USED AVAIL REFER MOUNTPOINT mypool@my_recursive_snapshot 0 - 144K - mypool/ROOT@my_recursive_snapshot 0 - 144K - mypool/ROOT/default@my_recursive_snapshot 0 - 777M - mypool/tmp@my_recursive_snapshot 0 - 176K - mypool/usr@my_recursive_snapshot 0 - 144K - mypool/usr/home@my_recursive_snapshot 0 - 184K - mypool/usr/ports@my_recursive_snapshot 0 - 144K - mypool/usr/src@my_recursive_snapshot 0 - 144K - mypool/var@my_recursive_snapshot 0 - 616K - mypool/var/crash@my_recursive_snapshot 0 - 148K - mypool/var/log@my_recursive_snapshot 0 - 178K - mypool/var/mail@my_recursive_snapshot 0 - 144K - mypool/var/newname@new_snapshot_name 0 - 87.5K - mypool/var/newname@my_recursive_snapshot 0 - 87.5K - mypool/var/tmp@my_recursive_snapshot 0 - 152K - .... Snapshots are not shown by a normal `zfs list` operation. To list snapshots, append `-t snapshot` to `zfs list`. `-t all` displays both file systems and snapshots. Snapshots are not mounted directly, showing no path in the `MOUNTPOINT` column. ZFS does not mention available disk space in the `AVAIL` column, as snapshots are read-only after their creation. Compare the snapshot to the original dataset: [source,shell] .... # zfs list -rt all mypool/usr/home NAME USED AVAIL REFER MOUNTPOINT mypool/usr/home 184K 93.2G 184K /usr/home mypool/usr/home@my_recursive_snapshot 0 - 184K - .... Displaying both the dataset and the snapshot together reveals how snapshots work in crossref:zfs[zfs-term-cow,COW] fashion. They save the changes (_delta_) made and not the complete file system contents all over again. This means that snapshots take little space when making changes. Observe space usage even more by copying a file to the dataset, then creating a second snapshot: [source,shell] .... # cp /etc/passwd /var/tmp # zfs snapshot mypool/var/tmp@after_cp # zfs list -rt all mypool/var/tmp NAME USED AVAIL REFER MOUNTPOINT mypool/var/tmp 206K 93.2G 118K /var/tmp mypool/var/tmp@my_recursive_snapshot 88K - 152K - mypool/var/tmp@after_cp 0 - 118K - .... The second snapshot contains the changes to the dataset after the copy operation. This yields enormous space savings. Notice that the size of the snapshot `_mypool/var/tmp@my_recursive_snapshot_` also changed in the `USED` column to show the changes between itself and the snapshot taken afterwards. [[zfs-zfs-snapshot-diff]] ==== Comparing Snapshots ZFS provides a built-in command to compare the differences in content between two snapshots. This is helpful with a lot of snapshots taken over time when the user wants to see how the file system has changed over time. For example, `zfs diff` lets a user find the latest snapshot that still contains a file deleted by accident. Doing this for the two snapshots created in the previous section yields this output: [source,shell] .... # zfs list -rt all mypool/var/tmp NAME USED AVAIL REFER MOUNTPOINT mypool/var/tmp 206K 93.2G 118K /var/tmp mypool/var/tmp@my_recursive_snapshot 88K - 152K - mypool/var/tmp@after_cp 0 - 118K - # zfs diff mypool/var/tmp@my_recursive_snapshot M /var/tmp/ + /var/tmp/passwd .... The command lists the changes between the specified snapshot (in this case `_mypool/var/tmp@my_recursive_snapshot_`) and the live file system. The first column shows the change type: [.informaltable] [cols="20%,80%"] |=== |+ |Adding the path or file. |- |Deleting the path or file. |M |Modifying the path or file. |R |Renaming the path or file. |=== Comparing the output with the table, it becomes clear that ZFS added [.filename]#passwd# after creating the snapshot `_mypool/var/tmp@my_recursive_snapshot_`. This also resulted in a modification to the parent directory mounted at `_/var/tmp_`. Comparing two snapshots is helpful when using the ZFS replication feature to transfer a dataset to a different host for backup purposes. Compare two snapshots by providing the full dataset name and snapshot name of both datasets: [source,shell] .... # cp /var/tmp/passwd /var/tmp/passwd.copy # zfs snapshot mypool/var/tmp@diff_snapshot # zfs diff mypool/var/tmp@my_recursive_snapshot mypool/var/tmp@diff_snapshot M /var/tmp/ + /var/tmp/passwd + /var/tmp/passwd.copy # zfs diff mypool/var/tmp@my_recursive_snapshot mypool/var/tmp@after_cp M /var/tmp/ + /var/tmp/passwd .... A backup administrator can compare two snapshots received from the sending host and determine the actual changes in the dataset. See the crossref:zfs[zfs-zfs-send,Replication] section for more information. [[zfs-zfs-snapshot-rollback]] ==== Snapshot Rollback When at least one snapshot is available, roll back to it at any time. Most often this is the case when the current state of the dataset is no longer valid or an older version is preferred. Scenarios such as local development tests gone wrong, botched system updates hampering the system functionality, or the need to restore deleted files or directories are all too common occurrences. To roll back a snapshot, use `zfs rollback _snapshotname_`. If a lot of changes are present, the operation will take a long time. During that time, the dataset always remains in a consistent state, much like a database that conforms to ACID principles is performing a rollback. This is happening while the dataset is live and accessible without requiring a downtime. Once the snapshot rolled back, the dataset has the same state as it had when the snapshot was originally taken. Rolling back to a snapshot discards all other data in that dataset not part of the snapshot. Taking a snapshot of the current state of the dataset before rolling back to a previous one is a good idea when requiring some data later. This way, the user can roll back and forth between snapshots without losing data that is still valuable. In the first example, roll back a snapshot because a careless `rm` operation removed more data than intended. [source,shell] .... # zfs list -rt all mypool/var/tmp NAME USED AVAIL REFER MOUNTPOINT mypool/var/tmp 262K 93.2G 120K /var/tmp mypool/var/tmp@my_recursive_snapshot 88K - 152K - mypool/var/tmp@after_cp 53.5K - 118K - mypool/var/tmp@diff_snapshot 0 - 120K - # ls /var/tmp passwd passwd.copy vi.recover # rm /var/tmp/passwd* # ls /var/tmp vi.recover .... At this point, the user notices the removal of extra files and wants them back. ZFS provides an easy way to get them back using rollbacks, when performing snapshots of important data on a regular basis. To get the files back and start over from the last snapshot, issue the command: [source,shell] .... # zfs rollback mypool/var/tmp@diff_snapshot # ls /var/tmp passwd passwd.copy vi.recover .... The rollback operation restored the dataset to the state of the last snapshot. Rolling back to a snapshot taken much earlier with other snapshots taken afterwards is also possible. When trying to do this, ZFS will issue this warning: [source,shell] .... # zfs list -rt snapshot mypool/var/tmp AME USED AVAIL REFER MOUNTPOINT mypool/var/tmp@my_recursive_snapshot 88K - 152K - mypool/var/tmp@after_cp 53.5K - 118K - mypool/var/tmp@diff_snapshot 0 - 120K - # zfs rollback mypool/var/tmp@my_recursive_snapshot cannot rollback to 'mypool/var/tmp@my_recursive_snapshot': more recent snapshots exist use '-r' to force deletion of the following snapshots: mypool/var/tmp@after_cp mypool/var/tmp@diff_snapshot .... This warning means that snapshots exist between the current state of the dataset and the snapshot to which the user wants to roll back. To complete the rollback delete these snapshots. ZFS cannot track all the changes between different states of the dataset, because snapshots are read-only. ZFS will not delete the affected snapshots unless the user specifies `-r` to confirm that this is the desired action. If that is the intention, and understanding the consequences of losing all intermediate snapshots, issue the command: [source,shell] .... # zfs rollback -r mypool/var/tmp@my_recursive_snapshot # zfs list -rt snapshot mypool/var/tmp NAME USED AVAIL REFER MOUNTPOINT mypool/var/tmp@my_recursive_snapshot 8K - 152K - # ls /var/tmp vi.recover .... The output from `zfs list -t snapshot` confirms the removal of the intermediate snapshots as a result of `zfs rollback -r`. [[zfs-zfs-snapshot-snapdir]] ==== Restoring Individual Files from Snapshots Snapshots live in a hidden directory under the parent dataset: [.filename]#.zfs/snapshots/snapshotname#. By default, these directories will not show even when executing a standard `ls -a` . Although the directory doesn't show, access it like any normal directory. The property named `snapdir` controls whether these hidden directories show up in a directory listing. Setting the property to `visible` allows them to appear in the output of `ls` and other commands that deal with directory contents. [source,shell] .... # zfs get snapdir mypool/var/tmp NAME PROPERTY VALUE SOURCE mypool/var/tmp snapdir hidden default # ls -a /var/tmp . .. passwd vi.recover # zfs set snapdir=visible mypool/var/tmp # ls -a /var/tmp . .. .zfs passwd vi.recover .... Restore individual files to a previous state by copying them from the snapshot back to the parent dataset. The directory structure below [.filename]#.zfs/snapshot# has a directory named like the snapshots taken earlier to make it easier to identify them. The next example shows how to restore a file from the hidden [.filename]#.zfs# directory by copying it from the snapshot containing the latest version of the file: [source,shell] .... # rm /var/tmp/passwd # ls -a /var/tmp . .. .zfs vi.recover # ls /var/tmp/.zfs/snapshot after_cp my_recursive_snapshot # ls /var/tmp/.zfs/snapshot/after_cp passwd vi.recover # cp /var/tmp/.zfs/snapshot/after_cp/passwd /var/tmp .... Even if the `snapdir` property is set to hidden, running `ls .zfs/snapshot` will still list the contents of that directory. The administrator decides whether to display these directories. This is a per-dataset setting. Copying files or directories from this hidden [.filename]#.zfs/snapshot# is simple enough. Trying it the other way around results in this error: [source,shell] .... # cp /etc/rc.conf /var/tmp/.zfs/snapshot/after_cp/ cp: /var/tmp/.zfs/snapshot/after_cp/rc.conf: Read-only file system .... The error reminds the user that snapshots are read-only and cannot change after creation. Copying files into and removing them from snapshot directories are both disallowed because that would change the state of the dataset they represent. Snapshots consume space based on how much the parent file system has changed since the time of the snapshot. The `written` property of a snapshot tracks the space the snapshot uses. To destroy snapshots and reclaim the space, use `zfs destroy _dataset_@_snapshot_`. Adding `-r` recursively removes all snapshots with the same name under the parent dataset. Adding `-n -v` to the command displays a list of the snapshots to be deleted and an estimate of the space it would reclaim without performing the actual destroy operation. [[zfs-zfs-clones]] === Managing Clones A clone is a copy of a snapshot treated more like a regular dataset. Unlike a snapshot, a clone is writeable and mountable, and has its own properties. After creating a clone using `zfs clone`, destroying the originating snapshot is impossible. To reverse the child/parent relationship between the clone and the snapshot use `zfs promote`. Promoting a clone makes the snapshot become a child of the clone, rather than of the original parent dataset. This will change how ZFS accounts for the space, but not actually change the amount of space consumed. Mounting the clone anywhere within the ZFS file system hierarchy is possible, not only below the original location of the snapshot. To show the clone feature use this example dataset: [source,shell] .... # zfs list -rt all camino/home/joe NAME USED AVAIL REFER MOUNTPOINT camino/home/joe 108K 1.3G 87K /usr/home/joe camino/home/joe@plans 21K - 85.5K - camino/home/joe@backup 0K - 87K - .... A typical use for clones is to experiment with a specific dataset while keeping the snapshot around to fall back to in case something goes wrong. Since snapshots cannot change, create a read/write clone of a snapshot. After achieving the desired result in the clone, promote the clone to a dataset and remove the old file system. Removing the parent dataset is not strictly necessary, as the clone and dataset can coexist without problems. [source,shell] .... # zfs clone camino/home/joe@backup camino/home/joenew # ls /usr/home/joe* /usr/home/joe: backup.txz plans.txt /usr/home/joenew: backup.txz plans.txt # df -h /usr/home Filesystem Size Used Avail Capacity Mounted on usr/home/joe 1.3G 31k 1.3G 0% /usr/home/joe usr/home/joenew 1.3G 31k 1.3G 0% /usr/home/joenew .... Creating a clone makes it an exact copy of the state the dataset was in when taking the snapshot. Changing the clone independently from its originating dataset is possible now. The connection between the two is the snapshot. ZFS records this connection in the property `origin`. Promoting the clone with `zfs promote` makes the clone an independent dataset. This removes the value of the `origin` property and disconnects the newly independent dataset from the snapshot. This example shows it: [source,shell] .... # zfs get origin camino/home/joenew NAME PROPERTY VALUE SOURCE camino/home/joenew origin camino/home/joe@backup - # zfs promote camino/home/joenew # zfs get origin camino/home/joenew NAME PROPERTY VALUE SOURCE camino/home/joenew origin - - .... After making some changes like copying [.filename]#loader.conf# to the promoted clone, for example, the old directory becomes obsolete in this case. Instead, the promoted clone can replace it. To do this, `zfs destroy` the old dataset first and then `zfs rename` the clone to the old dataset name (or to an entirely different name). [source,shell] .... # cp /boot/defaults/loader.conf /usr/home/joenew # zfs destroy -f camino/home/joe # zfs rename camino/home/joenew camino/home/joe # ls /usr/home/joe backup.txz loader.conf plans.txt # df -h /usr/home Filesystem Size Used Avail Capacity Mounted on usr/home/joe 1.3G 128k 1.3G 0% /usr/home/joe .... The cloned snapshot is now an ordinary dataset. It contains all the data from the original snapshot plus the files added to it like [.filename]#loader.conf#. Clones provide useful features to ZFS users in different scenarios. For example, provide jails as snapshots containing different sets of installed applications. Users can clone these snapshots and add their own applications as they see fit. Once satisfied with the changes, promote the clones to full datasets and provide them to end users to work with like they would with a real dataset. This saves time and administrative overhead when providing these jails. [[zfs-zfs-send]] === Replication Keeping data on a single pool in one location exposes it to risks like theft and natural or human disasters. Making regular backups of the entire pool is vital. ZFS provides a built-in serialization feature that can send a stream representation of the data to standard output. Using this feature, storing this data on another pool connected to the local system is possible, as is sending it over a network to another system. Snapshots are the basis for this replication (see the section on crossref:zfs[zfs-zfs-snapshot,ZFS snapshots]). The commands used for replicating data are `zfs send` and `zfs receive`. These examples show ZFS replication with these two pools: [source,shell] .... # zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT backup 960M 77K 896M - - 0% 0% 1.00x ONLINE - mypool 984M 43.7M 940M - - 0% 4% 1.00x ONLINE - .... The pool named _mypool_ is the primary pool where writing and reading data happens on a regular basis. Using a second standby pool _backup_ in case the primary pool becomes unavailable. Note that this fail-over is not done automatically by ZFS, but must be manually done by a system administrator when needed. Use a snapshot to provide a consistent file system version to replicate. After creating a snapshot of _mypool_, copy it to the _backup_ pool by replicating snapshots. This does not include changes made since the most recent snapshot. [source,shell] .... # zfs snapshot mypool@backup1 # zfs list -t snapshot NAME USED AVAIL REFER MOUNTPOINT mypool@backup1 0 - 43.6M - .... Now that a snapshot exists, use `zfs send` to create a stream representing the contents of the snapshot. Store this stream as a file or receive it on another pool. Write the stream to standard output, but redirect to a file or pipe or an error appears: [source,shell] .... # zfs send mypool@backup1 Error: Stream can not be written to a terminal. You must redirect standard output. .... To back up a dataset with `zfs send`, redirect to a file located on the mounted backup pool. Ensure that the pool has enough free space to accommodate the size of the sent snapshot, which means the data contained in the snapshot, not the changes from the previous snapshot. [source,shell] .... # zfs send mypool@backup1 > /backup/backup1 # zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT backup 960M 63.7M 896M - - 0% 6% 1.00x ONLINE - mypool 984M 43.7M 940M - - 0% 4% 1.00x ONLINE - .... The `zfs send` transferred all the data in the snapshot called _backup1_ to the pool named _backup_. To create and send these snapshots automatically, use a man:cron[8] job. Instead of storing the backups as archive files, ZFS can receive them as a live file system, allowing direct access to the backed up data. To get to the actual data contained in those streams, use `zfs receive` to transform the streams back into files and directories. The example below combines `zfs send` and `zfs receive` using a pipe to copy the data from one pool to another. Use the data directly on the receiving pool after the transfer is complete. It is only possible to replicate a dataset to an empty dataset. [source,shell] .... # zfs snapshot mypool@replica1 # zfs send -v mypool@replica1 | zfs receive backup/mypool send from @ to mypool@replica1 estimated size is 50.1M total estimated size is 50.1M TIME SENT SNAPSHOT # zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT backup 960M 63.7M 896M - - 0% 6% 1.00x ONLINE - mypool 984M 43.7M 940M - - 0% 4% 1.00x ONLINE - .... [[zfs-send-incremental]] ==== Incremental Backups `zfs send` can also determine the difference between two snapshots and send individual differences between the two. This saves disk space and transfer time. For example: [source,shell] .... # zfs snapshot mypool@replica2 # zfs list -t snapshot NAME USED AVAIL REFER MOUNTPOINT mypool@replica1 5.72M - 43.6M - mypool@replica2 0 - 44.1M - # zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT backup 960M 61.7M 898M - - 0% 6% 1.00x ONLINE - mypool 960M 50.2M 910M - - 0% 5% 1.00x ONLINE - .... Create a second snapshot called _replica2_. This second snapshot contains changes made to the file system between now and the previous snapshot, _replica1_. Using `zfs send -i` and indicating the pair of snapshots generates an incremental replica stream containing the changed data. This succeeds if the initial snapshot already exists on the receiving side. [source,shell] .... # zfs send -v -i mypool@replica1 mypool@replica2 | zfs receive /backup/mypool send from @replica1 to mypool@replica2 estimated size is 5.02M total estimated size is 5.02M TIME SENT SNAPSHOT # zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT backup 960M 80.8M 879M - - 0% 8% 1.00x ONLINE - mypool 960M 50.2M 910M - - 0% 5% 1.00x ONLINE - # zfs list NAME USED AVAIL REFER MOUNTPOINT backup 55.4M 240G 152K /backup backup/mypool 55.3M 240G 55.2M /backup/mypool mypool 55.6M 11.6G 55.0M /mypool # zfs list -t snapshot NAME USED AVAIL REFER MOUNTPOINT backup/mypool@replica1 104K - 50.2M - backup/mypool@replica2 0 - 55.2M - mypool@replica1 29.9K - 50.0M - mypool@replica2 0 - 55.0M - .... The incremental stream replicated the changed data rather than the entirety of _replica1_. Sending the differences alone took much less time to transfer and saved disk space by not copying the whole pool each time. This is useful when replicating over a slow network or one charging per transferred byte. A new file system, _backup/mypool_, is available with the files and data from the pool _mypool_. Specifying `-p` copies the dataset properties including compression settings, quotas, and mount points. Specifying `-R` copies all child datasets of the dataset along with their properties. Automate sending and receiving to create regular backups on the second pool. [[zfs-send-ssh]] ==== Sending Encrypted Backups over SSH Sending streams over the network is a good way to keep a remote backup, but it does come with a drawback. Data sent over the network link is not encrypted, allowing anyone to intercept and transform the streams back into data without the knowledge of the sending user. This is undesirable when sending the streams over the internet to a remote host. Use SSH to securely encrypt data sent over a network connection. Since ZFS requires redirecting the stream from standard output, piping it through SSH is easy. To keep the contents of the file system encrypted in transit and on the remote system, consider using https://wiki.freebsd.org/PEFS[PEFS]. Change some settings and take security precautions first. This describes the necessary steps required for the `zfs send` operation; for more information on SSH, see crossref:security[openssh,"OpenSSH"]. Change the configuration as follows: * Passwordless SSH access between sending and receiving host using SSH keys * ZFS requires the privileges of the `root` user to send and receive streams. This requires logging in to the receiving system as `root`. * Security reasons prevent `root` from logging in by default. * Use the crossref:zfs[zfs-zfs-allow,ZFS Delegation] system to allow a non-`root` user on each system to perform the respective send and receive operations. On the sending system: + [source,shell] .... # zfs allow -u someuser send,snapshot mypool .... * To mount the pool, the unprivileged user must own the directory, and regular users need permission to mount file systems. On the receiving system: + [source,shell] .... # sysctl vfs.usermount=1 vfs.usermount: 0 -> 1 # echo vfs.usermount=1 >> /etc/sysctl.conf # zfs create recvpool/backup # zfs allow -u someuser create,mount,receive recvpool/backup # chown someuser /recvpool/backup .... The unprivileged user can receive and mount datasets now, and replicates the _home_ dataset to the remote system: [source,shell] .... % zfs snapshot -r mypool/home@monday % zfs send -R mypool/home@monday | ssh someuser@backuphost zfs recv -dvu recvpool/backup .... Create a recursive snapshot called _monday_ of the file system dataset _home_ on the pool _mypool_. Then `zfs send -R` includes the dataset, all child datasets, snapshots, clones, and settings in the stream. Pipe the output through SSH to the waiting `zfs receive` on the remote host _backuphost_. Using an IP address or fully qualified domain name is good practice. The receiving machine writes the data to the _backup_ dataset on the _recvpool_ pool. Adding `-d` to `zfs recv` overwrites the name of the pool on the receiving side with the name of the snapshot. `-u` causes the file systems to not mount on the receiving side. Using `-v` shows more details about the transfer, including the elapsed time and the amount of data transferred. [[zfs-zfs-quota]] === Dataset, User, and Group Quotas Use crossref:zfs[zfs-term-quota,Dataset quotas] to restrict the amount of space consumed by a particular dataset. crossref:zfs[zfs-term-refquota,Reference Quotas] work in much the same way, but count the space used by the dataset itself, excluding snapshots and child datasets. Similarly, use crossref:zfs[zfs-term-userquota,user] and crossref:zfs[zfs-term-groupquota,group] quotas to prevent users or groups from using up all the space in the pool or dataset. The following examples assume that the users already exist in the system. Before adding a user to the system, make sure to create their home dataset first and set the `mountpoint` to `/home/_bob_`. Then, create the user and make the home directory point to the dataset's `mountpoint` location. This will properly set owner and group permissions without shadowing any pre-existing home directory paths that might exist. To enforce a dataset quota of 10 GB for [.filename]#storage/home/bob#: [source,shell] .... # zfs set quota=10G storage/home/bob .... To enforce a reference quota of 10 GB for [.filename]#storage/home/bob#: [source,shell] .... # zfs set refquota=10G storage/home/bob .... To remove a quota of 10 GB for [.filename]#storage/home/bob#: [source,shell] .... # zfs set quota=none storage/home/bob .... The general format is `userquota@_user_=_size_`, and the user's name must be in one of these formats: * POSIX compatible name such as _joe_. * POSIX numeric ID such as _789_. * SID name such as _joe.bloggs@example.com_. * SID numeric ID such as _S-1-123-456-789_. For example, to enforce a user quota of 50 GB for the user named _joe_: [source,shell] .... # zfs set userquota@joe=50G .... To remove any quota: [source,shell] .... # zfs set userquota@joe=none .... [NOTE] ==== User quota properties are not displayed by `zfs get all`. Non-`root` users can't see other's quotas unless granted the `userquota` privilege. Users with this privilege are able to view and set everyone's quota. ==== The general format for setting a group quota is: `groupquota@_group_=_size_`. To set the quota for the group _firstgroup_ to 50 GB, use: [source,shell] .... # zfs set groupquota@firstgroup=50G .... To remove the quota for the group _firstgroup_, or to make sure that one is not set, instead use: [source,shell] .... # zfs set groupquota@firstgroup=none .... As with the user quota property, non-`root` users can see the quotas associated with the groups to which they belong. A user with the `groupquota` privilege or `root` can view and set all quotas for all groups. To display the amount of space used by each user on a file system or snapshot along with any quotas, use `zfs userspace`. For group information, use `zfs groupspace`. For more information about supported options or how to display specific options alone, refer to man:zfs[1]. Privileged users and `root` can list the quota for [.filename]#storage/home/bob# using: [source,shell] .... # zfs get quota storage/home/bob .... [[zfs-zfs-reservation]] === Reservations crossref:zfs[zfs-term-reservation,Reservations] guarantee an always-available amount of space on a dataset. The reserved space will not be available to any other dataset. This useful feature ensures that free space is available for an important dataset or log files. The general format of the `reservation` property is `reservation=_size_`, so to set a reservation of 10 GB on [.filename]#storage/home/bob#, use: [source,shell] .... # zfs set reservation=10G storage/home/bob .... To clear any reservation: [source,shell] .... # zfs set reservation=none storage/home/bob .... The same principle applies to the `refreservation` property for setting a crossref:zfs[zfs-term-refreservation,Reference Reservation], with the general format `refreservation=_size_`. This command shows any reservations or refreservations that exist on [.filename]#storage/home/bob#: [source,shell] .... # zfs get reservation storage/home/bob # zfs get refreservation storage/home/bob .... [[zfs-zfs-compression]] === Compression ZFS provides transparent compression. Compressing data written at the block level saves space and also increases disk throughput. If data compresses by 25% the compressed data writes to the disk at the same rate as the uncompressed version, resulting in an effective write speed of 125%. Compression can also be a great alternative to crossref:zfs[zfs-zfs-deduplication,Deduplication] because it does not require extra memory. ZFS offers different compression algorithms, each with different trade-offs. The introduction of LZ4 compression in ZFS v5000 enables compressing the entire pool without the large performance trade-off of other algorithms. The biggest advantage to LZ4 is the _early abort_ feature. If LZ4 does not achieve at least 12.5% compression in the header part of the data, ZFS writes the block uncompressed to avoid wasting CPU cycles trying to compress data that is either already compressed or uncompressible. For details about the different compression algorithms available in ZFS, see the crossref:zfs[zfs-term-compression,Compression] entry in the terminology section. The administrator can see the effectiveness of compression using dataset properties. [source,shell] .... # zfs get used,compressratio,compression,logicalused mypool/compressed_dataset NAME PROPERTY VALUE SOURCE mypool/compressed_dataset used 449G - mypool/compressed_dataset compressratio 1.11x - mypool/compressed_dataset compression lz4 local mypool/compressed_dataset logicalused 496G - .... The dataset is using 449 GB of space (the used property). Without compression, it would have taken 496 GB of space (the `logicalused` property). This results in a 1.11:1 compression ratio. Compression can have an unexpected side effect when combined with crossref:zfs[zfs-term-userquota,User Quotas]. User quotas restrict how much actual space a user consumes on a dataset _after compression_. If a user has a quota of 10 GB, and writes 10 GB of compressible data, they will still be able to store more data. If they later update a file, say a database, with more or less compressible data, the amount of space available to them will change. This can result in the odd situation where a user did not increase the actual amount of data (the `logicalused` property), but the change in compression caused them to reach their quota limit. Compression can have a similar unexpected interaction with backups. Quotas are often used to limit data storage to ensure there is enough backup space available. Since quotas do not consider compression ZFS may write more data than would fit with uncompressed backups. [[zfs-zfs-compression-zstd]] === Zstandard Compression OpenZFS 2.0 added a new compression algorithm. Zstandard (Zstd) offers higher compression ratios than the default LZ4 while offering much greater speeds than the alternative, gzip. OpenZFS 2.0 is available starting with FreeBSD 12.1-RELEASE via package:sysutils/openzfs[] and has been the default in since FreeBSD 13.0-RELEASE. Zstd provides a large selection of compression levels, providing fine-grained control over performance versus compression ratio. One of the main advantages of Zstd is that the decompression speed is independent of the compression level. For data written once but read often, Zstd allows the use of the highest compression levels without a read performance penalty. Even with frequent data updates, enabling compression often provides higher performance. One of the biggest advantages comes from the compressed ARC feature. ZFS's Adaptive Replacement Cache (ARC) caches the compressed version of the data in RAM, decompressing it each time. This allows the same amount of RAM to store more data and metadata, increasing the cache hit ratio. ZFS offers 19 levels of Zstd compression, each offering incrementally more space savings in exchange for slower compression. The default level is `zstd-3` and offers greater compression than LZ4 without being much slower. Levels above 10 require large amounts of memory to compress each block and systems with less than 16 GB of RAM should not use them. ZFS uses a selection of the Zstd_fast_ levels also, which get correspondingly faster but supports lower compression ratios. ZFS supports `zstd-fast-1` through `zstd-fast-10`, `zstd-fast-20` through `zstd-fast-100` in increments of 10, and `zstd-fast-500` and `zstd-fast-1000` which provide minimal compression, but offer high performance. If ZFS is not able to get the required memory to compress a block with Zstd, it will fall back to storing the block uncompressed. This is unlikely to happen except at the highest levels of Zstd on memory constrained systems. ZFS counts how often this has occurred since loading the ZFS module with `kstat.zfs.misc.zstd.compress_alloc_fail`. [[zfs-zfs-deduplication]] === Deduplication When enabled, crossref:zfs[zfs-term-deduplication,deduplication] uses the checksum of each block to detect duplicate blocks. When a new block is a duplicate of an existing block, ZFS writes a new reference to the existing data instead of the whole duplicate block. Tremendous space savings are possible if the data contains a lot of duplicated files or repeated information. Warning: deduplication requires a large amount of memory, and enabling compression instead provides most of the space savings without the extra cost. To activate deduplication, set the `dedup` property on the target pool: [source,shell] .... # zfs set dedup=on pool .... Deduplicating only affects new data written to the pool. Merely activating this option will not deduplicate data already written to the pool. A pool with a freshly activated deduplication property will look like this example: [source,shell] .... # zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT pool 2.84G 2.19M 2.83G - - 0% 0% 1.00x ONLINE - .... The `DEDUP` column shows the actual rate of deduplication for the pool. A value of `1.00x` shows that data has not deduplicated yet. The next example copies some system binaries three times into different directories on the deduplicated pool created above. [source,shell] .... # for d in dir1 dir2 dir3; do > mkdir $d && cp -R /usr/bin $d & > done .... To observe deduplicating of redundant data, use: [source,shell] .... # zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT pool 2.84G 20.9M 2.82G - - 0% 0% 3.00x ONLINE - .... The `DEDUP` column shows a factor of `3.00x`. Detecting and deduplicating copies of the data uses a third of the space. The potential for space savings can be enormous, but comes at the cost of having enough memory to keep track of the deduplicated blocks. Deduplication is not always beneficial when the data in a pool is not redundant. ZFS can show potential space savings by simulating deduplication on an existing pool: [source,shell] .... # zdb -S pool Simulated DDT histogram: bucket allocated referenced ______ ______________________________ ______________________________ refcnt blocks LSIZE PSIZE DSIZE blocks LSIZE PSIZE DSIZE ------ ------ ----- ----- ----- ------ ----- ----- ----- 1 2.58M 289G 264G 264G 2.58M 289G 264G 264G 2 206K 12.6G 10.4G 10.4G 430K 26.4G 21.6G 21.6G 4 37.6K 692M 276M 276M 170K 3.04G 1.26G 1.26G 8 2.18K 45.2M 19.4M 19.4M 20.0K 425M 176M 176M 16 174 2.83M 1.20M 1.20M 3.33K 48.4M 20.4M 20.4M 32 40 2.17M 222K 222K 1.70K 97.2M 9.91M 9.91M 64 9 56K 10.5K 10.5K 865 4.96M 948K 948K 128 2 9.50K 2K 2K 419 2.11M 438K 438K 256 5 61.5K 12K 12K 1.90K 23.0M 4.47M 4.47M 1K 2 1K 1K 1K 2.98K 1.49M 1.49M 1.49M Total 2.82M 303G 275G 275G 3.20M 319G 287G 287G dedup = 1.05, compress = 1.11, copies = 1.00, dedup * compress / copies = 1.16 .... After `zdb -S` finishes analyzing the pool, it shows the space reduction ratio that activating deduplication would achieve. In this case, `1.16` is a poor space saving ratio mainly provided by compression. Activating deduplication on this pool would not save any amount of space, and is not worth the amount of memory required to enable deduplication. Using the formula _ratio = dedup * compress / copies_, system administrators can plan the storage allocation, deciding whether the workload will contain enough duplicate blocks to justify the memory requirements. If the data is reasonably compressible, the space savings may be good. Good practice is to enable compression first as compression also provides greatly increased performance. Enable deduplication in cases where savings are considerable and with enough available memory for the crossref:zfs[zfs-term-deduplication,DDT]. [[zfs-zfs-jail]] === ZFS and Jails Use `zfs jail` and the corresponding `jailed` property to delegate a ZFS dataset to a crossref:jails[jails,Jail]. `zfs jail _jailid_` attaches a dataset to the specified jail, and `zfs unjail` detaches it. To control the dataset from within a jail, set the `jailed` property. ZFS forbids mounting a jailed dataset on the host because it may have mount points that would compromise the security of the host. [[zfs-zfs-allow]] == Delegated Administration A comprehensive permission delegation system allows unprivileged users to perform ZFS administration functions. For example, if each user's home directory is a dataset, users need permission to create and destroy snapshots of their home directories. A user performing backups can get permission to use replication features. ZFS allows a usage statistics script to run with access to only the space usage data for all users. Delegating the ability to delegate permissions is also possible. Permission delegation is possible for each subcommand and most properties. [[zfs-zfs-allow-create]] === Delegating Dataset Creation `zfs allow _someuser_ create _mydataset_` gives the specified user permission to create child datasets under the selected parent dataset. A caveat: creating a new dataset involves mounting it. That requires setting the FreeBSD `vfs.usermount` man:sysctl[8] to `1` to allow non-root users to mount a file system. Another restriction aimed at preventing abuse: non-`root` users must own the mountpoint where mounting the file system. [[zfs-zfs-allow-allow]] === Delegating Permission Delegation `zfs allow _someuser_ allow _mydataset_` gives the specified user the ability to assign any permission they have on the target dataset, or its children, to other users. If a user has the `snapshot` permission and the `allow` permission, that user can then grant the `snapshot` permission to other users. [[zfs-advanced]] == Advanced Topics [[zfs-advanced-tuning]] === Tuning Adjust tunables to make ZFS perform best for different workloads. * [[zfs-advanced-tuning-arc_max]] `_vfs.zfs.arc.max_` starting with 13.x (`vfs.zfs.arc_max` for 12.x) - Upper size of the crossref:zfs[zfs-term-arc,ARC]. The default is all RAM but 1 GB, or 5/8 of all RAM, whichever is more. Use a lower value if the system runs any other daemons or processes that may require memory. Adjust this value at runtime with man:sysctl[8] and set it in [.filename]#/boot/loader.conf# or [.filename]#/etc/sysctl.conf#. * [[zfs-advanced-tuning-arc_meta_limit]] `_vfs.zfs.arc.meta_limit_` starting with 13.x (`vfs.zfs.arc_meta_limit` for 12.x) - Limit the amount of the crossref:zfs[zfs-term-arc,ARC] used to store metadata. The default is one fourth of `vfs.zfs.arc.max`. Increasing this value will improve performance if the workload involves operations on a large number of files and directories, or frequent metadata operations, at the cost of less file data fitting in the crossref:zfs[zfs-term-arc,ARC]. Adjust this value at runtime with man:sysctl[8] in [.filename]#/boot/loader.conf# or [.filename]#/etc/sysctl.conf#. * [[zfs-advanced-tuning-arc_min]] `_vfs.zfs.arc.min_` starting with 13.x (`vfs.zfs.arc_min` for 12.x) - Lower size of the crossref:zfs[zfs-term-arc,ARC]. The default is one half of `vfs.zfs.arc.meta_limit`. Adjust this value to prevent other applications from pressuring out the entire crossref:zfs[zfs-term-arc,ARC]. Adjust this value at runtime with man:sysctl[8] and in [.filename]#/boot/loader.conf# or [.filename]#/etc/sysctl.conf#. * [[zfs-advanced-tuning-vdev-cache-size]] `_vfs.zfs.vdev.cache.size_` - A preallocated amount of memory reserved as a cache for each device in the pool. The total amount of memory used will be this value multiplied by the number of devices. Set this value at boot time and in [.filename]#/boot/loader.conf#. * [[zfs-advanced-tuning-min-auto-ashift]] `_vfs.zfs.min_auto_ashift_` - Lower `ashift` (sector size) used automatically at pool creation time. The value is a power of two. The default value of `9` represents `2^9 = 512`, a sector size of 512 bytes. To avoid _write amplification_ and get the best performance, set this value to the largest sector size used by a device in the pool. + Common drives have 4 KB sectors. Using the default `ashift` of `9` with these drives results in write amplification on these devices. Data contained in a single 4 KB write is instead written in eight 512-byte writes. ZFS tries to read the native sector size from all devices when creating a pool, but drives with 4 KB sectors report that their sectors are 512 bytes for compatibility. Setting `vfs.zfs.min_auto_ashift` to `12` (`2^12 = 4096`) before creating a pool forces ZFS to use 4 KB blocks for best performance on these drives. + Forcing 4 KB blocks is also useful on pools with planned disk upgrades. Future disks use 4 KB sectors, and `ashift` values cannot change after creating a pool. + In some specific cases, the smaller 512-byte block size might be preferable. When used with 512-byte disks for databases or as storage for virtual machines, less data transfers during small random reads. This can provide better performance when using a smaller ZFS record size. * [[zfs-advanced-tuning-prefetch_disable]] `_vfs.zfs.prefetch_disable_` - Disable prefetch. A value of `0` enables and `1` disables it. The default is `0`, unless the system has less than 4 GB of RAM. Prefetch works by reading larger blocks than requested into the crossref:zfs[zfs-term-arc,ARC] in hopes to soon need the data. If the workload has a large number of random reads, disabling prefetch may actually improve performance by reducing unnecessary reads. Adjust this value at any time with man:sysctl[8]. * [[zfs-advanced-tuning-vdev-trim_on_init]] `_vfs.zfs.vdev.trim_on_init_` - Control whether new devices added to the pool have the `TRIM` command run on them. This ensures the best performance and longevity for SSDs, but takes extra time. If the device has already been secure erased, disabling this setting will make the addition of the new device faster. Adjust this value at any time with man:sysctl[8]. * [[zfs-advanced-tuning-vdev-max_pending]] `_vfs.zfs.vdev.max_pending_` - Limit the number of pending I/O requests per device. A higher value will keep the device command queue full and may give higher throughput. A lower value will reduce latency. Adjust this value at any time with man:sysctl[8]. * [[zfs-advanced-tuning-top_maxinflight]] `_vfs.zfs.top_maxinflight_` - Upper number of outstanding I/Os per top-level crossref:zfs[zfs-term-vdev,vdev]. Limits the depth of the command queue to prevent high latency. The limit is per top-level vdev, meaning the limit applies to each crossref:zfs[zfs-term-vdev-mirror,mirror], crossref:zfs[zfs-term-vdev-raidz,RAID-Z], or other vdev independently. Adjust this value at any time with man:sysctl[8]. * [[zfs-advanced-tuning-l2arc_write_max]] `_vfs.zfs.l2arc_write_max_` - Limit the amount of data written to the crossref:zfs[zfs-term-l2arc,L2ARC] per second. This tunable extends the longevity of SSDs by limiting the amount of data written to the device. Adjust this value at any time with man:sysctl[8]. * [[zfs-advanced-tuning-l2arc_write_boost]] `_vfs.zfs.l2arc_write_boost_` - Adds the value of this tunable to crossref:zfs[zfs-advanced-tuning-l2arc_write_max,`vfs.zfs.l2arc_write_max`] and increases the write speed to the SSD until evicting the first block from the crossref:zfs[zfs-term-l2arc,L2ARC]. This "Turbo Warmup Phase" reduces the performance loss from an empty crossref:zfs[zfs-term-l2arc,L2ARC] after a reboot. Adjust this value at any time with man:sysctl[8]. * [[zfs-advanced-tuning-scrub_delay]]`_vfs.zfs.scrub_delay_` - Number of ticks to delay between each I/O during a crossref:zfs[zfs-term-scrub,`scrub`]. To ensure that a `scrub` does not interfere with the normal operation of the pool, if any other I/O is happening the `scrub` will delay between each command. This value controls the limit on the total IOPS (I/Os Per Second) generated by the `scrub`. The granularity of the setting is determined by the value of `kern.hz` which defaults to 1000 ticks per second. Changing this setting results in a different effective IOPS limit. The default value is `4`, resulting in a limit of: 1000 ticks/sec / 4 = 250 IOPS. Using a value of _20_ would give a limit of: 1000 ticks/sec / 20 = 50 IOPS. Recent activity on the pool limits the speed of `scrub`, as determined by crossref:zfs[zfs-advanced-tuning-scan_idle,`vfs.zfs.scan_idle`]. Adjust this value at any time with man:sysctl[8]. * [[zfs-advanced-tuning-resilver_delay]] `_vfs.zfs.resilver_delay_` - Number of milliseconds of delay inserted between each I/O during a crossref:zfs[zfs-term-resilver,resilver]. To ensure that a resilver does not interfere with the normal operation of the pool, if any other I/O is happening the resilver will delay between each command. This value controls the limit of total IOPS (I/Os Per Second) generated by the resilver. ZFS determins the granularity of the setting by the value of `kern.hz` which defaults to 1000 ticks per second. Changing this setting results in a different effective IOPS limit. The default value is 2, resulting in a limit of: 1000 ticks/sec / 2 = 500 IOPS. Returning the pool to an crossref:zfs[zfs-term-online,Online] state may be more important if another device failing could crossref:zfs[zfs-term-faulted,Fault] the pool, causing data loss. A value of 0 will give the resilver operation the same priority as other operations, speeding the healing process. Other recent activity on the pool limits the speed of resilver, as determined by crossref:zfs[zfs-advanced-tuning-scan_idle,`vfs.zfs.scan_idle`]. Adjust this value at any time with man:sysctl[8]. * [[zfs-advanced-tuning-scan_idle]] `_vfs.zfs.scan_idle_` - Number of milliseconds since the last operation before considering the pool is idle. ZFS disables the rate limiting for crossref:zfs[zfs-term-scrub,`scrub`] and crossref:zfs[zfs-term-resilver,resilver] when the pool is idle. Adjust this value at any time with man:sysctl[8]. * [[zfs-advanced-tuning-txg-timeout]] `_vfs.zfs.txg.timeout_` - Upper number of seconds between crossref:zfs[zfs-term-txg,transaction group]s. The current transaction group writes to the pool and a fresh transaction group starts if this amount of time elapsed since the previous transaction group. A transaction group may trigger earlier if writing enough data. The default value is 5 seconds. A larger value may improve read performance by delaying asynchronous writes, but this may cause uneven performance when writing the transaction group. Adjust this value at any time with man:sysctl[8]. [[zfs-advanced-i386]] === ZFS on i386 Some of the features provided by ZFS are memory intensive, and may require tuning for upper efficiency on systems with limited RAM. ==== Memory As a lower value, the total system memory should be at least one gigabyte. The amount of recommended RAM depends upon the size of the pool and which features ZFS uses. A general rule of thumb is 1 GB of RAM for every 1 TB of storage. If using the deduplication feature, a general rule of thumb is 5 GB of RAM per TB of storage to deduplicate. While some users use ZFS with less RAM, systems under heavy load may panic due to memory exhaustion. ZFS may require further tuning for systems with less than the recommended RAM requirements. ==== Kernel Configuration Due to the address space limitations of the i386(TM) platform, ZFS users on the i386(TM) architecture must add this option to a custom kernel configuration file, rebuild the kernel, and reboot: [.programlisting] .... options KVA_PAGES=512 .... This expands the kernel address space, allowing the `vm.kvm_size` tunable to push beyond the imposed limit of 1 GB, or the limit of 2 GB for PAE. To find the most suitable value for this option, divide the desired address space in megabytes by four. In this example `512` for 2 GB. ==== Loader Tunables Increases the [.filename]#kmem# address space on all FreeBSD architectures. A test system with 1 GB of physical memory benefitted from adding these options to [.filename]#/boot/loader.conf# and then restarting: [.programlisting] .... vm.kmem_size="330M" vm.kmem_size_max="330M" vfs.zfs.arc.max="40M" vfs.zfs.vdev.cache.size="5M" .... For a more detailed list of recommendations for ZFS-related tuning, see https://wiki.freebsd.org/ZFSTuningGuide[]. [[zfs-links]] == Further Resources * https://openzfs.org/[OpenZFS] * https://wiki.freebsd.org/ZFSTuningGuide[FreeBSD Wiki - ZFS Tuning] * https://calomel.org/zfs_raid_speed_capacity.html[Calomel Blog - ZFS Raidz Performance, Capacity and Integrity] [[zfs-term]] == ZFS Features and Terminology More than a file system, ZFS is fundamentally different. ZFS combines the roles of file system and volume manager, enabling new storage devices to add to a live system and having the new space available on the existing file systems in that pool at once. By combining the traditionally separate roles, ZFS is able to overcome previous limitations that prevented RAID groups being able to grow. A _vdev_ is a top level device in a pool and can be a simple disk or a RAID transformation such as a mirror or RAID-Z array. ZFS file systems (called _datasets_) each have access to the combined free space of the entire pool. Used blocks from the pool decrease the space available to each file system. This approach avoids the common pitfall with extensive partitioning where free space becomes fragmented across the partitions. [.informaltable] [cols="10%,90%"] |=== |[[zfs-term-pool]]pool |A storage _pool_ is the most basic building block of ZFS. A pool consists of one or more vdevs, the underlying devices that store the data. A pool is then used to create one or more file systems (datasets) or block devices (volumes). These datasets and volumes share the pool of remaining free space. Each pool is uniquely identified by a name and a GUID. The ZFS version number on the pool determines the features available. |[[zfs-term-vdev]]vdev Types a|A pool consists of one or more vdevs, which themselves are a single disk or a group of disks, transformed to a RAID. When using a lot of vdevs, ZFS spreads data across the vdevs to increase performance and maximize usable space. All vdevs must be at least 128 MB in size. * [[zfs-term-vdev-disk]] _Disk_ - The most basic vdev type is a standard block device. This can be an entire disk (such as [.filename]#/dev/ada0# or [.filename]#/dev/da0#) or a partition ([.filename]#/dev/ada0p3#). On FreeBSD, there is no performance penalty for using a partition rather than the entire disk. This differs from recommendations made by the Solaris documentation. + [CAUTION] ==== Using an entire disk as part of a bootable pool is strongly discouraged, as this may render the pool unbootable. Likewise, you should not use an entire disk as part of a mirror or RAID-Z vdev. Reliably determining the size of an unpartitioned disk at boot time is impossible and there's no place to put in boot code. ==== * [[zfs-term-vdev-file]] _File_ - Regular files may make up ZFS pools, which is useful for testing and experimentation. Use the full path to the file as the device path in `zpool create`. * [[zfs-term-vdev-mirror]] _Mirror_ - When creating a mirror, specify the `mirror` keyword followed by the list of member devices for the mirror. A mirror consists of two or more devices, writing all data to all member devices. A mirror vdev will hold as much data as its smallest member. A mirror vdev can withstand the failure of all but one of its members without losing any data. + [NOTE] ==== To upgrade a regular single disk vdev to a mirror vdev at any time, use `zpool crossref:zfs[zfs-zpool-attach,attach]`. ==== * [[zfs-term-vdev-raidz]] _RAID-Z_ - ZFS uses RAID-Z, a variation on standard RAID-5 that offers better distribution of parity and eliminates the "RAID-5 write hole" in which the data and parity information become inconsistent after an unexpected restart. ZFS supports three levels of RAID-Z which provide varying levels of redundancy in exchange for decreasing levels of usable storage. ZFS uses RAID-Z1 through RAID-Z3 based on the number of parity devices in the array and the number of disks which can fail before the pool stops being operational. + In a RAID-Z1 configuration with four disks, each 1 TB, usable storage is 3 TB and the pool will still be able to operate in degraded mode with one faulted disk. If another disk goes offline before replacing and resilvering the faulted disk would result in losing all pool data. + In a RAID-Z3 configuration with eight disks of 1 TB, the volume will provide 5 TB of usable space and still be able to operate with three faulted disks. Sun(TM) recommends no more than nine disks in a single vdev. If more disks make up the configuration, the recommendation is to divide them into separate vdevs and stripe the pool data across them. + A configuration of two RAID-Z2 vdevs consisting of 8 disks each would create something like a RAID-60 array. A RAID-Z group's storage capacity is about the size of the smallest disk multiplied by the number of non-parity disks. Four 1 TB disks in RAID-Z1 has an effective size of about 3 TB, and an array of eight 1 TB disks in RAID-Z3 will yield 5 TB of usable space. * [[zfs-term-vdev-spare]] _Spare_ - ZFS has a special pseudo-vdev type for keeping track of available hot spares. Note that installed hot spares are not deployed automatically; manually configure them to replace the failed device using `zfs replace`. * [[zfs-term-vdev-log]] _Log_ - ZFS Log Devices, also known as ZFS Intent Log (crossref:zfs[zfs-term-zil,ZIL]) move the intent log from the regular pool devices to a dedicated device, typically an SSD. Having a dedicated log device improves the performance of applications with a high volume of synchronous writes like databases. Mirroring of log devices is possible, but RAID-Z is not supported. If using a lot of log devices, writes will be load-balanced across them. * [[zfs-term-vdev-cache]] _Cache_ - Adding a cache vdev to a pool will add the storage of the cache to the crossref:zfs[zfs-term-l2arc,L2ARC]. Mirroring cache devices is impossible. Since a cache device stores only new copies of existing data, there is no risk of data loss. |[[zfs-term-txg]] Transaction Group (TXG) |Transaction Groups are the way ZFS groups blocks changes together and writes them to the pool. Transaction groups are the atomic unit that ZFS uses to ensure consistency. ZFS assigns each transaction group a unique 64-bit consecutive identifier. There can be up to three active transaction groups at a time, one in each of these three states: * _Open_ - A new transaction group begins in the open state and accepts new writes. There is always a transaction group in the open state, but the transaction group may refuse new writes if it has reached a limit. Once the open transaction group has reached a limit, or reaching the crossref:zfs[zfs-advanced-tuning-txg-timeout,`vfs.zfs.txg.timeout`], the transaction group advances to the next state. * _Quiescing_ - A short state that allows any pending operations to finish without blocking the creation of a new open transaction group. Once all the transactions in the group have completed, the transaction group advances to the final state. * _Syncing_ - Write all the data in the transaction group to stable storage. This process will in turn change other data, such as metadata and space maps, that ZFS will also write to stable storage. The process of syncing involves several passes. On the first and biggest, all the changed data blocks; next come the metadata, which may take several passes to complete. Since allocating space for the data blocks generates new metadata, the syncing state cannot finish until a pass completes that does not use any new space. The syncing state is also where _synctasks_ complete. Synctasks are administrative operations such as creating or destroying snapshots and datasets that complete the uberblock change. Once the sync state completes the transaction group in the quiescing state advances to the syncing state. All administrative functions, such as crossref:zfs[zfs-term-snapshot,`snapshot`] write as part of the transaction group. ZFS adds a created synctask to the open transaction group, and that group advances as fast as possible to the syncing state to reduce the latency of administrative commands. |[[zfs-term-arc]]Adaptive Replacement Cache (ARC) |ZFS uses an Adaptive Replacement Cache (ARC), rather than a more traditional Least Recently Used (LRU) cache. An LRU cache is a simple list of items in the cache, sorted by how recently object was used, adding new items to the head of the list. When the cache is full, evicting items from the tail of the list makes room for more active objects. An ARC consists of four lists; the Most Recently Used (MRU) and Most Frequently Used (MFU) objects, plus a ghost list for each. These ghost lists track evicted objects to prevent adding them back to the cache. This increases the cache hit ratio by avoiding objects that have a history of occasional use. Another advantage of using both an MRU and MFU is that scanning an entire file system would evict all data from an MRU or LRU cache in favor of this freshly accessed content. With ZFS, there is also an MFU that tracks the most frequently used objects, and the cache of the most commonly accessed blocks remains. |[[zfs-term-l2arc]]L2ARC |L2ARC is the second level of the ZFS caching system. RAM stores the primary ARC. Since the amount of available RAM is often limited, ZFS can also use crossref:zfs[zfs-term-vdev-cache,cache vdevs]. Solid State Disks (SSDs) are often used as these cache devices due to their higher speed and lower latency compared to traditional spinning disks. L2ARC is entirely optional, but having one will increase read speeds for cached files on the SSD instead of having to read from the regular disks. L2ARC can also speed up crossref:zfs[zfs-term-deduplication,deduplication] because a deduplication table (DDT) that does not fit in RAM but does fit in the L2ARC will be much faster than a DDT that must read from disk. Limits on the data rate added to the cache devices prevents prematurely wearing out SSDs with extra writes. Until the cache is full (the first block evicted to make room), writes to the L2ARC limit to the sum of the write limit and the boost limit, and afterwards limit to the write limit. A pair of man:sysctl[8] values control these rate limits. crossref:zfs[zfs-advanced-tuning-l2arc_write_max,`vfs.zfs.l2arc_write_max`] controls the number of bytes written to the cache per second, while crossref:zfs[zfs-advanced-tuning-l2arc_write_boost,`vfs.zfs.l2arc_write_boost`] adds to this limit during the "Turbo Warmup Phase" (Write Boost). |[[zfs-term-zil]]ZIL |ZIL accelerates synchronous transactions by using storage devices like SSDs that are faster than those used in the main storage pool. When an application requests a synchronous write (a guarantee that the data is stored to disk rather than merely cached for later writes), writing the data to the faster ZIL storage then later flushing it out to the regular disks greatly reduces latency and improves performance. Synchronous workloads like databases will profit from a ZIL alone. Regular asynchronous writes such as copying files will not use the ZIL at all. |[[zfs-term-cow]]Copy-On-Write |Unlike a traditional file system, ZFS writes a different block rather than overwriting the old data in place. When completing this write the metadata updates to point to the new location. When a shorn write (a system crash or power loss in the middle of writing a file) occurs, the entire original contents of the file are still available and ZFS discards the incomplete write. This also means that ZFS does not require a man:fsck[8] after an unexpected shutdown. |[[zfs-term-dataset]]Dataset |_Dataset_ is the generic term for a ZFS file system, volume, snapshot or clone. Each dataset has a unique name in the format _poolname/path@snapshot_. The root of the pool is a dataset as well. Child datasets have hierarchical names like directories. For example, _mypool/home_, the home dataset, is a child of _mypool_ and inherits properties from it. Expand this further by creating _mypool/home/user_. This grandchild dataset will inherit properties from the parent and grandparent. Set properties on a child to override the defaults inherited from the parent and grandparent. Administration of datasets and their children can be crossref:zfs[zfs-zfs-allow,delegated]. |[[zfs-term-filesystem]]File system |A ZFS dataset is most often used as a file system. Like most other file systems, a ZFS file system mounts somewhere in the systems directory hierarchy and contains files and directories of its own with permissions, flags, and other metadata. |[[zfs-term-volume]]Volume |ZFS can also create volumes, which appear as disk devices. Volumes have a lot of the same features as datasets, including copy-on-write, snapshots, clones, and checksumming. Volumes can be useful for running other file system formats on top of ZFS, such as UFS virtualization, or exporting iSCSI extents. |[[zfs-term-snapshot]]Snapshot |The crossref:zfs[zfs-term-cow,copy-on-write] (COW) design of ZFS allows for nearly instantaneous, consistent snapshots with arbitrary names. After taking a snapshot of a dataset, or a recursive snapshot of a parent dataset that will include all child datasets, new data goes to new blocks, but without reclaiming the old blocks as free space. The snapshot contains the original file system version and the live file system contains any changes made since taking the snapshot using no other space. New data written to the live file system uses new blocks to store this data. The snapshot will grow as the blocks are no longer used in the live file system, but in the snapshot alone. Mount these snapshots read-only allows recovering of previous file versions. A crossref:zfs[zfs-zfs-snapshot,rollback] of a live file system to a specific snapshot is possible, undoing any changes that took place after taking the snapshot. Each block in the pool has a reference counter which keeps track of the snapshots, clones, datasets, or volumes use that block. As files and snapshots get deleted, the reference count decreases, reclaiming the free space when no longer referencing a block. Marking snapshots with a crossref:zfs[zfs-zfs-snapshot,hold] results in any attempt to destroy it will returns an `EBUSY` error. Each snapshot can have holds with a unique name each. The crossref:zfs[zfs-zfs-snapshot,release] command removes the hold so the snapshot can deleted. Snapshots, cloning, and rolling back works on volumes, but independently mounting does not. |[[zfs-term-clone]]Clone |Cloning a snapshot is also possible. A clone is a writable version of a snapshot, allowing the file system to fork as a new dataset. As with a snapshot, a clone initially consumes no new space. As new data written to a clone uses new blocks, the size of the clone grows. When blocks are overwritten in the cloned file system or volume, the reference count on the previous block decreases. Removing the snapshot upon which a clone bases is impossible because the clone depends on it. The snapshot is the parent, and the clone is the child. Clones can be _promoted_, reversing this dependency and making the clone the parent and the previous parent the child. This operation requires no new space. Since the amount of space used by the parent and child reverses, it may affect existing quotas and reservations. |[[zfs-term-checksum]]Checksum |Every block is also checksummed. The checksum algorithm used is a per-dataset property, see crossref:zfs[zfs-zfs-set,`set`]. The checksum of each block is transparently validated when read, allowing ZFS to detect silent corruption. If the data read does not match the expected checksum, ZFS will attempt to recover the data from any available redundancy, like mirrors or RAID-Z. Triggering a validation of all checksums with crossref:zfs[zfs-term-scrub,`scrub`]. Checksum algorithms include: * `fletcher2` * `fletcher4` * `sha256` The `fletcher` algorithms are faster, but `sha256` is a strong cryptographic hash and has a much lower chance of collisions at the cost of some performance. Deactivating checksums is possible, but strongly discouraged. |[[zfs-term-compression]]Compression |Each dataset has a compression property, which defaults to off. Set this property to an available compression algorithm. This causes compression of all new data written to the dataset. Beyond a reduction in space used, read and write throughput often increases because fewer blocks need reading or writing. [[zfs-term-compression-lz4]] * _LZ4_ - Added in ZFS pool version 5000 (feature flags), LZ4 is now the recommended compression algorithm. LZ4 works about 50% faster than LZJB when operating on compressible data, and is over three times faster when operating on uncompressible data. LZ4 also decompresses about 80% faster than LZJB. On modern CPUs, LZ4 can often compress at over 500 MB/s, and decompress at over 1.5 GB/s (per single CPU core). [[zfs-term-compression-lzjb]] * _LZJB_ - The default compression algorithm. Created by Jeff Bonwick (one of the original creators of ZFS). LZJB offers good compression with less CPU overhead compared to GZIP. In the future, the default compression algorithm will change to LZ4. [[zfs-term-compression-gzip]] * _GZIP_ - A popular stream compression algorithm available in ZFS. One of the main advantages of using GZIP is its configurable level of compression. When setting the `compress` property, the administrator can choose the level of compression, ranging from `gzip1`, the lowest level of compression, to `gzip9`, the highest level of compression. This gives the administrator control over how much CPU time to trade for saved disk space. [[zfs-term-compression-zle]] * _ZLE_ - Zero Length Encoding is a special compression algorithm that compresses continuous runs of zeros alone. This compression algorithm is useful when the dataset contains large blocks of zeros. |[[zfs-term-copies]]Copies |When set to a value greater than 1, the `copies` property instructs ZFS to maintain copies of each block in the crossref:zfs[zfs-term-filesystem,file system] or crossref:zfs[zfs-term-volume,volume]. Setting this property on important datasets provides added redundancy from which to recover a block that does not match its checksum. In pools without redundancy, the copies feature is the single form of redundancy. The copies feature can recover from a single bad sector or other forms of minor corruption, but it does not protect the pool from the loss of an entire disk. |[[zfs-term-deduplication]]Deduplication |Checksums make it possible to detect duplicate blocks when writing data. With deduplication, the reference count of an existing, identical block increases, saving storage space. ZFS keeps a deduplication table (DDT) in memory to detect duplicate blocks. The table contains a list of unique checksums, the location of those blocks, and a reference count. When writing new data, ZFS calculates checksums and compares them to the list. When finding a match it uses the existing block. Using the SHA256 checksum algorithm with deduplication provides a secure cryptographic hash. Deduplication is tunable. If `dedup` is `on`, then a matching checksum means that the data is identical. Setting `dedup` to `verify`, ZFS performs a byte-for-byte check on the data ensuring they are actually identical. If the data is not identical, ZFS will note the hash collision and store the two blocks separately. As the DDT must store the hash of each unique block, it consumes a large amount of memory. A general rule of thumb is 5-6 GB of ram per 1 TB of deduplicated data). In situations not practical to have enough RAM to keep the entire DDT in memory, performance will suffer greatly as the DDT must read from disk before writing each new block. Deduplication can use L2ARC to store the DDT, providing a middle ground between fast system memory and slower disks. Consider using compression instead, which often provides nearly as much space savings without the increased memory. |[[zfs-term-scrub]]Scrub |Instead of a consistency check like man:fsck[8], ZFS has `scrub`. `scrub` reads all data blocks stored on the pool and verifies their checksums against the known good checksums stored in the metadata. A periodic check of all the data stored on the pool ensures the recovery of any corrupted blocks before needing them. A scrub is not required after an unclean shutdown, but good practice is at least once every three months. ZFS verifies the checksum of each block during normal use, but a scrub makes certain to check even infrequently used blocks for silent corruption. ZFS improves data security in archival storage situations. Adjust the relative priority of `scrub` with crossref:zfs[zfs-advanced-tuning-scrub_delay,`vfs.zfs.scrub_delay`] to prevent the scrub from degrading the performance of other workloads on the pool. |[[zfs-term-quota]]Dataset Quota a|ZFS provides fast and accurate dataset, user, and group space accounting as well as quotas and space reservations. This gives the administrator fine grained control over space allocation and allows reserving space for critical file systems. ZFS supports different types of quotas: the dataset quota, the crossref:zfs[zfs-term-refquota,reference quota (refquota)], the crossref:zfs[zfs-term-userquota,user quota], and the crossref:zfs[zfs-term-groupquota,group quota]. Quotas limit the total size of a dataset and its descendants, including snapshots of the dataset, child datasets, and the snapshots of those datasets. [NOTE] ==== Volumes do not support quotas, as the `volsize` property acts as an implicit quota. ==== |[[zfs-term-refquota]]Reference Quota |A reference quota limits the amount of space a dataset can consume by enforcing a hard limit. This hard limit includes space referenced by the dataset alone and does not include space used by descendants, such as file systems or snapshots. |[[zfs-term-userquota]]User Quota |User quotas are useful to limit the amount of space used by the specified user. |[[zfs-term-groupquota]]Group Quota |The group quota limits the amount of space that a specified group can consume. |[[zfs-term-reservation]]Dataset Reservation |The `reservation` property makes it possible to guarantee an amount of space for a specific dataset and its descendants. This means that setting a 10 GB reservation on [.filename]#storage/home/bob# prevents other datasets from using up all free space, reserving at least 10 GB of space for this dataset. Unlike a regular crossref:zfs[zfs-term-refreservation,`refreservation`], space used by snapshots and descendants is not counted against the reservation. For example, if taking a snapshot of [.filename]#storage/home/bob#, enough disk space other than the `refreservation` amount must exist for the operation to succeed. Descendants of the main data set are not counted in the `refreservation` amount and so do not encroach on the space set. Reservations of any sort are useful in situations such as planning and testing the suitability of disk space allocation in a new system, or ensuring that enough space is available on file systems for audio logs or system recovery procedures and files. |[[zfs-term-refreservation]]Reference Reservation |The `refreservation` property makes it possible to guarantee an amount of space for the use of a specific dataset _excluding_ its descendants. This means that setting a 10 GB reservation on [.filename]#storage/home/bob#, and another dataset tries to use the free space, reserving at least 10 GB of space for this dataset. In contrast to a regular crossref:zfs[zfs-term-reservation,reservation], space used by snapshots and descendant datasets is not counted against the reservation. For example, if taking a snapshot of [.filename]#storage/home/bob#, enough disk space other than the `refreservation` amount must exist for the operation to succeed. Descendants of the main data set are not counted in the `refreservation` amount and so do not encroach on the space set. |[[zfs-term-resilver]]Resilver |When replacing a failed disk, ZFS must fill the new disk with the lost data. _Resilvering_ is the process of using the parity information distributed across the remaining drives to calculate and write the missing data to the new drive. |[[zfs-term-online]]Online |A pool or vdev in the `Online` state has its member devices connected and fully operational. Individual devices in the `Online` state are functioning. |[[zfs-term-offline]]Offline |The administrator puts individual devices in an `Offline` state if enough redundancy exists to avoid putting the pool or vdev into a crossref:zfs[zfs-term-faulted,Faulted] state. An administrator may choose to offline a disk in preparation for replacing it, or to make it easier to identify. |[[zfs-term-degraded]]Degraded |A pool or vdev in the `Degraded` state has one or more disks that disappeared or failed. The pool is still usable, but if other devices fail, the pool may become unrecoverable. Reconnecting the missing devices or replacing the failed disks will return the pool to an crossref:zfs[zfs-term-online,Online] state after the reconnected or new device has completed the crossref:zfs[zfs-term-resilver,Resilver] process. |[[zfs-term-faulted]]Faulted |A pool or vdev in the `Faulted` state is no longer operational. Accessing the data is no longer possible. A pool or vdev enters the `Faulted` state when the number of missing or failed devices exceeds the level of redundancy in the vdev. If reconnecting missing devices the pool will return to an crossref:zfs[zfs-term-online,Online] state. Insufficient redundancy to compensate for the number of failed disks loses the pool contents and requires restoring from backups. |=== diff --git a/documentation/content/en/books/porters-handbook/makefiles/_index.adoc b/documentation/content/en/books/porters-handbook/makefiles/_index.adoc index 54fa80d1e0..2759aa7d32 100644 --- a/documentation/content/en/books/porters-handbook/makefiles/_index.adoc +++ b/documentation/content/en/books/porters-handbook/makefiles/_index.adoc @@ -1,5443 +1,5443 @@ --- title: Chapter 5. Configuring the Makefile prev: books/porters-handbook/slow-porting next: books/porters-handbook/special description: Configuring the Makefile for FreeBSD Ports tags: ["makefiles", "configuring", "naming", "versions"] showBookMenu: true weight: 5 path: "/books/porters-handbook/makefiles/" --- [[makefiles]] = Configuring the Makefile :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 5 :partnums: :source-highlighter: rouge :experimental: :g-plus-plus: g++ :images-path: books/porters-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] Configuring the [.filename]#Makefile# is pretty simple, and again we suggest looking at existing examples before starting. Also, there is a crossref:porting-samplem[porting-samplem,sample Makefile] in this handbook, so take a look and please follow the ordering of variables and sections in that template to make the port easier for others to read. Consider these problems in sequence during the design of the new [.filename]#Makefile#: [[makefile-source]] == The Original Source Does it live in `DISTDIR` as a standard ``gzip``ped tarball named something like [.filename]#foozolix-1.2.tar.gz#? If so, go on to the next step. If not, the distribution file format might require overriding one or more of `DISTVERSION`, `DISTNAME`, `EXTRACT_CMD`, `EXTRACT_BEFORE_ARGS`, `EXTRACT_AFTER_ARGS`, `EXTRACT_SUFX`, or `DISTFILES`. In the worst case, create a custom `do-extract` target to override the default. This is rarely, if ever, necessary. [[makefile-naming]] == Naming The first part of the port's [.filename]#Makefile# names the port, describes its version number, and lists it in the correct category. [[makefile-portname]] === `PORTNAME` Set `PORTNAME` to the base name of the software. It is used as the base for the FreeBSD package, and for crossref:makefiles[makefile-distname,`DISTNAME`]. [IMPORTANT] ==== The package name must be unique across the entire ports tree. Make sure that the `PORTNAME` is not already in use by an existing port, and that no other port already has the same `PKGBASE`. If the name has already been used, add either crossref:makefiles[porting-pkgnameprefix-suffix,`PKGNAMEPREFIX` or `PKGNAMESUFFIX`]. ==== [[makefile-versions]] === Versions, `DISTVERSION` _or_ `PORTVERSION` Set `DISTVERSION` to the version number of the software. `PORTVERSION` is the version used for the FreeBSD package. It will be automatically derived from `DISTVERSION` to be compatible with FreeBSD's package versioning scheme. If the version contains _letters_, it might be needed to set `PORTVERSION` and not `DISTVERSION`. [IMPORTANT] ==== Only one of `PORTVERSION` and `DISTVERSION` can be set at a time. ==== From time to time, some software will use a version scheme that is not compatible with how `DISTVERSION` translates in `PORTVERSION`. [TIP] ==== When updating a port, it is possible to use man:pkg-version[8]'s `-t` argument to check if the new version is greater or lesser than before. See crossref:makefiles[makefile-versions-ex-pkg-version]. ==== [[makefile-versions-ex-pkg-version]] .Using man:pkg-version[8] to Compare Versions [example] ==== `pkg version -t` takes two versions as arguments, it will respond with `<`, `=` or `>` if the first version is less, equal, or more than the second version, respectively. [source,shell] .... % pkg version -t 1.2 1.3 < <.> % pkg version -t 1.2 1.2 = <.> % pkg version -t 1.2 1.2.0 = <.> % pkg version -t 1.2 1.2.p1 > <.> % pkg version -t 1.2.a1 1.2.b1 < <.> % pkg version -t 1.2 1.2p1 < <.> .... <.> `1.2` is before `1.3`. <.> `1.2` and `1.2` are equal as they have the same version. <.> `1.2` and `1.2.0` are equal as nothing equals zero. <.> `1.2` is after `1.2.p1` as `.p1`, think "pre-release 1". <.> `1.2.a1` is before `1.2.b1`, think "alpha" and "beta", and `a` is before `b`. <.> `1.2` is before `1.2p1` as `2p1`, think "2, patch level 1" which is a version after any `2.X` but before `3`. [NOTE] **** In here, the `a`, `b`, and `p` are used as if meaning "alpha", "beta" or "pre-release" and "patch level", but they are only letters and are sorted alphabetically, so any letter can be used, and they will be sorted appropriately. **** ==== .Examples of `DISTVERSION` and the Derived `PORTVERSION` [cols="10%,90%", frame="none", options="header"] |=== | DISTVERSION | PORTVERSION |0.7.1d |0.7.1.d |10Alpha3 |10.a3 |3Beta7-pre2 |3.b7.p2 |8:f_17 |8f.17 |=== [[makefile-versions-ex1]] .Using `DISTVERSION` [example] ==== When the version only contains numbers separated by dots, dashes or underscores, use `DISTVERSION`. [.programlisting] .... PORTNAME= nekoto DISTVERSION= 1.2-4 .... It will generate a `PORTVERSION` of `1.2.4`. ==== [[makefile-versions-ex2]] .Using `DISTVERSION` When the Version Starts with a Letter or a Prefix [example] ==== When the version starts or ends with a letter, or a prefix or a suffix that is not part of the version, use `DISTVERSIONPREFIX`, `DISTVERSION`, and `DISTVERSIONSUFFIX`. If the version is `v1.2-4`: [.programlisting] .... PORTNAME= nekoto DISTVERSIONPREFIX= v DISTVERSION= 1_2_4 .... Some of the time, projects using GitHub will use their name in their versions. For example, the version could be `nekoto-1.2-4`: [.programlisting] .... PORTNAME= nekoto DISTVERSIONPREFIX= nekoto- DISTVERSION= 1.2_4 .... Those projects also sometimes use some string at the end of the version, for example, `1.2-4_RELEASE`: [.programlisting] .... PORTNAME= nekoto DISTVERSION= 1.2-4 DISTVERSIONSUFFIX= _RELEASE .... Or they do both, for example, `nekoto-1.2-4_RELEASE`: [.programlisting] .... PORTNAME= nekoto DISTVERSIONPREFIX= nekoto- DISTVERSION= 1.2-4 DISTVERSIONSUFFIX= _RELEASE .... `DISTVERSIONPREFIX` and `DISTVERSIONSUFFIX` will not be used while constructing `PORTVERSION`, but only used in `DISTNAME`. All will generate a `PORTVERSION` of `1.2.4`. ==== [[makefile-versions-ex3]] .Using `DISTVERSION` When the Version Contains Letters Meaning "alpha", "beta", or "pre-release" [example] ==== When the version contains numbers separated by dots, dashes or underscores, and letters are used to mean "alpha", "beta" or "pre-release", which is, before the version without the letters, use `DISTVERSION`. [.programlisting] .... PORTNAME= nekoto DISTVERSION= 1.2-pre4 .... [.programlisting] .... PORTNAME= nekoto DISTVERSION= 1.2p4 .... Both will generate a `PORTVERSION` of `1.2.p4` which is before than 1.2. man:pkg-version[8] can be used to check that fact: [source,shell] .... % pkg version -t 1.2.p4 1.2 < .... ==== [[makefile-versions-ex4]] .Not Using `DISTVERSION` When the Version Contains Letters Meaning "Patch Level" [example] ==== When the version contains letters that are not meant as "alpha", "beta", or "pre", but more in a "patch level", and meaning after the version without the letters, use `PORTVERSION`. [.programlisting] .... PORTNAME= nekoto PORTVERSION= 1.2p4 .... In this case, using `DISTVERSION` is not possible because it would generate a version of `1.2.p4` which would be before `1.2` and not after. man:pkg-version[8] will verify this: [source,shell] .... % pkg version -t 1.2 1.2.p4 > <.> % pkg version -t 1.2 1.2p4 < <.> .... <.> `1.2` is after `1.2.p4`, which is _wrong_ in this case. <.> `1.2` is before `1.2p4`, which is what was needed. ==== For some more advanced examples of setting `PORTVERSION`, when the software's versioning is really not compatible with FreeBSD's, or `DISTNAME` when the distribution file does not contain the version itself, see -crossref:makefiles[makefile-distname]. +crossref:makefiles[makefile-distname, `DISTNAME`]. [[makefile-naming-revepoch]] === `PORTREVISION` and `PORTEPOCH` [[makefile-portrevision]] ==== `PORTREVISION` `PORTREVISION` is a monotonically increasing value which is reset to 0 with every increase of `DISTVERSION`, typically every time there is a new official vendor release. If `PORTREVISION` is non-zero, the value is appended to the package name. Changes to `PORTREVISION` are used by automated tools like man:pkg-version[8] to determine that a new package is available. `PORTREVISION` must be increased each time a change is made to the port that changes the generated package in any way. That includes changes that only affect a package built with non-default crossref:makefiles[makefile-options,options]. Examples of when `PORTREVISION` must be bumped: * Addition of patches to correct security vulnerabilities, bugs, or to add new functionality to the port. * Changes to the port [.filename]#Makefile# to enable or disable compile-time options in the package. * Changes in the packing list or the install-time behavior of the package. For example, a change to a script which generates initial data for the package, like man:ssh[1] host keys. * Version bump of a port's shared library dependency (in this case, someone trying to install the old package after installing a newer version of the dependency will fail since it will look for the old libfoo.x instead of libfoo.(x+1)). * Silent changes to the port distfile which have significant functional differences. For example, changes to the distfile requiring a correction to [.filename]#distinfo# with no corresponding change to `DISTVERSION`, where a `diff -ru` of the old and new versions shows non-trivial changes to the code. * Changes to `MAINTAINER`. Examples of changes which do not require a `PORTREVISION` bump: * Style changes to the port skeleton with no functional change to what appears in the resulting package. * Changes to `MASTER_SITES` or other functional changes to the port which do not affect the resulting package. * Trivial patches to the distfile such as correction of typos, which are not important enough that users of the package have to go to the trouble of upgrading. * Build fixes which cause a package to become compilable where it was previously failing. As long as the changes do not introduce any functional change on any other platforms on which the port did previously build. Since `PORTREVISION` reflects the content of the package, if the package was not previously buildable then there is no need to increase `PORTREVISION` to mark a change. A rule of thumb is to decide whether a change committed to a port is something which _some_ people would benefit from having. Either because of an enhancement, fix, or by virtue that the new package will actually work at all. Then weigh that against that fact that it will cause everyone who regularly updates their ports tree to be compelled to update. If yes, `PORTREVISION` must be bumped. [NOTE] ==== People using binary packages will _never_ see the update if `PORTREVISION` is not bumped. Without increasing `PORTREVISION`, the package builders have no way to detect the change and thus, will not rebuild the package. ==== [[makefile-portepoch]] ==== `PORTEPOCH` From time to time a software vendor or FreeBSD porter will do something silly and release a version of their software which is actually numerically less than the previous version. An example of this is a port which goes from foo-20000801 to foo-1.0 (the former will be incorrectly treated as a newer version since 20000801 is a numerically greater value than 1). [TIP] ==== The results of version number comparisons are not always obvious. `pkg version` (see man:pkg-version[8]) can be used to test the comparison of two version number strings. For example: [source,shell] .... % pkg version -t 0.031 0.29 > .... The `>` output indicates that version 0.031 is considered greater than version 0.29, which may not have been obvious to the porter. ==== In situations such as this, `PORTEPOCH` must be increased. If `PORTEPOCH` is nonzero it is appended to the package name as described in section 0 above. `PORTEPOCH` must never be decreased or reset to zero, because that would cause comparison to a package from an earlier epoch to fail. For example, the package would not be detected as out of date. The new version number, `1.0,1` in the above example, is still numerically less than the previous version, 20000801, but the `,1` suffix is treated specially by automated tools and found to be greater than the implied suffix `,0` on the earlier package. Dropping or resetting `PORTEPOCH` incorrectly leads to no end of grief. If the discussion above was not clear enough, please consult the {freebsd-ports}. It is expected that `PORTEPOCH` will not be used for the majority of ports, and that sensible use of `DISTVERSION`, or that use `PORTVERSION` carefully, can often preempt it becoming necessary if a future release of the software changes the version structure. However, care is needed by FreeBSD porters when a vendor release is made without an official version number - such as a code "snapshot" release. The temptation is to label the release with the release date, which will cause problems as in the example above when a new "official" release is made. For example, if a snapshot release is made on the date `20000917`, and the previous version of the software was version `1.2`, do not use `20000917` for `DISTVERSION`. The correct way is a `DISTVERSION` of `1.2.20000917`, or similar, so that the succeeding release, say `1.3`, is still a numerically greater value. [[makefile-portrevision-example]] ==== Example of `PORTREVISION` and `PORTEPOCH` Usage The `gtkmumble` port, version `0.10`, is committed to the ports collection: [.programlisting] .... PORTNAME= gtkmumble DISTVERSION= 0.10 .... `PKGNAME` becomes `gtkmumble-0.10`. A security hole is discovered which requires a local FreeBSD patch. `PORTREVISION` is bumped accordingly. [.programlisting] .... PORTNAME= gtkmumble DISTVERSION= 0.10 PORTREVISION= 1 .... `PKGNAME` becomes `gtkmumble-0.10_1` A new version is released by the vendor, numbered `0.2` (it turns out the author actually intended `0.10` to actually mean `0.1.0`, not "what comes after 0.9" - oops, too late now). Since the new minor version `2` is numerically less than the previous version `10`, `PORTEPOCH` must be bumped to manually force the new package to be detected as "newer". Since it is a new vendor release of the code, `PORTREVISION` is reset to 0 (or removed from the [.filename]#Makefile#). [.programlisting] .... PORTNAME= gtkmumble DISTVERSION= 0.2 PORTEPOCH= 1 .... `PKGNAME` becomes `gtkmumble-0.2,1` The next release is 0.3. Since `PORTEPOCH` never decreases, the version variables are now: [.programlisting] .... PORTNAME= gtkmumble DISTVERSION= 0.3 PORTEPOCH= 1 .... `PKGNAME` becomes `gtkmumble-0.3,1` [NOTE] ==== If `PORTEPOCH` were reset to `0` with this upgrade, someone who had installed the `gtkmumble-0.10_1` package would not detect the `gtkmumble-0.3` package as newer, since `3` is still numerically less than `10`. Remember, this is the whole point of `PORTEPOCH` in the first place. ==== [[porting-pkgnameprefix-suffix]] === `PKGNAMEPREFIX` and `PKGNAMESUFFIX` Two optional variables, `PKGNAMEPREFIX` and `PKGNAMESUFFIX`, are combined with `PORTNAME` and `PORTVERSION` to form `PKGNAME` as `${PKGNAMEPREFIX}${PORTNAME}${PKGNAMESUFFIX}-${PORTVERSION}`. Make sure this conforms to our crossref:makefiles[porting-pkgname,guidelines for a good package name]. In particular, the use of a hyphen (`-`) in `PORTVERSION` is _not_ allowed. Also, if the package name has the _language-_ or the _-compiled.specifics_ part (see below), use `PKGNAMEPREFIX` and `PKGNAMESUFFIX`, respectively. Do not make them part of `PORTNAME`. [[porting-pkgname]] === Package Naming Conventions These are the conventions to follow when naming packages. This is to make the package directory easy to scan, as there are already thousands of packages and users are going to turn away if they hurt their eyes! Package names take the form of [.filename]#language_region-name-compiled.specifics-version.numbers#. The package name is defined as `${PKGNAMEPREFIX}${PORTNAME}${PKGNAMESUFFIX}-${PORTVERSION}`. Make sure to set the variables to conform to that format. [[porting-pkgname-language]] [.filename]#language_region-#:: FreeBSD strives to support the native language of its users. The _language-_ part is a two letter abbreviation of the natural language defined by ISO-639 when the port is specific to a certain language. Examples are `ja` for Japanese, `ru` for Russian, `vi` for Vietnamese, `zh` for Chinese, `ko` for Korean and `de` for German. + If the port is specific to a certain region within the language area, add the two letter country code as well. Examples are `en_US` for US English and `fr_CH` for Swiss French. + The _language-_ part is set in `PKGNAMEPREFIX`. [[porting-pkgname-name]] [.filename]#name#:: Make sure that the port's name and version are clearly separated and placed into `PORTNAME` and `DISTVERSION`. The only reason for `PORTNAME` to contain a version part is if the upstream distribution is really named that way, as in the package:textproc/libxml2[] or package:japanese/kinput2-freewnn[] ports. Otherwise, `PORTNAME` cannot contain any version-specific information. It is quite normal for several ports to have the same `PORTNAME`, as the package:www/apache*[] ports do; in that case, different versions (and different index entries) are distinguished by `PKGNAMEPREFIX` and `PKGNAMESUFFIX` values. + There is a tradition of naming `Perl 5` modules by prepending `p5-` and converting the double-colon separator to a hyphen. For example, the `Data::Dumper` module becomes `p5-Data-Dumper`. [[porting-pkgname-compiled-specifics]] [.filename]#-compiled.specifics#:: If the port can be built with different crossref:makefiles[makefile-masterdir,hardcoded defaults] (usually part of the directory name in a family of ports), the _-compiled.specifics_ part states the compiled-in defaults. The hyphen is optional. Examples are paper size and font units. + The _-compiled.specifics_ part is set in `PKGNAMESUFFIX`. [[porting-pkgname-version-numbers]] [.filename]#-version.numbers#:: The version string follows a dash (`-`) and is a period-separated list of integers and single lowercase alphabetics. In particular, it is not permissible to have another dash inside the version string. The only exception is the string `pl` (meaning "patchlevel"), which can be used _only_ when there are no major and minor version numbers in the software. If the software version has strings like "alpha", "beta", "rc", or "pre", take the first letter and put it immediately after a period. If the version string continues after those names, the numbers follow the single alphabet without an extra period between them (for example, `1.0b2`). + The idea is to make it easier to sort ports by looking at the version string. In particular, make sure version number components are always delimited by a period, and if the date is part of the string, use the `d__yyyy.mm.dd__` format, not `_dd.mm.yyyy_` or the non-Y2K compliant `_yy.mm.dd_` format. It is important to prefix the version with a letter, here `d` (for date), in case a release with an actual version number is made, which would be numerically less than `_yyyy_`. [IMPORTANT] ==== Package name must be unique among all of the ports tree, check that there is not already a port with the same `PORTNAME` and if there is add one of crossref:makefiles[porting-pkgnameprefix-suffix,`PKGNAMEPREFIX` or `PKGNAMESUFFIX`]. ==== Here are some (real) examples on how to convert the name as called by the software authors to a suitable package name, for each line, only one of `DISTVERSION` or `PORTVERSION` is set in, depending on which would be used in the port's [.filename]#Makefile#: .Package Naming Examples [cols="1,1,1,1,1,1,1", frame="none", options="header"] |=== | Distribution Name | PKGNAMEPREFIX | PORTNAME | PKGNAMESUFFIX | DISTVERSION | PORTVERSION | Reason or comment |mule-2.2.2 |(empty) |mule |(empty) |2.2.2 | |No changes required |mule-1.0.1 |(empty) |mule |1 |1.0.1 | |This is version 1 of mule, and version 2 already exists |EmiClock-1.0.2 |(empty) |emiclock |(empty) |1.0.2 | |No uppercase names for single programs |rdist-1.3alpha |(empty) |rdist |(empty) |1.3alpha | |Version will be `1.3.a` |es-0.9-beta1 |(empty) |es |(empty) |0.9-beta1 | |Version will be `0.9.b1` |mailman-2.0rc3 |(empty) |mailman |(empty) |2.0rc3 | |Version will be `2.0.r3` |v3.3beta021.src |(empty) |tiff |(empty) | |3.3 |What the heck was that anyway? |tvtwm |(empty) |tvtwm |(empty) | |p11 |No version in the filename, use what upstream says it is |piewm |(empty) |piewm |(empty) |1.0 | |No version in the filename, use what upstream says it is |xvgr-2.10pl1 |(empty) |xvgr |(empty) | |2.10.pl1 |In that case, `pl1` means patch level, so using DISTVERSION is not possible. |gawk-2.15.6 |ja- |gawk |(empty) |2.15.6 | |Japanese language version |psutils-1.13 |(empty) |psutils |-letter |1.13 | |Paper size hardcoded at package build time |pkfonts |(empty) |pkfonts |300 |1.0 | |Package for 300dpi fonts |=== If there is absolutely no trace of version information in the original source and it is unlikely that the original author will ever release another version, just set the version string to `1.0` (like the `piewm` example above). Otherwise, ask the original author or use the date string the source file was released on (`d__yyyy.mm.dd__`, or `d__yyyymmdd__`) as the version. [TIP] ==== Use any letter. Here, `d` here stands for date, if the source is a Git repository, `g` followed by the commit date is commonly used, using `s` for snapshot is also common. ==== [[makefile-categories]] == Categorization [[makefile-categories-definition]] === `CATEGORIES` When a package is created, it is put under [.filename]#/usr/ports/packages/All# and links are made from one or more subdirectories of [.filename]#/usr/ports/packages#. The names of these subdirectories are specified by the variable `CATEGORIES`. It is intended to make life easier for the user when he is wading through the pile of packages on the FTP site or the CDROM. Please take a look at the crossref:makefiles[porting-categories,current list of categories] and pick the ones that are suitable for the port. This list also determines where in the ports tree the port is imported. If there is more than one category here, the port files must be put in the subdirectory with the name of the first category. See crossref:makefiles[choosing-categories,below] for more discussion about how to pick the right categories. [[porting-categories]] === Current List of Categories Here is the current list of port categories. Those marked with an asterisk (`*`) are _virtual_ categories-those that do not have a corresponding subdirectory in the ports tree. They are only used as secondary categories, and only for search purposes. [NOTE] ==== For non-virtual categories, there is a one-line description in `COMMENT` in that subdirectory's [.filename]#Makefile#. ==== [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | Category | Description | Notes |[.filename]#accessibility# |Ports to help disabled users. | |[.filename]#afterstep#`*` |Ports to support the http://www.afterstep.org/[AfterStep] window manager. | |[.filename]#arabic# |Arabic language support. | |[.filename]#archivers# |Archiving tools. | |[.filename]#astro# |Astronomical ports. | |[.filename]#audio# |Sound support. | |[.filename]#benchmarks# |Benchmarking utilities. | |[.filename]#biology# |Biology-related software. | |[.filename]#cad# |Computer aided design tools. | |[.filename]#chinese# |Chinese language support. | |[.filename]#comms# |Communication software. |Mostly software to talk to the serial port. |[.filename]#converters# |Character code converters. | |[.filename]#databases# |Databases. | |[.filename]#deskutils# |Things that used to be on the desktop before computers were invented. | |[.filename]#devel# |Development utilities. |Do not put libraries here just because they are libraries. They should _not_ be in this category unless they truly do not belong anywhere else. |[.filename]#dns# |DNS-related software. | |[.filename]#docs#`*` |Meta-ports for FreeBSD documentation. | |[.filename]#editors# |General editors. |Specialized editors go in the section for those tools. For example, a mathematical-formula editor will go in [.filename]#math#, and have [.filename]#editors# as a second category. |[.filename]#education#`*` |Education-related software. |This includes applications, utilities, or games primarily or substantially designed to help the user learn a specific topic or study in general. It also includes course-writing applications, course-delivery applications, and classroom or school management applications |[.filename]#elisp#`*` |Emacs-lisp ports. | |[.filename]#emulators# |Emulators for other operating systems. |Terminal emulators do _not_ belong here. X-based ones go to [.filename]#x11# and text-based ones to either [.filename]#comms# or [.filename]#misc#, depending on the exact functionality. |[.filename]#enlightenment#`*` |Ports related to the Enlightenment window manager. | |[.filename]#finance# |Monetary, financial and related applications. | |[.filename]#french# |French language support. | |[.filename]#ftp# |FTP client and server utilities. |If the port speaks both FTP and HTTP, put it in [.filename]#ftp# with a secondary category of [.filename]#www#. |[.filename]#games# |Games. | |[.filename]#geography#`*` |Geography-related software. | |[.filename]#german# |German language support. | |[.filename]#gnome#`*` |Ports from the https://www.gnome.org/[GNOME] Project. | |[.filename]#gnustep#`*` |Software related to the GNUstep desktop environment. | |[.filename]#graphics# |Graphics utilities. | |[.filename]#hamradio#`*` |Software for amateur radio. | |[.filename]#haskell#`*` |Software related to the Haskell language. | |[.filename]#hebrew# |Hebrew language support. | |[.filename]#hungarian# |Hungarian language support. | |[.filename]#irc# |Internet Relay Chat utilities. | |[.filename]#japanese# |Japanese language support. | |[.filename]#java# |Software related to the Java(TM) language. |The [.filename]#java# category must not be the only one for a port. Save for ports directly related to the Java language, porters are also encouraged not to use [.filename]#java# as the main category of a port. |[.filename]#kde#`*` |Ports from the https://www.kde.org/[KDE] Project (generic). | |[.filename]#kde-applications#`*` |Applications from the https://www.kde.org/[KDE] Project. | |[.filename]#kde-frameworks#`*` |Add-on libraries from the https://www.kde.org/[KDE] Project for programming with Qt. | |[.filename]#kde-plasma#`*` |Desktop from the https://www.kde.org/[KDE] Project. | |[.filename]#kld#`*` |Kernel loadable modules. | |[.filename]#korean# |Korean language support. | |[.filename]#lang# |Programming languages. | |[.filename]#linux#`*` |Linux applications and support utilities. | |[.filename]#lisp#`*` |Software related to the Lisp language. | |[.filename]#mail# |Mail software. | |[.filename]#mate#`*` |Ports related to the MATE desktop environment, a fork of GNOME 2. | |[.filename]#math# |Numerical computation software and other utilities for mathematics. | |[.filename]#mbone#`*` |MBone applications. | |[.filename]#misc# |Miscellaneous utilities |Things that do not belong anywhere else. If at all possible, try to find a better category for the port than `misc`, as ports tend to be overlooked in here. |[.filename]#multimedia# |Multimedia software. | |[.filename]#net# |Miscellaneous networking software. | |[.filename]#net-im# |Instant messaging software. | |[.filename]#net-mgmt# |Networking management software. | |[.filename]#net-p2p# |Peer to peer network applications. | |[.filename]#net-vpn#`*` |Virtual Private Network applications. | |[.filename]#news# |USENET news software. | |[.filename]#parallel#`*` |Applications dealing with parallelism in computing. | |[.filename]#pear#`*` |Ports related to the Pear PHP framework. | |[.filename]#perl5#`*` |Ports that require Perl version 5 to run. | |[.filename]#plan9#`*` |Various programs from https://9p.io/wiki/plan9/Download/index.html[Plan9]. | |[.filename]#polish# |Polish language support. | |[.filename]#ports-mgmt# |Ports for managing, installing and developing FreeBSD ports and packages. | |[.filename]#portuguese# |Portuguese language support. | |[.filename]#print# |Printing software. |Desktop publishing tools (previewers, etc.) belong here too. |[.filename]#python#`*` |Software related to the https://www.python.org/[Python] language. | |[.filename]#ruby#`*` |Software related to the https://www.ruby-lang.org/[Ruby] language. | |[.filename]#rubygems#`*` |Ports of https://www.rubygems.org/[RubyGems] packages. | |[.filename]#russian# |Russian language support. | |[.filename]#scheme#`*` |Software related to the Scheme language. | |[.filename]#science# |Scientific ports that do not fit into other categories such as [.filename]#astro#, [.filename]#biology# and [.filename]#math#. | |[.filename]#security# |Security utilities. | |[.filename]#shells# |Command line shells. | |[.filename]#spanish#`*` |Spanish language support. | |[.filename]#sysutils# |System utilities. | |[.filename]#tcl#`*` |Ports that use Tcl to run. | |[.filename]#textproc# |Text processing utilities. |It does not include desktop publishing tools, which go to [.filename]#print#. |[.filename]#tk#`*` |Ports that use Tk to run. | |[.filename]#ukrainian# |Ukrainian language support. | |[.filename]#vietnamese# |Vietnamese language support. | |[.filename]#wayland#`*` |Ports to support the Wayland display server. | |[.filename]#windowmaker#`*` |Ports to support the Window Maker window manager. | |[.filename]#www# |Software related to the World Wide Web. |HTML language support belongs here too. |[.filename]#x11# |The X Window System and friends. |This category is only for software that directly supports the window system. Do not put regular X applications here. Most of them go into other [.filename]#x11-*# categories (see below). |[.filename]#x11-clocks# |X11 clocks. | |[.filename]#x11-drivers# |X11 drivers. | |[.filename]#x11-fm# |X11 file managers. | |[.filename]#x11-fonts# |X11 fonts and font utilities. | |[.filename]#x11-servers# |X11 servers. | |[.filename]#x11-themes# |X11 themes. | |[.filename]#x11-toolkits# |X11 toolkits. | |[.filename]#x11-wm# |X11 window managers. | |[.filename]#xfce#`*` |Ports related to the https://www.xfce.org/[Xfce] desktop environment. | |[.filename]#zope#`*` |https://www.zope.org/[Zope] support. | |=== [[choosing-categories]] === Choosing the Right Category As many of the categories overlap, choosing which of the categories will be the primary category of the port can be tedious. There are several rules that govern this issue. Here is the list of priorities, in decreasing order of precedence: * The first category must be a physical category (see crossref:makefiles[porting-categories,above]). This is necessary to make the packaging work. Virtual categories and physical categories may be intermixed after that. * Language specific categories always come first. For example, if the port installs Japanese X11 fonts, then the `CATEGORIES` line would read [.filename]#japanese x11-fonts#. * Specific categories are listed before less-specific ones. For instance, an HTML editor is listed as [.filename]#www editors#, not the other way around. Also, do not list [.filename]#net# when the port belongs to any of [.filename]#irc#, [.filename]#mail#, [.filename]#news#, [.filename]#security#, or [.filename]#www#, as [.filename]#net# is included implicitly. * [.filename]#x11# is used as a secondary category only when the primary category is a natural language. In particular, do not put [.filename]#x11# in the category line for X applications. * Emacs modes are placed in the same ports category as the application supported by the mode, not in [.filename]#editors#. For example, an Emacs mode to edit source files of some programming language goes into [.filename]#lang#. * Ports installing loadable kernel modules also have the virtual category [.filename]#kld# in their `CATEGORIES` line. This is one of the things handled automatically by adding `USES=kmod`. * [.filename]#misc# does not appear with any other non-virtual category. If there is `misc` with something else in `CATEGORIES`, that means `misc` can safely be deleted and the port placed only in the other subdirectory. * If the port truly does not belong anywhere else, put it in [.filename]#misc#. If the category is not clearly defined, please put a comment to that effect in the https://bugs.freebsd.org/submit/[port submission] in the bug database so we can discuss it before we import it. As a committer, send a note to the {freebsd-ports} so we can discuss it first. Too often, new ports are imported to the wrong category only to be moved right away. [[proposing-categories]] === Proposing a New Category As the Ports Collection has grown over time, various new categories have been introduced. New categories can either be _virtual_ categories-those that do not have a corresponding subdirectory in the ports tree- or _physical_ categories-those that do. This section discusses the issues involved in creating a new physical category. Read it thoroughly before proposing a new one. Our existing practice has been to avoid creating a new physical category unless either a large number of ports would logically belong to it, or the ports that would belong to it are a logically distinct group that is of limited general interest (for instance, categories related to spoken human languages), or preferably both. The rationale for this is that such a change creates a extref:{committers-guide}[fair amount of work, ports] for both the committers and also for all users who track changes to the Ports Collection. In addition, proposed category changes just naturally seem to attract controversy. (Perhaps this is because there is no clear consensus on when a category is "too big", nor whether categories should lend themselves to browsing (and thus what number of categories would be an ideal number), and so forth.) Here is the procedure: [.procedure] . Propose the new category on {freebsd-ports}. Include a detailed rationale for the new category, including why the existing categories are not sufficient, and the list of existing ports proposed to move. (If there are new ports pending in Bugzilla that would fit this category, list them too.) If you are the maintainer and/or submitter, respectively, mention that as it may help the case. . Participate in the discussion. . If it seems that there is support for the idea, file a PR which includes both the rationale and the list of existing ports that need to be moved. Ideally, this PR would also include these patches: ** [.filename]##Makefile##s for the new ports once they are repocopied ** [.filename]#Makefile# for the new category ** [.filename]#Makefile# for the old ports' categories ** [.filename]##Makefile##s for ports that depend on the old ports ** (for extra credit, include the other files that have to change, as per the procedure in the Committer's Guide.) . Since it affects the ports infrastructure and involves moving and patching many ports but also possibly running regression tests on the build cluster, assign the PR to the {portmgr}. . If that PR is approved, a committer will need to follow the rest of the procedure that is extref:{committers-guide}[outlined in the Committer's Guide, ports]. Proposing a new virtual category is similar to the above but much less involved, since no ports will actually have to move. In this case, the only patches to include in the PR would be those to add the new category to `CATEGORIES` of the affected ports. [[proposing-reorg]] === Proposing Reorganizing All the Categories Occasionally someone proposes reorganizing the categories with either a 2-level structure, or some other kind of keyword structure. To date, nothing has come of any of these proposals because, while they are very easy to make, the effort involved to retrofit the entire existing ports collection with any kind of reorganization is daunting to say the very least. Please read the history of these proposals in the mailing list archives before posting this idea. Furthermore, be prepared to be challenged to offer a working prototype. [[makefile-distfiles]] == The Distribution Files The second part of the [.filename]#Makefile# describes the files that must be downloaded to build the port, and where they can be downloaded. [[makefile-distname]] === `DISTNAME` `DISTNAME` is the name of the port as called by the authors of the software. `DISTNAME` defaults to `${PORTNAME}-${DISTVERSIONPREFIX}${DISTVERSION}${DISTVERSIONSUFFIX}`, and if not set, `DISTVERSION` defaults to `${PORTVERSION}` so override `DISTNAME` only if necessary. `DISTNAME` is only used in two places. First, the distribution file list (`DISTFILES`) defaults to `${DISTNAME}${EXTRACT_SUFX}`. Second, the distribution file is expected to extract into a subdirectory named `WRKSRC`, which defaults to [.filename]#work/${DISTNAME}#. Some vendor's distribution names which do not fit into the `${PORTNAME}-${PORTVERSION}`-scheme can be handled automatically by setting `DISTVERSIONPREFIX`, `DISTVERSION`, and `DISTVERSIONSUFFIX`. `PORTVERSION` will be derived from `DISTVERSION` automatically. [IMPORTANT] ==== Only one of `PORTVERSION` and `DISTVERSION` can be set at a time. If `DISTVERSION` does not derive a correct `PORTVERSION`, do not use `DISTVERSION`. ==== If the upstream version scheme can be derived into a ports-compatible version scheme, set some variable to the upstream version, _do not_ use `DISTVERSION` as the variable name. Set `PORTVERSION` to the computed version based on the variable you created, and set `DISTNAME` accordingly. If the upstream version scheme cannot easily be coerced into a ports-compatible value, set `PORTVERSION` to a sensible value, and set `DISTNAME` with `PORTNAME` with the verbatim upstream version. [[makefile-distname-ex1]] .Deriving `PORTVERSION` Manually [example] ==== BIND9 uses a version scheme that is not compatible with the ports versions (it has `-` in its versions) and cannot be derived using `DISTVERSION` because after the 9.9.9 release, it will release a "patchlevels" in the form of `9.9.9-P1`. DISTVERSION would translate that into `9.9.9.p1`, which, in the ports versioning scheme means 9.9.9 pre-release 1, which is before 9.9.9 and not after. So `PORTVERSION` is manually derived from an `ISCVERSION` variable to output `9.9.9p1`. The order into which the ports framework, and pkg, will sort versions is checked using the `-t` argument of man:pkg-version[8]: [source,shell] .... % pkg version -t 9.9.9 9.9.9.p1 > <.> % pkg version -t 9.9.9 9.9.9p1 < <.> .... <.> The `>` sign means that the first argument passed to `-t` is greater than the second argument. `9.9.9` is after `9.9.9.p1`. <.> The `<` sign means that the first argument passed to `-t` is less than the second argument. `9.9.9` is before `9.9.9p1`. In the port [.filename]#Makefile#, for example package:dns/bind99[], it is achieved by: [.programlisting] .... PORTNAME= bind PORTVERSION= ${ISCVERSION:S/-P/P/:S/b/.b/:S/a/.a/:S/rc/.rc/} CATEGORIES= dns net MASTER_SITES= ISC/bind9/${ISCVERSION} PKGNAMESUFFIX= 99 DISTNAME= ${PORTNAME}-${ISCVERSION} MAINTAINER= mat@FreeBSD.org COMMENT= BIND DNS suite with updated DNSSEC and DNS64 WWW= https://www.isc.org/bind/ LICENSE= ISCL # ISC releases things like 9.8.0-P1 or 9.8.1rc1, which our versioning does not like ISCVERSION= 9.9.9-P6 .... Define upstream version in `ISCVERSION`, with a comment saying _why_ it is needed. Use `ISCVERSION` to get a ports-compatible `PORTVERSION`. Use `ISCVERSION` directly to get the correct URL for fetching the distribution file. Use `ISCVERSION` directly to name the distribution file. ==== [[makefile-distname-ex2]] .Derive `DISTNAME` from `PORTVERSION` [example] ==== From time to time, the distribution file name has little or no relation to the version of the software. In package:comms/kermit[], only the last element of the version is present in the distribution file: [.programlisting] .... PORTNAME= kermit PORTVERSION= 9.0.304 CATEGORIES= comms ftp net MASTER_SITES= ftp://ftp.kermitproject.org/kermit/test/tar/ DISTNAME= cku${PORTVERSION:E}-dev20 .... The `:E` man:make[1] modifier returns the suffix of the variable, in this case, `304`. The distribution file is correctly generated as `cku304-dev20.tar.gz`. ==== [[makefile-distname-ex3]] .Exotic Case 1 [example] ==== Sometimes, there is no relation between the software name, its version, and the distribution file it is distributed in. From package:audio/libworkman[]: [.programlisting] .... PORTNAME= libworkman PORTVERSION= 1.4 CATEGORIES= audio MASTER_SITES= LOCAL/jim DISTNAME= ${PORTNAME}-1999-06-20 .... ==== [[makefile-distname-ex4]] .Exotic Case 2 [example] ==== In package:comms/librs232[], the distribution file is not versioned, so using crossref:makefiles[makefile-dist_subdir,`DIST_SUBDIR`] is needed: [.programlisting] .... PORTNAME= librs232 PORTVERSION= 20160710 CATEGORIES= comms MASTER_SITES= http://www.teuniz.net/RS-232/ DISTNAME= RS-232 DIST_SUBDIR= ${PORTNAME}-${PORTVERSION} .... ==== [NOTE] ==== `PKGNAMEPREFIX` and `PKGNAMESUFFIX` do not affect `DISTNAME`. Also note that if `WRKSRC` is equal to [.filename]#${WRKDIR}/${DISTNAME}# while the original source archive is named something other than `${PORTNAME}-${PORTVERSION}${EXTRACT_SUFX}`, leave `DISTNAME` alone- defining only `DISTFILES` is easier than both `DISTNAME` and `WRKSRC` (and possibly `EXTRACT_SUFX`). ==== [[makefile-master_sites]] === `MASTER_SITES` Record the directory part of the FTP/HTTP-URL pointing at the original tarball in `MASTER_SITES`. Do not forget the trailing slash ([.filename]#/#)! The `make` macros will try to use this specification for grabbing the distribution file with `FETCH` if they cannot find it already on the system. It is recommended that multiple sites are included on this list, preferably from different continents. This will safeguard against wide-area network problems. [IMPORTANT] ==== `MASTER_SITES` must not be blank. It must point to the actual site hosting the distribution files. It cannot point to web archives, or the FreeBSD distribution files cache sites. The only exception to this rule is ports that do not have any distribution files. For example, meta-ports do not have any distribution files, so `MASTER_SITES` does not need to be set. ==== [[makefile-master_sites-shorthand]] ==== Using `MASTER_SITE_*` Variables Shortcut abbreviations are available for popular archives like SourceForge (`SOURCEFORGE`), GNU (`GNU`), or Perl CPAN (`PERL_CPAN`). `MASTER_SITES` can use them directly: [.programlisting] .... MASTER_SITES= GNU/make .... The older expanded format still works, but all ports have been converted to the compact format. The expanded format looks like this: [.programlisting] .... MASTER_SITES= ${MASTER_SITE_GNU} MASTER_SITE_SUBDIR= make .... These values and variables are defined in https://cgit.freebsd.org/ports/tree/Mk/bsd.sites.mk[Mk/bsd.sites.mk]. New entries are added often, so make sure to check the latest version of this file before submitting a port. [TIP] ==== For any `MASTER_SITE_FOO` variable, the shorthand `_FOO_` can be used. For example, use: [.programlisting] .... MASTER_SITES= FOO .... If `MASTER_SITE_SUBDIR` is needed, use this: [.programlisting] .... MASTER_SITES= FOO/bar .... ==== [NOTE] ==== Some `MASTER_SITE_*` names are quite long, and for ease of use, shortcuts have been defined: [[makefile-master_sites-shortcut]] .Shortcuts for `MASTER_SITE_*` Macros [cols="1,1", frame="none", options="header"] |=== | Macro | Shortcut |`PERL_CPAN` |`CPAN` |`GITHUB` |`GH` |`GITHUB_CLOUD` |`GHC` |`LIBREOFFICE_DEV` |`LODEV` |`NETLIB` |`NL` |`RUBYGEMS` |`RG` |`SOURCEFORGE` |`SF` |=== ==== [[makefile-master_sites-magic]] ==== Magic MASTER_SITES Macros Several "magic" macros exist for popular sites with a predictable directory structure. For these, just use the abbreviation and the system will choose a subdirectory automatically. For a port named `Stardict`, of version `1.2.3`, and hosted on SourceForge, adding this line: [.programlisting] .... MASTER_SITES= SF .... infers a subdirectory named `/project/stardict/stardict/1.2.3`. If the inferred directory is incorrect, it can be overridden: [.programlisting] .... MASTER_SITES= SF/stardict/WyabdcRealPeopleTTS/${PORTVERSION} .... This can also be written as [.programlisting] .... MASTER_SITES= SF MASTER_SITE_SUBDIR= stardict/WyabdcRealPeopleTTS/${PORTVERSION} .... [[makefile-master_sites-popular]] .Magic `MASTER_SITES` Macros [cols="1,1", frame="none", options="header"] |=== | Macro | Assumed subdirectory |`APACHE_COMMONS_BINARIES` |`${PORTNAME:S,commons-,,}` |`APACHE_COMMONS_SOURCE` |`${PORTNAME:S,commons-,,}` |`APACHE_JAKARTA` |`${PORTNAME:S,-,/,}/source` |`BERLIOS` |`${PORTNAME:tl}.berlios` |`CHEESESHOP` |`source/${DISTNAME:C/(.).\*/\1/}/${DISTNAME:C/(.*)-[0-9].*/\1/}` |`CPAN` |`${PORTNAME:C/-.*//}` |`DEBIAN` |`pool/main/${PORTNAME:C/^((lib)?.).*$/\1/}/${PORTNAME}` |`FARSIGHT` |`${PORTNAME}` |`FESTIVAL` |`${PORTREVISION}` |`GCC` |`releases/${DISTNAME}` |`GENTOO` |`distfiles` |`GIMP` |`${PORTNAME}/${PORTVERSION:R}/` |`GH` |`${GH_ACCOUNT}/${GH_PROJECT}/tar.gz/${GH_TAGNAME}?dummy=/` |`GHC` |`${GH_ACCOUNT}/${GH_PROJECT}/` |`GNOME` |`sources/${PORTNAME}/${PORTVERSION:C/^([0-9]+\.[0-9]+).*/\1/}` |`GNU` |`${PORTNAME}` |`GNUPG` |`${PORTNAME}` |`GNU_ALPHA` |`${PORTNAME}` |`HORDE` |`${PORTNAME}` |`LODEV` |`${PORTNAME}` |`MATE` |`${PORTVERSION:C/^([0-9]+\.[0-9]+).*/\1/}` |`MOZDEV` |`${PORTNAME:tl}` |`NL` |`${PORTNAME}` |`QT` |`archive/qt/${PORTVERSION:R}` |`SAMBA` |`${PORTNAME}` |`SAVANNAH` |`${PORTNAME:tl}` |`SF` |`${PORTNAME:tl}/${PORTNAME:tl}/${PORTVERSION}` |=== [[makefile-master_sites-github]] === `USE_GITHUB` If the distribution file comes from a specific commit or tag on https://github.com/[GitHub] for which there is no officially released file, there is an easy way to set the right `DISTNAME` and `MASTER_SITES` automatically. [WARNING] ==== As of 2023-02-21 link:https://github.blog/2023-02-21-update-on-the-future-stability-of-source-code-archives-and-hashes/[GitHub] have announced that source downloads will be stable for a year. Please switch to release assets and if not available ask upstream to generate ones. ==== These variables are available: [[makefile-master_sites-github-description]] .`USE_GITHUB` Description [cols="1,1,1", options="header"] |=== | Variable | Description | Default |`GH_ACCOUNT` |Account name of the GitHub user hosting the project |`${PORTNAME}` |`GH_PROJECT` |Name of the project on GitHub |`${PORTNAME}` |`GH_TAGNAME` |Name of the tag to download (2.0.1, hash, ...) Using the name of a branch here is incorrect. It is also possible to use the hash of a commit id to do a snapshot. |`${DISTVERSIONPREFIX}${DISTVERSION}${DISTVERSIONSUFFIX}` |`GH_SUBDIR` |When the software needs an additional distribution file to be extracted within `${WRKSRC}`, this variable can be used. See the examples in -crossref:makefiles[makefile-master_sites-github-multiple] for more information. +crossref:makefiles[makefile-master_sites-github-multiple, Fetching Multiple Files from GitHub] for more information. |(none) |`GH_TUPLE` |`GH_TUPLE` allows putting `GH_ACCOUNT`, `GH_PROJECT`, `GH_TAGNAME`, and `GH_SUBDIR` into a single variable. The format is _account_`:`_project_`:`_tagname_`:`_group_`/`_subdir_. The `/`_subdir_ part is optional. It is helpful when there is more than one GitHub project from which to fetch. | |=== [IMPORTANT] ==== Do not use `GH_TUPLE` for the default distribution file, as it has no default. ==== [[makefile-master_sites-github-ex1]] .Simple Use of `USE_GITHUB` [example] ==== While trying to make a port for version `1.2.7` of pkg from the FreeBSD user on github, at https://github.com/freebsd/pkg/[], The [.filename]#Makefile# would end up looking like this (slightly stripped for the example): [.programlisting] .... PORTNAME= pkg DISTVERSION= 1.2.7 USE_GITHUB= yes GH_ACCOUNT= freebsd .... It will automatically have `MASTER_SITES` set to `GH` and `WRKSRC` to `${WRKDIR}/pkg-1.2.7`. ==== [[makefile-master_sites-github-ex2]] .More Complete Use of `USE_GITHUB` [example] ==== While trying to make a port for the bleeding edge version of pkg from the FreeBSD user on github, at https://github.com/freebsd/pkg/[], the [.filename]#Makefile# ends up looking like this (slightly stripped for the example): [.programlisting] .... PORTNAME= pkg-devel DISTVERSION= 1.3.0.a.20140411 USE_GITHUB= yes GH_ACCOUNT= freebsd GH_PROJECT= pkg GH_TAGNAME= 6dbb17b .... It will automatically have `MASTER_SITES` set to `GH` and `WRKSRC` to `${WRKDIR}/pkg-6dbb17b`. [TIP] **** `20140411` is the date of the commit referenced in `GH_TAGNAME`, not the date the [.filename]#Makefile# is edited, or the date the commit is made. **** ==== [[makefile-master_sites-github-ex3]] .Use of `USE_GITHUB` with `DISTVERSIONPREFIX` [example] ==== From time to time, `GH_TAGNAME` is a slight variation from `DISTVERSION`. For example, if the version is `1.0.2`, the tag is `v1.0.2`. In those cases, it is possible to use `DISTVERSIONPREFIX` or `DISTVERSIONSUFFIX`: [.programlisting] .... PORTNAME= foo DISTVERSIONPREFIX= v DISTVERSION= 1.0.2 USE_GITHUB= yes .... It will automatically set `GH_TAGNAME` to `v1.0.2`, while `WRKSRC` will be kept to `${WRKDIR}/foo-1.0.2`. ==== [[makefile-master_sites-github-ex4]] .Using `USE_GITHUB` When Upstream Does Not Use Versions [example] ==== If there never was a version upstream, do not invent one like `0.1` or `1.0`. Create the port with a `DISTVERSION` of `g__YYYYMMDD__`, where `g` is for Git, and `_YYYYMMDD_` represents the date the commit referenced in `GH_TAGNAME`. [.programlisting] .... PORTNAME= bar DISTVERSION= g20140411 USE_GITHUB= yes GH_TAGNAME= c472d66b .... This creates a versioning scheme that increases over time, and that is still before version `0` (see crossref:makefiles[makefile-versions-ex-pkg-version] for details on man:pkg-version[8]): [source,shell] .... % pkg version -t g20140411 0 < .... Which means using `PORTEPOCH` will not be needed in case upstream decides to cut versions in the future. ==== [[makefile-master_sites-github-ex5]] .Using `USE_GITHUB` to Access a Commit Between Two Versions [example] ==== If the current version of the software uses a Git tag, and the port needs to be updated to a newer, intermediate version, without a tag, use man:git-describe[1] to find out the version to use: [source,shell] .... % git describe --tags f0038b1 v0.7.3-14-gf0038b1 .... `v0.7.3-14-gf0038b1` can be split into three parts: `v0.7.3`:: This is the last Git tag that appears in the commit history before the requested commit. `-14`:: This means that the requested commit, `f0038b1`, is the 14th commit after the `v0.7.3` tag. `-gf0038b1`:: The `-g` means "Git", and the `f0038b1` is the commit hash that this reference points to. [.programlisting] .... PORTNAME= bar DISTVERSIONPREFIX= v DISTVERSION= 0.7.3-14 DISTVERSIONSUFFIX= -gf0038b1 USE_GITHUB= yes .... This creates a versioning scheme that increases over time (well, over commits), and does not conflict with the creation of a `0.7.4` version. (See crossref:makefiles[makefile-versions-ex-pkg-version] for details on man:pkg-version[8]): [source,shell] .... % pkg version -t 0.7.3 0.7.3.14 < % pkg version -t 0.7.3.14 0.7.4 < .... [NOTE] **** If the requested commit is the same as a tag, a shorter description is shown by default. The longer version is equivalent: [source,shell] .... % git describe --tags c66c71d v0.7.3 % git describe --tags --long c66c71d v0.7.3-0-gc66c71d .... **** ==== [[makefile-master_sites-github-multiple]] ==== Fetching Multiple Files from GitHub The `USE_GITHUB` framework also supports fetching multiple distribution files from different places in GitHub. -It works in a way very similar to crossref:makefiles[porting-master-sites-n]. +It works in a way very similar to crossref:makefiles[porting-master-sites-n, Multiple Distribution or Patches Files from Multiple Locations]. Multiple values are added to `GH_ACCOUNT`, `GH_PROJECT`, and `GH_TAGNAME`. Each different value is assigned a group. The main value can either have no group, or the `:DEFAULT` group. A value can be omitted if it is the same as the default as listed in -crossref:makefiles[makefile-master_sites-github-description]. +crossref:makefiles[makefile-master_sites-github-description,.`USE_GITHUB` Description]. `GH_TUPLE` can also be used when there are a lot of distribution files. It helps keep the account, project, tagname, and group information at the same place. For each group, a `${WRKSRC_group}` helper variable is created, containing the directory into which the file has been extracted. The `${WRKSRC_group}` variables can be used to move directories around during `post-extract`, or add to `CONFIGURE_ARGS`, or whatever is needed so that the software builds correctly. [CAUTION] ==== The `:__group__` part _must_ be used for _only one_ distribution file. It is used as a unique key and using it more than once will overwrite the previous values. ==== [NOTE] ==== As this is only syntactic sugar above `DISTFILES` and `MASTER_SITES`, the group names must adhere to the restrictions on group names outlined in -crossref:makefiles[porting-master-sites-n] +crossref:makefiles[porting-master-sites-n, Multiple Distribution or Patches Files from Multiple Locations] ==== When fetching multiple files from GitHub, sometimes the default distribution file is not fetched from GitHub. To disable fetching the default distribution, set: [.programlisting] .... USE_GITHUB= nodefault .... [IMPORTANT] ==== When using `USE_GITHUB=nodefault`, the [.filename]#Makefile# must set `DISTFILES` in its crossref:porting-order[porting-order-portname,top block]. The definition should be: [.programlisting] .... DISTFILES= ${DISTNAME}${EXTRACT_SUFX} .... ==== [[makefile-master_sites-github-multi]] .Use of `USE_GITHUB` with Multiple Distribution Files [example] ==== From time to time, there is a need to fetch more than one distribution file. For example, when the upstream git repository uses submodules. This can be done easily using groups in the `GH_*` variables: [.programlisting] .... PORTNAME= foo DISTVERSION= 1.0.2 USE_GITHUB= yes GH_ACCOUNT= bar:icons,contrib GH_PROJECT= foo-icons:icons foo-contrib:contrib GH_TAGNAME= 1.0:icons fa579bc:contrib GH_SUBDIR= ext/icons:icons CONFIGURE_ARGS= --with-contrib=${WRKSRC_contrib} .... This will fetch three distribution files from github. The default one comes from [.filename]#foo/foo# and is version `1.0.2`. The second one, with the `icons` group, comes from [.filename]#bar/foo-icons# and is in version `1.0`. The third one comes from [.filename]#bar/foo-contrib# and uses the Git commit `fa579bc`. The distribution files are named [.filename]#foo-foo-1.0.2_GH0.tar.gz#, [.filename]#bar-foo-icons-1.0_GH0.tar.gz#, and [.filename]#bar-foo-contrib-fa579bc_GH0.tar.gz#. All the distribution files are extracted in `${WRKDIR}` in their respective subdirectories. The default file is still extracted in `${WRKSRC}`, in this case, [.filename]#${WRKDIR}/foo-1.0.2#. Each additional distribution file is extracted in `${WRKSRC_group}`. Here, for the `icons` group, it is called `${WRKSRC_icons}` and it contains [.filename]#${WRKDIR}/foo-icons-1.0#. The file with the `contrib` group is called `${WRKSRC_contrib}` and contains `${WRKDIR}/foo-contrib-fa579bc`. The software's build system expects to find the icons in a [.filename]#ext/icons# subdirectory in its sources, so `GH_SUBDIR` is used. `GH_SUBDIR` makes sure that [.filename]#ext# exists, but that [.filename]#ext/icons# does not already exist. Then it does this: [.programlisting] .... post-extract: @${MV} ${WRKSRC_icons} ${WRKSRC}/ext/icons .... ==== [[makefile-master_sites-github-multi2]] .Use of `USE_GITHUB` with Multiple Distribution Files Using `GH_TUPLE` [example] ==== This is functionally equivalent to -crossref:makefiles[makefile-master_sites-github-multi], but using `GH_TUPLE`: +crossref:makefiles[makefile-master_sites-github-multi,.Use of `USE_GITHUB` with Multiple Distribution Files], but using `GH_TUPLE`: [.programlisting] .... PORTNAME= foo DISTVERSION= 1.0.2 USE_GITHUB= yes GH_TUPLE= bar:foo-icons:1.0:icons/ext/icons \ bar:foo-contrib:fa579bc:contrib CONFIGURE_ARGS= --with-contrib=${WRKSRC_contrib} .... Grouping was used in the previous example with `bar:icons,contrib`. Some redundant information is present with `GH_TUPLE` because grouping is not possible. ==== [[makefile-master_sites-github-submodules]] .How to Use `USE_GITHUB` with Git Submodules? [example] ==== Ports with GitHub as an upstream repository sometimes use submodules. See man:git-submodule[1] for more information. The problem with submodules is that each is a separate repository. As such, they each must be fetched separately. Using package:finance/moneymanagerex[] as an example, its GitHub repository is https://github.com/moneymanagerex/moneymanagerex/[]. It has a https://github.com/moneymanagerex/moneymanagerex/blob/master/.gitmodules[.gitmodules] file at the root. This file describes all the submodules used in this repository, and lists additional repositories needed. This file will tell what additional repositories are needed: [.programlisting] .... [submodule "lib/wxsqlite3"] path = lib/wxsqlite3 url = https://github.com/utelle/wxsqlite3.git [submodule "3rd/mongoose"] path = 3rd/mongoose url = https://github.com/cesanta/mongoose.git [submodule "3rd/LuaGlue"] path = 3rd/LuaGlue url = https://github.com/moneymanagerex/LuaGlue.git [submodule "3rd/cgitemplate"] path = 3rd/cgitemplate url = https://github.com/moneymanagerex/html-template.git [...] .... The only information missing from that file is the commit hash or tag to use as a version. This information is found after cloning the repository: [source,shell] .... % git clone --recurse-submodules https://github.com/moneymanagerex/moneymanagerex.git Cloning into 'moneymanagerex'... remote: Counting objects: 32387, done. [...] Submodule '3rd/LuaGlue' (https://github.com/moneymanagerex/LuaGlue.git) registered for path '3rd/LuaGlue' Submodule '3rd/cgitemplate' (https://github.com/moneymanagerex/html-template.git) registered for path '3rd/cgitemplate' Submodule '3rd/mongoose' (https://github.com/cesanta/mongoose.git) registered for path '3rd/mongoose' Submodule 'lib/wxsqlite3' (https://github.com/utelle/wxsqlite3.git) registered for path 'lib/wxsqlite3' [...] Cloning into '/home/mat/work/freebsd/ports/finance/moneymanagerex/moneymanagerex/3rd/LuaGlue'... Cloning into '/home/mat/work/freebsd/ports/finance/moneymanagerex/moneymanagerex/3rd/cgitemplate'... Cloning into '/home/mat/work/freebsd/ports/finance/moneymanagerex/moneymanagerex/3rd/mongoose'... Cloning into '/home/mat/work/freebsd/ports/finance/moneymanagerex/moneymanagerex/lib/wxsqlite3'... [...] Submodule path '3rd/LuaGlue': checked out 'c51d11a247ee4d1e9817dfa2a8da8d9e2f97ae3b' Submodule path '3rd/cgitemplate': checked out 'cd434eeeb35904ebcd3d718ba29c281a649b192c' Submodule path '3rd/mongoose': checked out '2140e5992ab9a3a9a34ce9a281abf57f00f95cda' Submodule path 'lib/wxsqlite3': checked out 'fb66eb230d8aed21dec273b38c7c054dcb7d6b51' [...] % cd moneymanagerex % git submodule status c51d11a247ee4d1e9817dfa2a8da8d9e2f97ae3b 3rd/LuaGlue (heads/master) cd434eeeb35904ebcd3d718ba29c281a649b192c 3rd/cgitemplate (cd434ee) 2140e5992ab9a3a9a34ce9a281abf57f00f95cda 3rd/mongoose (6.2-138-g2140e59) fb66eb230d8aed21dec273b38c7c054dcb7d6b51 lib/wxsqlite3 (v3.4.0) [...] .... It can also be found on GitHub. Each subdirectory that is a submodule is shown as `_directory @ hash_`, for example, `mongoose @ 2140e59`. [NOTE] **** While getting the information from GitHub seems more straightforward, the information found using `git submodule status` will provide more meaningful information. For example, here, ``lib/wxsqlite3``'s commit hash `fb66eb2` correspond to `v3.4.0`. Both can be used interchangeably, but when a tag is available, use it. **** Now that all the required information has been gathered, the [.filename]#Makefile# can be written (only GitHub-related lines are shown): [.programlisting] .... PORTNAME= moneymanagerex DISTVERSIONPREFIX= v DISTVERSION= 1.3.0 USE_GITHUB= yes GH_TUPLE= utelle:wxsqlite3:v3.4.0:wxsqlite3/lib/wxsqlite3 \ moneymanagerex:LuaGlue:c51d11a:lua_glue/3rd/LuaGlue \ moneymanagerex:html-template:cd434ee:html_template/3rd/cgitemplate \ cesanta:mongoose:2140e59:mongoose/3rd/mongoose \ [...] .... ==== [[makefile-master_sites-gitlab]] === `USE_GITLAB` Similar to GitHub, if the distribution file comes from https://gitlab.com/[gitlab.com] or is hosting the GitLab software, these variables are available for use and might need to be set. [[makefile-master_sites-gitlab-description]] .`USE_GITLAB` Description [cols="1,1,1", options="header"] |=== | Variable | Description | Default |`GL_SITE` |Site name hosting the GitLab project |https://gitlab.com/ |`GL_ACCOUNT` |Account name of the GitLab user hosting the project |`${PORTNAME}` |`GL_PROJECT` |Name of the project on GitLab |`${PORTNAME}` |`GL_COMMIT` |The commit hash to download. Must be the full 160 bit, 40 character hex sha1 hash. This is a required variable for GitLab. |`(none)` |`GL_SUBDIR` |When the software needs an additional distribution file to be extracted within `${WRKSRC}`, this variable can be used. See the examples in - crossref:makefiles[makefile-master_sites-gitlab-multiple] for more information. + crossref:makefiles[makefile-master_sites-gitlab-multiple, Fetching Multiple Files from GitLab] for more information. |(none) |`GL_TUPLE` |`GL_TUPLE` allows putting `GL_SITE`, `GL_ACCOUNT`, `GL_PROJECT`, `GL_COMMIT`, and `GL_SUBDIR` into a single variable. The format is _site_`:`_account_`:`_project_`:`_commit_`:`_group_`/`_subdir_. The _site_`:` and `/`_subdir_ part is optional. It is helpful when there are more than one GitLab project from which to fetch. | |=== [[makefile-master_sites-gitlab-ex1]] .Simple Use of `USE_GITLAB` [example] ==== While trying to make a port for version `1.14` of libsignon-glib from the accounts-sso user on gitlab.com, at https://gitlab.com/accounts-sso/libsignon-glib/[], The [.filename]#Makefile# would end up looking like this for fetching the distribution files: [.programlisting] .... PORTNAME= libsignon-glib DISTVERSION= 1.14 USE_GITLAB= yes GL_ACCOUNT= accounts-sso GL_COMMIT= e90302e342bfd27bc8c9132ab9d0ea3d8723fd03 .... It will automatically have `MASTER_SITES` set to https://gitlab.com/[gitlab.com] and `WRKSRC` to `${WRKDIR}/libsignon-glib-e90302e342bfd27bc8c9132ab9d0ea3d8723fd03-e90302e342bfd27bc8c9132ab9d0ea3d8723fd03`. ==== [[makefile-master_sites-gitlab-ex2]] .More Complete Use of `USE_GITLAB` [example] ==== A more complete use of the above if port had no versioning and foobar from the foo user on project bar on a self hosted GitLab site `https://gitlab.example.com/`, the [.filename]#Makefile# ends up looking like this for fetching distribution files: [.programlisting] .... PORTNAME= foobar DISTVERSION= g20170906 USE_GITLAB= yes GL_SITE= https://gitlab.example.com GL_ACCOUNT= foo GL_PROJECT= bar GL_COMMIT= 9c1669ce60c3f4f5eb43df874d7314483fb3f8a6 .... It will have `MASTER_SITES` set to `"https://gitlab.example.com"` and `WRKSRC` to `${WRKDIR}/bar-9c1669ce60c3f4f5eb43df874d7314483fb3f8a6-9c1669ce60c3f4f5eb43df874d7314483fb3f8a6`. [TIP] ====== `20170906` is the date of the commit referenced in `GL_COMMIT`, not the date the [.filename]#Makefile# is edited, or the date the commit to the FreeBSD ports tree is made. ====== [NOTE] ====== ``GL_SITE``'s protocol, port and webroot can all be modified in the same variable. ====== ==== [[makefile-master_sites-gitlab-multiple]] ==== Fetching Multiple Files from GitLab The `USE_GITLAB` framework also supports fetching multiple distribution files from different places from GitLab and GitLab hosted sites. -It works in a way very similar to crossref:makefiles[porting-master-sites-n] and -crossref:makefiles[makefile-master_sites-gitlab-multiple]. +It works in a way very similar to crossref:makefiles[porting-master-sites-n, Multiple Distribution or Patches Files from Multiple Locations] and +crossref:makefiles[makefile-master_sites-gitlab-multiple, Fetching Multiple Files from GitLab]. Multiple values are added to `GL_SITE`, `GL_ACCOUNT`, `GL_PROJECT` and `GL_COMMIT`. Each different value is assigned a group. -crossref:makefiles[makefile-master_sites-gitlab-description]. +crossref:makefiles[makefile-master_sites-gitlab-description,.`USE_GITLAB` Description]. `GL_TUPLE` can also be used when there are a lot of distribution files. It helps keep the site, account, project, commit, and group information at the same place. For each group, a `${WRKSRC_group}` helper variable is created, containing the directory into which the file has been extracted. The `${WRKSRC_group}` variables can be used to move directories around during `post-extract`, or add to `CONFIGURE_ARGS`, or whatever is needed so that the software builds correctly. [CAUTION] ==== The `:__group__` part _must_ be used for _only one_ distribution file. It is used as a unique key and using it more than once will overwrite the previous values. ==== [NOTE] ==== As this is only syntactic sugar above `DISTFILES` and `MASTER_SITES`, the group names must adhere to the restrictions on group names outlined in -crossref:makefiles[porting-master-sites-n] +crossref:makefiles[porting-master-sites-n, Multiple Distribution or Patches Files from Multiple Locations] ==== When fetching multiple files using GitLab, sometimes the default distribution file is not fetched from a GitLab site. To disable fetching the default distribution, set: [.programlisting] .... USE_GITLAB= nodefault .... [IMPORTANT] ==== When using `USE_GITLAB=nodefault`, the [.filename]#Makefile# must set `DISTFILES` in its crossref:makefiles[porting-order-portname,top block]. The definition should be: [.programlisting] .... DISTFILES= ${DISTNAME}${EXTRACT_SUFX} .... ==== [[makefile-master_sites-gitlab-multi]] .Use of `USE_GITLAB` with Multiple Distribution Files [example] ==== From time to time, there is a need to fetch more than one distribution file. For example, when the upstream git repository uses submodules. This can be done easily using groups in the `GL_*` variables: [.programlisting] .... PORTNAME= foo DISTVERSION= 1.0.2 USE_GITLAB= yes GL_SITE= https://gitlab.example.com:9434/gitlab:icons GL_ACCOUNT= bar:icons,contrib GL_PROJECT= foo-icons:icons foo-contrib:contrib GL_COMMIT= c189207a55da45305c884fe2b50e086fcad4724b ae7368cab1ca7ca754b38d49da064df87968ffe4:icons 9e4dd76ad9b38f33fdb417a4c01935958d5acd2a:contrib GL_SUBDIR= ext/icons:icons CONFIGURE_ARGS= --with-contrib=${WRKSRC_contrib} .... This will fetch two distribution files from gitlab.com and one from `gitlab.example.com` hosting GitLab. The default one comes from [.filename]#https://gitlab.com/foo/foo# and commit is `c189207a55da45305c884fe2b50e086fcad4724b`. The second one, with the `icons` group, comes from [.filename]#https://gitlab.example.com:9434/gitlab/bar/foo-icons# and commit is `ae7368cab1ca7ca754b38d49da064df87968ffe4`. The third one comes from [.filename]#https://gitlab.com/bar/foo-contrib# and is commit `9e4dd76ad9b38f33fdb417a4c01935958d5acd2a`. The distribution files are named [.filename]#foo-foo-c189207a55da45305c884fe2b50e086fcad4724b_GL0.tar.gz#, [.filename]#bar-foo-icons-ae7368cab1ca7ca754b38d49da064df87968ffe4_GL0.tar.gz#, and [.filename]#bar-foo-contrib-9e4dd76ad9b38f33fdb417a4c01935958d5acd2a_GL0.tar.gz#. All the distribution files are extracted in `${WRKDIR}` in their respective subdirectories. The default file is still extracted in `${WRKSRC}`, in this case, [.filename]#${WRKDIR}/foo-c189207a55da45305c884fe2b50e086fcad4724b-c189207a55da45305c884fe2b50e086fcad4724b#. Each additional distribution file is extracted in `${WRKSRC_group}`. Here, for the `icons` group, it is called `${WRKSRC_icons}` and it contains [.filename]#${WRKDIR}/foo-icons-ae7368cab1ca7ca754b38d49da064df87968ffe4-ae7368cab1ca7ca754b38d49da064df87968ffe4#. The file with the `contrib` group is called `${WRKSRC_contrib}` and contains `${WRKDIR}/foo-contrib-9e4dd76ad9b38f33fdb417a4c01935958d5acd2a-9e4dd76ad9b38f33fdb417a4c01935958d5acd2a`. The software's build system expects to find the icons in a [.filename]#ext/icons# subdirectory in its sources, so `GL_SUBDIR` is used. `GL_SUBDIR` makes sure that [.filename]#ext# exists, but that [.filename]#ext/icons# does not already exist. Then it does this: [.programlisting] .... post-extract: @${MV} ${WRKSRC_icons} ${WRKSRC}/ext/icons .... ==== [[makefile-master_sites-gitlab-multi2]] .Use of `USE_GITLAB` with Multiple Distribution Files Using `GL_TUPLE` [example] ==== This is functionally equivalent to -crossref:makefiles[makefile-master_sites-gitlab-multi], but using `GL_TUPLE`: +crossref:makefiles[makefile-master_sites-gitlab-multi,.Use of `USE_GITLAB` with Multiple Distribution Files], but using `GL_TUPLE`: [.programlisting] .... PORTNAME= foo DISTVERSION= 1.0.2 USE_GITLAB= yes GL_COMMIT= c189207a55da45305c884fe2b50e086fcad4724b GL_TUPLE= https://gitlab.example.com:9434/gitlab:bar:foo-icons:ae7368cab1ca7ca754b38d49da064df87968ffe4:icons/ext/icons \ bar:foo-contrib:9e4dd76ad9b38f33fdb417a4c01935958d5acd2a:contrib CONFIGURE_ARGS= --with-contrib=${WRKSRC_contrib} .... Grouping was used in the previous example with `bar:icons,contrib`. Some redundant information is present with `GL_TUPLE` because grouping is not possible. ==== [[makefile-extract_sufx]] === `EXTRACT_SUFX` If there is one distribution file, and it uses an odd suffix to indicate the compression mechanism, set `EXTRACT_SUFX`. For example, if the distribution file was named [.filename]#foo.tar.gzip# instead of the more normal [.filename]#foo.tar.gz#, write: [.programlisting] .... DISTNAME= foo EXTRACT_SUFX= .tar.gzip .... The `USES=tar[:__xxx__]`, `USES=lha` or `USES=zip` automatically set `EXTRACT_SUFX` to the most common archives extensions as necessary, see crossref:uses[uses,Using `USES` Macros] for more details. If neither of these are set then `EXTRACT_SUFX` defaults to `.tar.gz`. [NOTE] ==== As `EXTRACT_SUFX` is only used in `DISTFILES`, only set one of them.. ==== [[makefile-distfiles-definition]] === `DISTFILES` Sometimes the names of the files to be downloaded have no resemblance to the name of the port. For example, it might be called [.filename]#source.tar.gz# or similar. In other cases the application's source code might be in several different archives, all of which must be downloaded. If this is the case, set `DISTFILES` to be a space separated list of all the files that must be downloaded. [.programlisting] .... DISTFILES= source1.tar.gz source2.tar.gz .... If not explicitly set, `DISTFILES` defaults to `${DISTNAME}${EXTRACT_SUFX}`. [[makefile-extract_only]] === `EXTRACT_ONLY` If only some of the `DISTFILES` must be extracted-for example, one of them is the source code, while another is an uncompressed document-list the filenames that must be extracted in `EXTRACT_ONLY`. [.programlisting] .... DISTFILES= source.tar.gz manual.html EXTRACT_ONLY= source.tar.gz .... When none of the `DISTFILES` need to be uncompressed, set `EXTRACT_ONLY` to the empty string. [.programlisting] .... EXTRACT_ONLY= .... [[porting-patchfiles]] === `PATCHFILES` If the port requires some additional patches that are available by FTP or HTTP, set `PATCHFILES` to the names of the files and `PATCH_SITES` to the URL of the directory that contains them (the format is the same as `MASTER_SITES`). If the patch is not relative to the top of the source tree (that is, `WRKSRC`) because it contains some extra pathnames, set `PATCH_DIST_STRIP` accordingly. For instance, if all the pathnames in the patch have an extra `foozolix-1.0/` in front of the filenames, then set `PATCH_DIST_STRIP=-p1`. Do not worry if the patches are compressed; they will be decompressed automatically if the filenames end with [.filename]#.Z#, [.filename]#.gz#, [.filename]#.bz2# or [.filename]#.xz#. If the patch is distributed with some other files, such as documentation, in a compressed tarball, using `PATCHFILES` is not possible. If that is the case, add the name and the location of the patch tarball to `DISTFILES` and `MASTER_SITES`. Then, use `EXTRA_PATCHES` to point to those files and [.filename]#bsd.port.mk# will automatically apply them. In particular, do _not_ copy patch files into [.filename]#${PATCHDIR}#. That directory may not be writable. [TIP] ==== If there are multiple patches and they need mixed values for the strip parameter, it can be added alongside the patch name in `PATCHFILES`, e.g: [.programlisting] .... PATCHFILES= patch1 patch2:-p1 .... This does not conflict with crossref:makefiles[porting-master-sites-n,the master site grouping feature], adding a group also works: [.programlisting] .... PATCHFILES= patch2:-p1:source2 .... ==== [NOTE] ==== The tarball will have been extracted alongside the regular source by then, so there is no need to explicitly extract it if it is a regular compressed tarball. Take extra care not to overwrite something that already exists in that directory if extracting it manually. Also, do not forget to add a command to remove the copied patch in the `pre-clean` target. ==== [[porting-master-sites-n]] === Multiple Distribution or Patches Files from Multiple Locations (Consider this to be a somewhat "advanced topic"; those new to this document may wish to skip this section at first). This section has information on the fetching mechanism known as both `MASTER_SITES:n` and `MASTER_SITES_NN`. We will refer to this mechanism as `MASTER_SITES:n`. A little background first. OpenBSD has a neat feature inside `DISTFILES` and `PATCHFILES` which allows files and patches to be postfixed with `:n` identifiers. Here, `n` can be any word containing `[0-9a-zA-Z_]` and denote a group designation. For example: [.programlisting] .... DISTFILES= alpha:0 beta:1 .... In OpenBSD, distribution file [.filename]#alpha# will be associated with variable `MASTER_SITES0` instead of our common `MASTER_SITES` and [.filename]#beta# with `MASTER_SITES1`. This is a very interesting feature which can decrease that endless search for the correct download site. Just picture 2 files in `DISTFILES` and 20 sites in `MASTER_SITES`, the sites slow as hell where [.filename]#beta# is carried by all sites in `MASTER_SITES`, and [.filename]#alpha# can only be found in the 20th site. It would be such a waste to check all of them if the maintainer knew this beforehand, would it not? Not a good start for that lovely weekend! Now that you have the idea, just imagine more `DISTFILES` and more `MASTER_SITES`. Surely our "distfiles survey meister" would appreciate the relief to network strain that this would bring. In the next sections, information will follow on the FreeBSD implementation of this idea. We improved a bit on OpenBSD's concept. [IMPORTANT] ==== The group names cannot have dashes in them (`-`), in fact, they cannot have any characters out of the `[a-zA-Z0-9_]` range. This is because, while man:make[1] is ok with variable names containing dashes, man:sh[1] is not. ==== [[porting-master-sites-n-simplified]] ==== Simplified Information This section explains how to quickly prepare fine grained fetching of multiple distribution files and patches from different sites and subdirectories. We describe here a case of simplified `MASTER_SITES:n` usage. This will be sufficient for most scenarios. More detailed information are available in -crossref:makefiles[ports-master-sites-n-detailed]. +crossref:makefiles[ports-master-sites-n-detailed, Detailed Information]. Some applications consist of multiple distribution files that must be downloaded from a number of different sites. For example, Ghostscript consists of the core of the program, and then a large number of driver files that are used depending on the user's printer. Some of these driver files are supplied with the core, but many others must be downloaded from a variety of different sites. To support this, each entry in `DISTFILES` may be followed by a colon and a "group name". Each site listed in `MASTER_SITES` is then followed by a colon, and the group that indicates which distribution files are downloaded from this site. For example, consider an application with the source split in two parts, [.filename]#source1.tar.gz# and [.filename]#source2.tar.gz#, which must be downloaded from two different sites. The port's [.filename]#Makefile# would include lines like -crossref:makefiles[ports-master-sites-n-example-simple-use-one-file-per-site]. +crossref:makefiles[ports-master-sites-n-example-simple-use-one-file-per-site,.Simplified Use of `MASTER_SITES:n` with One File Per Site]. [[ports-master-sites-n-example-simple-use-one-file-per-site]] .Simplified Use of `MASTER_SITES:n` with One File Per Site [example] ==== [.programlisting] .... MASTER_SITES= ftp://ftp1.example.com/:source1 \ http://www.example.com/:source2 DISTFILES= source1.tar.gz:source1 \ source2.tar.gz:source2 .... ==== Multiple distribution files can have the same group. Continuing the previous example, suppose that there was a third distfile, [.filename]#source3.tar.gz#, that is downloaded from `ftp.example2.com`. The [.filename]#Makefile# would then be written like -crossref:makefiles[ports-master-sites-n-example-simple-use-more-than-one-file-per-site]. +crossref:makefiles[ports-master-sites-n-example-simple-use-more-than-one-file-per-site,.Simplified Use of `MASTER_SITES:n` with More Than One File Per Site]. [[ports-master-sites-n-example-simple-use-more-than-one-file-per-site]] .Simplified Use of `MASTER_SITES:n` with More Than One File Per Site [example] ==== [.programlisting] .... MASTER_SITES= ftp://ftp.example.com/:source1 \ http://www.example.com/:source2 DISTFILES= source1.tar.gz:source1 \ source2.tar.gz:source2 \ source3.tar.gz:source2 .... ==== [[ports-master-sites-n-detailed]] ==== Detailed Information Okay, so the previous example did not reflect the new port's needs? In this section we will explain in detail how the fine grained fetching mechanism `MASTER_SITES:n` works and how it can be used. . Elements can be postfixed with `:__n__` where _n_ is `[^:,]+`, that is, _n_ could conceptually be any alphanumeric string but we will limit it to `[a-zA-Z_][0-9a-zA-Z_]+` for now. + Moreover, string matching is case sensitive; that is, `n` is different from `N`. + However, these words cannot be used for postfixing purposes since they yield special meaning: `default`, `all` and `ALL` (they are used internally in item crossref:makefiles[porting-master-sites-n-what-changes-in-port-targets, ii]). Furthermore, `DEFAULT` is a special purpose word (check item crossref:makefiles[porting-master-sites-n-DEFAULT-group,3]). . Elements postfixed with `:n` belong to the group `n`, `:m` belong to group `m` and so forth. + [[porting-master-sites-n-DEFAULT-group]] . Elements without a postfix are groupless, they all belong to the special group `DEFAULT`. Any elements postfixed with `DEFAULT`, is just being redundant unless an element belongs to both `DEFAULT` and other groups at the same time (check item crossref:makefiles[porting-master-sites-n-comma-operator,5]). + These examples are equivalent but the first one is preferred: + [.programlisting] .... MASTER_SITES= alpha .... + [.programlisting] .... MASTER_SITES= alpha:DEFAULT .... . Groups are not exclusive, an element may belong to several different groups at the same time and a group can either have either several different elements or none at all. + [[porting-master-sites-n-comma-operator]] . When an element belongs to several groups at the same time, use the comma operator (`,`). + Instead of repeating it several times, each time with a different postfix, we can list several groups at once in a single postfix. For instance, `:m,n,o` marks an element that belongs to group `m`, `n` and `o`. + All these examples are equivalent but the last one is preferred: + [.programlisting] .... MASTER_SITES= alpha alpha:SOME_SITE .... + [.programlisting] .... MASTER_SITES= alpha:DEFAULT alpha:SOME_SITE .... + [.programlisting] .... MASTER_SITES= alpha:SOME_SITE,DEFAULT .... + [.programlisting] .... MASTER_SITES= alpha:DEFAULT,SOME_SITE .... . All sites within a given group are sorted according to `MASTER_SORT_AWK`. All groups within `MASTER_SITES` and `PATCH_SITES` are sorted as well. + [[porting-master-sites-n-group-semantics]] . Group semantics can be used in any of the variables `MASTER_SITES`, `PATCH_SITES`, `MASTER_SITE_SUBDIR`, `PATCH_SITE_SUBDIR`, `DISTFILES`, and `PATCHFILES` according to this syntax: .. All `MASTER_SITES`, `PATCH_SITES`, `MASTER_SITE_SUBDIR` and `PATCH_SITE_SUBDIR` elements must be terminated with the forward slash `/` character. If any elements belong to any groups, the group postfix `:__n__` must come right after the terminator `/`. The `MASTER_SITES:n` mechanism relies on the existence of the terminator `/` to avoid confusing elements where a `:n` is a valid part of the element with occurrences where `:n` denotes group `n`. For compatibility purposes, since the `/` terminator was not required before in both `MASTER_SITE_SUBDIR` and `PATCH_SITE_SUBDIR` elements, if the postfix immediate preceding character is not a `/` then `:n` will be considered a valid part of the element instead of a group postfix even if an element is postfixed with `:n`. See both - crossref:makefiles[ports-master-sites-n-example-detailed-use-master-site-subdir] + crossref:makefiles[ports-master-sites-n-example-detailed-use-master-site-subdir,.Detailed Use of `MASTER_SITES:n` in `MASTER_SITE_SUBDIR`] and - crossref:makefiles[ports-master-sites-n-example-detailed-use-complete-example-master-sites]. + crossref:makefiles[ports-master-sites-n-example-detailed-use-complete-example-master-sites,.Detailed Use of `MASTER_SITES:n` with Comma Operator, Multiple Files, Multiple Sites and Multiple Subdirectories]. + [[ports-master-sites-n-example-detailed-use-master-site-subdir]] .Detailed Use of `MASTER_SITES:n` in `MASTER_SITE_SUBDIR` [example] ==== [.programlisting] .... MASTER_SITE_SUBDIR= old:n new/:NEW .... *** Directories within group `DEFAULT` -> old:n *** Directories within group `NEW` -> new ==== + [[ports-master-sites-n-example-detailed-use-complete-example-master-sites]] .Detailed Use of `MASTER_SITES:n` with Comma Operator, Multiple Files, Multiple Sites and Multiple Subdirectories [example] ==== [.programlisting] .... MASTER_SITES= http://site1/%SUBDIR%/ http://site2/:DEFAULT \ http://site3/:group3 http://site4/:group4 \ http://site5/:group5 http://site6/:group6 \ http://site7/:DEFAULT,group6 \ http://site8/%SUBDIR%/:group6,group7 \ http://site9/:group8 DISTFILES= file1 file2:DEFAULT file3:group3 \ file4:group4,group5,group6 file5:grouping \ file6:group7 MASTER_SITE_SUBDIR= directory-trial:1 directory-n/:groupn \ directory-one/:group6,DEFAULT \ directory .... The previous example results in this fine grained fetching. Sites are listed in the exact order they will be used. *** [.filename]#file1# will be fetched from **** `MASTER_SITE_OVERRIDE` **** http://site1/directory-trial:1/ **** http://site1/directory-one/ **** http://site1/directory/ **** http://site2/ **** http://site7/ **** `MASTER_SITE_BACKUP` *** [.filename]#file2# will be fetched exactly as [.filename]#file1# since they both belong to the same group **** `MASTER_SITE_OVERRIDE` **** http://site1/directory-trial:1/ **** http://site1/directory-one/ **** http://site1/directory/ **** http://site2/ **** http://site7/ **** `MASTER_SITE_BACKUP` *** [.filename]#file3# will be fetched from **** `MASTER_SITE_OVERRIDE` **** http://site3/ **** `MASTER_SITE_BACKUP` *** [.filename]#file4# will be fetched from **** `MASTER_SITE_OVERRIDE` **** http://site4/ **** http://site5/ **** http://site6/ **** http://site7/ **** http://site8/directory-one/ **** `MASTER_SITE_BACKUP` *** [.filename]#file5# will be fetched from **** `MASTER_SITE_OVERRIDE` **** `MASTER_SITE_BACKUP` *** [.filename]#file6# will be fetched from **** `MASTER_SITE_OVERRIDE` **** http://site8/ **** `MASTER_SITE_BACKUP` ==== . How do I group one of the special macros from [.filename]#bsd.sites.mk#, for example, SourceForge (`SF`)? + This has been simplified as much as possible. See -crossref:makefiles[ports-master-sites-n-example-detailed-use-master-site-sourceforge]. +crossref:makefiles[ports-master-sites-n-example-detailed-use-master-site-sourceforge,.Detailed Use of `MASTER_SITES:n` with SourceForge (`SF`)]. + [[ports-master-sites-n-example-detailed-use-master-site-sourceforge]] .Detailed Use of `MASTER_SITES:n` with SourceForge (`SF`) [example] ==== [.programlisting] .... MASTER_SITES= http://site1/ SF/something/1.0:sourceforge,TEST DISTFILES= something.tar.gz:sourceforge .... [.filename]#something.tar.gz# will be fetched from all sites within SourceForge. ==== . How do I use this with `PATCH*`? + All examples were done with `MASTER*` but they work exactly the same for `PATCH*` ones as can be seen in -crossref:makefiles[ports-master-sites-n-example-detailed-use-patch-sites]. +crossref:makefiles[ports-master-sites-n-example-detailed-use-patch-sites,.Simplified Use of `MASTER_SITES:n` with `PATCH_SITES`]. + [[ports-master-sites-n-example-detailed-use-patch-sites]] .Simplified Use of `MASTER_SITES:n` with `PATCH_SITES` [example] ==== [.programlisting] .... PATCH_SITES= http://site1/ http://site2/:test PATCHFILES= patch1:test .... ==== [[port-master-sites-n-what-changed]] ==== What Does Change for Ports? What Does Not? [lowerroman] . All current ports remain the same. The `MASTER_SITES:n` feature code is only activated if there are elements postfixed with `:__n__` like elements according to the aforementioned syntax rules, especially as shown in item crossref:makefiles[porting-master-sites-n-group-semantics, 7]. + [[porting-master-sites-n-what-changes-in-port-targets]] . The port targets remain the same: `checksum`, `makesum`, `patch`, `configure`, `build`, etc. With the obvious exceptions of `do-fetch`, `fetch-list`, `master-sites` and `patch-sites`. ** `do-fetch`: deploys the new grouping postfixed `DISTFILES` and `PATCHFILES` with their matching group elements within both `MASTER_SITES` and `PATCH_SITES` which use matching group elements within both `MASTER_SITE_SUBDIR` and `PATCH_SITE_SUBDIR`. Check - crossref:makefiles[ports-master-sites-n-example-detailed-use-complete-example-master-sites]. + crossref:makefiles[ports-master-sites-n-example-detailed-use-complete-example-master-sites,.Detailed Use of `MASTER_SITES:n` with Comma Operator, Multiple Files, Multiple Sites and Multiple Subdirectories]. ** `fetch-list`: works like old `fetch-list` with the exception that it groups just like `do-fetch`. ** `master-sites` and `patch-sites`: (incompatible with older versions) only return the elements of group `DEFAULT`; in fact, they execute targets `master-sites-default` and `patch-sites-default` respectively. + Furthermore, using target either `master-sites-all` or `patch-sites-all` is preferred to directly checking either `MASTER_SITES` or `PATCH_SITES`. Also, directly checking is not guaranteed to work in any future versions. Check item crossref:makefiles[porting-master-sites-n-new-port-targets-master-sites-all, B] for more information on these new port targets. . New port targets .. There are `master-sites-_n_` and `patch-sites-_n_` targets which will list the elements of the respective group _n_ within `MASTER_SITES` and `PATCH_SITES` respectively. For instance, both `master-sites-DEFAULT` and `patch-sites-DEFAULT` will return the elements of group `DEFAULT`, `master-sites-test` and `patch-sites-test` of group `test`, and thereon. + [[porting-master-sites-n-new-port-targets-master-sites-all]] .. There are new targets `master-sites-all` and `patch-sites-all` which do the work of the old `master-sites` and `patch-sites` ones. They return the elements of all groups as if they all belonged to the same group with the caveat that it lists as many `MASTER_SITE_BACKUP` and `MASTER_SITE_OVERRIDE` as there are groups defined within either `DISTFILES` or `PATCHFILES`; respectively for `master-sites-all` and `patch-sites-all`. [[makefile-dist_subdir]] === `DIST_SUBDIR` Do not let the port clutter [.filename]#/usr/ports/distfiles#. If the port requires a lot of files to be fetched, or contains a file that has a name that might conflict with other ports (for example, [.filename]#Makefile#), set `DIST_SUBDIR` to the name of the port (`${PORTNAME}` or `${PKGNAMEPREFIX}${PORTNAME}` are fine). This will change `DISTDIR` from the default [.filename]#/usr/ports/distfiles# to [.filename]#/usr/ports/distfiles/${DIST_SUBDIR}#, and in effect puts everything that is required for the port into that subdirectory. It will also look at the subdirectory with the same name on the backup master site at http://distcache.FreeBSD.org[http://distcache.FreeBSD.org] (Setting `DISTDIR` explicitly in [.filename]#Makefile# will not accomplish this, so please use `DIST_SUBDIR`.) [NOTE] ==== This does not affect `MASTER_SITES` defined in the [.filename]#Makefile#. ==== [[makefile-maintainer]] == `MAINTAINER` Set your mail-address here. Please. _:-)_ Only a single address without the comment part is allowed as a `MAINTAINER` value. The format used is `user@hostname.domain`. Please do not include any descriptive text such as a real name in this entry. That merely confuses the Ports infrastructure and most tools using it. The maintainer is responsible for keeping the port up to date and making sure that it works correctly. For a detailed description of the responsibilities of a port maintainer, refer to extref:{contributing}[The challenge for port maintainers, maintain-port]. [NOTE] ==== A maintainer volunteers to keep a port in good working order. Maintainers have the primary responsibility for their ports, but not exclusive ownership. Ports exist for the benefit of the community and, in reality, belong to the community. What this means is that people other than the maintainer can make changes to a port. Large changes to the Ports Collection might require changes to many ports. The FreeBSD Ports Management Team or members of other teams might modify ports to fix dependency issues or other problems, like a version bump for a shared library update. Some types of fixes have "blanket approval" from the {portmgr}, allowing any committer to fix those categories of problems on any port. These fixes do not need approval from the maintainer. Blanket approval for most ports applies to fixes like infrastructure changes, or trivial and _tested_ build and runtime fixes. The current list is available in extref:{committers-guide}[Ports section of the Committer's Guide, ports-qa-misc-blanket-approval]. ==== Other changes to the port will be sent to the maintainer for review and approval before being committed. If the maintainer does not respond to an update request after two weeks (excluding major public holidays), then that is considered a maintainer timeout, and the update can be made without explicit maintainer approval. If the maintainer does not respond within three months, or if there have been three consecutive timeouts, then that maintainer is considered absent without leave, and all of their ports can be assigned back to the pool. Exceptions to this are anything maintained by the {portmgr}, or the {security-officer}. No unauthorized commits may ever be made to ports maintained by those groups. We reserve the right to modify the maintainer's submission to better match existing policies and style of the Ports Collection without explicit blessing from the submitter or the maintainer. Also, large infrastructural changes can result in a port being modified without the maintainer's consent. These kinds of changes will never affect the port's functionality. The {portmgr} reserves the right to revoke or override anyone's maintainership for any reason, and the {security-officer} reserves the right to revoke or override maintainership for security reasons. [[makefile-comment]] == `COMMENT` The comment is a one-line description of a port shown by `pkg info`. Please follow these rules when composing it: . The COMMENT string should be 70 characters or less. . Do _not_ include the package name or version number of software. . The comment must begin with a capital and end without a period. . Do not start with an indefinite article (that is, A or An). . Capitalize names such as Apache, JavaScript, or Perl. . Use a serial comma for lists of words: "green, red, and blue." . Check for spelling errors. Here is an example: [.programlisting] .... COMMENT= Cat chasing a mouse all over the screen .... The COMMENT variable immediately follows the MAINTAINER variable in the [.filename]#Makefile#. [[makefile-www]] == Project website Each port should point to a website that provides more information about the software. Whenever possible, this should be the official project website maintained by the developers of the software. [.programlisting] .... WWW= https://ffmpeg.org/ .... But it can also be a directory or resource in the source code repository: [.programlisting] .... WWW= https://sourceforge.net/projects/mpd/ .... The WWW variable immediately follows the COMMENT variable in the [.filename]#Makefile#. If the same content can be accessed via HTTP and HTTPS, the URL starting with `https://` shall be used. If the URI is the root of the website or directory, it must be terminated with a slash. This information used to be placed into the last line of the [.filename]#pkg-descr# file. It has been moved into the Makefile for easier maintenance and processing. Having a `WWW:` line at the end of the [.filename]#pkg-descr# file is deprecated. [[licenses]] == Licenses Each port must document the license under which it is available. If it is not an OSI approved license it must also document any restrictions on redistribution. [[licenses-license]] === `LICENSE` A short name for the license or licenses if more than one license apply. -If it is one of the licenses listed in crossref:makefiles[licenses-license-list], only `LICENSE_FILE` and `LICENSE_DISTFILES` variables can be set. +If it is one of the licenses listed in crossref:makefiles[licenses-license-list,.Predefined License List], only `LICENSE_FILE` and `LICENSE_DISTFILES` variables can be set. If this is a license that has not been defined in the ports framework (see -crossref:makefiles[licenses-license-list]), the `LICENSE_PERMS` and `LICENSE_NAME` must be set, along with either `LICENSE_FILE` or `LICENSE_TEXT`. +crossref:makefiles[licenses-license-list,.Predefined License List]), the `LICENSE_PERMS` and `LICENSE_NAME` must be set, along with either `LICENSE_FILE` or `LICENSE_TEXT`. `LICENSE_DISTFILES` and `LICENSE_GROUPS` can also be set, but are not required. -The predefined licenses are shown in crossref:makefiles[licenses-license-list]. +The predefined licenses are shown in crossref:makefiles[licenses-license-list,.Predefined License List]. The current list is always available in [.filename]#Mk/bsd.licenses.db.mk#. [[licenses-license-ex1]] .Simplest Usage, Predefined Licenses [example] ==== When the [.filename]#README# of some software says "This software is under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version." but does not provide the license file, use this: [.programlisting] .... LICENSE= LGPL21+ .... When the software provides the license file, use this: [.programlisting] .... LICENSE= LGPL21+ LICENSE_FILE= ${WRKSRC}/COPYING .... ==== For the predefined licenses, the default permissions are `dist-mirror dist-sell pkg-mirror pkg-sell auto-accept`. [[licenses-license-list]] .Predefined License List [cols="1,1,1,1", frame="none", options="header"] |=== | Short Name | Name | Group | Permissions |`AGPLv3` |GNU Affero General Public License version 3 |`FSF GPL OSI` |(default) |`AGPLv3+` |GNU Affero General Public License version 3 (or later) |`FSF GPL OSI` |(default) |`APACHE10` |Apache License 1.0 |`FSF` |(default) |`APACHE11` |Apache License 1.1 |`FSF OSI` |(default) |`APACHE20` |Apache License 2.0 |`FSF OSI` |(default) |`ART10` |Artistic License version 1.0 |`OSI` |(default) |`ART20` |Artistic License version 2.0 |`FSF GPL OSI` |(default) |`ARTPERL10` |Artistic License (perl) version 1.0 |`OSI` |(default) |`BSD` |BSD license Generic Version (deprecated) |`FSF OSI COPYFREE` |(default) |`BSD2CLAUSE` |BSD 2-clause "Simplified" License |`FSF OSI COPYFREE` |(default) |`BSD3CLAUSE` |BSD 3-clause "New" or "Revised" License |`FSF OSI COPYFREE` |(default) |`BSD4CLAUSE` |BSD 4-clause "Original" or "Old" License |`FSF` |(default) |`BSL` |Boost Software License |`FSF OSI COPYFREE` |(default) |`CC-BY-1.0` |Creative Commons Attribution 1.0 | |(default) |`CC-BY-2.0` |Creative Commons Attribution 2.0 | |(default) |`CC-BY-2.5` |Creative Commons Attribution 2.5 | |(default) |`CC-BY-3.0` |Creative Commons Attribution 3.0 | |(default) |`CC-BY-4.0` |Creative Commons Attribution 4.0 | |(default) |`CC-BY-NC-1.0` |Creative Commons Attribution Non Commercial 1.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-2.0` |Creative Commons Attribution Non Commercial 2.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-2.5` |Creative Commons Attribution Non Commercial 2.5 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-3.0` |Creative Commons Attribution Non Commercial 3.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-4.0` |Creative Commons Attribution Non Commercial 4.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-ND-1.0` |Creative Commons Attribution Non Commercial No Derivatives 1.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-ND-2.0` |Creative Commons Attribution Non Commercial No Derivatives 2.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-ND-2.5` |Creative Commons Attribution Non Commercial No Derivatives 2.5 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-ND-3.0` |Creative Commons Attribution Non Commercial No Derivatives 3.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-ND-4.0` |Creative Commons Attribution Non Commercial No Derivatives 4.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-SA-1.0` |Creative Commons Attribution Non Commercial Share Alike 1.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-SA-2.0` |Creative Commons Attribution Non Commercial Share Alike 2.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-SA-2.5` |Creative Commons Attribution Non Commercial Share Alike 2.5 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-SA-3.0` |Creative Commons Attribution Non Commercial Share Alike 3.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-NC-SA-4.0` |Creative Commons Attribution Non Commercial Share Alike 4.0 | |`dist-mirror``pkg-mirror``auto-accept` |`CC-BY-ND-1.0` |Creative Commons Attribution No Derivatives 1.0 | |(default) |`CC-BY-ND-2.0` |Creative Commons Attribution No Derivatives 2.0 | |(default) |`CC-BY-ND-2.5` |Creative Commons Attribution No Derivatives 2.5 | |(default) |`CC-BY-ND-3.0` |Creative Commons Attribution No Derivatives 3.0 | |(default) |`CC-BY-ND-4.0` |Creative Commons Attribution No Derivatives 4.0 | |(default) |`CC-BY-SA-1.0` |Creative Commons Attribution Share Alike 1.0 | |(default) |`CC-BY-SA-2.0` |Creative Commons Attribution Share Alike 2.0 | |(default) |`CC-BY-SA-2.5` |Creative Commons Attribution Share Alike 2.5 | |(default) |`CC-BY-SA-3.0` |Creative Commons Attribution Share Alike 3.0 | |(default) |`CC-BY-SA-4.0` |Creative Commons Attribution Share Alike 4.0 | |(default) |`CC0-1.0` |Creative Commons Zero v1.0 Universal |`FSF GPL COPYFREE` |(default) |`CDDL` |Common Development and Distribution License |`FSF OSI` |(default) |`CPAL-1.0` |Common Public Attribution License |`FSF OSI` |(default) |`ClArtistic` |Clarified Artistic License |`FSF GPL OSI` |(default) |`EPL` |Eclipse Public License |`FSF OSI` |(default) |`GFDL` |GNU Free Documentation License |`FSF` |(default) |`GMGPL` |GNAT Modified General Public License |`FSF GPL OSI` |(default) |`GPLv1` |GNU General Public License version 1 |`FSF GPL OSI` |(default) |`GPLv1+` |GNU General Public License version 1 (or later) |`FSF GPL OSI` |(default) |`GPLv2` |GNU General Public License version 2 |`FSF GPL OSI` |(default) |`GPLv2+` |GNU General Public License version 2 (or later) |`FSF GPL OSI` |(default) |`GPLv3` |GNU General Public License version 3 |`FSF GPL OSI` |(default) |`GPLv3+` |GNU General Public License version 3 (or later) |`FSF GPL OSI` |(default) |`GPLv3RLE` |GNU GPL version 3 Runtime Library Exception |`FSF GPL OSI` |(default) |`GPLv3RLE+` |GNU GPL version 3 Runtime Library Exception (or later) |`FSF GPL OSI` |(default) |`ISCL` |Internet Systems Consortium License |`FSF GPL OSI COPYFREE` |(default) |`LGPL20` |GNU Library General Public License version 2.0 |`FSF GPL OSI` |(default) |`LGPL20+` |GNU Library General Public License version 2.0 (or later) |`FSF GPL OSI` |(default) |`LGPL21` |GNU Lesser General Public License version 2.1 |`FSF GPL OSI` |(default) |`LGPL21+` |GNU Lesser General Public License version 2.1 (or later) |`FSF GPL OSI` |(default) |`LGPL3` |GNU Lesser General Public License version 3 |`FSF GPL OSI` |(default) |`LGPL3+` |GNU Lesser General Public License version 3 (or later) |`FSF GPL OSI` |(default) |`LPPL10` |LaTeX Project Public License version 1.0 |`FSF OSI` |`dist-mirror dist-sell` |`LPPL11` |LaTeX Project Public License version 1.1 |`FSF OSI` |`dist-mirror dist-sell` |`LPPL12` |LaTeX Project Public License version 1.2 |`FSF OSI` |`dist-mirror dist-sell` |`LPPL13` |LaTeX Project Public License version 1.3 |`FSF OSI` |`dist-mirror dist-sell` |`LPPL13a` |LaTeX Project Public License version 1.3a |`FSF OSI` |`dist-mirror dist-sell` |`LPPL13b` |LaTeX Project Public License version 1.3b |`FSF OSI` |`dist-mirror dist-sell` |`LPPL13c` |LaTeX Project Public License version 1.3c |`FSF OSI` |`dist-mirror dist-sell` |`MIT` |MIT license / X11 license |`COPYFREE FSF GPL OSI` |(default) |`MPL10` |Mozilla Public License version 1.0 |`FSF OSI` |(default) |`MPL11` |Mozilla Public License version 1.1 |`FSF OSI` |(default) |`MPL20` |Mozilla Public License version 2.0 |`FSF OSI` |(default) |`NCSA` |University of Illinois/NCSA Open Source License |`COPYFREE FSF GPL OSI` |(default) |`NONE` |No license specified | |`none` |`OFL10` |SIL Open Font License version 1.0 (https://scripts.sil.org/OFL/) |`FONTS` |(default) |`OFL11` |SIL Open Font License version 1.1 (https://scripts.sil.org/OFL/) |`FONTS` |(default) |`OWL` |Open Works License (owl.apotheon.org) |`COPYFREE` |(default) |`OpenSSL` |OpenSSL License |`FSF` |(default) |`PD` |Public Domain |`GPL COPYFREE` |(default) |`PHP202` |PHP License version 2.02 |`FSF OSI` |(default) |`PHP30` |PHP License version 3.0 |`FSF OSI` |(default) |`PHP301` |PHP License version 3.01 |`FSF OSI` |(default) |`PSFL` |Python Software Foundation License |`FSF GPL OSI` |(default) |`PostgreSQL` |PostgreSQL License |`FSF GPL OSI COPYFREE` |(default) |`RUBY` |Ruby License |`FSF` |(default) |`UNLICENSE` |The Unlicense |`COPYFREE FSF GPL` |(default) |`WTFPL` |Do What the Fuck You Want To Public License version 2 |`GPL FSF COPYFREE` |(default) |`WTFPL1` |Do What the Fuck You Want To Public License version 1 |`GPL FSF COPYFREE` |(default) |`ZLIB` |zlib License |`GPL FSF OSI` |(default) |`ZPL21` |Zope Public License version 2.1 |`GPL OSI` |(default) |=== [[licenses-license_perms]] === `LICENSE_PERMS` and `LICENSE_PERMS_NAME_` Permissions. use `none` if empty. .License Permissions List [[licenses-license_perms-dist-mirror]] `dist-mirror`:: Redistribution of the distribution files is permitted. The distribution files will be added to the FreeBSD `MASTER_SITE_BACKUP` CDN. [[licenses-license_perms-no-dist-mirror]] `no-dist-mirror`:: Redistribution of the distribution files is prohibited. This is equivalent to setting crossref:special[porting-restrictions-restricted,`RESTRICTED`]. The distribution files will _not_ be added to the FreeBSD `MASTER_SITE_BACKUP` CDN. [[licenses-license_perms-dist-sell]] `dist-sell`:: Selling of distribution files is permitted. The distribution files will be present on the installer images. [[licenses-license_perms-no-dist-sell]] `no-dist-sell`:: Selling of distribution files is prohibited. This is equivalent to setting crossref:special[porting-restrictions-no_cdrom,`NO_CDROM`]. [[licenses-license_perms-pkg-mirror]] `pkg-mirror`:: Free redistribution of package is permitted. The package will be distributed on the FreeBSD package CDN https://pkg.freebsd.org/[https://pkg.freebsd.org/]. [[licenses-license_perms-no-pkg-mirror]] `no-pkg-mirror`:: Free redistribution of package is prohibited. Equivalent to setting crossref:special[porting-restrictions-no_package,`NO_PACKAGE`]. The package will _not_ be distributed from the FreeBSD package CDN https://pkg.freebsd.org/[https://pkg.freebsd.org/]. [[licenses-license_perms-pkg-sell]] `pkg-sell`:: Selling of package is permitted. The package will be present on the installer images. [[licenses-license_perms-no-pkg-sell]] `no-pkg-sell`:: Selling of package is prohibited. This is equivalent to setting crossref:special[porting-restrictions-no_cdrom,`NO_CDROM`]. The package will _not_ be present on the installer images. [[licenses-license_perms-auto-accept]] `auto-accept`:: License is accepted by default. Prompts to accept a license are not displayed unless the user has defined `LICENSES_ASK`. Use this unless the license states the user must accept the terms of the license. [[licenses-license_perms-no-auto-accept]] `no-auto-accept`:: License is not accepted by default. The user will always be asked to confirm the acceptance of this license. This must be used if the license states that the user must accept its terms. When both `_permission_` and `no-_permission_` is present the `no-_permission_` will cancel `_permission_`. When `_permission_` is not present, it is considered to be a `no-_permission_`. [WARNING] ==== Some missing permissions will prevent a port (and all ports depending on it) from being usable by package users: A port without the `auto-accept` permission will never be be built and all the ports depending on it will be ignored. A port without the `pkg-mirror` permission will be removed, as well as all the ports depending on it, after the build and they will ever end up being distributed. ==== [[licenses-license_perms-ex1]] .Nonstandard License [example] ==== Read the terms of the license and translate those using the available permissions. [.programlisting] .... LICENSE= UNKNOWN LICENSE_NAME= unknown LICENSE_TEXT= This program is NOT in public domain.\ It can be freely distributed for non-commercial purposes only. LICENSE_PERMS= dist-mirror no-dist-sell pkg-mirror no-pkg-sell auto-accept .... ==== [[licenses-license_perms-ex2]] .Standard and Nonstandard Licenses [example] ==== Read the terms of the license and express those using the available permissions. In case of doubt, please ask for guidance on the {freebsd-ports}. [.programlisting] .... LICENSE= WARSOW GPLv2 LICENSE_COMB= multi LICENSE_NAME_WARSOW= Warsow Content License LICENSE_FILE_WARSOW= ${WRKSRC}/docs/license.txt LICENSE_PERMS_WARSOW= dist-mirror pkg-mirror auto-accept .... When the permissions of the GPLv2 and the UNKNOWN licenses are mixed, the port ends up with `dist-mirror dist-sell pkg-mirror pkg-sell auto-accept dist-mirror no-dist-sell pkg-mirror no-pkg-sell auto-accept`. The `no-_permissions_` cancel the _permissions_. The resulting list of permissions are _dist-mirror pkg-mirror auto-accept_. The distribution files and the packages will not be available on the installer images. ==== [[licenses-license_groups]] === `LICENSE_GROUPS` and `LICENSE_GROUPS_NAME` Groups the license belongs. .Predefined License Groups List [[licenses-license_groups-FSF]] `FSF`:: Free Software Foundation Approved, see the https://www.fsf.org/licensing/[FSF Licensing & Compliance Team]. [[licenses-license_groups-GPL]] `GPL`:: GPL Compatible [[licenses-license_groups-OSI]] `OSI`:: OSI Approved, see the Open Source Initiative https://opensource.org/licenses/[Open Source Licenses] page. [[licenses-license_groups-COPYFREE]] `COPYFREE`:: Comply with Copyfree Standard Definition, see the https://copyfree.org/standard/licenses/[Copyfree Licenses] page. [[licenses-license_groups-FONTS]] `FONTS`:: Font licenses [[licenses-license_name]] === `LICENSE_NAME` and `LICENSE_NAME_NAME` Full name of the license. [[licenses-license_name-ex1]] .`LICENSE_NAME` [example] ==== [.programlisting] .... LICENSE= UNRAR LICENSE_NAME= UnRAR License LICENSE_FILE= ${WRKSRC}/license.txt LICENSE_PERMS= dist-mirror dist-sell pkg-mirror pkg-sell auto-accept .... ==== [[licenses-license_file]] === `LICENSE_FILE` and `LICENSE_FILE_NAME` Full path to the file containing the license text, usually [.filename]#${WRKSRC}/some/file#. If the file is not in the distfile, and its content is too long to be put in crossref:makefiles[licenses-license_text,`LICENSE_TEXT`], put it in a new file in [.filename]#${FILESDIR}#. [[licenses-license_file-ex1]] .`LICENSE_FILE` [example] ==== [.programlisting] .... LICENSE= GPLv3+ LICENSE_FILE= ${WRKSRC}/COPYING .... ==== [[licenses-license_text]] === `LICENSE_TEXT` and `LICENSE_TEXT_NAME` Text to use as a license. Useful when the license is not in the distribution files and its text is short. [[licenses-license_text-ex1]] .`LICENSE_TEXT` [example] ==== [.programlisting] .... LICENSE= UNKNOWN LICENSE_NAME= unknown LICENSE_TEXT= This program is NOT in public domain.\ It can be freely distributed for non-commercial purposes only,\ and THERE IS NO WARRANTY FOR THIS PROGRAM. LICENSE_PERMS= dist-mirror no-dist-sell pkg-mirror no-pkg-sell auto-accept .... ==== [[licenses-license_distfiles]] === `LICENSE_DISTFILES` and `LICENSE_DISTFILES_NAME` The distribution files to which the licenses apply. Defaults to all the distribution files. [[licenses-license_distfiles-ex1]] .`LICENSE_DISTFILES` [example] ==== Used when the distribution files do not all have the same license. For example, one has a code license, and another has some artwork that cannot be redistributed: [.programlisting] .... MASTER_SITES= SF/some-game DISTFILES= ${DISTNAME}${EXTRACT_SUFX} artwork.zip LICENSE= BSD3CLAUSE ARTWORK LICENSE_COMB= dual LICENSE_NAME_ARTWORK= The game artwork license LICENSE_TEXT_ARTWORK= The README says that the files cannot be redistributed LICENSE_PERMS_ARTWORK= pkg-mirror pkg-sell auto-accept LICENSE_DISTFILES_BSD3CLAUSE= ${DISTNAME}${EXTRACT_SUFX} LICENSE_DISTFILES_ARTWORK= artwork.zip .... ==== [[licenses-license_comb]] === `LICENSE_COMB` Set to `multi` if all licenses apply. Set to `dual` if any license applies. Defaults to `single`. [[licenses-license_comb-ex1]] .Dual Licenses [example] ==== When a port says "This software may be distributed under the GNU General Public License or the Artistic License", it means that either license can be used. Use this: [.programlisting] .... LICENSE= ART10 GPLv1 LICENSE_COMB= dual .... If license files are provided, use this: [.programlisting] .... LICENSE= ART10 GPLv1 LICENSE_COMB= dual LICENSE_FILE_ART10= ${WRKSRC}/Artistic LICENSE_FILE_GPLv1= ${WRKSRC}/Copying .... ==== [[licenses-license_comb-ex2]] .Multiple Licenses [example] ==== When part of a port has one license, and another part has a different license, use `multi`: [.programlisting] .... LICENSE= GPLv2 LGPL21+ LICENSE_COMB= multi .... ==== [[makefile-portscout]] == `PORTSCOUT` Portscout is an automated distfile check utility for the FreeBSD Ports Collection, described in detail in crossref:keeping-up[distfile-survey,Portscout: the FreeBSD Ports Distfile Scanner]. `PORTSCOUT` defines special conditions within which the Portscout distfile scanner is restricted. Situations where `PORTSCOUT` is set include: * When distfiles have to be ignored for specific versions. For example, to exclude version _8.2_ and version _8.3_ from distfile version checks because they are known to be broken, add: + [.programlisting] .... PORTSCOUT= skipv:8.2,8.3 .... * When distfile version checks have to be disabled completely. For example, if a port is not going to be updated ever again, add: + [.programlisting] .... PORTSCOUT= ignore:1 .... * When specific versions or specific major and minor revisions of a distfile must be checked. For example, if only version _0.6.4_ must be monitored because newer versions have compatibility issues with FreeBSD, add: + [.programlisting] .... PORTSCOUT= limit:^0\.6\.4 .... * When URLs listing the available versions differ from the download URLs. For example, to limit distfile version checks to the download page for the package:databases/pgtune[] port, add: + [.programlisting] .... PORTSCOUT= site:http://www.renpy.org/dl/release/ .... [[makefile-depend]] == Dependencies Many ports depend on other ports. This is a very convenient feature of most Unix-like operating systems, including FreeBSD. Multiple ports can share a common dependency, rather than bundling that dependency with every port or package that needs it. There are seven variables that can be used to ensure that all the required bits will be on the user's machine. There are also some pre-supported dependency variables for common cases, plus a few more to control the behavior of dependencies. [IMPORTANT] ==== When software has extra dependencies that provide extra features, the base dependencies listed in `*_DEPENDS` should include the extra dependencies that would benefit most users. The base dependencies should never be a "minimal" dependency set. The goal is not to include every dependency possible. Only include those that will benefit most people. ==== [[makefile-lib_depends]] === `LIB_DEPENDS` This variable specifies the shared libraries this port depends on. It is a list of `_lib:dir_` tuples where `_lib_` is the name of the shared library, `_dir_` is the directory in which to find it in case it is not available. For example, [.programlisting] .... LIB_DEPENDS= libjpeg.so:graphics/jpeg .... will check for a shared jpeg library with any version, and descend into the [.filename]#graphics/jpeg# subdirectory of the ports tree to build and install it if it is not found. The dependency is checked twice, once from within the `build` target and then from within the `install` target. Also, the name of the dependency is put into the package so that `pkg install` (see man:pkg-install[8]) will automatically install it if it is not on the user's system. [[makefile-run_depends]] === `RUN_DEPENDS` This variable specifies executables or files this port depends on during run-time. It is a list of ``_path:dir_``[:``_target_``] tuples where `_path_` is the name of the executable or file, _dir_ is the directory in which to find it in case it is not available, and _target_ is the target to call in that directory. If _path_ starts with a slash (`/`), it is treated as a file and its existence is tested with `test -e`; otherwise, it is assumed to be an executable, and `which -s` is used to determine if the program exists in the search path. For example, [.programlisting] .... RUN_DEPENDS= ${LOCALBASE}/news/bin/innd:news/inn \ xmlcatmgr:textproc/xmlcatmgr .... will check if the file or directory [.filename]#/usr/local/news/bin/innd# exists, and build and install it from the [.filename]#news/inn# subdirectory of the ports tree if it is not found. It will also see if an executable called `xmlcatmgr` is in the search path, and descend into [.filename]#textproc/xmlcatmgr# to build and install it if it is not found. [NOTE] ==== In this case, `innd` is actually an executable; if an executable is in a place that is not expected to be in the search path, use the full pathname. ==== [NOTE] ==== The official search `PATH` used on the ports build cluster is [.programlisting] .... /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin .... ==== The dependency is checked from within the `install` target. Also, the name of the dependency is put into the package so that `pkg install` (see man:pkg-install[8]) will automatically install it if it is not on the user's system. The _target_ part can be omitted if it is the same as `DEPENDS_TARGET`. A quite common situation is when `RUN_DEPENDS` is literally the same as `BUILD_DEPENDS`, especially if ported software is written in a scripted language or if it requires the same build and run-time environment. In this case, it is both tempting and intuitive to directly assign one to the other: [.programlisting] .... RUN_DEPENDS= ${BUILD_DEPENDS} .... However, such assignment can pollute run-time dependencies with entries not defined in the port's original `BUILD_DEPENDS`. This happens because of man:make[1]'s lazy evaluation of variable assignment. Consider a [.filename]#Makefile# with `USE_*`, which are processed by [.filename]#ports/Mk/bsd.*.mk# to augment initial build dependencies. For example, `USES= gmake` adds package:devel/gmake[] to `BUILD_DEPENDS`. To prevent such additional dependencies from polluting `RUN_DEPENDS`, create another variable with the current content of `BUILD_DEPENDS` and assign it to both `BUILD_DEPENDS` and `RUN_DEPENDS`: [.programlisting] .... MY_DEPENDS= some:devel/some \ other:lang/other BUILD_DEPENDS= ${MY_DEPENDS} RUN_DEPENDS= ${MY_DEPENDS} .... [IMPORTANT] ==== _Do not_ use `:=` to assign `BUILD_DEPENDS` to `RUN_DEPENDS` or vice-versa. All variables are expanded immediately, which is exactly the wrong thing to do and almost always a failure. ==== [[makefile-build_depends]] === `BUILD_DEPENDS` This variable specifies executables or files this port requires to build. Like `RUN_DEPENDS`, it is a list of ``_path:dir_``[:``_target_``] tuples. For example, [.programlisting] .... BUILD_DEPENDS= unzip:archivers/unzip .... will check for an executable called `unzip`, and descend into the [.filename]#archivers/unzip# subdirectory of the ports tree to build and install it if it is not found. [NOTE] ==== "build" here means everything from extraction to compilation. The dependency is checked from within the `extract` target. The _target_ part can be omitted if it is the same as `DEPENDS_TARGET` ==== [[makefile-fetch_depends]] === `FETCH_DEPENDS` This variable specifies executables or files this port requires to fetch. Like the previous two, it is a list of ``_path:dir_``[:``_target_``] tuples. For example, [.programlisting] .... FETCH_DEPENDS= ncftp2:net/ncftp2 .... will check for an executable called `ncftp2`, and descend into the [.filename]#net/ncftp2# subdirectory of the ports tree to build and install it if it is not found. The dependency is checked from within the `fetch` target. The _target_ part can be omitted if it is the same as `DEPENDS_TARGET`. [[makefile-extract_depends]] === `EXTRACT_DEPENDS` This variable specifies executables or files this port requires for extraction. Like the previous, it is a list of ``_path:dir_``[:``_target_``] tuples. For example, [.programlisting] .... EXTRACT_DEPENDS= unzip:archivers/unzip .... will check for an executable called `unzip`, and descend into the [.filename]#archivers/unzip# subdirectory of the ports tree to build and install it if it is not found. The dependency is checked from within the `extract` target. The _target_ part can be omitted if it is the same as `DEPENDS_TARGET`. [NOTE] ==== Use this variable only if the extraction does not already work (the default assumes `tar`) and cannot be made to work using `USES=tar`, `USES=lha` or `USES=zip` described in crossref:uses[uses,Using `USES` Macros]. ==== [[makefile-patch_depends]] === `PATCH_DEPENDS` This variable specifies executables or files this port requires to patch. Like the previous, it is a list of ``_path:dir_``[:``_target_``] tuples. For example, [.programlisting] .... PATCH_DEPENDS= ${NONEXISTENT}:java/jfc:extract .... will descend into the [.filename]#java/jfc# subdirectory of the ports tree to extract it. The dependency is checked from within the `patch` target. The _target_ part can be omitted if it is the same as `DEPENDS_TARGET`. [[makefile-uses]] === `USES` Parameters can be added to define different features and dependencies used by the port. They are specified by adding this line to the [.filename]#Makefile#: [.programlisting] .... USES= feature[:arguments] .... For the complete list of values, please see crossref:uses[uses,Using `USES` Macros]. [WARNING] ==== `USES` cannot be assigned after inclusion of [.filename]#bsd.port.pre.mk#. ==== [[makefile-use-vars]] === `USE_*` Several variables exist to define common dependencies shared by many ports. Their use is optional, but helps to reduce the verbosity of the port [.filename]##Makefile##s. Each of them is styled as `USE_*`. These variables may be used only in the port [.filename]##Makefile##s and [.filename]#ports/Mk/bsd.*.mk#. They are not meant for user-settable options - use `PORT_OPTIONS` for that purpose. [NOTE] ==== It is _always_ incorrect to set any `USE_*` in [.filename]#/etc/make.conf#. For instance, setting [.programlisting] .... USE_GCC=X.Y .... (where X.Y is version number) would add a dependency on gccXY for every port, including `lang/gccXY` itself! ==== [[makefile-use-vars-table]] .`USE_*` [cols="1,1", frame="none", options="header"] |=== | Variable | Means |`USE_GCC` a| The port requires GCC (`gcc` or `{g-plus-plus}`) to build. Some ports need a specific, old GCC version, some require modern, recent versions. It is typically set to `yes` (means always use stable, modern GCC from ports per `GCC_DEFAULT` in [.filename]#Mk/bsd.default-versions.mk#). This is also the default value. The exact version can also be specified, with a value such as `10`. GCC from the base system is used when it satisfies the requested version, otherwise an appropriate compiler is built from ports, and `CC` and `CXX` are adjusted accordingly. The `:build` argument following the version specifier adds only a build time dependency to the port. For example: [example] ==== [.programlisting] .... USE_GCC=yes # port requires a current version of GCC USE_GCC=11:build # port requires GCC 11 at build time only .... ==== [NOTE] ==== `USE_GCC=any` is deprecated and should not be used in new ports ==== |=== Variables related to gmake and [.filename]#configure# are described in crossref:special[building,Building Mechanisms], while autoconf, automake and libtool are described in crossref:special[using-autotools,Using GNU Autotools]. Perl related variables are described in crossref:special[using-perl,Using Perl]. X11 variables are listed in crossref:special[using-x11,Using X11]. crossref:special[using-gnome,Using Gnome] deals with GNOME and crossref:special[using-kde,Using KDE] with KDE related variables. crossref:special[using-java,Using Java] documents Java variables, while crossref:special[using-php,Web Applications, Apache and PHP] contains information on Apache, PHP and PEAR modules. Python is discussed in crossref:special[using-python,Using Python], while Ruby in crossref:special[using-ruby,Using Ruby]. crossref:special[using-sdl,Using SDL] provides variables used for SDL applications and finally, crossref:special[using-xfce,Using Xfce] contains information on Xfce. [[makefile-version-dependency]] === Minimal Version of a Dependency A minimal version of a dependency can be specified in any `*_DEPENDS` except `LIB_DEPENDS` using this syntax: [.programlisting] .... p5-Spiffy>=0.26:devel/p5-Spiffy .... The first field contains a dependent package name, which must match the entry in the package database, a comparison sign, and a package version. The dependency is satisfied if p5-Spiffy-0.26 or newer is installed on the machine. [[makefile-note-on-dependencies]] === Notes on Dependencies As mentioned above, the default target to call when a dependency is required is `DEPENDS_TARGET`. It defaults to `install`. This is a user variable; it is never defined in a port's [.filename]#Makefile#. If the port needs a special way to handle a dependency, use the `:target` part of `*_DEPENDS` instead of redefining `DEPENDS_TARGET`. When running `make clean`, the port dependencies are automatically cleaned too. If this is not desirable, define `NOCLEANDEPENDS` in the environment. This may be particularly desirable if the port has something that takes a long time to rebuild in its dependency list, such as KDE, GNOME or Mozilla. To depend on another port unconditionally, use the variable `${NONEXISTENT}` as the first field of `BUILD_DEPENDS` or `RUN_DEPENDS`. Use this only when the source of the other port is needed. Compilation time can be saved by specifying the target too. For instance [.programlisting] .... BUILD_DEPENDS= ${NONEXISTENT}:graphics/jpeg:extract .... will always descend to the `jpeg` port and extract it. [[makefile-circular-dependencies]] === Circular Dependencies Are Fatal [IMPORTANT] ==== Do not introduce any circular dependencies into the ports tree! ==== The ports building technology does not tolerate circular dependencies. If one is introduced, someone, somewhere in the world, will have their FreeBSD installation broken almost immediately, with many others quickly to follow. These can really be hard to detect. If in doubt, before making that change, make sure to run: `cd /usr/ports; make index`. That process can be quite slow on older machines, but it may be able to save a large number of people, including yourself, a lot of grief in the process. [[makefile-automatic-dependencies]] === Problems Caused by Automatic Dependencies Dependencies must be declared either explicitly or by using the crossref:makefiles[makefile-options,OPTIONS framework]. Using other methods like automatic detection complicates indexing, which causes problems for port and package management. [[makefile-automatic-dependencies-bad]] .Wrong Declaration of an Optional Dependency [example] ==== [.programlisting] .... .include .if exists(${LOCALBASE}/bin/foo) LIB_DEPENDS= libbar.so:foo/bar .endif .... ==== The problem with trying to automatically add dependencies is that files and settings outside an individual port can change at any time. For example: an index is built, then a batch of ports are installed. But one of the ports installs the tested file. The index is now incorrect, because an installed port unexpectedly has a new dependency. The index may still be wrong even after rebuilding if other ports also determine their need for dependencies based on the existence of other files. [[makefile-automatic-dependencies-good]] .Correct Declaration of an Optional Dependency [example] ==== [.programlisting] .... OPTIONS_DEFINE= BAR BAR_DESC= Calling cellphones via bar BAR_LIB_DEPENDS= libbar.so:foo/bar .... ==== Testing option variables is the correct method. It will not cause inconsistencies in the index of a batch of ports, provided the options were defined prior to the index build. Simple scripts can then be used to automate the building, installation, and updating of these ports and their packages. [[makefile-masterdir]] == Slave Ports and `MASTERDIR` If the port needs to build slightly different versions of packages by having a variable (for instance, resolution, or paper size) take different values, create one subdirectory per package to make it easier for users to see what to do, but try to share as many files as possible between ports. Typically, by using variables cleverly, only a very short [.filename]#Makefile# is needed in all but one of the directories. In the sole [.filename]#Makefile#, use `MASTERDIR` to specify the directory where the rest of the files are. Also, use a variable as part of crossref:makefiles[porting-pkgname,`PKGNAMESUFFIX`] so the packages will have different names. This will be best demonstrated by an example. This is part of [.filename]#print/pkfonts300/Makefile#; [.programlisting] .... PORTNAME= pkfonts${RESOLUTION} PORTVERSION= 1.0 DISTFILES= pk${RESOLUTION}.tar.gz PLIST= ${PKGDIR}/pkg-plist.${RESOLUTION} .if !defined(RESOLUTION) RESOLUTION= 300 .else .if ${RESOLUTION} != 118 && ${RESOLUTION} != 240 && \ ${RESOLUTION} != 300 && ${RESOLUTION} != 360 && \ ${RESOLUTION} != 400 && ${RESOLUTION} != 600 .BEGIN: @${ECHO_MSG} "Error: invalid value for RESOLUTION: \"${RESOLUTION}\"" @${ECHO_MSG} "Possible values are: 118, 240, 300, 360, 400 and 600." @${FALSE} .endif .endif .... package:print/pkfonts300[] also has all the regular patches, package files, etc. Running `make` there, it will take the default value for the resolution (300) and build the port normally. As for other resolutions, this is the _entire_ [.filename]#print/pkfonts360/Makefile#: [.programlisting] .... RESOLUTION= 360 MASTERDIR= ${.CURDIR}/../pkfonts300 .include "${MASTERDIR}/Makefile" .... ([.filename]#print/pkfonts118/Makefile#, [.filename]#print/pkfonts600/Makefile#, and all the other are similar). `MASTERDIR` definition tells [.filename]#bsd.port.mk# that the regular set of subdirectories like `FILESDIR` and `SCRIPTDIR` are to be found under [.filename]#pkfonts300#. The `RESOLUTION=360` line will override the `RESOLUTION=300` line in [.filename]#pkfonts300/Makefile# and the port will be built with resolution set to 360. [[makefile-manpages]] == Man Pages If the port anchors its man tree somewhere other than `PREFIX`, use `MANDIRS` to specify those directories. Note that the files corresponding to manual pages must be placed in [.filename]#pkg-plist# along with the rest of the files. The purpose of `MANDIRS` is to enable automatic compression of manual pages, therefore the file names are suffixed with [.filename]#.gz#. [[makefile-info]] == Info Files If the package needs to install GNU info files, list them in `INFO` (without the trailing `.info`), one entry per document. These files are assumed to be installed to [.filename]#PREFIX/INFO_PATH#. Change `INFO_PATH` if the package uses a different location. However, this is not recommended. These entries contain just the path relative to [.filename]#PREFIX/INFO_PATH#. For example, package:lang/gcc34[] installs info files to [.filename]#PREFIX/INFO_PATH/gcc34#, and `INFO` will be something like this: [.programlisting] .... INFO= gcc34/cpp gcc34/cppinternals gcc34/g77 ... .... Appropriate installation/de-installation code will be automatically added to the temporary [.filename]#pkg-plist# before package registration. [[makefile-options]] == Makefile Options Many applications can be built with optional or differing configurations. Examples include choice of natural (human) language, GUI versus command-line, or type of database to support. Users may need a different configuration than the default, so the ports system provides hooks the port author can use to control which variant will be built. Supporting these options properly will make users happy, and effectively provide two or more ports for the price of one. [[makefile-options-options]] === `OPTIONS` [[makefile-options-background]] ==== Background `OPTIONS_*` give the user installing the port a dialog showing the available options, and then saves those options to [.filename]#${PORT_DBDIR}/${OPTIONS_NAME}/options#. The next time the port is built, the options are reused. `PORT_DBDIR` defaults to [.filename]#/var/db/ports#. `OPTIONS_NAME` is to the port origin with an underscore as the space separator, for example, for package:dns/bind99[] it will be `dns_bind99`. When the user runs `make config` (or runs `make build` for the first time), the framework checks for [.filename]#${PORT_DBDIR}/${OPTIONS_NAME}/options#. If that file does not exist, the values of `OPTIONS_*` are used, and a dialog box is displayed where the options can be enabled or disabled. Then [.filename]#options# is saved and the configured variables are used when building the port. If a new version of the port adds new `OPTIONS`, the dialog will be presented to the user with the saved values of old `OPTIONS` prefilled. `make showconfig` shows the saved configuration. Use `make rmconfig` to remove the saved configuration. [[makefile-options-syntax]] ==== Syntax `OPTIONS_DEFINE` contains a list of `OPTIONS` to be used. These are independent of each other and are not grouped: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 .... Once defined, `OPTIONS` are described (optional, but strongly recommended): [.programlisting] .... OPT1_DESC= Describe OPT1 OPT2_DESC= Describe OPT2 OPT3_DESC= Describe OPT3 OPT4_DESC= Describe OPT4 OPT5_DESC= Describe OPT5 OPT6_DESC= Describe OPT6 .... [.filename]#ports/Mk/bsd.options.desc.mk# has descriptions for many common `OPTIONS`. While often useful, override them if the description is insufficient for the port. [TIP] ==== When describing options, view it from the perspective of the user: "What functionality does it change?" and "Why would I want to enable this?" Do not just repeat the name. For example, describing the `NLS` option as "include NLS support" does not help the user, who can already see the option name but may not know what it means. Describing it as "Native Language Support via gettext utilities" is much more helpful. ==== [IMPORTANT] ==== Option names are always in all uppercase. They cannot use mixed case or lowercase. ==== `OPTIONS` can be grouped as radio choices, where only one choice from each group is allowed: [.programlisting] .... OPTIONS_SINGLE= SG1 OPTIONS_SINGLE_SG1= OPT3 OPT4 .... [WARNING] ==== There _must_ be one of each `OPTIONS_SINGLE` group selected at all times for the options to be valid. One option of each group _must_ be added to `OPTIONS_DEFAULT`. ==== `OPTIONS` can be grouped as radio choices, where none or only one choice from each group is allowed: [.programlisting] .... OPTIONS_RADIO= RG1 OPTIONS_RADIO_RG1= OPT7 OPT8 .... `OPTIONS` can also be grouped as "multiple-choice" lists, where _at least one_ option must be enabled: [.programlisting] .... OPTIONS_MULTI= MG1 OPTIONS_MULTI_MG1= OPT5 OPT6 .... `OPTIONS` can also be grouped as "multiple-choice" lists, where none or any option can be enabled: [.programlisting] .... OPTIONS_GROUP= GG1 OPTIONS_GROUP_GG1= OPT9 OPT10 .... `OPTIONS` are unset by default, unless they are listed in `OPTIONS_DEFAULT`: [.programlisting] .... OPTIONS_DEFAULT= OPT1 OPT3 OPT6 .... `OPTIONS` definitions must appear before the inclusion of [.filename]#bsd.port.options.mk#. `PORT_OPTIONS` values can only be tested after the inclusion of [.filename]#bsd.port.options.mk#. Inclusion of [.filename]#bsd.port.pre.mk# can be used instead, too, and is still widely used in ports written before the introduction of [.filename]#bsd.port.options.mk#. But be aware that some variables will not work as expected after the inclusion of [.filename]#bsd.port.pre.mk#, typically some `USE_*` flags. [[ports-options-simple-use]] .Simple Use of `OPTIONS` [example] ==== [.programlisting] .... OPTIONS_DEFINE= FOO BAR OPTIONS_DEFAULT=FOO FOO_DESC= Option foo support BAR_DESC= Feature bar support # Will add --with-foo / --without-foo FOO_CONFIGURE_WITH= foo BAR_RUN_DEPENDS= bar:bar/bar .include .... ==== [[ports-options-check-unset]] .Check for Unset Port `OPTIONS` [example] ==== [.programlisting] .... .if ! ${PORT_OPTIONS:MEXAMPLES} CONFIGURE_ARGS+=--without-examples .endif .... The form shown above is discouraged. The preferred method is using a configure knob to really enable and disable the feature to match the option: [.programlisting] .... # Will add --with-examples / --without-examples EXAMPLES_CONFIGURE_WITH= examples .... ==== [[ports-options-practical-use]] .Practical Use of `OPTIONS` [example] ==== [.programlisting] .... OPTIONS_DEFINE= EXAMPLES OPTIONS_DEFAULT= PGSQL LDAP SSL OPTIONS_SINGLE= BACKEND OPTIONS_SINGLE_BACKEND= MYSQL PGSQL BDB OPTIONS_MULTI= AUTH OPTIONS_MULTI_AUTH= LDAP PAM SSL EXAMPLES_DESC= Install extra examples MYSQL_DESC= Use MySQL as backend PGSQL_DESC= Use PostgreSQL as backend BDB_DESC= Use Berkeley DB as backend LDAP_DESC= Build with LDAP authentication support PAM_DESC= Build with PAM support SSL_DESC= Build with OpenSSL support # Will add USE_PGSQL=yes PGSQL_USE= pgsql=yes # Will add --enable-postgres / --disable-postgres PGSQL_CONFIGURE_ENABLE= postgres ICU_LIB_DEPENDS= libicuuc.so:devel/icu # Will add --with-examples / --without-examples EXAMPLES_CONFIGURE_WITH= examples # Check other OPTIONS .include .... ==== [[makefile-options-default]] ==== Default Options These options are always on by default. * `DOCS` - build and install documentation. * `NLS` - Native Language Support. * `EXAMPLES` - build and install examples. * `IPV6` - IPv6 protocol support. [NOTE] ==== There is no need to add these to `OPTIONS_DEFAULT`. To have them active, and show up in the options selection dialog, however, they must be added to `OPTIONS_DEFINE`. ==== [[makefile-options-auto-activation]] === Feature Auto-Activation When using a GNU configure script, keep an eye on which optional features are activated by auto-detection. Explicitly disable optional features that are not needed by adding `--without-xxx` or `--disable-xxx` in `CONFIGURE_ARGS`. [[makefile-options-auto-activation-bad]] .Wrong Handling of an Option [example] ==== [.programlisting] .... .if ${PORT_OPTIONS:MFOO} LIB_DEPENDS+= libfoo.so:devel/foo CONFIGURE_ARGS+= --enable-foo .endif .... ==== In the example above, imagine a library libfoo is installed on the system. The user does not want this application to use libfoo, so he toggled the option off in the `make config` dialog. But the application's configure script detects the library present in the system and includes its support in the resulting executable. Now when the user decides to remove libfoo from the system, the ports system does not protest (no dependency on libfoo was recorded) but the application breaks. [[makefile-options-auto-activation-good]] .Correct Handling of an Option [example] ==== [.programlisting] .... FOO_LIB_DEPENDS= libfoo.so:devel/foo # Will add --enable-foo / --disable-foo FOO_CONFIGURE_ENABLE= foo .... ==== [NOTE] ==== Under some circumstances, the shorthand conditional syntax can cause problems with complex constructs. The errors are usually `Malformed conditional`, an alternative syntax can be used. [.programlisting] .... .if !empty(VARIABLE:MVALUE) .... as an alternative to [.programlisting] .... .if ${VARIABLE:MVALUE} .... ==== [[options-helpers]] === Options Helpers There are some macros to help simplify conditional values which differ based on the options set. For easier access, a comprehensive list is provided: `PLIST_SUB`, `SUB_LIST`:: -For automatic `%%_OPT_%%` and `%%NO__OPT__%%` generation, see crossref:makefiles[options_sub]. +For automatic `%%_OPT_%%` and `%%NO__OPT__%%` generation, see crossref:makefiles[options_sub, `OPTIONS_SUB`]. + -For more complex usage, see crossref:makefiles[options-variables]. +For more complex usage, see crossref:makefiles[options-variables, Generic Variables Replacement, `OPT_VARIABLE` and `OPT_VARIABLE_OFF`]. `CONFIGURE_ARGS`:: -For `--enable-_x_` and `--disable-_x_`, see crossref:makefiles[options-configure_enable]. +For `--enable-_x_` and `--disable-_x_`, see crossref:makefiles[options-configure_enable, `OPT_CONFIGURE_ENABLE`]. + -For `--with-_x_` and `--without-_x_`, see crossref:makefiles[options-configure_with]. +For `--with-_x_` and `--without-_x_`, see crossref:makefiles[options-configure_with, `OPT_CONFIGURE_WITH`]. + -For all other cases, see crossref:makefiles[options-configure_on]. +For all other cases, see crossref:makefiles[options-configure_on, `OPT_CONFIGURE_ON` and `OPT_CONFIGURE_OFF`]. `CMAKE_ARGS`:: For arguments that are booleans (`on`, `off`, `true`, `false`, `0`, `1`) see -crossref:makefiles[options-cmake_bool]. +crossref:makefiles[options-cmake_bool, `OPT_CMAKE_BOOL` and `OPT_CMAKE_BOOL_OFF`]. + -For all other cases, see crossref:makefiles[options-cmake_on]. +For all other cases, see crossref:makefiles[options-cmake_on, `OPT_CMAKE_ON` and `OPT_CMAKE_OFF`]. `MESON_ARGS`:: -For arguments that take `true` or `false`, see crossref:makefiles[options-meson_true]. +For arguments that take `true` or `false`, see crossref:makefiles[options-meson_true, `OPT_MESON_TRUE` and `OPT_MESON_FALSE`]. + -For arguments that take `yes` or `no`, use crossref:makefiles[options-meson_yes]. +For arguments that take `yes` or `no`, use crossref:makefiles[options-meson_yes, `OPT_MESON_YES` and `OPT_MESON_NO`]. + -For arguments that take `enabled` or `disabled`, see crossref:makefiles[options-meson_enabled]. +For arguments that take `enabled` or `disabled`, see crossref:makefiles[options-meson_enabled, `OPT_MESON_ENABLED` and `OPT_MESON_DISABLED`]. + -For all other cases, use crossref:makefiles[options-meson_on]. +For all other cases, use crossref:makefiles[options-meson_on, `OPT_MESON_ON` and `OPT_MESON_OFF`]. `QMAKE_ARGS`:: -See crossref:makefiles[options-qmake_on]. +See crossref:makefiles[options-qmake_on, `OPT_QMAKE_ON` and `OPT_QMAKE_OFF`]. `USE_*`:: -See crossref:makefiles[options-use]. +See crossref:makefiles[options-use, `OPT_USE` and `OPT_USE_OFF`]. `*_DEPENDS`:: -See crossref:makefiles[options-dependencies]. +See crossref:makefiles[options-dependencies, Dependencies, `OPT_DEPTYPE` and `OPT_DEPTYPE_OFF`]. `*` (Any variable):: The most used variables have direct helpers, see -crossref:makefiles[options-variables]. +crossref:makefiles[options-variables, Generic Variables Replacement, `OPT_VARIABLE` and `OPT_VARIABLE_OFF`]. + -For any variable without a specific helper, see crossref:makefiles[options-vars]. +For any variable without a specific helper, see crossref:makefiles[options-vars, `OPT_VARS` and `OPT_VARS_OFF`]. Options dependencies:: When an option need another option to work, see -crossref:makefiles[options-implies]. +crossref:makefiles[options-implies, `OPT_IMPLIES`]. Options conflicts:: When an option cannot work if another is also enabled, see -crossref:makefiles[options-prevents]. +crossref:makefiles[options-prevents, `OPT_PREVENTS` and `OPT_PREVENTS_MSG`]. Build targets:: When an option need some extra processing, see -crossref:makefiles[options-targets]. +crossref:makefiles[options-targets, Additional Build Targets, `_target_-_OPT_-on` and `_target_-_OPT_-off`]. [[options_sub]] ==== `OPTIONS_SUB` If `OPTIONS_SUB` is set to `yes` then each of the options added to `OPTIONS_DEFINE` will be added to `PLIST_SUB` and `SUB_LIST`, for example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPTIONS_SUB= yes .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} PLIST_SUB+= OPT1="" NO_OPT1="@comment " SUB_LIST+= OPT1="" NO_OPT1="@comment " .else PLIST_SUB+= OPT1="@comment " NO_OPT1="" SUB_LIST+= OPT1="@comment " NO_OPT1="" .endif .... [NOTE] ==== The value of `OPTIONS_SUB` is ignored. Setting it to any value will add `PLIST_SUB` and `SUB_LIST` entries for _all_ options. ==== [[options-use]] ==== `OPT_USE` and `OPT_USE_OFF` When option _OPT_ is selected, for each `_key=value_` pair in ``OPT_USE``, _value_ is appended to the corresponding `USE_KEY`. If _value_ has spaces in it, replace them with commas and they will be changed back to spaces during processing. `OPT_USE_OFF` works the same way, but when `OPT` is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_USES= xorg OPT1_USE= mysql=yes xorg=x11,xextproto,xext,xrandr OPT1_USE_OFF= openssl=yes .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} USE_MYSQL= yes USES+= xorg USE_XORG= x11 xextproto xext xrandr .else USE_OPENSSL= yes .endif .... [[options-configure-helpers]] ==== `CONFIGURE_ARGS` Helpers [[options-configure_enable]] ===== `OPT_CONFIGURE_ENABLE` When option _OPT_ is selected, for each _entry_ in `OPT_CONFIGURE_ENABLE` then `--enable-_entry_` is appended to `CONFIGURE_ARGS`. When option _OPT_ is _not_ selected, `--disable-_entry_` is appended to `CONFIGURE_ARGS`. An optional argument can be specified with an `=` symbol. This argument is only appended to the `--enable-_entry_` configure option. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 OPT1_CONFIGURE_ENABLE= test1 test2 OPT2_CONFIGURE_ENABLE= test2=exhaustive .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} CONFIGURE_ARGS+= --enable-test1 --enable-test2 .else CONFIGURE_ARGS+= --disable-test1 --disable-test2 .endif .if ${PORT_OPTIONS:MOPT2} CONFIGURE_ARGS+= --enable-test2=exhaustive .else CONFIGURE_ARGS+= --disable-test2 .endif .... [[options-configure_with]] ===== `OPT_CONFIGURE_WITH` When option _OPT_ is selected, for each _entry_ in `_OPT_CONFIGURE_WITH` then `--with-_entry_` is appended to `CONFIGURE_ARGS`. When option _OPT_ is _not_ selected, `--without-_entry_` is appended to `CONFIGURE_ARGS`. An optional argument can be specified with an `=` symbol. This argument is only appended to the `--with-_entry_` configure option. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 OPT1_CONFIGURE_WITH= test1 OPT2_CONFIGURE_WITH= test2=exhaustive .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 .include .if ${PORT_OPTIONS:MOPT1} CONFIGURE_ARGS+= --with-test1 .else CONFIGURE_ARGS+= --without-test1 .endif .if ${PORT_OPTIONS:MOPT2} CONFIGURE_ARGS+= --with-test2=exhaustive .else CONFIGURE_ARGS+= --without-test2 .endif .... [[options-configure_on]] ===== `OPT_CONFIGURE_ON` and `OPT_CONFIGURE_OFF` When option _OPT_ is selected, the value of `OPT_CONFIGURE_ON`, if defined, is appended to `CONFIGURE_ARGS`. `OPT_CONFIGURE_OFF` works the same way, but when `OPT` is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_CONFIGURE_ON= --add-test OPT1_CONFIGURE_OFF= --no-test .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} CONFIGURE_ARGS+= --add-test .else CONFIGURE_ARGS+= --no-test .endif .... [TIP] ==== -Most of the time, the helpers in crossref:makefiles[options-configure_enable] -and crossref:makefiles[options-configure_with] provide a shorter and more comprehensive functionality. +Most of the time, the helpers in crossref:makefiles[options-configure_enable, `OPT_CONFIGURE_ENABLE`] +and crossref:makefiles[options-configure_with, `OPT_CONFIGURE_WITH`] provide a shorter and more comprehensive functionality. ==== [[options-cmake-helpers]] ==== `CMAKE_ARGS` Helpers [[options-cmake_on]] ===== `OPT_CMAKE_ON` and `OPT_CMAKE_OFF` When option _OPT_ is selected, the value of `OPT_CMAKE_ON`, if defined, is appended to `CMAKE_ARGS`. `OPT_CMAKE_OFF` works the same way, but when `OPT` is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_CMAKE_ON= -DTEST:BOOL=true -DDEBUG:BOOL=true OPT1_CMAKE_OFF= -DOPTIMIZE:BOOL=true .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} CMAKE_ARGS+= -DTEST:BOOL=true -DDEBUG:BOOL=true .else CMAKE_ARGS+= -DOPTIMIZE:BOOL=true .endif .... [TIP] ==== -See crossref:makefiles[options-cmake_bool] for a shorter helper when the value is boolean. +See crossref:makefiles[options-cmake_bool, `OPT_CMAKE_BOOL` and `OPT_CMAKE_BOOL_OFF`] for a shorter helper when the value is boolean. ==== [[options-cmake_bool]] ===== `OPT_CMAKE_BOOL` and `OPT_CMAKE_BOOL_OFF` When option _OPT_ is selected, for each _entry_ in `OPT_CMAKE_BOOL` then `-D_entry_:BOOL=true` is appended to `CMAKE_ARGS`. When option _OPT_ is _not_ selected, `-D_entry_:BOOL=false` is appended to `CONFIGURE_ARGS`. `OPT_CMAKE_BOOL_OFF` is the opposite, `-D_entry_:BOOL=false` is appended to `CMAKE_ARGS` when the option is selected, and `-D_entry_:BOOL=true` when the option is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_CMAKE_BOOL= TEST DEBUG OPT1_CMAKE_BOOL_OFF= OPTIMIZE .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} CMAKE_ARGS+= -DTEST:BOOL=true -DDEBUG:BOOL=true \ -DOPTIMIZE:BOOL=false .else CMAKE_ARGS+= -DTEST:BOOL=false -DDEBUG:BOOL=false \ -DOPTIMIZE:BOOL=true .endif .... [[options-meson-helpers]] ==== `MESON_ARGS` Helpers [[options-meson_on]] ===== `OPT_MESON_ON` and `OPT_MESON_OFF` When option _OPT_ is selected, the value of `OPT_MESON_ON`, if defined, is appended to `MESON_ARGS`. `OPT_MESON_OFF` works the same way, but when `OPT` is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_MESON_ON= -Dopt=1 OPT1_MESON_OFF= -Dopt=2 .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} MESON_ARGS+= -Dopt=1 .else MESON_ARGS+= -Dopt=2 .endif .... [[options-meson_true]] ===== `OPT_MESON_TRUE` and `OPT_MESON_FALSE` When option _OPT_ is selected, for each _entry_ in `OPT_MESON_TRUE` then `-D_entry_=true` is appended to `MESON_ARGS`. When option _OPT_ is _not_ selected, `-D_entry_=false` is appended to `MESON_ARGS`. `OPT_MESON_FALSE` is the opposite, `-D_entry_=false` is appended to `MESON_ARGS` when the option is selected, and `-D_entry_=true` when the option is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_MESON_TRUE= test debug OPT1_MESON_FALSE= optimize .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} MESON_ARGS+= -Dtest=true -Ddebug=true \ -Doptimize=false .else MESON_ARGS+= -Dtest=false -Ddebug=false \ -Doptimize=true .endif .... [[options-meson_yes]] ===== `OPT_MESON_YES` and `OPT_MESON_NO` When option _OPT_ is selected, for each _entry_ in `OPT_MESON_YES` then `-D_entry_=yes` is appended to `MESON_ARGS`. When option _OPT_ is _not_ selected, `-D_entry_=no` is appended to `MESON_ARGS`. `OPT_MESON_NO` is the opposite, `-D_entry_=no` is appended to `MESON_ARGS` when the option is selected, and `-D_entry_=yes` when the option is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_MESON_YES= test debug OPT1_MESON_NO= optimize .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} MESON_ARGS+= -Dtest=yes -Ddebug=yes \ -Doptimize=no .else MESON_ARGS+= -Dtest=no -Ddebug=no \ -Doptimize=yes .endif .... [[options-meson_enabled]] ===== `OPT_MESON_ENABLED` and `OPT_MESON_DISABLED` When option _OPT_ is selected, for each _entry_ in `OPT_MESON_ENABLED` then `-D_entry_=enabled` is appended to `MESON_ARGS`. When option _OPT_ is _not_ selected, `-D_entry_=disabled` is appended to `MESON_ARGS`. `OPT_MESON_DISABLED` is the opposite, `-D_entry_=disabled` is appended to `MESON_ARGS` when the option is selected, and `-D_entry_=enabled` when the option is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_MESON_ENABLED= test OPT1_MESON_DISABLED= debug .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} MESON_ARGS+= -Dtest=enabled -Ddebug=disabled .else MESON_ARGS+= -Dtest=disabled -Ddebug=enabled .endif .... [[options-qmake_on]] ==== `OPT_QMAKE_ON` and `OPT_QMAKE_OFF` When option _OPT_ is selected, the value of `OPT_QMAKE_ON`, if defined, is appended to `QMAKE_ARGS`. `OPT_QMAKE_OFF` works the same way, but when `OPT` is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_QMAKE_ON= -DTEST:BOOL=true OPT1_QMAKE_OFF= -DPRODUCTION:BOOL=true .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} QMAKE_ARGS+= -DTEST:BOOL=true .else QMAKE_ARGS+= -DPRODUCTION:BOOL=true .endif .... [[options-implies]] ==== `OPT_IMPLIES` Provides a way to add dependencies between options. When _OPT_ is selected, all the options listed in this variable will be selected too. Using the crossref:makefiles[options-configure_enable,`OPT_CONFIGURE_ENABLE`] described earlier to illustrate: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 OPT1_IMPLIES= OPT2 OPT1_CONFIGURE_ENABLE= opt1 OPT2_CONFIGURE_ENABLE= opt2 .... Is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 .include .if ${PORT_OPTIONS:MOPT1} CONFIGURE_ARGS+= --enable-opt1 .else CONFIGURE_ARGS+= --disable-opt1 .endif .if ${PORT_OPTIONS:MOPT2} || ${PORT_OPTIONS:MOPT1} CONFIGURE_ARGS+= --enable-opt2 .else CONFIGURE_ARGS+= --disable-opt2 .endif .... [[options-implies-ex1]] .Simple Use of `OPT_IMPLIES` [example] ==== This port has a `X11` option, and a `GNOME` option that needs the `X11` option to be selected to build. [.programlisting] .... OPTIONS_DEFINE= X11 GNOME OPTIONS_DEFAULT= X11 X11_USES= xorg X11_USE= xorg=xi,xextproto GNOME_USE= gnome=gtk30 GNOME_IMPLIES= X11 .... ==== [[options-prevents]] ==== `OPT_PREVENTS` and `OPT_PREVENTS_MSG` Provides a way to add conflicts between options. When _OPT_ is selected, all the options listed in `OPT_PREVENTS` must be un-selected. If `OPT_PREVENTS_MSG` is set and a conflict is triggered, its content will be shown explaining why they conflict. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 OPT1_PREVENTS= OPT2 OPT1_PREVENTS_MSG= OPT1 and OPT2 enable conflicting options .... Is roughly equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 .include .if ${PORT_OPTIONS:MOPT2} && ${PORT_OPTIONS:MOPT1} BROKEN= Option OPT1 conflicts with OPT2 (select only one) .endif .... The only difference is that the first one will write an error after running `make config`, suggesting changing the selected options. [[options-prevents-ex1]] .Simple Use of `OPT_PREVENTS` [example] ==== This port has `X509` and `SCTP` options. Both options add patches, but the patches conflict with each other, so they cannot be selected at the same time. [.programlisting] .... OPTIONS_DEFINE= X509 SCTP SCTP_PATCHFILES= ${PORTNAME}-6.8p1-sctp-2573.patch.gz:-p1 SCTP_CONFIGURE_WITH= sctp X509_PATCH_SITES= http://www.roumenpetrov.info/openssh/x509/:x509 X509_PATCHFILES= ${PORTNAME}-7.0p1+x509-8.5.diff.gz:-p1:x509 X509_PREVENTS= SCTP X509_PREVENTS_MSG= X509 and SCTP patches conflict .... ==== [[options-vars]] ==== `OPT_VARS` and `OPT_VARS_OFF` Provides a generic way to set and append to variables. [WARNING] ==== Before using `OPT_VARS` and `OPT_VARS_OFF`, see if there is already a more -specific helper available in crossref:makefiles[options-variables]. +specific helper available in crossref:makefiles[options-variables, Generic Variables Replacement, `OPT_VARIABLE` and `OPT_VARIABLE_OFF`]. ==== When option _OPT_ is selected, and `OPT_VARS` defined, `_key_=_value_` and `_key_+=_value_` pairs are evaluated from `OPT_VARS`. An `=` cause the existing value of `KEY` to be overwritten, an `+=` appends to the value. `OPT_VARS_OFF` works the same way, but when `OPT` is _not_ selected. [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 OPT3 OPT1_VARS= also_build+=bin1 OPT2_VARS= also_build+=bin2 OPT3_VARS= bin3_build=yes OPT3_VARS_OFF= bin3_build=no MAKE_ARGS= ALSO_BUILD="${ALSO_BUILD}" BIN3_BUILD="${BIN3_BUILD}" .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT2 MAKE_ARGS= ALSO_BUILD="${ALSO_BUILD}" BIN3_BUILD="${BIN3_BUILD}" .include .if ${PORT_OPTIONS:MOPT1} ALSO_BUILD+= bin1 .endif .if ${PORT_OPTIONS:MOPT2} ALSO_BUILD+= bin2 .endif .if ${PORT_OPTIONS:MOPT2} BIN3_BUILD= yes .else BIN3_BUILD= no .endif .... [IMPORTANT] ==== Values containing whitespace must be enclosed in quotes: [.programlisting] .... OPT_VARS= foo="bar baz" .... This is due to the way man:make[1] variable expansion deals with whitespace. When `OPT_VARS= foo=bar baz` is expanded, the variable ends up containing two strings, `foo=bar` and `baz`. But the submitter probably intended there to be only one string, `foo=bar baz`. Quoting the value prevents whitespace from being used as a delimiter. Also, _do not_ add extra spaces after the `_var_=` sign and before the value, it would also be split into two strings. _This will not work_: [.programlisting] .... OPT_VARS= foo= bar .... ==== [[options-dependencies]] ==== Dependencies, `OPT_DEPTYPE` and `OPT_DEPTYPE_OFF` For any of these dependency types: * `PKG_DEPENDS` * `EXTRACT_DEPENDS` * `PATCH_DEPENDS` * `FETCH_DEPENDS` * `BUILD_DEPENDS` * `LIB_DEPENDS` * `RUN_DEPENDS` When option _OPT_ is selected, the value of `OPT_DEPTYPE`, if defined, is appended to `DEPTYPE`. `OPT_DEPTYPE_OFF` works the same, but when `OPT` is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_LIB_DEPENDS= liba.so:devel/a OPT1_LIB_DEPENDS_OFF= libb.so:devel/b .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} LIB_DEPENDS+= liba.so:devel/a .else LIB_DEPENDS+= libb.so:devel/b .endif .... [[options-variables]] ==== Generic Variables Replacement, `OPT_VARIABLE` and `OPT_VARIABLE_OFF` For any of these variables: * `ALL_TARGET` * `BINARY_ALIAS` * `BROKEN` * `CATEGORIES` * `CFLAGS` * `CONFIGURE_ENV` * `CONFLICTS` * `CONFLICTS_BUILD` * `CONFLICTS_INSTALL` * `CPPFLAGS` * `CXXFLAGS` * `DESKTOP_ENTRIES` * `DISTFILES` * `EXTRACT_ONLY` * `EXTRA_PATCHES` * `GH_ACCOUNT` * `GH_PROJECT` * `GH_SUBDIR` * `GH_TAGNAME` * `GH_TUPLE` * `GL_ACCOUNT` * `GL_COMMIT` * `GL_PROJECT` * `GL_SITE` * `GL_SUBDIR` * `GL_TUPLE` * `IGNORE` * `INFO` * `INSTALL_TARGET` * `LDFLAGS` * `LIBS` * `MAKE_ARGS` * `MAKE_ENV` * `MASTER_SITES` * `PATCHFILES` * `PATCH_SITES` * `PLIST_DIRS` * `PLIST_FILES` * `PLIST_SUB` * `PORTDOCS` * `PORTEXAMPLES` * `SUB_FILES` * `SUB_LIST` * `TEST_TARGET` * `USES` When option _OPT_ is selected, the value of `OPT_ABOVEVARIABLE`, if defined, is appended to `_ABOVEVARIABLE_`. `OPT_ABOVEVARIABLE_OFF` works the same way, but when `OPT` is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 OPT1_USES= gmake OPT1_CFLAGS_OFF= -DTEST .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include .if ${PORT_OPTIONS:MOPT1} USES+= gmake .else CFLAGS+= -DTEST .endif .... [NOTE] ==== Some variables are not in this list, in particular `PKGNAMEPREFIX` and `PKGNAMESUFFIX`. This is intentional. A port _must not_ change its name when its option set changes. ==== [WARNING] ==== Some of these variables, at least `ALL_TARGET`, `DISTFILES` and `INSTALL_TARGET`, have their default values set _after_ the options are processed. With these lines in the [.filename]#Makefile#: [.programlisting] .... ALL_TARGET= all DOCS_ALL_TARGET= doc .... If the `DOCS` option is enabled, `ALL_TARGET` will have a final value of `all doc`; if the option is disabled, it would have a value of `all`. With only the options helper line in the [.filename]#Makefile#: [.programlisting] .... DOCS_ALL_TARGET= doc .... If the `DOCS` option is enabled, `ALL_TARGET` will have a final value of `doc`; if the option is disabled, it would have a value of `all`. ==== [[options-targets]] ==== Additional Build Targets, `_target_-_OPT_-on` and `_target_-_OPT_-off` These [.filename]#Makefile# targets can accept optional extra build targets: * `pre-fetch` * `do-fetch` * `post-fetch` * `pre-extract` * `do-extract` * `post-extract` * `pre-patch` * `do-patch` * `post-patch` * `pre-configure` * `do-configure` * `post-configure` * `pre-build` * `do-build` * `post-build` * `pre-install` * `do-install` * `post-install` * `post-stage` * `pre-package` * `do-package` * `post-package` When option _OPT_ is selected, the target `_TARGET_-_OPT_-on`, if defined, is executed after `_TARGET_`. `_TARGET_-_OPT_-off` works the same way, but when `OPT` is _not_ selected. For example: [.programlisting] .... OPTIONS_DEFINE= OPT1 post-patch-OPT1-on: @${REINPLACE_CMD} -e '/opt1/s|/usr/bin/|${EXAMPLESDIR}/|' ${WRKSRC}/Makefile post-patch-OPT1-off: @${REINPLACE_CMD} -e '/opt1/s|/usr/bin/|${PREFIX}/bin/|' ${WRKSRC}/Makefile .... is equivalent to: [.programlisting] .... OPTIONS_DEFINE= OPT1 .include post-patch: .if ${PORT_OPTIONS:MOPT1} @${REINPLACE_CMD} -e '/opt1/s|/usr/bin/|${EXAMPLESDIR}/|' ${WRKSRC}/Makefile .else @${REINPLACE_CMD} -e '/opt1/s|/usr/bin/|${PREFIX}/bin/|' ${WRKSRC}/Makefile .endif .... [[makefile-wrkdir]] == Specifying the Working Directory Each port is extracted into a working directory, which must be writable. The ports system defaults to having `DISTFILES` unpack in to a directory called `${DISTNAME}`. In other words, if the [.filename]#Makefile# has: [.programlisting] .... PORTNAME= foo DISTVERSION= 1.0 .... then the port's distribution files contain a top-level directory, [.filename]#foo-1.0#, and the rest of the files are located under that directory. A number of variables can be overridden if that is not the case. [[makefile-wrksrc]] === `WRKSRC` The variable lists the name of the directory that is created when the application's distfiles are extracted. If our previous example extracted into a directory called [.filename]#foo# (and not [.filename]#foo-1.0#) write: [.programlisting] .... WRKSRC= ${WRKDIR}/foo .... or possibly [.programlisting] .... WRKSRC= ${WRKDIR}/${PORTNAME} .... [[makefile-wrksrc_subdir]] === `WRKSRC_SUBDIR` If the source files needed for the port are in a subdirectory of the extracted distribution file, set `WRKSRC_SUBDIR` to that directory. [.programlisting] .... WRKSRC_SUBDIR= src .... [[makefile-no_wrksubdir]] === `NO_WRKSUBDIR` If the port does not extract in to a subdirectory at all, then set `NO_WRKSUBDIR` to indicate that. [.programlisting] .... NO_WRKSUBDIR= yes .... [NOTE] ==== Because `WRKDIR` is the only directory that is supposed to be writable during the build, and is used to store many files recording the status of the build, the port's extraction will be forced into a subdirectory. ==== [[conflicts]] == Conflict Handling There are three different variables to register a conflict between packages and ports: `CONFLICTS`, `CONFLICTS_INSTALL` and `CONFLICTS_BUILD`. [NOTE] ==== The conflict variables automatically set the variable `IGNORE`, which is more fully documented in crossref:porting-dads[dads-noinstall,Marking a Port Not Installable with `BROKEN`, `FORBIDDEN`, or `IGNORE`]. ==== When removing one of several conflicting ports, it is advisable to retain `CONFLICTS` in those other ports for a few months to cater for users who only update once in a while. [[conclicts-conflicts_install]] `CONFLICTS_INSTALL`:: If the package cannot coexist with other packages (because of file conflicts, runtime incompatibilities, etc.). `CONFLICTS_INSTALL` check is done after the build stage and prior to the install stage. [[conclicts-conflicts_build]] `CONFLICTS_BUILD`:: If the port cannot be built when other specific ports are already installed. Build conflicts are not recorded in the resulting package. [[conclicts-conflicts]] `CONFLICTS`:: If the port cannot be built if a certain port is already installed and the resulting package cannot coexist with the other package. `CONFLICTS` check is done prior to the build stage and prior to the install stage. Each space-separated item in the `CONFLICTS*` variable values is matched against packages except the one being built, using shell globbing rules. This allows listing all flavors of a port in a conflict list instead of having to take pains to exclude the flavor being built from that list. For example, if git-lite is installed, `CONFLICTS_INSTALL=git git-lite` would allow to perform: [source,shell] .... % make -C devel/git FLAVOR=lite all deinstall install .... But the following command would report a conflict, since the package base name installed is `git-lite`, while `git` would be built, but cannot be installed in addition to `git-lite`: [source,shell] .... % make -C devel/git FLAVOR=default all deinstall install .... Without that feature, the Makefile would need one `_flavor__CONFLICTS_INSTALL` for each flavor, listing every other flavor. The most common content of one of these variable is the package base of another port. The package base is the package name without the appended version, it can be obtained by running `make -V PKGBASE`. [[conflicts-ex1]] .Basic usage of `CONFLICTS*` [example] ==== package:dns/bind99[] cannot be installed if package:dns/bind910[] is present because they install same files. First gather the package base to use: [source,shell] .... % make -C dns/bind99 -V PKGBASE bind99 % make -C dns/bind910 -V PKGBASE bind910 .... Then add to the [.filename]#Makefile# of package:dns/bind99[]: [.programlisting] .... CONFLICTS_INSTALL= bind910 .... And add to the [.filename]#Makefile# of package:dns/bind910[]: [.programlisting] .... CONFLICTS_INSTALL= bind99 .... ==== Sometimes, only certain versions of another port are incompatible. When this is the case, use the full package name including the version. If necessary, use shell globs like `*` and `?` so that all necessary versions are matched. [[conflicts-ex2]] .Using `CONFLICTS*` With Globs. [example] ==== From versions from 2.0 and up-to 2.4.1_2, package:deskutils/gnotime[] used to install a bundled version of package:databases/qof[]. To reflect this past, the [.filename]#Makefile# of package:databases/qof[] contains: [.programlisting] .... CONFLICTS_INSTALL= gnotime-2.[0-3]* \ gnotime-2.4.0* gnotime-2.4.1 \ gnotime-2.4.1_[12] .... The first entry match versions `2.0` through `2.3`, the second all the revisions of `2.4.0`, the third the exact `2.4.1` version, and the last the first and second revisions of the `2.4.1` version. package:deskutils/gnotime[] does not have any conflicts line because its current version does not conflict with anything else. ==== The variable `DISABLE_CONFLICTS` may be temporarily set when making targets that are not affected by conflicts. The variable is not to be set in port Makefiles. [source,shell] .... % make -DDISABLE_CONFLICTS patch .... [[install]] == Installing Files [IMPORTANT] ==== The `install` phase is very important to the end user because it adds files to their system. All the additional commands run in the port [.filename]#Makefile#'s `*-install` targets should be echoed to the screen. _Do not_ silence these commands with `@` or `.SILENT`. ==== [[install-macros]] === `INSTALL_*` Macros Use the macros provided in [.filename]#bsd.port.mk# to ensure correct modes of files in the port's `*-install` targets. Set ownership directly in [.filename]#pkg-plist# with the corresponding entries, such as `@(_owner_,_group_,)`, `@owner _owner_`, and `@group _group_`. These operators work until overridden, or until the end of [.filename]#pkg-plist#, so remember to reset them after they are no longer needed. The default ownership is `root:wheel`. See crossref:plist[plist-keywords-base,Base Keywords] for more information. * `INSTALL_PROGRAM` is a command to install binary executables. * `INSTALL_SCRIPT` is a command to install executable scripts. * `INSTALL_LIB` is a command to install shared libraries (but not static libraries). * `INSTALL_KLD` is a command to install kernel loadable modules. Some architectures do not like having the modules stripped, so use this command instead of `INSTALL_PROGRAM`. * `INSTALL_DATA` is a command to install sharable data, including static libraries. * `INSTALL_MAN` is a command to install manpages and other documentation (it does not compress anything). These variables are set to the man:install[1] command with the appropriate flags for each situation. [IMPORTANT] ==== Do not use `INSTALL_LIB` to install static libraries, because stripping them renders them useless. Use `INSTALL_DATA` instead. ==== [[install-strip]] === Stripping Binaries and Shared Libraries Installed binaries should be stripped. Do not strip binaries manually unless absolutely required. The `INSTALL_PROGRAM` macro installs and strips a binary at the same time. The `INSTALL_LIB` macro does the same thing to shared libraries. When a file must be stripped, but neither `INSTALL_PROGRAM` nor `INSTALL_LIB` macros are desirable, `${STRIP_CMD}` strips the program or shared library. This is typically done within the `post-install` target. For example: [.programlisting] .... post-install: ${STRIP_CMD} ${STAGEDIR}${PREFIX}/bin/xdl .... When multiple files need to be stripped: [.programlisting] .... post-install: .for l in geometry media body track world ${STRIP_CMD} ${STAGEDIR}${PREFIX}/lib/lib${PORTNAME}-${l}.so.0 .endfor .... Use man:file[1] on a file to determine if it has been stripped. Binaries are reported by man:file[1] as `stripped`, or `not stripped`. Additionally, man:strip[1] will detect programs that have already been stripped and exit cleanly. [IMPORTANT] ==== When `WITH_DEBUG` is defined, elf files _must not_ be stripped. The variables (`STRIP_CMD`, `INSTALL_PROGRAM`, `INSTALL_LIB`, ...) and crossref:uses[uses,`USES`] provided by the framework handle this automatically. Some software, add `-s` to their `LDFLAGS`, in this case, either remove `-s` if `WITH_DEBUG` is set, or remove it unconditionally and use `STRIP_CMD` in `post-install`. ==== [[install-copytree]] === Installing a Whole Tree of Files Sometimes, a large number of files must be installed while preserving their hierarchical organization. For example, copying over a whole directory tree from `WRKSRC` to a target directory under `PREFIX`. Note that `PREFIX`, `EXAMPLESDIR`, `DATADIR`, and other path variables must always be prepended with `STAGEDIR` to respect staging (see crossref:special[staging,Staging]). Two macros exist for this situation. The advantage of using these macros instead of `cp` is that they guarantee proper file ownership and permissions on target files. The first macro, `COPYTREE_BIN`, will set all the installed files to be executable, thus being suitable for installing into [.filename]#PREFIX/bin#. The second macro, `COPYTREE_SHARE`, does not set executable permissions on files, and is therefore suitable for installing files under [.filename]#PREFIX/share# target. [.programlisting] .... post-install: ${MKDIR} ${STAGEDIR}${EXAMPLESDIR} (cd ${WRKSRC}/examples && ${COPYTREE_SHARE} . ${STAGEDIR}${EXAMPLESDIR}) .... This example will install the contents of the [.filename]#examples# directory in the vendor distfile to the proper examples location of the port. [.programlisting] .... post-install: ${MKDIR} ${STAGEDIR}${DATADIR}/summer (cd ${WRKSRC}/temperatures && ${COPYTREE_SHARE} "June July August" ${STAGEDIR}${DATADIR}/summer) .... And this example will install the data of summer months to the [.filename]#summer# subdirectory of a [.filename]#DATADIR#. Additional `find` arguments can be passed via the third argument to `COPYTREE_*` macros. For example, to install all files from the first example except Makefiles, one can use these commands. [.programlisting] .... post-install: ${MKDIR} ${STAGEDIR}${EXAMPLESDIR} (cd ${WRKSRC}/examples && \ ${COPYTREE_SHARE} . ${STAGEDIR}${EXAMPLESDIR} "! -name Makefile") .... These macros do not add the installed files to [.filename]#pkg-plist#. They must be added manually. For optional documentation (`PORTDOCS`, see crossref:makefiles[install-documentation]) and examples (`PORTEXAMPLES`), the `%%PORTDOCS%%` or `%%PORTEXAMPLES%%` prefixes must be prepended in [.filename]#pkg-plist#. [[install-documentation]] === Install Additional Documentation If the software has some documentation other than the standard man and info pages that is useful for the user, install it under `DOCSDIR`. This can be done, like the previous item, in the `post-install` target. Create a new directory for the port. The directory name is `DOCSDIR`. This usually equals `PORTNAME`. However, if the user might want different versions of the port to be installed at the same time, the whole `PKGNAME` can be used. Since only the files listed in [.filename]#pkg-plist# are installed, it is safe to always install documentation to `STAGEDIR` (see crossref:special[staging,Staging]). Hence `.if` blocks are only needed when the installed files are large enough to cause significant I/O overhead. [.programlisting] .... post-install: ${MKDIR} ${STAGEDIR}${DOCSDIR} ${INSTALL_DATA} ${WRKSRC}/docs/xvdocs.ps ${STAGEDIR}${DOCSDIR} .... On the other hand, if there is a DOCS option in the port, install the documentation in a `post-install-DOCS-on` target. -These targets are described in crossref:makefiles[options-targets]. +These targets are described in crossref:makefiles[options-targets, Additional Build Targets, `_target_-_OPT_-on` and `_target_-_OPT_-off`]. Here are some handy variables and how they are expanded by default when used in the [.filename]#Makefile#: * `DATADIR` gets expanded to [.filename]#PREFIX/share/PORTNAME#. * `DATADIR_REL` gets expanded to [.filename]#share/PORTNAME#. * `DOCSDIR` gets expanded to [.filename]#PREFIX/share/doc/PORTNAME#. * `DOCSDIR_REL` gets expanded to [.filename]#share/doc/PORTNAME#. * `EXAMPLESDIR` gets expanded to [.filename]#PREFIX/share/examples/PORTNAME#. * `EXAMPLESDIR_REL` gets expanded to [.filename]#share/examples/PORTNAME#. [NOTE] ==== The `DOCS` option only controls additional documentation installed in `DOCSDIR`. It does not apply to standard man pages and info pages. Things installed in `EXAMPLESDIR` are controlled by the `EXAMPLES` option. ==== These variables are exported to `PLIST_SUB`. Their values will appear there as pathnames relative to [.filename]#PREFIX# if possible. That is, [.filename]#share/doc/PORTNAME# will be substituted for `%%DOCSDIR%%` in the packing list by default, and so on. (See more on [.filename]#pkg-plist# substitution crossref:plist[plist-sub,here].) All conditionally installed documentation files and directories are included in [.filename]#pkg-plist# with the `%%PORTDOCS%%` prefix, for example: [.programlisting] .... %%PORTDOCS%%%%DOCSDIR%%/AUTHORS %%PORTDOCS%%%%DOCSDIR%%/CONTACT .... As an alternative to enumerating the documentation files in [.filename]#pkg-plist#, a port can set the variable `PORTDOCS` to a list of file names and shell glob patterns to add to the final packing list. The names will be relative to `DOCSDIR`. Therefore, a port that utilizes `PORTDOCS`, and uses a non-default location for its documentation, must set `DOCSDIR` accordingly. If a directory is listed in `PORTDOCS` or matched by a glob pattern from this variable, the entire subtree of contained files and directories will be registered in the final packing list. If the `DOCS` option has been unset then files and directories listed in `PORTDOCS` would not be installed or added to port packing list. Installing the documentation at `PORTDOCS` as shown above remains up to the port itself. A typical example of utilizing `PORTDOCS`: [.programlisting] .... PORTDOCS= README.* ChangeLog docs/* .... [NOTE] ==== The equivalents of `PORTDOCS` for files installed under `DATADIR` and `EXAMPLESDIR` are `PORTDATA` and `PORTEXAMPLES`, respectively. The contents of [.filename]#pkg-message# are displayed upon installation. See crossref:pkg-files[porting-message,the section on using [.filename]#pkg-message#] for details. [.filename]#pkg-message# does not need to be added to [.filename]#pkg-plist#. ==== [[install-subdirs]] === Subdirectories Under `PREFIX` Try to let the port put things in the right subdirectories of `PREFIX`. Some ports lump everything and put it in the subdirectory with the port's name, which is incorrect. Also, many ports put everything except binaries, header files and manual pages in a subdirectory of [.filename]#lib#, which does not work well with the BSD paradigm. Many of the files must be moved to one of these directories: [.filename]#etc# (setup/configuration files), [.filename]#libexec# (executables started internally), [.filename]#sbin# (executables for superusers/managers), [.filename]#info# (documentation for info browser) or [.filename]#share# (architecture independent files). See man:hier[7] for details; the rules governing [.filename]#/usr# pretty much apply to [.filename]#/usr/local# too. The exception are ports dealing with USENET "news". They may use [.filename]#PREFIX/news# as a destination for their files. [[binary-alias]] == Use `BINARY_ALIAS` to Rename Commands Instead of Patching the Build When `BINARY_ALIAS` is defined it will create symlinks of the given commands in a directory which will be prepended to `PATH`. Use it to substitute hardcoded commands the build phase relies on without having to patch any build files. [[binary-alias-ex1]] .Using `BINARY_ALIAS` to Make `gsed` Available as `sed` [example] ==== Some ports expect `sed` to behave like GNU sed and use features that man:sed[1] does not provide. GNU sed is available from package:textproc/gsed[] on FreeBSD. Use `BINARY_ALIAS` to substitute `sed` with `gsed` for the duration of the build: [.programlisting] .... BUILD_DEPENDS= gsed:textproc/gsed ... BINARY_ALIAS= sed=gsed .... ==== [[binary-alias-ex2]] .Using `BINARY_ALIAS` to Provide Aliases for Hardcoded `python3` Commands [example] ==== A port that has a hardcoded reference to `python3` in its build scripts will need to have it available in `PATH` at build time. Use `BINARY_ALIAS` to create an alias that points to the right Python 3 binary: [.programlisting] .... USES= python:3.4+,build ... BINARY_ALIAS= python3=${PYTHON_CMD} .... See crossref:special[using-python,Using Python] for more information about `USES=python`. ==== [NOTE] ==== Binary aliases are created after the dependencies provided via `BUILD_DEPENDS` and `LIB_DEPENDS` are processed and before the `configure` target. This leads to various limitations. For example, programs installed via `TEST_DEPENDS` cannot be used to create a binary alias as test dependencies specified this way are processed after binary aliases are created. ==== diff --git a/documentation/content/en/books/porters-handbook/order/_index.adoc b/documentation/content/en/books/porters-handbook/order/_index.adoc index 2e260b3b21..cf00bccfdf 100644 --- a/documentation/content/en/books/porters-handbook/order/_index.adoc +++ b/documentation/content/en/books/porters-handbook/order/_index.adoc @@ -1,289 +1,289 @@ --- title: Chapter 15. Order of Variables in Port Makefiles prev: books/porters-handbook/porting-samplem next: books/porters-handbook/keeping-up description: Order of Variables in FreeBSD Port Makefiles tags: ["order", "PORTNAME", "PATCHFILES", "MAINTAINER", "LICENSE", "dependencies", "USES"] showBookMenu: true weight: 15 path: "/books/porters-handbook/order/" --- [[porting-order]] = Order of Variables in Port Makefiles :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 15 :partnums: :source-highlighter: rouge :experimental: :images-path: books/porters-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] The first sections of the [.filename]#Makefile# must always come in the same order. This standard makes it so everyone can easily read any port without having to search for variables in a random order. [NOTE] ==== The sections and variables described here are mandatory in a ordinary port. In a slave port, many sections and variables can be skipped. ==== [IMPORTANT] ==== Each following block must be separated from the previous block by a single blank line. In the following blocks, only set the variables that are required by the port. Define these variables in the order they are shown here. ==== [[porting-order-portname]] == `PORTNAME` Block This block is the most important. It defines the port name, version, distribution file location, and category. The variables must be in this order: * crossref:makefiles[makefile-portname,`PORTNAME`] * crossref:makefiles[makefile-versions,`PORTVERSION`][crossref:order[portversion-footnote, 1]] * crossref:makefiles[makefile-versions,`DISTVERSIONPREFIX`] * crossref:makefiles[makefile-versions,`DISTVERSION`][crossref:order[portversion-footnote, 1]] * crossref:makefiles[makefile-versions,`DISTVERSIONSUFFIX`] * crossref:makefiles[makefile-portrevision,`PORTREVISION`] * crossref:makefiles[makefile-portepoch,`PORTEPOCH`] * crossref:makefiles[makefile-categories,`CATEGORIES`] * crossref:makefiles[makefile-master_sites,`MASTER_SITES`] * crossref:makefiles[makefile-master_sites-shorthand,`MASTER_SITE_SUBDIR`] (deprecated) * crossref:makefiles[porting-pkgnameprefix-suffix,`PKGNAMEPREFIX`] * crossref:makefiles[porting-pkgnameprefix-suffix,`PKGNAMESUFFIX`] * crossref:makefiles[makefile-distname,`DISTNAME`] * crossref:makefiles[makefile-extract_sufx,`EXTRACT_SUFX`] * crossref:makefiles[makefile-distfiles-definition,`DISTFILES`] * crossref:makefiles[makefile-dist_subdir,`DIST_SUBDIR`] * crossref:makefiles[makefile-extract_only,`EXTRACT_ONLY`] [[portversion-footnote]] [IMPORTANT] ==== Only one of PORTVERSION and DISTVERSION can be used. ==== [[porting-order-patch]] == `PATCHFILES` Block This block is optional. The variables are: * crossref:makefiles[porting-patchfiles,`PATCH_SITES`] * crossref:makefiles[porting-patchfiles,`PATCHFILES`] * crossref:makefiles[porting-patchfiles,`PATCH_DIST_STRIP`] [[porting-order-maintainer]] == `MAINTAINER` Block This block is mandatory. The variables are: * crossref:makefiles[makefile-maintainer,`MAINTAINER`] * crossref:makefiles[makefile-comment,`COMMENT`] * crossref:makefiles[makefile-www,`WWW`] [[porting-order-license]] == `LICENSE` Block This block is optional, although it is highly recommended. The variables are: * crossref:makefiles[licenses-license,`LICENSE`] * crossref:makefiles[licenses-license_comb,`LICENSE_COMB`] * crossref:makefiles[licenses-license_groups,`LICENSE_GROUPS`] or `LICENSE_GROUPS_NAME` * crossref:makefiles[licenses-license_name,`LICENSE_NAME`] or `LICENSE_NAME_NAME` * crossref:makefiles[licenses-license_text,`LICENSE_TEXT`] or `LICENSE_TEXT_NAME` * crossref:makefiles[licenses-license_file,`LICENSE_FILE`] or `LICENSE_FILE_NAME` * crossref:makefiles[licenses-license_perms,`LICENSE_PERMS`] or `LICENSE_PERMS_NAME_` * crossref:makefiles[licenses-license_distfiles,`LICENSE_DISTFILES`] or `LICENSE_DISTFILES_NAME` If there are multiple licenses, sort the different LICENSE_VAR_NAME variables by license name. [[porting-order-broken]] == Generic `BROKEN`/`IGNORE`/`DEPRECATED` Messages This block is optional. The variables are: * crossref:porting-dads[dads-deprecated,`DEPRECATED`] * crossref:porting-dads[dads-deprecated,`EXPIRATION_DATE`] * crossref:porting-dads[dads-noinstall,`FORBIDDEN`] * crossref:porting-dads[dads-noinstall,`BROKEN`] * crossref:porting-dads[dads-noinstall,`BROKEN_*`] * crossref:porting-dads[dads-noinstall,`IGNORE`] * crossref:porting-dads[dads-noinstall,`IGNORE_*`] * crossref:porting-dads[dads-noinstall,`ONLY_FOR_ARCHS`] * crossref:porting-dads[dads-noinstall,`ONLY_FOR_ARCHS_REASON*`] * crossref:porting-dads[dads-noinstall,`NOT_FOR_ARCHS`] * crossref:porting-dads[dads-noinstall,`NOT_FOR_ARCHS_REASON*`] [NOTE] ==== `BROKEN_*` and `IGNORE_*` can be any generic variables, for example, `IGNORE_amd64`, `BROKEN_FreeBSD_10`, etc. With the exception of variables that depend on a crossref:uses[uses,`USES`], -place those in crossref:order[porting-order-uses]. +place those in crossref:order[porting-order-uses, `USES` and `USE_x`]. For instance, `IGNORE_WITH_PHP` only works if crossref:uses[uses-php,`php`] is set, and `BROKEN_SSL` only if crossref:uses[uses-ssl,`ssl`] is set. If the port is marked BROKEN when some conditions are met, and such conditions can only be tested after including [.filename]#bsd.port.options.mk# or [.filename]#bsd.port.pre.mk#, then those variables should be set later, in -crossref:order[porting-order-rest]. +crossref:order[porting-order-rest, The Rest of the Variables]. ==== [[porting-order-depends]] == The Dependencies Block This block is optional. The variables are: * crossref:makefiles[makefile-fetch_depends,`FETCH_DEPENDS`] * crossref:makefiles[makefile-extract_depends,`EXTRACT_DEPENDS`] * crossref:makefiles[makefile-patch_depends,`PATCH_DEPENDS`] * crossref:makefiles[makefile-build_depends,`BUILD_DEPENDS`] * crossref:makefiles[makefile-lib_depends,`LIB_DEPENDS`] * crossref:makefiles[makefile-run_depends,`RUN_DEPENDS`] * `TEST_DEPENDS` [[porting-order-flavors]] == Flavors This block is optional. Start this section with defining `FLAVORS`. Continue with the possible Flavors helpers. See crossref:flavors[flavors-using,Using FLAVORS] for more Information. Constructs setting variables not available as helpers using `.if ${FLAVOR:U} == foo` should go in their respective sections below. [[porting-order-uses]] == `USES` and `USE_x` Start this section with defining `USES`, and then possible `USE_x`. Keep related variables close together. For example, if using crossref:makefiles[makefile-master_sites-github,`USE_GITHUB`], always put the `GH_*` variables right after it. [[porting-order-variables]] == Standard bsd.port.mk Variables This section block is for variables that can be defined in [.filename]#bsd.port.mk# that do not belong in any of the previous section blocks. Order is not important, however try to keep similar variables together. For example uid and gid variables `USERS` and `GROUPS`. Configuration variables `CONFIGURE_*` and `*_CONFIGURE`. List of files, and directories `PORTDOCS` and `PORTEXAMPLES`. [[porting-order-options]] == Options and Helpers If the port uses the crossref:makefiles[makefile-options,options framework], define `OPTIONS_DEFINE` and `OPTIONS_DEFAULT` first, then the other `OPTIONS_*` variables first, then the `*_DESC` descriptions, then the options helpers. Try and sort all of those alphabetically. [[porting-order-options-ex1]] .Options Variables Order Example [example] ==== The `FOO` and `BAR` options do not have a standard description, so one need to be written. The other options already have one in [.filename]#Mk/bsd.options.desc.mk# so writing one is not needed. The `DOCS` and `EXAMPLES` use target helpers to install their files, they are shown here for completeness, -though they belong in crossref:order[porting-order-targets], so other variables and targets could be inserted before them. +though they belong in crossref:order[porting-order-targets, The Targets], so other variables and targets could be inserted before them. [.programlisting] .... OPTIONS_DEFINE= DOCS EXAMPLES FOO BAR OPTIONS_DEFAULT= FOO OPTIONS_RADIO= SSL OPTIONS_RADIO_SSL= OPENSSL GNUTLS OPTIONS_SUB= yes BAR_DESC= Enable bar support FOO_DESC= Enable foo support BAR_CONFIGURE_WITH= bar=${LOCALBASE} FOO_CONFIGURE_ENABLE= foo GNUTLS_CONFIGURE_ON= --with-ssl=gnutls OPENSSL_CONFIGURE_ON= --with-ssl=openssl post-install-DOCS-on: ${MKDIR} ${STAGEDIR}${DOCSDIR} cd ${WRKSRC}/doc && ${COPYTREE_SHARE} . ${STAGEDIR}${DOCSDIR} post-install-EXAMPLES-on: ${MKDIR} ${STAGEDIR}${EXAMPLESDIR} cd ${WRKSRC}/ex && ${COPYTREE_SHARE} . ${STAGEDIR}${EXAMPLESDIR} .... ==== [[porting-order-rest]] == The Rest of the Variables And then, the rest of the variables that are not mentioned in the previous blocks. [[porting-order-targets]] == The Targets After all the variables are defined, the optional man:make[1] targets can be defined. Keep `pre-*` before `post-*` and in the same order as the different stages run: * `fetch` * `extract` * `patch` * `configure` * `build` * `install` * `test` [TIP] ==== When using options helpers target keep them alphabetically sorted, but keep the `*-on` before the `*-off`. When also using the main target, keep the main target before the optional ones: [.programlisting] .... post-install: # install generic bits post-install-DOCS-on: # Install documentation post-install-X11-on: # Install X11 related bits post-install-X11-off: # Install bits that should be there if X11 is disabled .... ==== diff --git a/documentation/content/en/books/porters-handbook/pkg-files/_index.adoc b/documentation/content/en/books/porters-handbook/pkg-files/_index.adoc index 40a4c0bb6c..90d2cf755d 100644 --- a/documentation/content/en/books/porters-handbook/pkg-files/_index.adoc +++ b/documentation/content/en/books/porters-handbook/pkg-files/_index.adoc @@ -1,357 +1,357 @@ --- title: Chapter 9. pkg-* prev: books/porters-handbook/plist next: books/porters-handbook/testing description: Tricks about the pkg-* files tags: ["pkg", "pkg-message", "UCL", "pkg-install", "pkg-deinstall"] showBookMenu: true weight: 9 path: "/books/porters-handbook/pkg-files/" --- [[pkg-files]] = pkg-* :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 9 :partnums: :source-highlighter: rouge :experimental: :images-path: books/porters-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] There are some tricks we have not mentioned yet about the [.filename]#pkg-*# files that come in handy sometimes. [[porting-message]] == pkg-message To display a message when the package is installed, place the message in [.filename]#pkg-message#. This capability is often useful to display additional installation steps to be taken after a `pkg install` or `pkg upgrade`. [IMPORTANT] ==== * [.filename]#pkg-message# must contain only information that is _vital_ to setup and operation on FreeBSD, and that is unique to the port in question. * Setup information should only be shown on initial install. Upgrade instructions should be shown only when upgrading from the relevant version. * Do not surround the messages with either whitespace or lines of symbols (like `----------`, `**********`, or `==========`). Leave the formatting to man:pkg[8]. * Committers have blanket approval to constrain existing messages to install or upgrade ranges using the UCL format specifications. * Please be sure to refer to the proper tools for handling services. ** Use `service name start` to start a service rather than using `/usr/local/etc/rc.d/name start` ** Use `sysrc name_enable=YES` to change options in rc.conf ==== pkg-message supports two formats: raw:: A regular plain text file. Its message is only displayed on install. UCL:: If the file starts with "`[`" then it is considered to be a UCL file. The UCL format is described on https://github.com/vstakhov/libucl[libucl's GitHub page]. [NOTE] ==== Do not add an entry for [.filename]#pkg-message# in [.filename]#pkg-plist#. ==== [[porting-message-ucl]] === UCL in pkg-message The format is the following. It should be an array of objects. The objects themselves can have these keywords: `message`:: The actual message to be displayed. This keyword is mandatory. `type`:: When the message should be displayed. `maximum_version`:: Only if `type` is `upgrade`. Display if upgrading from a version strictly lower than the version specified. `minimum_version`:: Only if `type` is `upgrade`. Display if upgrading from a version strictly greater than the version specified. The `maximum_version` and `minimum_version` keywords can be combined. The `type` keyword can have three values: `install`:: The message should only be displayed when the package is installed. `remove`:: The message should only be displayed when the package is removed. `upgrade`:: the message should only be displayed during an upgrade of the package.. [IMPORTANT] ==== To preserve the compatibility with non UCL [.filename]#pkg-message# files, the first line of a UCL [.filename]#pkg-message# _MUST be_ a single "`[`", and the last line _MUST be_ a single "`]`". ==== [[porting-message-ucl-short-ex]] .UCL Short Strings [example] ==== The message is delimited by double quotes `"`, this is used for simple single line strings: [.programlisting] .... [ { type: install message: "Simple message" } ] .... ==== [[porting-message-ucl-multiline-ex]] .UCL Multiline Strings [example] ==== Multiline strings use the standard here document notation. The multiline delimiter _must_ start just after `<<` symbols without any whitespace and it _must_ consist of capital letters only. To finish a multiline string, add the delimiter string on a line of its own without any whitespace. -The message from crossref:pkg-files[porting-message-ucl-short-ex] can be written as: +The message from crossref:pkg-files[porting-message-ucl-short-ex,.UCL Short Strings] can be written as: [.programlisting] .... [ { type: install message: < 1.0 and < 3.0 remove that file." } ] .... [IMPORTANT] **** When displaying a message on upgrade, it is important to limit when it is being shown to the user. Most of the time it is by using `maximum_version` to limit its usage to upgrades from before a certain version when something specific needs to be done. **** ==== [[pkg-install]] == pkg-install, pkg-pre-install, and pkg-post-install If the port needs to execute commands when the binary package is installed with `pkg add` or `pkg install`, use [.filename]#pkg-install#. It is run twice by `pkg`, the first time as `${SH} pkg-install ${PKGNAME} PRE-INSTALL` before the package is installed, and the second time as `${SH} pkg-install ${PKGNAME} POST-INSTALL` after it has been installed. `$2` can be tested to determine which mode the script is being run in. The `PKG_PREFIX` environment variable is set to the package installation directory. If using [.filename]#pkg-pre-install# or [.filename]#pkg-post-install# instead, the script is run only once (before or after installing the package), with the single argument `${PKGNAME}`. Using [.filename]#pkg-pre-install.lua# or [.filename]#pkg-post-install.lua# will run a lua script instead of a shell script. Lua scripts run by `pkg` provide some extensions and a few restrictions, both explained in man:pkg-lua-script[5]. [NOTE] ==== Using [.filename]#pkg-pre-install# (or [.filename]#pkg-pre-install.lua#) and [.filename]#pkg-post-install# (or [.filename]#pkg-post-install.lua#) is preferred to using [.filename]#pkg-install#. ==== These scripts are automatically added to the packing list. [IMPORTANT] ==== These scripts are here to simplify package configuration after installation. They _must not_ be abused to start services, stop services, or run any other commands that will modify the currently running system. ==== [[pkg-deinstall]] == pkg-deinstall, pkg-pre-deinstall, and pkg-post-deinstall These scripts execute when a package is removed. The [.filename]#pkg-deinstall# script is run twice by `pkg delete`. The first time as `${SH} pkg-deinstall ${PKGNAME} DEINSTALL` before the port is de-installed and the second time as `${SH} pkg-deinstall ${PKGNAME} POST-DEINSTALL` after the port has been de-installed. `$2` can be tested to determine which mode the script is being run in. The `PKG_PREFIX` environment variable is set to the package installation directory. If using [.filename]#pkg-pre-deinstall# or [.filename]#pkg-post-deinstall# instead, the script is run only once (before or after deinstalling the package), with the single argument `${PKGNAME}`. Using [.filename]#pkg-pre-deinstall.lua# or [.filename]#pkg-post-deinstall.lua# will run a lua script instead of a shell script. Lua scripts run by `pkg` provide some extensions and a few restrictions, both explained in man:pkg-lua-script[5]. [NOTE] ==== Using [.filename]#pkg-pre-deinstall# (or [.filename]#pkg-pre-deinstall.lua#) and [.filename]#pkg-post-deinstall# (or [.filename]#pkg-post-deinstall.lua#) is preferred to using [.filename]#pkg-deinstall#. ==== These scripts are automatically added to the packing list. [IMPORTANT] ==== These scripts are here to simplify cleanup after package deinstallation. They _must not_ be abused to start services, stop services, or run any other commands that will modify the currently running system. ==== [[pkg-names]] == Changing the Names of pkg-* All the names of [.filename]#pkg-\*# are defined using variables that can be changed in the [.filename]#Makefile# if needed. This is especially useful when sharing the same [.filename]#pkg-*# files among several ports or when it is necessary to write to one of these files. See crossref:porting-dads[porting-wrkdir,writing to places other than `WRKDIR`] for why it is a bad idea to write directly into the directory containing the [.filename]#pkg-*# files. Here is a list of variable names and their default values. (`PKGDIR` defaults to `${MASTERDIR}`.) [.informaltable] [cols="1,1", frame="none", options="header"] |=== | Variable | Default value |`DESCR` |`${PKGDIR}/pkg-descr` |`PLIST` |`${PKGDIR}/pkg-plist` |`PKGINSTALL` |`${PKGDIR}/pkg-install` |`PKGPREINSTALL` |`${PKGDIR}/pkg-pre-install` |`PKGPOSTINSTALL` |`${PKGDIR}/pkg-post-install` |`PKGDEINSTALL` |`${PKGDIR}/pkg-deinstall` |`PKGPREDEINSTALL` |`${PKGDIR}/pkg-pre-deinstall` |`PKGPOSTDEINSTALL` |`${PKGDIR}/pkg-post-deinstall` |`PKGMESSAGE` |`${PKGDIR}/pkg-message` |=== [[using-sub-files]] == Making Use of `SUB_FILES` and `SUB_LIST` `SUB_FILES` and `SUB_LIST` are useful for dynamic values in port files, such as the installation `PREFIX` in [.filename]#pkg-message#. `SUB_FILES` specifies a list of files to be automatically modified. Each [.filename]#file# in the `SUB_FILES` list must have a corresponding [.filename]#file.in# present in `FILESDIR`. A modified version will be created as [.filename]#${WRKDIR}/file#. Files defined as a value of `USE_RC_SUBR` are automatically added to `SUB_FILES`. For the files [.filename]#pkg-message#, [.filename]#pkg-install#, and [.filename]#pkg-deinstall#, the corresponding Makefile variable is automatically set to point to the processed version. `SUB_LIST` is a list of `VAR=VALUE` pairs. For each pair, `%%VAR%%` will be replaced with `VALUE` in each file listed in `SUB_FILES`. Several common pairs are automatically defined: `PREFIX`, `LOCALBASE`, `DATADIR`, `DOCSDIR`, `EXAMPLESDIR`, `WWWDIR`, and `ETCDIR`. Any line beginning with `@comment` followed by a space, will be deleted from resulting files after a variable substitution. This example replaces `%%ARCH%%` with the system architecture in a [.filename]#pkg-message#: [.programlisting] .... SUB_FILES= pkg-message SUB_LIST= ARCH=${ARCH} .... Note that for this example, [.filename]#pkg-message.in# must exist in `FILESDIR`. Example of a good [.filename]#pkg-message.in#: [.programlisting] .... Now it is time to configure this package. Copy %%PREFIX%%/shared/examples/putsy/%%ARCH%%.conf into your home directory as .putsy.conf and edit it. .... diff --git a/documentation/content/en/books/porters-handbook/plist/_index.adoc b/documentation/content/en/books/porters-handbook/plist/_index.adoc index 7050ef8317..c670c4ac0e 100644 --- a/documentation/content/en/books/porters-handbook/plist/_index.adoc +++ b/documentation/content/en/books/porters-handbook/plist/_index.adoc @@ -1,694 +1,694 @@ --- title: Chapter 8. Advanced pkg-plist Practices prev: books/porters-handbook/flavors next: books/porters-handbook/pkg-files description: Advanced pkg-plist Practices tags: ["pkg-plist", "practices", "configuration"] showBookMenu: true weight: 8 path: "/books/porters-handbook/plist/" --- [[plist]] = Advanced pkg-plist Practices :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 8 :partnums: :source-highlighter: rouge :experimental: :images-path: books/porters-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[plist-sub]] == Changing pkg-plist Based on Make Variables Some ports, particularly the `p5-` ports, need to change their [.filename]#pkg-plist# depending on what options they are configured with (or version of `perl`, in the case of `p5-` ports). To make this easy, any instances in [.filename]#pkg-plist# of `%%OSREL%%`, `%%PERL_VER%%`, and `%%PERL_VERSION%%` will be substituted appropriately. The value of `%%OSREL%%` is the numeric revision of the operating system (for example, `4.9`). `%%PERL_VERSION%%` and `%%PERL_VER%%` is the full version number of `perl` (for example, `5.8.9`). Several other `%%_VARS_%%` related to port's documentation files are described in crossref:makefiles[install-documentation,the relevant section]. To make other substitutions, set `PLIST_SUB` with a list of `_VAR=VALUE_` pairs and instances of `%%_VAR_%%` will be substituted with _VALUE_ in [.filename]#pkg-plist#. For instance, if a port installs many files in a version-specific subdirectory, use a placeholder for the version so that [.filename]#pkg-plist# does not have to be regenerated every time the port is updated. For example, set: [.programlisting] .... OCTAVE_VERSION= ${PORTREVISION} PLIST_SUB= OCTAVE_VERSION=${OCTAVE_VERSION} .... in the [.filename]#Makefile# and use `%%OCTAVE_VERSION%%` wherever the version shows up in [.filename]#pkg-plist#. When the port is upgraded, it will not be necessary to edit dozens (or in some cases, hundreds) of lines in [.filename]#pkg-plist#. If files are installed conditionally on the options set in the port, the usual way of handling it is prefixing [.filename]#pkg-plist# lines with a `%%OPT%%` for lines needed when the option is enabled, or `%%NO_OPT%%` when the option is disabled, and adding `OPTIONS_SUB=yes` to the [.filename]#Makefile#. See crossref:makefiles[options_sub,`OPTIONS_SUB`] for more information. For instance, if there are files that are only installed when the `X11` option is enabled, and [.filename]#Makefile# has: [.programlisting] .... OPTIONS_DEFINE= X11 OPTIONS_SUB= yes .... In [.filename]#pkg-plist#, put `%%X11%%` in front of the lines only being installed when the option is enabled, like this : [.programlisting] .... %%X11%%bin/foo-gui .... This substitution will be done between the `pre-install` and `do-install` targets, by reading from [.filename]#PLIST# and writing to [.filename]#TMPPLIST# (default: [.filename]#WRKDIR/.PLIST.mktmp#). So if the port builds [.filename]#PLIST# on the fly, do so in or before `pre-install`. Also, if the port needs to edit the resulting file, do so in `post-install` to a file named [.filename]#TMPPLIST#. Another way of modifying a port's packing list is based on setting the variables `PLIST_FILES` and `PLIST_DIRS`. The value of each variable is regarded as a list of pathnames to write to [.filename]#TMPPLIST# along with [.filename]#PLIST# contents. While names listed in `PLIST_FILES` and `PLIST_DIRS` are subject to `%%_VAR_%%` substitution as described above, it is better to use the `${_VAR_}` directly. Except for that, names from `PLIST_FILES` will appear in the final packing list unchanged, while `@dir` will be prepended to names from `PLIST_DIRS`. To take effect, `PLIST_FILES` and `PLIST_DIRS` must be set before [.filename]#TMPPLIST# is written, that is, in `pre-install` or earlier. From time to time, using `OPTIONS_SUB` is not enough. In those cases, adding a specific `_TAG_` to `PLIST_SUB` inside the [.filename]#Makefile# with a special value of `@comment`, makes package tools to ignore the line. For instance, if some files are only installed when the `X11` option is on and the architecture is `i386`: [.programlisting] .... .include .if ${PORT_OPTIONS:MX11} && ${ARCH} == "i386" PLIST_SUB+= X11I386="" .else PLIST_SUB+= X11I386="@comment " .endif .... [[plist-cleaning]] == Empty Directories [[plist-dir-cleaning]] === Cleaning Up Empty Directories When being de-installed, a port has to remove empty directories it created. Most of these directories are removed automatically by man:pkg[8], but for directories created outside of [.filename]#${PREFIX}#, or empty directories, some more work needs to be done. This is usually accomplished by adding `@dir` lines for those directories. Subdirectories must be deleted before deleting parent directories. [.programlisting] .... [...] @dir /var/games/oneko/saved-games @dir /var/games/oneko .... [[plist-dir-empty]] === Creating Empty Directories Empty directories created during port installation need special attention. They must be present when the package is created. If they are not created by the port code, create them in the [.filename]#Makefile#: [.programlisting] .... post-install: ${MKDIR} ${STAGEDIR}${PREFIX}/some/directory .... Add the directory to [.filename]#pkg-plist# like any other. For example: [.programlisting] .... @dir some/directory .... [[plist-config]] == Configuration Files If the port installs configuration files to [.filename]#PREFIX/etc# (or elsewhere) do _not_ list them in [.filename]#pkg-plist#. That will cause `pkg delete` to remove files that have been carefully edited by the user, and a re-installation will wipe them out. Instead, install sample files with a [.filename]#filename.sample# extension. The `@sample` macro automates this, see crossref:plist[plist-keywords-sample] for what it does exactly. For each sample file, add a line to [.filename]#pkg-plist#: [.programlisting] .... @sample etc/orbit.conf.sample .... If there is a very good reason not to install a working configuration file by default, only list the sample filename in [.filename]#pkg-plist#, without the `@sample` followed by a space part, and add a crossref:pkg-files[porting-message,message] pointing out that the user must copy and edit the file before the software will work. [TIP] ==== When a port installs its configuration in a subdirectory of [.filename]#${PREFIX}/etc#, use `ETCDIR`, which defaults to `${PREFIX}/etc/${PORTNAME}`, it can be overridden in the ports [.filename]#Makefile# if there is a convention for the port to use some other directory. The `%%ETCDIR%%` macro will be used in its stead in [.filename]#pkg-plist#. ==== [NOTE] ==== The sample configuration files should always have the [.filename]#.sample# suffix. If for some historical reason using the standard suffix is not possible, or if the sample files come from some other directory, use this construct: [.programlisting] .... @sample etc/orbit.conf-dist etc/orbit.conf .... or [.programlisting] .... @sample %%EXAMPLESDIR%%/orbit.conf etc/orbit.conf .... The format is `@sample _sample-file actual-config-file_`. ==== [[plist-dynamic]] == Dynamic Versus Static Package List A _static package list_ is a package list which is available in the Ports Collection either as [.filename]#pkg-plist# (with or without variable substitution), or embedded into the [.filename]#Makefile# via `PLIST_FILES` and `PLIST_DIRS`. Even if the contents are auto-generated by a tool or a target in the Makefile _before_ the inclusion into the Ports Collection by a committer (for example, using `make makeplist`), this is still considered a static list, since it is possible to examine it without having to download or compile the distfile. A _dynamic package list_ is a package list which is generated at the time the port is compiled based upon the files and directories which are installed. It is not possible to examine it before the source code of the ported application is downloaded and compiled, or after running a `make clean`. While the use of dynamic package lists is not forbidden, maintainers should use static package lists wherever possible, as it enables users to man:grep[1] through available ports to discover, for example, which port installs a certain file. Dynamic lists should be primarily used for complex ports where the package list changes drastically based upon optional features of the port (and thus maintaining a static package list is infeasible), or ports which change the package list based upon the version of dependent software used. For example, ports which generate docs with Javadoc. [[plist-autoplist]] == Automated Package List Creation First, make sure the port is almost complete, with only [.filename]#pkg-plist# missing. Running `make makeplist` will show an example for [.filename]#pkg-plist#. The output of `makeplist` must be double checked for correctness as it tries to automatically guess a few things, and can get it wrong. User configuration files should be installed as [.filename]#filename.sample#, as -it is described in crossref:plist[plist-config]. +it is described in crossref:plist[plist-config, Configuration Files]. [.filename]#info/dir# must not be listed and appropriate [.filename]#install-info# lines must be added as noted in the crossref:makefiles[makefile-info,info files] section. Any libraries installed by the port must be listed as specified in the crossref:special[porting-shlibs,shared libraries] section. [[plist-autoplist-regex]] === Expanding `PLIST_SUB` with Regular Expressions Strings to be replaced sometimes need to be very specific to avoid undesired replacements. This is a common problem with shorter values. To address this problem, for each `_PLACEHOLDER_=_value_`, a `PLACEHOLDER_regex=regex` can be set, with the `_regex_` part matching _value_ more precisely. [[plist-autoplist-regex-ex1]] .Using PLIST_SUB with Regular Expressions [example] ==== Perl ports can install architecture dependent files in a specific tree. On FreeBSD to ease porting, this tree is called `mach`. For example, a port that installs a file whose path contains `mach` could have that part of the path string replaced with the wrong values. Consider this [.filename]#Makefile#: [.programlisting] .... PORTNAME= Machine-Build DISTVERSION= 1 CATEGORIES= devel perl5 MASTER_SITES= CPAN PKGNAMEPREFIX= p5- MAINTAINER= perl@FreeBSD.org COMMENT= Building machine WWW= https://search.cpan.org/dist/Machine-Build USES= perl5 USE_PERL5= configure PLIST_SUB= PERL_ARCH=mach .... The files installed by the port are: [.programlisting] .... /usr/local/bin/machine-build /usr/local/lib/perl5/site_perl/man/man1/machine-build.1.gz /usr/local/lib/perl5/site_perl/man/man3/Machine::Build.3.gz /usr/local/lib/perl5/site_perl/Machine/Build.pm /usr/local/lib/perl5/site_perl/mach/5.20/Machine/Build/Build.so .... Running `make makeplist` wrongly generates: [.programlisting] .... bin/%%PERL_ARCH%%ine-build %%PERL5_MAN1%%/%%PERL_ARCH%%ine-build.1.gz %%PERL5_MAN3%%/Machine::Build.3.gz %%SITE_PERL%%/Machine/Build.pm %%SITE_PERL%%/%%PERL_ARCH%%/%%PERL_VER%%/Machine/Build/Build.so .... Change the `PLIST_SUB` line from the [.filename]#Makefile# to: [.programlisting] .... PLIST_SUB= PERL_ARCH=mach \ PERL_ARCH_regex=\bmach\b .... Now `make makeplist` correctly generates: [.programlisting] .... bin/machine-build %%PERL5_MAN1%%/machine-build.1.gz %%PERL5_MAN3%%/Machine::Build.3.gz %%SITE_PERL%%/Machine/Build.pm %%SITE_PERL%%/%%PERL_ARCH%%/%%PERL_VER%%/Machine/Build/Build.so .... ==== [[plist-keywords]] == Expanding Package List with Keywords All keywords can also take optional arguments in parentheses. The arguments are owner, group, and mode. This argument is used on the file or directory referenced. To change the owner, group, and mode of a configuration file, use: [.programlisting] .... @sample(games,games,640) etc/config.sample .... The arguments are optional. If only the group and mode need to be changed, use: [.programlisting] .... @sample(,games,660) etc/config.sample .... [WARNING] ==== If a keyword is used on an crossref:makefiles[makefile-options,optional] entry, it must to be added after the helper: [.programlisting] .... %%FOO%%@sample etc/orbit.conf.sample .... This is because the options plist helpers are used to comment out the line, so they need to be put first. See crossref:makefiles[options_sub,`OPTIONS_SUB`] for more information. ==== [[plist-keywords-desktop-file-utils]] === `@desktop-file-utils` Will run `update-desktop-database -q` after installation and deinstallation. _Never_ use directly, add crossref:uses[uses-desktop-file-utils,`USES=desktop-file-utils`] to the [.filename]#Makefile#. [[plist-keywords-fc]] === `@fc` _directory_ Add a `@dir` entry for the directory passed as an argument, and run `fc-cache -fs` on that directory after installation and deinstallation. [[plist-keywords-fontsdir]] === `@fontsdir` _directory_ Add a `@dir` entry for the directory passed as an argument, and run `mkfontscale` and `mkfontdir` on that directory after installation and deinstallation. Additionally, on deinstallation, it removes the [.filename]#fonts.scale# and [.filename]#fonts.dir# cache files if they are empty. [[plist-keywords-info]] === `@info` _file_ Add the file passed as argument to the plist, and updates the info document index on installation and deinstallation. Additionally, it removes the index if empty on deinstallation. This should never be used manually, but always through `INFO`. See crossref:makefiles[makefile-info,Info Files] for more information. [[plist-keywords-kld]] === `@kld` _directory_ Runs `kldxref` on the directory on installation and deinstallation. Additionally, on deinstallation, it will remove the directory if empty. [[plist-keywords-rmtry]] === `@rmtry` _file_ Will remove the file on deinstallation, and not give an error if the file is not there. [[plist-keywords-sample]] === `@sample` _file_ [_file_] This is used to handle installation of configuration files, through example files bundled with the package. The "actual", non-sample, file is either the second filename, if present, or the first filename without the [.filename]#.sample# extension. This does three things. First, add the first file passed as argument, the sample file, to the plist. Then, on installation, if the actual file is not found, copy the sample file to the actual file. And finally, on deinstallation, remove the actual file if it has not been modified. -See crossref:plist[plist-config] for more information. +See crossref:plist[plist-config, Configuration Files] for more information. [[plist-keywords-shared-mime-info]] === `@shared-mime-info` _directory_ Runs `update-mime-database` on the directory on installation and deinstallation. [[plist-keywords-shell]] === `@shell` _file_ Add the file passed as argument to the plist. On installation, add the full path to _file_ to [.filename]#/etc/shells#, while making sure it is not added twice. On deinstallation, remove it from [.filename]#/etc/shells#. [[plist-keywords-terminfo]] === `@terminfo` Do not use by itself. If the port installs [.filename]#*.terminfo# files, add crossref:uses[uses-terminfo,USES=terminfo] to its [.filename]#Makefile#. On installation and deinstallation, if `tic` is present, refresh [.filename]#${PREFIX}/shared/misc/terminfo.db# from the [.filename]#*.terminfo# files in [.filename]#${PREFIX}/shared/misc#. [[plist-keywords-base]] === Base Keywords There are a few keywords that are hardcoded, and documented in man:pkg-create[8]. For the sake of completeness, they are also documented here. [[plist-keywords-base-empty]] ==== `@` [_file_] The empty keyword is a placeholder to use when the file's owner, group, or mode need to be changed. For example, to set the group of the file to `games` and add the setgid bit, add: [.programlisting] .... @(,games,2755) sbin/daemon .... [[plist-keywords-base-exec]] ==== `@preexec` _command_, `@postexec` _command_, `@preunexec` _command_, `@postunexec` _command_ Execute _command_ as part of the package installation or deinstallation process. `@preexec` _command_:: Execute _command_ as part of the [.filename]#pre-install# scripts. `@postexec` _command_:: Execute _command_ as part of the [.filename]#post-install# scripts. `@preunexec` _command_:: Execute _command_ as part of the [.filename]#pre-deinstall# scripts. `@postunexec` _command_:: Execute _command_ as part of the [.filename]#post-deinstall# scripts. If _command_ contains any of these sequences somewhere in it, they are expanded inline. For these examples, assume that `@cwd` is set to [.filename]#/usr/local# and the last extracted file was [.filename]#bin/emacs#. `%F`:: Expand to the last filename extracted (as specified). In the example case [.filename]#bin/emacs#. `%D`:: Expand to the current directory prefix, as set with `@cwd`. In the example case [.filename]#/usr/local#. `%B`:: Expand to the basename of the fully qualified filename, that is, the current directory prefix plus the last filespec, minus the trailing filename. In the example case, that would be [.filename]#/usr/local/bin#. `%f`:: Expand to the filename part of the fully qualified name, or the converse of `%B`. In the example case, [.filename]#emacs#. [IMPORTANT] ==== These keywords are here to help you set up the package so that it is as ready to use as possible. They _must not_ be abused to start services, stop services, or run any other commands that will modify the currently running system. ==== [[plist-keywords-base-mode]] ==== `@mode` _mode_ Set default permission for all subsequently extracted files to _mode_. Format is the same as that used by man:chmod[1]. Use without an arg to set back to default permissions (mode of the file while being packed). [IMPORTANT] ==== This must be a numeric mode, like `644`, `4755`, or `600`. It cannot be a relative mode like `u+s`. ==== [[plist-keywords-base-owner]] ==== `@owner` _user_ Set default ownership for all subsequent files to _user_. Use without an argument to set back to default ownership (`root`). [[plist-keywords-base-group]] ==== `@group` _group_ Set default group ownership for all subsequent files to _group_. Use without an arg to set back to default group ownership (`wheel`). [[plist-keywords-base-comment]] ==== `@comment` _string_ This line is ignored when packing. [[plist-keywords-base-dir]] ==== `@dir` _directory_ Declare directory name. By default, directories created under `PREFIX` by a package installation are automatically removed. Use this when an empty directory under `PREFIX` needs to be created, or when the directory needs to have non default owner, group, or mode. Directories outside of `PREFIX` need to be registered. For example, [.filename]#/var/db/${PORTNAME}# needs to have a `@dir` entry whereas [.filename]#${PREFIX}/shared/${PORTNAME}# does not if it contains files or uses the default owner, group, and mode. [[plist-keywords-base-exec-deprecated]] ==== `@exec` _command_, `@unexec` _command_ (Deprecated) Execute _command_ as part of the installation or deinstallation process. -Please use crossref:plist[plist-keywords-base-exec] instead. +Please use crossref:plist[plist-keywords-base-exec, `@preexec` _command_, `@postexec` _command_, `@preunexec` _command_, `@postunexec` _command_] instead. [[plist-keywords-base-dirrm]] ==== `@dirrm` _directory_ (Deprecated) Declare directory name to be deleted at deinstall time. By default, directories created under `PREFIX` by a package installation are deleted when the package is deinstalled. [[plist-keywords-base-dirrmtry]] ==== `@dirrmtry` _directory_ (Deprecated) Declare directory name to be removed, as for `@dirrm`, but does not issue a warning if the directory cannot be removed. [[plist-keywords-creating-new]] === Creating New Keywords Package list files can be extended by keywords that are defined in the [.filename]#${PORTSDIR}/Keywords# directory. The settings for each keyword are stored in a UCL file named [.filename]#keyword.ucl#. The file must contain at least one of these sections: * `attributes` * `action` * `pre-install` * `post-install` * `pre-deinstall` * `post-deinstall` * `pre-upgrade` * `post-upgrade` [[plist-keywords-attributes]] ==== `attributes` Changes the owner, group, or mode used by the keyword. Contains an associative array where the possible keys are `owner`, `group`, and `mode`. The values are, respectively, a user name, a group name, and a file mode. For example: [.programlisting] .... attributes: { owner: "games", group: "games", mode: 0555 } .... [[plist-keywords-action]] ==== `action` Defines what happens to the keyword's parameter. Contains an array where the possible values are: `setprefix`:: Set the prefix for the next plist entries. `dir`:: Register a directory to be created on install and removed on deinstall. `dirrm`:: Register a directory to be deleted on deinstall. Deprecated. `dirrmtry`:: Register a directory to try and deleted on deinstall. Deprecated. `file`:: Register a file. `setmode`:: Set the mode for the next plist entries. `setowner`:: Set the owner for the next plist entries. `setgroup`:: Set the group for the next plist entries. `comment`:: Does not do anything, equivalent to not entering an `action` section. `ignore_next`:: Ignore the next entry in the plist. [[plist-keywords-arguments]] ==== `arguments` If set to `true`, adds argument handling, splitting the whole line, `%@`, into numbered arguments, `%1`, `%2`, and so on. For example, for this line: [.programlisting] .... @foo some.content other.content .... `%1` and `%2` will contain: [.programlisting] .... some.content other.content .... It also affects how the crossref:plist[plist-keywords-action,`action`] entry works. When there is more than one argument, the argument number must be specified. For example: [.programlisting] .... actions: [file(1)] .... [[plist-keywords-pre-post]] ==== `pre-install`, `post-install`, `pre-deinstall`, `post-deinstall`, `pre-upgrade`, `post-upgrade` These keywords contains a man:sh[1] script to be executed before or after installation, deinstallation, or upgrade of the package. In addition to the usual `@exec %_foo_` placeholders described in -crossref:plist[plist-keywords-base-exec], there is a new one, `%@`, which represents the argument of the keyword. +crossref:plist[plist-keywords-base-exec, `@preexec` _command_, `@postexec` _command_, `@preunexec` _command_, `@postunexec` _command_], there is a new one, `%@`, which represents the argument of the keyword. [[plist-keywords-examples]] ==== Custom Keyword Examples [[plist-keywords-fc-example]] .Example of a `@dirrmtryecho` Keyword [example] ==== This keyword does two things, it adds a `@dirrmtry _directory_` line to the packing list, and echoes the fact that the directory is removed when deinstalling the package. [.programlisting] .... actions: [dirrmtry] post-deinstall: < libfoo.so.42 -rwxr-xr-x 1 nobody nobody 15 Aug 3 11:24 libfoo.so.42* % ls -lF ${STAGEDIR}${PREFIX}/bin lrwxr-xr-x 1 nobody nobody 181 Aug 3 11:27 bar@ -> ../libexec/foo/bar % ls -lF ${STAGEDIRDIR}${PREFIX}/share lrwxr-xr-x 1 nobody nobody 181 Aug 3 11:27 foo@ -> ../../../var/cache/foo .... ==== [[bundled-libs]] == Bundled Libraries This section explains why bundled dependencies are considered bad and what to do about them. [[bundled-libs-why-bad]] === Why Bundled Libraries Are Bad Some software requires the porter to locate third-party libraries and add the required dependencies to the port. Other software bundles all necessary libraries into the distribution file. The second approach seems easier at first, but there are some serious drawbacks: This list is loosely based on the https://fedoraproject.org/wiki/Packaging:No_Bundled_Libraries[Fedora] and https://wiki.gentoo.org/wiki/Why_not_bundle_dependencies[Gentoo] wikis, both licensed under the https://creativecommons.org/licenses/by-sa/3.0/[CC-BY-SA 3.0] license. Security:: If vulnerabilities are found in the upstream library and fixed there, they might not be fixed in the library bundled with the port. One reason could be that the author is not aware of the problem. This means that the porter must fix them, or upgrade to a non-vulnerable version, and send a patch to the author. This all takes time, which results in software being vulnerable longer than necessary. This in turn makes it harder to coordinate a fix without unnecessarily leaking information about the vulnerability. Bugs:: This problem is similar to the problem with security in the last paragraph, but generally less severe. Forking:: It is easier for the author to fork the upstream library once it is bundled. While convenient on first sight, it means that the code diverges from upstream making it harder to address security or other problems with the software. A reason for this is that patching becomes harder. + Another problem of forking is that because code diverges from upstream, bugs get solved over and over again instead of just once at a central location. This defeats the idea of open source software in the first place. Symbol collision:: When a library is installed on the system, it might collide with the bundled version. This can cause immediate errors at compile or link time. It can also cause errors when running the program which might be harder to track down. The latter problem could be caused because the versions of the two libraries are incompatible. Licensing:: When bundling projects from different sources, license issues can arise more easily, especially when licenses are incompatible. Waste of resources:: Bundled libraries waste resources on several levels. It takes longer to build the actual application, especially if these libraries are already present on the system. At run-time, they can take up unnecessary memory when the system-wide library is already loaded by one program and the bundled library is loaded by another program. Waste of effort:: When a library needs patches for FreeBSD, these patches have to be duplicated again in the bundled library. This wastes developer time because the patches might not apply cleanly. It can also be hard to notice that these patches are required in the first place. [[bundled-libs-practices]] === What to do About Bundled Libraries Whenever possible, use the unbundled version of the library by adding a `LIB_DEPENDS` to the port. If such a port does not exist yet, consider creating it. Only use bundled libraries if the upstream has a good track record on security and using unbundled versions leads to overly complex patches. [NOTE] ==== In some very special cases, for example emulators, like Wine, a port has to bundle libraries, because they are in a different architecture, or they have been modified to fit the software's use. In that case, those libraries should not be exposed to other ports for linking. Add `BUNDLE_LIBS=yes` to the port's [.filename]#Makefile#. This will tell man:pkg[8] to not compute provided libraries. Always ask the {portmgr} before adding this to a port. ==== [[porting-shlibs]] == Shared Libraries If the port installs one or more shared libraries, define a `USE_LDCONFIG` make variable, which will instruct a [.filename]#bsd.port.mk# to run `${LDCONFIG} -m` on the directory where the new library is installed (usually [.filename]#PREFIX/lib#) during `post-install` target to register it into the shared library cache. This variable, when defined, will also facilitate addition of an appropriate `@exec /sbin/ldconfig -m` and `@unexec /sbin/ldconfig -R` pair into [.filename]#pkg-plist#, so that a user who installed the package can start using the shared library immediately and de-installation will not cause the system to still believe the library is there. [.programlisting] .... USE_LDCONFIG= yes .... The default directory can be overridden by setting `USE_LDCONFIG` to a list of directories into which shared libraries are to be installed. For example, if the port installs shared libraries into [.filename]#PREFIX/lib/foo# and [.filename]#PREFIX/lib/bar# use this in [.filename]#Makefile#: [.programlisting] .... USE_LDCONFIG= ${PREFIX}/lib/foo ${PREFIX}/lib/bar .... Please double-check, often this is not necessary at all or can be avoided through `-rpath` or setting `LD_RUN_PATH` during linking (see package:lang/mosml[] for an example), or through a shell-wrapper which sets `LD_LIBRARY_PATH` before invoking the binary, like package:www/seamonkey[] does. When installing 32-bit libraries on a 64-bit system, use `USE_LDCONFIG32` instead. If the software uses crossref:special[using-autotools,autotools], and specifically `libtool`, add crossref:uses[uses-libtool,`USES=libtool`]. When the major library version number increments in the update to the new port version, all other ports that link to the affected library must have their `PORTREVISION` incremented, to force recompilation with the new library version. [[porting-restrictions]] == Ports with Distribution Restrictions or Legal Concerns Licenses vary, and some of them place restrictions on how the application can be packaged, whether it can be sold for profit, and so on. [IMPORTANT] ==== It is the responsibility of a porter to read the licensing terms of the software and make sure that the FreeBSD project will not be held accountable for violating them by redistributing the source or compiled binaries either via FTP/HTTP or CD-ROM. If in doubt, please contact the {freebsd-ports}. ==== In situations like this, the variables described in the next sections can be set. [[porting-restrictions-no_package]] === `NO_PACKAGE` This variable indicates that we may not generate a binary package of the application. For instance, the license may disallow binary redistribution, or it may prohibit distribution of packages created from patched sources. However, the port's `DISTFILES` may be freely mirrored on FTP/HTTP. They may also be distributed on a CD-ROM (or similar media) unless `NO_CDROM` is set as well. If the binary package is not generally useful, and the application must always be compiled from the source code, use `NO_PACKAGE`. For example, if the application has configuration information that is site specific hard coded into it at compile time, set `NO_PACKAGE`. Set `NO_PACKAGE` to a string describing the reason why the package cannot be generated. [[porting-restrictions-no_cdrom]] === `NO_CDROM` This variable alone indicates that, although we are allowed to generate binary packages, we may put neither those packages nor the port's `DISTFILES` onto a CD-ROM (or similar media) for resale. However, the binary packages and the port's `DISTFILES` will still be available via FTP/HTTP. If this variable is set along with `NO_PACKAGE`, then only the port's `DISTFILES` will be available, and only via FTP/HTTP. Set `NO_CDROM` to a string describing the reason why the port cannot be redistributed on CD-ROM. For instance, use this if the port's license is for "non-commercial" use only. [[porting-restrictions-nofetchfiles]] === `NOFETCHFILES` Files defined in `NOFETCHFILES` are not fetchable from any of `MASTER_SITES`. An example of such a file is when the file is supplied on CD-ROM by the vendor. Tools which check for the availability of these files on `MASTER_SITES` have to ignore these files and not report about them. [[porting-restrictions-restricted]] === `RESTRICTED` Set this variable alone if the application's license permits neither mirroring the application's `DISTFILES` nor distributing the binary package in any way. Do not set `NO_CDROM` or `NO_PACKAGE` along with `RESTRICTED`, since the latter variable implies the former ones. Set `RESTRICTED` to a string describing the reason why the port cannot be redistributed. Typically, this indicates that the port contains proprietary software and that the user will need to manually download the `DISTFILES`, possibly after registering for the software or agreeing to accept the terms of an EULA. [[porting-restrictions-restricted_files]] === `RESTRICTED_FILES` When `RESTRICTED` or `NO_CDROM` is set, this variable defaults to `${DISTFILES} ${PATCHFILES}`, otherwise it is empty. If only some of the distribution files are restricted, then set this variable to list them. [[porting-restrictions-legal_text]] === `LEGAL_TEXT` If the port has legal concerns not addressed by the above variables, set `LEGAL_TEXT` to a string explaining the concern. For example, if special permission was obtained for FreeBSD to redistribute the binary, this variable must indicate so. [[porting-restrictions-legal]] === [.filename]#/usr/ports/LEGAL# and `LEGAL` A port which sets any of the above variables must also be added to [.filename]#/usr/ports/LEGAL#. The first column is a glob which matches the restricted distfiles. The second column is the port's origin. The third column is the output of `make -VLEGAL`. [[porting-restrictions-examples]] === Examples The preferred way to state "the distfiles for this port must be fetched manually" is as follows: [.programlisting] .... .if !exists(${DISTDIR}/${DISTNAME}${EXTRACT_SUFX}) IGNORE= may not be redistributed because of licensing reasons. Please visit some-website to accept their license and download ${DISTFILES} into ${DISTDIR} .endif .... This both informs the user, and sets the proper metadata on the user's machine for use by automated programs. Note that this stanza must be preceded by an inclusion of [.filename]#bsd.port.pre.mk#. [[building]] == Building Mechanisms [[parallel-builds]] === Building Ports in Parallel The FreeBSD ports framework supports parallel building using multiple `make` sub-processes, which allows SMP systems to utilize all of their available CPU power, allowing port builds to be faster and more effective. This is achieved by passing `-jX` flag to man:make[1] running on vendor code. This is the default build behavior of ports. Unfortunately, not all ports handle parallel building well and it may be required to explicitly disable this feature by adding the `MAKE_JOBS_UNSAFE=yes` variable. It is used when a port is known to be broken with `-jX` due to race conditions causing intermittent build failures. [IMPORTANT] ==== When setting `MAKE_JOBS_UNSAFE`, it is very important to explain either with a comment in the [.filename]#Makefile#, or at least in the commit message, _why_ the port does not build when enabling. Otherwise, it is almost impossible to either fix the problem, or test if it has been fixed when committing an update at a later date. ==== [[using-make]] === `make`, `gmake`, and `imake` Several differing `make` implementations exist. Ported software often requires a particular implementation, like GNU `make`, known in FreeBSD as `gmake`. If the port uses GNU make, add `gmake` to `USES`. `MAKE_CMD` can be used to reference the specific command configured by the `USES` setting in the port's [.filename]#Makefile#. Only use `MAKE_CMD` within the application [.filename]##Makefile##s in `WRKSRC` to call the `make` implementation expected by the ported software. If the port is an X application that uses imake to create [.filename]##Makefile##s from [.filename]##Imakefile##s, set `USES= imake`. See the crossref:uses[uses-imake,`USES=imake`] section of crossref:uses[uses,Using `USES` Macros] for more details. If the port's source [.filename]#Makefile# has something other than `all` as the main build target, set `ALL_TARGET` accordingly. The same goes for `install` and `INSTALL_TARGET`. [[using-configure]] === `configure` Script If the port uses the `configure` script to generate [.filename]#Makefile# from [.filename]#Makefile.in#, set `GNU_CONFIGURE=yes`. To give extra arguments to the `configure` script (the default argument is `--prefix=${PREFIX} --infodir=${PREFIX}/${INFO_PATH} --mandir=${PREFIX}/man --build=${CONFIGURE_TARGET}`), set those extra arguments in `CONFIGURE_ARGS`. Extra environment variables can be passed using `CONFIGURE_ENV`. [[using-configure-variables]] .Variables for Ports That Use `configure` [cols="1,1", frame="none", options="header"] |=== | Variable | Means |`GNU_CONFIGURE` |The port uses `configure` script to prepare build. |`HAS_CONFIGURE` |Same as `GNU_CONFIGURE`, except default configure target is not added to `CONFIGURE_ARGS`. |`CONFIGURE_ARGS` |Additional arguments passed to `configure` script. |`CONFIGURE_ENV` |Additional environment variables to be set for `configure` script run. |`CONFIGURE_TARGET` |Override default configure target. Default value is `${MACHINE_ARCH}-portbld-freebsd${OSREL}`. |=== [[using-cmake]] === Using `cmake` For ports that use CMake, define `USES= cmake`. [[using-cmake-variables]] .Variables for Ports That Use `cmake` [cols="1,1", frame="none", options="header"] |=== | Variable | Means |`CMAKE_ARGS` |Port specific CMake flags to be passed to the `cmake` binary. |`CMAKE_ON` |For each entry in `CMAKE_ON`, an enabled boolean value is added to -`CMAKE_ARGS`. See crossref:special[using-cmake-example2]. +`CMAKE_ARGS`. See crossref:special[using-cmake-example2,.`CMAKE_ON` and `CMAKE_OFF`]. |`CMAKE_OFF` |For each entry in `CMAKE_OFF`, a disabled boolean value is added to -`CMAKE_ARGS`. See crossref:special[using-cmake-example2]. +`CMAKE_ARGS`. See crossref:special[using-cmake-example2,.`CMAKE_ON` and `CMAKE_OFF`]. |`CMAKE_BUILD_TYPE` |Type of build (CMake predefined build profiles). Default is `Release`, or `Debug` if `WITH_DEBUG` is set. |`CMAKE_SOURCE_PATH` |Path to the source directory. Default is `${WRKSRC}`. |`CONFIGURE_ENV` |Additional environment variables to be set for the `cmake` binary. |=== [[using-cmake-user-variables]] .Variables the Users Can Define for `cmake` Builds [cols="1,1", frame="none", options="header"] |=== | Variable | Means |`CMAKE_NOCOLOR` |Disables color build output. Default not set, unless `BATCH` or `PACKAGE_BUILDING` are set. |=== CMake supports these build profiles: `Debug`, `Release`, `RelWithDebInfo` and `MinSizeRel`. `Debug` and `Release` profiles respect system `\*FLAGS`, `RelWithDebInfo` and `MinSizeRel` will set `CFLAGS` to `-O2 -g` and `-Os -DNDEBUG` correspondingly. The lower-cased value of `CMAKE_BUILD_TYPE` is exported to `PLIST_SUB` and must be used if the port installs [.filename]#*.cmake# depending on the build type (see package:devel/kf5-kcrash[] for an example). Please note that some projects may define their own build profiles and/or force particular build type by setting `CMAKE_BUILD_TYPE` in [.filename]#CMakeLists.txt#. To make a port for such a project respect `CFLAGS` and `WITH_DEBUG`, the `CMAKE_BUILD_TYPE` definitions must be removed from those files. Most CMake-based projects support an out-of-source method of building. The out-of-source build for a port is the default setting. An in-source build can be requested by using the `:insource` suffix. With out-of-source builds, `CONFIGURE_WRKSRC`, `BUILD_WRKSRC` and `INSTALL_WRKSRC` will be set to `${WRKDIR}/.build` and this directory will be used to keep all files generated during configuration and build stages, leaving the source directory intact. [[using-cmake-example]] .`USES= cmake` Example [example] ==== This snippet demonstrates the use of CMake for a port. `CMAKE_SOURCE_PATH` is not usually required, but can be set when the sources are not located in the top directory, or if only a subset of the project is intended to be built by the port. [.programlisting] .... USES= cmake CMAKE_SOURCE_PATH= ${WRKSRC}/subproject .... ==== [[using-cmake-example2]] .`CMAKE_ON` and `CMAKE_OFF` [example] ==== When adding boolean values to `CMAKE_ARGS`, it is easier to use the `CMAKE_ON` and `CMAKE_OFF` variables instead. This: [.programlisting] .... CMAKE_ON= VAR1 VAR2 CMAKE_OFF= VAR3 .... Is equivalent to: [.programlisting] .... CMAKE_ARGS= -DVAR1:BOOL=TRUE -DVAR2:BOOL=TRUE -DVAR3:BOOL=FALSE .... [IMPORTANT] ====== This is only for the default values off `CMAKE_ARGS`. The helpers described in crossref:makefiles[options-cmake_bool,`OPT_CMAKE_BOOL` and `OPT_CMAKE_BOOL_OFF`] use the same semantics, but for optional values. ====== ==== [[using-scons]] === Using `scons` If the port uses SCons, define `USES=scons`. To make third party [.filename]#SConstruct# respect everything that is passed to SCons in the environment (that is, most importantly, `CC/CXX/CFLAGS/CXXFLAGS`), patch [.filename]#SConstruct# so build `Environment` is constructed like this: [.programlisting] .... env = Environment(**ARGUMENTS) .... It may be then modified with `env.Append` and `env.Replace`. [[using-cargo]] === Building Rust Applications with `cargo` For ports that use Cargo, define `USES=cargo`. [[using-cargo-user-variables]] .Variables the Users Can Define for `cargo` Builds [cols="1,1,1", frame="none", options="header"] |=== | Variable | Default | Description |`CARGO_CRATES` | |List of crates the port depends on. Each entry needs to have a format like `cratename-semver` for example, `libc-0.2.40`. Port maintainers can generate this list from [.filename]#Cargo.lock# using `make cargo-crates`. Manually bumping crate versions is possible but be mindful of transitive dependencies. If the list generated by `make cargo-crates` is big, it might be convenient to place it inside a `Makefile.crates` file in the top-level port directory. If present, the ports framework sources that file automatically. This help keep the main port Makefile within a manageable size. |`CARGO_FEATURES` | |List of application features to build (space separated list). To deactivate all default features add the special token `--no-default-features` to `CARGO_FEATURES`. Manually passing it to `CARGO_BUILD_ARGS`, `CARGO_INSTALL_ARGS`, and `CARGO_TEST_ARGS` is not needed. |`CARGO_CARGOTOML` |`${WRKSRC}/Cargo.toml` |The path to the [.filename]#Cargo.toml# to use. |`CARGO_CARGOLOCK` |`${WRKSRC}/Cargo.lock` |The path to the [.filename]#Cargo.lock# to use for `make cargo-crates`. It is possible to specify more than one lock file when necessary. |`CARGO_ENV` | |A list of environment variables to pass to Cargo similar to `MAKE_ENV`. |`RUSTFLAGS` | |Flags to pass to the Rust compiler. |`CARGO_CONFIGURE` |`yes` |Use the default `do-configure`. |`CARGO_UPDATE_ARGS` | |Extra arguments to pass to Cargo during the configure phase. Valid arguments can be looked up with `cargo update --help`. |`CARGO_BUILDDEP` |`yes` |Add a build dependency on package:lang/rust[]. |`CARGO_CARGO_BIN` |`${LOCALBASE}/bin/cargo` |Location of the `cargo` binary. |`CARGO_BUILD` |`yes` |Use the default `do-build`. |`CARGO_BUILD_ARGS` | |Extra arguments to pass to Cargo during the build phase. Valid arguments can be looked up with `cargo build --help`. |`CARGO_INSTALL` |`yes` |Use the default `do-install`. |`CARGO_INSTALL_ARGS` | |Extra arguments to pass to Cargo during the install phase. Valid arguments can be looked up with `cargo install --help`. |`CARGO_INSTALL_PATH` |`.` |Path to the crate to install. This is passed to `cargo install` via its `--path` argument. When multiple paths are specified `cargo install` is run multiple times. |`CARGO_TEST` |`yes` |Use the default `do-test`. |`CARGO_TEST_ARGS` | |Extra arguments to pass to Cargo during the test phase. Valid arguments can be looked up with `cargo test --help`. |`CARGO_TARGET_DIR` |`${WRKDIR}/target` |Location of the cargo output directory. |`CARGO_DIST_SUBDIR` |[.filename]#rust/crates# |Directory relative to `DISTDIR` where the crate distribution files will be stored. |`CARGO_VENDOR_DIR` |`${WRKSRC}/cargo-crates` |Location of the vendor directory where all crates will be extracted to. Try to keep this under `PATCH_WRKSRC`, so that patches can be applied easily. |`CARGO_USE_GITHUB` |`no` |Enable fetching of crates locked to specific Git commits on GitHub via `GH_TUPLE`. This will try to patch all [.filename]#Cargo.toml# under `WRKDIR` to point to the offline sources instead of fetching them from a Git repository during the build. |`CARGO_USE_GITLAB` |`no` |Same as `CARGO_USE_GITHUB` but for GitLab instances and `GL_TUPLE`. |=== [[cargo-ex1]] .Creating a Port for a Simple Rust Application [example] ==== Creating a Cargo based port is a three stage process. First we need to provide a ports template that fetches the application distribution file: [.programlisting] .... PORTNAME= tokei DISTVERSIONPREFIX= v DISTVERSION= 7.0.2 CATEGORIES= devel MAINTAINER= tobik@FreeBSD.org COMMENT= Display statistics about your code WWW= https://github.com/XAMPPRocky/tokei/ USES= cargo USE_GITHUB= yes GH_ACCOUNT= Aaronepower .include .... Generate an initial [.filename]#distinfo#: [source,shell] .... % make makesum => Aaronepower-tokei-v7.0.2_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/. => Attempting to fetch https://codeload.github.com/Aaronepower/tokei/tar.gz/v7.0.2?dummy=/Aaronepower-tokei-v7.0.2_GH0.tar.gz fetch: https://codeload.github.com/Aaronepower/tokei/tar.gz/v7.0.2?dummy=/Aaronepower-tokei-v7.0.2_GH0.tar.gz: size of remote file is not known Aaronepower-tokei-v7.0.2_GH0.tar.gz 45 kB 239 kBps 00m00s .... Now the distribution file is ready to use and we can go ahead and extract crate dependencies from the bundled [.filename]#Cargo.lock#: [source,shell] .... % make cargo-crates CARGO_CRATES= aho-corasick-0.6.4 \ ansi_term-0.11.0 \ arrayvec-0.4.7 \ atty-0.2.9 \ bitflags-1.0.1 \ byteorder-1.2.2 \ [...] .... The output of this command needs to be pasted directly into the Makefile: [.programlisting] .... PORTNAME= tokei DISTVERSIONPREFIX= v DISTVERSION= 7.0.2 CATEGORIES= devel MAINTAINER= tobik@FreeBSD.org COMMENT= Display statistics about your code WWW= https://github.com/XAMPPRocky/tokei/ USES= cargo USE_GITHUB= yes GH_ACCOUNT= Aaronepower CARGO_CRATES= aho-corasick-0.6.4 \ ansi_term-0.11.0 \ arrayvec-0.4.7 \ atty-0.2.9 \ bitflags-1.0.1 \ byteorder-1.2.2 \ [...] .include .... [.filename]#distinfo# needs to be regenerated to contain all the crate distribution files: [source,shell] .... % make makesum => rust/crates/aho-corasick-0.6.4.tar.gz doesn't seem to exist in /usr/ports/distfiles/. => Attempting to fetch https://crates.io/api/v1/crates/aho-corasick/0.6.4/download?dummy=/rust/crates/aho-corasick-0.6.4.tar.gz rust/crates/aho-corasick-0.6.4.tar.gz 100% of 24 kB 6139 kBps 00m00s => rust/crates/ansi_term-0.11.0.tar.gz doesn't seem to exist in /usr/ports/distfiles/. => Attempting to fetch https://crates.io/api/v1/crates/ansi_term/0.11.0/download?dummy=/rust/crates/ansi_term-0.11.0.tar.gz rust/crates/ansi_term-0.11.0.tar.gz 100% of 16 kB 21 MBps 00m00s => rust/crates/arrayvec-0.4.7.tar.gz doesn't seem to exist in /usr/ports/distfiles/. => Attempting to fetch https://crates.io/api/v1/crates/arrayvec/0.4.7/download?dummy=/rust/crates/arrayvec-0.4.7.tar.gz rust/crates/arrayvec-0.4.7.tar.gz 100% of 22 kB 3237 kBps 00m00s => rust/crates/atty-0.2.9.tar.gz doesn't seem to exist in /usr/ports/distfiles/. => Attempting to fetch https://crates.io/api/v1/crates/atty/0.2.9/download?dummy=/rust/crates/atty-0.2.9.tar.gz rust/crates/atty-0.2.9.tar.gz 100% of 5898 B 81 MBps 00m00s => rust/crates/bitflags-1.0.1.tar.gz doesn't seem to exist in /usr/ports/distfiles/. [...] .... The port is now ready for a test build and further adjustments like creating a plist, writing a description, adding license information, options, etc. as normal. If you are not testing your port in a clean environment like with poudriere, remember to run `make clean` before any testing. ==== [[cargo-ex2]] .Enabling Additional Application Features [example] ==== Some applications define additional features in their [.filename]#Cargo.toml#. They can be compiled in by setting `CARGO_FEATURES` in the port. Here we enable Tokei's `json` and `yaml` features: [.programlisting] .... CARGO_FEATURES= json yaml .... ==== [[cargo-ex4]] .Encoding Application Features As Port Options [example] ==== An example `[features]` section in [.filename]#Cargo.toml# could look like this: [.programlisting] .... [features] pulseaudio_backend = ["librespot-playback/pulseaudio-backend"] portaudio_backend = ["librespot-playback/portaudio-backend"] default = ["pulseaudio_backend"] .... `pulseaudio_backend` is a default feature. It is always enabled unless we explicitly turn off default features by adding `--no-default-features` to `CARGO_FEATURES`. Here we turn the `portaudio_backend` and `pulseaudio_backend` features into port options: [.programlisting] .... CARGO_FEATURES= --no-default-features OPTIONS_DEFINE= PORTAUDIO PULSEAUDIO PORTAUDIO_VARS= CARGO_FEATURES+=portaudio_backend PULSEAUDIO_VARS= CARGO_FEATURES+=pulseaudio_backend .... ==== [[cargo-ex3]] .Listing Crate Licenses [example] ==== Crates have their own licenses. It is important to know what they are when adding a `LICENSE` block to the port (see crossref:makefiles[licenses,Licenses]). The helper target `cargo-crates-licenses` will try to list all the licenses of all crates defined in `CARGO_CRATES`. [source,shell] .... % make cargo-crates-licenses aho-corasick-0.6.4 Unlicense/MIT ansi_term-0.11.0 MIT arrayvec-0.4.7 MIT/Apache-2.0 atty-0.2.9 MIT bitflags-1.0.1 MIT/Apache-2.0 byteorder-1.2.2 Unlicense/MIT [...] .... [NOTE] ====== The license names `make cargo-crates-licenses` outputs are SPDX 2.1 licenses expression which do not match the license names defined in the ports framework. They need to be translated to the names from crossref:makefiles[licenses-license-list,Predefined License List]. ====== ==== [[using-meson]] === Using `meson` For ports that use Meson, define `USES=meson`. [[using-meson-variables]] .Variables for Ports That Use `meson` [cols="1,1", frame="none", options="header"] |=== | Variable | Description |`MESON_ARGS` |Port specific Meson flags to be passed to the `meson` binary. |`MESON_BUILD_DIR` |Path to the build directory relative to `WRKSRC`. Default is `_build`. |=== [[using-meson-example]] .`USES=meson` Example [example] ==== This snippet demonstrates the use of Meson for a port. [.programlisting] .... USES= meson MESON_ARGS= -Dfoo=enabled .... ==== [[using-go]] === Building Go Applications For ports that use Go, define `USES=go`. Refer to crossref:uses[uses-go,`go`] for a list of variables that can be set to control the build process. [[go-ex1]] .Creating a Port for a Go Modules Based Application [example] ==== In most cases, it is sufficient to set the `GO_MODULE` variable to the value specified by the `module` directive in `go.mod`: [.programlisting] .... PORTNAME= hey DISTVERSIONPREFIX= v DISTVERSION= 0.1.4 CATEGORIES= benchmarks MAINTAINER= dmgk@FreeBSD.org COMMENT= Tiny program that sends some load to a web application WWW= https://github.com/rakyll/hey/ LICENSE= APACHE20 LICENSE_FILE= ${WRKSRC}/LICENSE USES= go:modules GO_MODULE= github.com/rakyll/hey PLIST_FILES= bin/hey .include .... If the "easy" way is not adequate or more control over dependencies is needed, the full porting process is described below. Creating a Go-based port is a five-stage process. First we need to provide a ports template that fetches the application distribution file: [.programlisting] .... PORTNAME= ghq DISTVERSIONPREFIX= v DISTVERSION= 0.12.5 CATEGORIES= devel MAINTAINER= tobik@FreeBSD.org COMMENT= Remote repository management made easy WWW= https://github.com/x-motemen/ghq/ USES= go:modules USE_GITHUB= yes GH_ACCOUNT= motemen .include .... Generate an initial [.filename]#distinfo#: [source,shell] .... % make makesum ===> License MIT accepted by the user => motemen-ghq-v0.12.5_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/. => Attempting to fetch https://codeload.github.com/motemen/ghq/tar.gz/v0.12.5?dummy=/motemen-ghq-v0.12.5_GH0.tar.gz fetch: https://codeload.github.com/motemen/ghq/tar.gz/v0.12.5?dummy=/motemen-ghq-v0.12.5_GH0.tar.gz: size of remote file is not known motemen-ghq-v0.12.5_GH0.tar.gz 32 kB 177 kBps 00s .... Now the distribution file is ready to use and we can extract the required Go module dependencies. This step requires having package:ports-mgmt/modules2tuple[] installed: [source,shell] .... % make gomod-vendor [...] GH_TUPLE= \ Songmu:gitconfig:v0.0.2:songmu_gitconfig/vendor/github.com/Songmu/gitconfig \ daviddengcn:go-colortext:186a3d44e920:daviddengcn_go_colortext/vendor/github.com/daviddengcn/go-colortext \ go-yaml:yaml:v2.2.2:go_yaml_yaml/vendor/gopkg.in/yaml.v2 \ golang:net:3ec191127204:golang_net/vendor/golang.org/x/net \ golang:sync:112230192c58:golang_sync/vendor/golang.org/x/sync \ golang:xerrors:3ee3066db522:golang_xerrors/vendor/golang.org/x/xerrors \ motemen:go-colorine:45d19169413a:motemen_go_colorine/vendor/github.com/motemen/go-colorine \ urfave:cli:v1.20.0:urfave_cli/vendor/github.com/urfave/cli .... The output of this command needs to be pasted directly into the Makefile: [.programlisting] .... PORTNAME= ghq DISTVERSIONPREFIX= v DISTVERSION= 0.12.5 CATEGORIES= devel MAINTAINER= tobik@FreeBSD.org COMMENT= Remote repository management made easy WWW= https://github.com/x-motemen/ghq/ USES= go:modules USE_GITHUB= yes GH_ACCOUNT= motemen GH_TUPLE= Songmu:gitconfig:v0.0.2:songmu_gitconfig/vendor/github.com/Songmu/gitconfig \ daviddengcn:go-colortext:186a3d44e920:daviddengcn_go_colortext/vendor/github.com/daviddengcn/go-colortext \ go-yaml:yaml:v2.2.2:go_yaml_yaml/vendor/gopkg.in/yaml.v2 \ golang:net:3ec191127204:golang_net/vendor/golang.org/x/net \ golang:sync:112230192c58:golang_sync/vendor/golang.org/x/sync \ golang:xerrors:3ee3066db522:golang_xerrors/vendor/golang.org/x/xerrors \ motemen:go-colorine:45d19169413a:motemen_go_colorine/vendor/github.com/motemen/go-colorine \ urfave:cli:v1.20.0:urfave_cli/vendor/github.com/urfave/cli .include .... [.filename]#distinfo# needs to be regenerated to contain all the distribution files: [source,shell] .... % make makesum => Songmu-gitconfig-v0.0.2_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/. => Attempting to fetch https://codeload.github.com/Songmu/gitconfig/tar.gz/v0.0.2?dummy=/Songmu-gitconfig-v0.0.2_GH0.tar.gz fetch: https://codeload.github.com/Songmu/gitconfig/tar.gz/v0.0.2?dummy=/Songmu-gitconfig-v0.0.2_GH0.tar.gz: size of remote file is not known Songmu-gitconfig-v0.0.2_GH0.tar.gz 5662 B 936 kBps 00s => daviddengcn-go-colortext-186a3d44e920_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/. => Attempting to fetch https://codeload.github.com/daviddengcn/go-colortext/tar.gz/186a3d44e920?dummy=/daviddengcn-go-colortext-186a3d44e920_GH0.tar.gz fetch: https://codeload.github.com/daviddengcn/go-colortext/tar.gz/186a3d44e920?dummy=/daviddengcn-go-colortext-186a3d44e920_GH0.tar.gz: size of remote file is not known daviddengcn-go-colortext-186a3d44e920_GH0.tar. 4534 B 1098 kBps 00s [...] .... The port is now ready for a test build and further adjustments like creating a plist, writing a description, adding license information, options, etc. as normal. If you are not testing your port in a clean environment like with poudriere, remember to run `make clean` before any testing. ==== [[go-ex2]] .Setting Output Binary Name or Installation Path [example] ==== Some ports need to install the resulting binary under a different name or to a path other than the default `${PREFIX}/bin`. This can be done by using `GO_TARGET` tuple syntax, for example: [.programlisting] .... GO_TARGET= ./cmd/ipfs:ipfs-go .... will install `ipfs` binary as `${PREFIX}/bin/ipfs-go` and [.programlisting] .... GO_TARGET= ./dnscrypt-proxy:${PREFIX}/sbin/dnscrypt-proxy .... will install `dnscrypt-proxy` to `${PREFIX}/sbin`. ==== [[using-cabal]] === Building Haskell Applications with `cabal` For ports that use Cabal, build system defines `USES=cabal`. Refer to crossref:uses[uses-cabal,`cabal`] for a list of variables that can be set to control the build process. [[cabal-ex1]] .Creating a Port for a Hackage-hosted Haskell Application [example] ==== When preparing a Haskell Cabal port, package:devel/hs-cabal-install[] and package:ports-mgmt/hs-cabal2tuple[] programs are required, so make sure they are installed beforehand. First we need to define common ports variables that allow cabal-install to fetch the package distribution file: [.programlisting] .... PORTNAME= ShellCheck DISTVERSION= 0.6.0 CATEGORIES= devel MAINTAINER= haskell@FreeBSD.org COMMENT= Shell script analysis tool WWW= https://www.shellcheck.net/ USES= cabal .include .... This minimal Makefile fetches the distribution file with the `cabal-extract` helper target: [source,shell] .... % make cabal-extract [...] Downloading the latest package list from hackage.haskell.org cabal get ShellCheck-0.6.0 Downloading ShellCheck-0.6.0 Downloaded ShellCheck-0.6.0 Unpacking to ShellCheck-0.6.0/ .... Now that we have ShellCheck.cabal package description file under `${WRKSRC}`, we can use `cabal-configure` to generate the build plan: [source,shell] .... % make cabal-configure [...] Resolving dependencies... Build profile: -w ghc-8.10.7 -O1 In order, the following would be built (use -v for more details): - Diff-0.4.1 (lib) (requires download & build) - OneTuple-0.3.1 (lib) (requires download & build) [...] .... Once done, a list of required dependencies can generated: [source,shell] .... % make make-use-cabal USE_CABAL= QuickCheck-2.12.6.1 \ hashable-1.3.0.0 \ integer-logarithms-1.0.3 \ [...] .... Haskell packages may contain revisions, just like FreeBSD ports. Revisions can affect [.filename]#.cabal# files only. Note additional version numbers after the `_` symbol. Put newly generated `USE_CABAL` list instead of an old one. Finally, [.filename]#distinfo# needs to be regenerated to contain all the distribution files: [source,shell] .... % make makesum => ShellCheck-0.6.0.tar.gz doesn't seem to exist in /usr/local/poudriere/ports/git/distfiles/cabal. => Attempting to fetch https://hackage.haskell.org/package/ShellCheck-0.6.0/ShellCheck-0.6.0.tar.gz ShellCheck-0.6.0.tar.gz 136 kB 642 kBps 00s => QuickCheck-2.12.6.1/QuickCheck-2.12.6.1.tar.gz doesn't seem to exist in /usr/local/poudriere/ports/git/distfiles/cabal. => Attempting to fetch https://hackage.haskell.org/package/QuickCheck-2.12.6.1/QuickCheck-2.12.6.1.tar.gz QuickCheck-2.12.6.1/QuickCheck-2.12.6.1.tar.gz 65 kB 361 kBps 00s [...] .... The port is now ready for a test build and further adjustments like creating a plist, writing a description, adding license information, options, etc. as normal. If you are not testing your port in a clean environment like with poudriere, remember to run `make clean` before any testing. ==== Some Haskell ports install various data files under `share/${PORTNAME}`. For such cases special handling is required on the port side. The port should define the `CABAL_WRAPPER_SCRIPTS` knob listing each executable that is going to use data files. Moreover, in rare cases the program being ported uses data files of other Haskell packages, in which case the `FOO_DATADIR_VARS` comes to the rescue. [[cabal-ex2]] .Handling Data Files in a Haskell Port [example] ==== `devel/hs-profiteur` is a Haskell application that generates a single-page HTML with some content. [.programlisting] .... PORTNAME= profiteur [...] USES= cabal USE_CABAL= OneTuple-0.3.1_2 \ QuickCheck-2.14.2 \ [...] .include .... It installs HTML templates under `share/profiteur`, so we need to add `CABAL_WRAPPER_SCRIPTS` knob: [.programlisting] .... [...] USE_CABAL= OneTuple-0.3.1_2 \ QuickCheck-2.14.2 \ [...] CABAL_WRAPPER_SCRIPTS= ${CABAL_EXECUTABLES} .include .... The program also tries to access the `jquery.js` file, which is a part of `js-jquery-3.3.1` Haskell package. For that file to be found, we need to make the wrapper script to look for `js-jquery` data files in `share/profiteur` too. We use `profiteur_DATADIR_VARS` for this: [.programlisting] .... [...] CABAL_WRAPPER_SCRIPTS= ${CABAL_EXECUTABLES} profiteur_DATADIR_VARS= js-jquery .include .... Now the port will install the actual binary into `libexec/cabal/profiteur` and the script into `bin/profiteur`. ==== There is no easy way to find out a proper value for the `FOO_DATADIR_VARS` knob apart from running the program and checking that everything works. Luckily, the need to use `FOO_DATADIR_VARS` is very rare. Another corner case when porting complex Haskell programs is the presence of VCS dependencies in the `cabal.project` file. [[cabal-ex3]] .Porting Haskell Applications with VCS Dependencies [example] ==== `net-p2p/cardano-node` is an extremely complex piece of software. In its `cabal.project` there are a lot of blocks like this: [.programlisting] .... [...] source-repository-package type: git location: https://github.com/input-output-hk/cardano-crypto tag: f73079303f663e028288f9f4a9e08bcca39a923e [...] .... Dependencies of type `source-repository-package` are automatically pulled in by `cabal` during the build process. Unfortunately, this makes use of the network after the `fetch` stage. This is disallowed by the ports framework. These sources need to be listed in the port's Makefile. The `make-use-cabal` helper target can make it easy for packages hosted on GitHub. Running this target after the usual `cabal-extract` and `cabal-configure` will produce not only the `USE_CABAL` knob, but also `GH_TUPLE`: [source,shell] .... % make make-use-cabal USE_CABAL= Diff-0.4.1 \ Glob-0.10.2_3 \ HUnit-1.6.2.0 \ [...] GH_TUPLE= input-output-hk:cardano-base:0f3a867493059e650cda69e20a5cbf1ace289a57:cardano_base/dist-newstyle/src/cardano-b_-c8db9876882556ed \ input-output-hk:cardano-crypto:f73079303f663e028288f9f4a9e08bcca39a923e:cardano_crypto/dist-newstyle/src/cardano-c_-253fd88117badd8f \ [...] .... It might be useful to separate the `GH_TUPLE` items coming from `make-use-cabal` from the other ones to make it easy to update the port: [.programlisting] .... GH_TUPLE= input-output-hk:cardano-base:0f3a867493059e650cda69e20a5cbf1ace289a57:cardano_base/dist-newstyle/src/cardano-b_-c8db9876882556ed \ input-output-hk:cardano-crypto:f73079303f663e028288f9f4a9e08bcca39a923e:cardano_crypto/dist-newstyle/src/cardano-c_-253fd88117badd8f \ [...] GH_TUPLE+= bitcoin-core:secp256k1:ac83be33d0956faf6b7f61a60ab524ef7d6a473a:secp .... Haskell ports with VCS dependencies also require the following hack for the time being: [.programlisting] .... BINARY_ALIAS= git=true .... ==== [[using-autotools]] == Using GNU Autotools If a port needs any of the GNU Autotools software, add `USES=autoreconf`. See crossref:uses[uses-autoreconf,`autoreconf`] for more information. [[using-gettext]] == Using GNU `gettext` [[using-gettext-basic]] === Basic Usage If the port requires `gettext`, set `USES= gettext`, and the port will inherit a dependency on [.filename]#libintl.so# from package:devel/gettext[]. Other values for `gettext` usage are listed in crossref:uses[uses-gettext,`USES=gettext`]. A rather common case is a port using `gettext` and `configure`. Generally, GNU `configure` should be able to locate `gettext` automatically. [.programlisting] .... USES= gettext GNU_CONFIGURE= yes .... If it ever fails to, hints at the location of `gettext` can be passed in `CPPFLAGS` and `LDFLAGS` using `localbase` as follows: [.programlisting] .... USES= gettext localbase:ldflags GNU_CONFIGURE= yes .... [[using-gettext-optional]] === Optional Usage Some software products allow for disabling NLS. For example, through passing `--disable-nls` to `configure`. In that case, the port must use `gettext` conditionally, depending on the status of the `NLS` option. For ports of low to medium complexity, use this idiom: [.programlisting] .... GNU_CONFIGURE= yes OPTIONS_DEFINE= NLS OPTIONS_SUB= yes NLS_USES= gettext NLS_CONFIGURE_ENABLE= nls .include .... Or using the older way of using options: [.programlisting] .... GNU_CONFIGURE= yes OPTIONS_DEFINE= NLS .include .if ${PORT_OPTIONS:MNLS} USES+= gettext PLIST_SUB+= NLS="" .else CONFIGURE_ARGS+= --disable-nls PLIST_SUB+= NLS="@comment " .endif .include .... The next item on the to-do list is to arrange so that the message catalog files are included in the packing list conditionally. The [.filename]#Makefile# part of this task is already provided by the idiom. It is explained in the section on crossref:plist[plist-sub,advanced [.filename]#pkg-plist# practices]. In a nutshell, each occurrence of `%%NLS%%` in [.filename]#pkg-plist# will be replaced by "`@comment `" if NLS is disabled, or by a null string if NLS is enabled. Consequently, the lines prefixed by `%%NLS%%` will become mere comments in the final packing list if NLS is off; otherwise the prefix will be just left out. Then insert `%%NLS%%` before each path to a message catalog file in [.filename]#pkg-plist#. For example: [.programlisting] .... %%NLS%%share/locale/fr/LC_MESSAGES/foobar.mo %%NLS%%share/locale/no/LC_MESSAGES/foobar.mo .... In high complexity cases, more advanced techniques may be needed, such as crossref:plist[plist-dynamic,dynamic packing list generation]. [[using-gettext-catalog-directories]] === Handling Message Catalog Directories There is a point to note about installing message catalog files. The target directories for them, which reside under [.filename]#LOCALBASE/share/locale#, must not be created and removed by a port. The most popular languages have their respective directories listed in [.filename]#PORTSDIR/Templates/BSD.local.dist#. The directories for many other languages are governed by the package:devel/gettext[] port. Consult its [.filename]#pkg-plist# and see whether the port is going to install a message catalog file for a unique language. [[using-perl]] == Using Perl If `MASTER_SITES` is set to `CPAN`, the correct subdirectory is usually selected automatically. If the default subdirectory is wrong, `CPAN/Module` can be used to change it. `MASTER_SITES` can also be set to the old `MASTER_SITE_PERL_CPAN`, then the preferred value of `MASTER_SITE_SUBDIR` is the top-level hierarchy name. For example, the recommended value for `p5-Module-Name` is `Module`. The top-level hierarchy can be examined at https://cpan.org/modules/by-module/[cpan.org]. This keeps the port working when the author of the module changes. The exception to this rule is when the relevant directory does not exist or the distfile does not exist in that directory. In such case, using author's id as `MASTER_SITE_SUBDIR` is allowed. The `CPAN:AUTHOR` macro can be used, which will be translated to the hashed author directory. For example, `CPAN:AUTHOR` will be converted to `authors/id/A/AU/AUTHOR`. When a port needs Perl support, it must set `USES=perl5` with the optional `USE_PERL5` described in crossref:uses[uses-perl5,the perl5 USES description]. [[using-perl-variables]] .Read-Only Variables for Ports That Use Perl [cols="1,1", frame="none", options="header"] |=== | Read only variables | Means |`PERL` |The full path of the Perl 5 interpreter, either in the system or installed from a port, but without the version number. Use this when the software needs the path to the Perl interpreter. To replace "``#!``"lines in scripts, use crossref:uses[uses-shebangfix,`shebangfix`]. |`PERL_VERSION` |The full version of Perl installed (for example, `5.8.9`). |`PERL_LEVEL` |The installed Perl version as an integer of the form `MNNNPP` (for example, `500809`). |`PERL_ARCH` |Where Perl stores architecture dependent libraries. Defaults to `${ARCH}-freebsd`. |`PERL_PORT` |Name of the Perl port that is installed (for example, `perl5`). |`SITE_PERL` |Directory name where site specific Perl packages go. This value is added to `PLIST_SUB`. |=== [NOTE] ==== Ports of Perl modules which do not have an official website must link to `cpan.org` in the WWW line of [.filename]#Makefile#. The preferred URL form is `https://search.cpan.org/dist/Module-Name/` (including the trailing slash). ==== [NOTE] ==== Do not use `${SITE_PERL}` in dependency declarations. Doing so assumes that [.filename]#perl5.mk# has been included, which is not always true. Ports depending on this port will have incorrect dependencies if this port's files move later in an upgrade. The right way to declare Perl module dependencies is shown in the example below. ==== [[use-perl-dependency-example]] .Perl Dependency Example [example] ==== [.programlisting] .... p5-IO-Tee>=0.64:devel/p5-IO-Tee .... ==== For Perl ports that install manual pages, the macro `PERL5_MAN3` and `PERL5_MAN1` can be used inside [.filename]#pkg-plist#. For example, [.programlisting] .... lib/perl5/5.14/man/man1/event.1.gz lib/perl5/5.14/man/man3/AnyEvent::I3.3.gz .... can be replaced with [.programlisting] .... %%PERL5_MAN1%%/event.1.gz %%PERL5_MAN3%%/AnyEvent::I3.3.gz .... [NOTE] ==== There are no `PERL5_MAN_x_` macros for the other sections (_x_ in `2` and `4` to `9`) because those get installed in the regular directories. ==== [[use-perl-ex-build]] .A Port Which Only Requires Perl to Build [example] ==== As the default USE_PERL5 value is build and run, set it to: [.programlisting] .... USES= perl5 USE_PERL5= build .... ==== [[use-perl-ex-patch]] .A Port Which Also Requires Perl to Patch [example] ==== From time to time, using man:sed[1] for patching is not enough. When using man:perl[1] is easier, use: [.programlisting] .... USES= perl5 USE_PERL5= patch build run .... ==== [[use-perl-ex-configure]] .A Perl Module Which Needs `ExtUtils::MakeMaker` to Build [example] ==== Most Perl modules come with a [.filename]#Makefile.PL# configure script. In this case, set: [.programlisting] .... USES= perl5 USE_PERL5= configure .... ==== [[use-perl-ex-modbuild]] .A Perl Module Which Needs `Module::Build` to Build [example] ==== When a Perl module comes with a [.filename]#Build.PL# configure script, it can require Module::Build, in which case, set [.programlisting] .... USES= perl5 USE_PERL5= modbuild .... If it instead requires Module::Build::Tiny, set [.programlisting] .... USES= perl5 USE_PERL5= modbuildtiny .... ==== [[using-x11]] == Using X11 [[x11-variables]] === X.Org Components The X11 implementation available in The Ports Collection is X.Org. If the application depends on X components, add `USES= xorg` and set `USE_XORG` to the list of required components. A full list can be found in crossref:uses[uses-xorg,`xorg`]. The Mesa Project is an effort to provide free OpenGL implementation. To specify a dependency on various components of this project, use `USES= gl` and `USE_GL`. See crossref:uses[uses-gl,`gl`] for a full list of available components. For backwards compatibility, the value of `yes` maps to `glu`. [[use-xorg-example]] .`USE_XORG` Example [example] ==== [.programlisting] .... USES= gl xorg USE_GL= glu USE_XORG= xrender xft xkbfile xt xaw .... ==== [[using-xorg-variables]] .Variables for Ports That Use X [cols="1,1", frame="none"] |=== |`USES= imake` |The port uses `imake`. |`XMKMF` |Set to the path of `xmkmf` if not in the `PATH`. Defaults to `xmkmf -a`. |=== [[using-x11-vars]] .Using X11-Related Variables [example] ==== [.programlisting] .... # Use some X11 libraries USES= xorg USE_XORG= x11 xpm .... ==== [[x11-motif]] === Ports That Require Motif If the port requires a Motif library, define `USES= motif` in the [.filename]#Makefile#. Default Motif implementation is package:x11-toolkits/open-motif[]. Users can choose package:x11-toolkits/lesstif[] instead by setting `WANT_LESSTIF` in their [.filename]#make.conf#. Similarly package:x11-toolkits/open-motif-devel[] can be chosen by setting `WANT_OPEN_MOTIF_DEVEL` in [.filename]#make.conf#. `MOTIFLIB` will be set by [.filename]#motif.mk# to reference the appropriate Motif library. Please patch the source of the port to use `${MOTIFLIB}` wherever the Motif library is referenced in the original [.filename]#Makefile# or [.filename]#Imakefile#. There are two common cases: * If the port refers to the Motif library as `-lXm` in its [.filename]#Makefile# or [.filename]#Imakefile#, substitute `${MOTIFLIB}` for it. * If the port uses `XmClientLibs` in its [.filename]#Imakefile#, change it to `${MOTIFLIB} ${XTOOLLIB} ${XLIB}`. Note that `MOTIFLIB` (usually) expands to `-L/usr/local/lib -lXm -lXp` or `/usr/local/lib/libXm.a`, so there is no need to add `-L` or `-l` in front. [[x11-fonts]] === X11 Fonts If the port installs fonts for the X Window System, put them in [.filename]#LOCALBASE/lib/X11/fonts/local#. [[x11-fake-display]] === Getting a Fake `DISPLAY` with Xvfb Some applications require a working X11 display for compilation to succeed. This poses a problem for machines that operate headless. When this variable is used, the build infrastructure will start the virtual framebuffer X server. The working `DISPLAY` is then passed to the build. See crossref:uses[uses-display,`USES=display`] for the possible arguments. [.programlisting] .... USES= display .... [[desktop-entries]] === Desktop Entries Desktop entries (https://standards.freedesktop.org/desktop-entry-spec/latest/[a Freedesktop standard]) provide a way to automatically adjust desktop features when a new program is installed, without requiring user intervention. For example, newly-installed programs automatically appear in the application menus of compatible desktop environments. Desktop entries originated in the GNOME desktop environment, but are now a standard and also work with KDE and Xfce. This bit of automation provides a real benefit to the user, and desktop entries are encouraged for applications which can be used in a desktop environment. [[desktop-entries-predefined]] ==== Using Predefined [.filename]#.desktop# Files Ports that include predefined [.filename]#*.desktop# must include those files in [.filename]#pkg-plist# and install them in the [.filename]#$LOCALBASE/share/applications# directory. The crossref:makefiles[install-macros,`INSTALL_DATA` macro] is useful for installing these files. [[updating-desktop-database]] ==== Updating Desktop Database If a port has a MimeType entry in its [.filename]#portname.desktop#, the desktop database must be updated after install and deinstall. To do this, define `USES`= desktop-file-utils. [[desktop-entries-macro]] ==== Creating Desktop Entries with `DESKTOP_ENTRIES` Desktop entries can be easily created for applications by using `DESKTOP_ENTRIES`. A file named [.filename]#name.desktop# will be created, installed, and added to [.filename]#pkg-plist# automatically. Syntax is: [.programlisting] .... DESKTOP_ENTRIES= "NAME" "COMMENT" "ICON" "COMMAND" "CATEGORY" StartupNotify .... The list of possible categories is available on the https://standards.freedesktop.org/menu-spec/latest/apa.html[Freedesktop website]. `StartupNotify` indicates whether the application is compatible with _startup notifications_. These are typically a graphic indicator like a clock that appear at the mouse pointer, menu, or panel to give the user an indication when a program is starting. A program that is compatible with startup notifications clears the indicator after it has started. Programs that are not compatible with startup notifications would never clear the indicator (potentially confusing and infuriating the user), and must have `StartupNotify` set to `false` so the indicator is not shown at all. Example: [.programlisting] .... DESKTOP_ENTRIES= "ToME" "Roguelike game based on JRR Tolkien's work" \ "${DATADIR}/xtra/graf/tome-128.png" \ "tome -v -g" "Application;Game;RolePlaying;" \ false .... `DESKTOP_ENTRIES` are installed in the directory pointed to by the `DESKTOPDIR` variable. `DESKTOPDIR` defaults to [.filename]#${PREFIX}/share/applications# [[using-gnome]] == Using GNOME [[using-gnome-introduction]] === Introduction This chapter explains the GNOME framework as used by ports. The framework can be loosely divided into the base components, GNOME desktop components, and a few special macros that simplify the work of port maintainers. [[use-gnome]] === Using `USE_GNOME` Adding this variable to the port allows the use of the macros and components defined in [.filename]#bsd.gnome.mk#. The code in [.filename]#bsd.gnome.mk# adds the needed build-time, run-time or library dependencies or the handling of special files. GNOME applications under FreeBSD use the `USE_GNOME` infrastructure. Include all the needed components as a space-separated list. The `USE_GNOME` components are divided into these virtual lists: basic components, GNOME 3 components and legacy components. If the port needs only GTK3 libraries, this is the shortest way to define it: [.programlisting] .... USE_GNOME= gtk30 .... `USE_GNOME` components automatically add the dependencies they need. -Please see crossref:special[gnome-components] for an exhaustive list of all `USE_GNOME` components and which other components they imply and their dependencies. +Please see crossref:special[gnome-components, GNOME Components] for an exhaustive list of all `USE_GNOME` components and which other components they imply and their dependencies. Here is an example [.filename]#Makefile# for a GNOME port that uses many of the techniques outlined in this document. Please use it as a guide for creating new ports. [.programlisting] .... PORTNAME= regexxer DISTVERSION= 0.10 CATEGORIES= devel textproc gnome MASTER_SITES= GNOME MAINTAINER= kwm@FreeBSD.org COMMENT= Interactive tool for performing search and replace operations WWW= http://regexxer.sourceforge.net/ USES= gettext gmake localbase:ldflags pathfix pkgconfig tar:xz GNU_CONFIGURE= yes USE_GNOME= gnomeprefix intlhack gtksourceviewmm3 GLIB_SCHEMAS= org.regexxer.gschema.xml .include .... [NOTE] ==== The `USE_GNOME` macro without any arguments does not add any dependencies to the port. `USE_GNOME` cannot be set after [.filename]#bsd.port.pre.mk#. ==== [[using-gnome-variables]] === Variables This section explains which macros are available and how they are used. Like they are used in the above example. -The crossref:special[gnome-components] has a more in-depth explanation. +The crossref:special[gnome-components, GNOME Components] has a more in-depth explanation. `USE_GNOME` has to be set for these macros to be of use. `GLIB_SCHEMAS`:: List of all the glib schema files the port installs. The macro will add the files to the port plist and handle the registration of these files on install and deinstall. + The glib schema files are written in XML and end with the [.filename]#gschema.xml# extension. They are installed in the [.filename]#share/glib-2.0/schemas/# directory. These schema files contain all application config values with their default settings. The actual database used by the applications is built by glib-compile-schema, which is run by the `GLIB_SCHEMAS` macro. + [.programlisting] .... GLIB_SCHEMAS=foo.gschema.xml .... + [NOTE] ==== Do not add glib schemas to the [.filename]#pkg-plist#. If they are listed in [.filename]#pkg-plist#, they will not be registered and the applications might not work properly. ==== `GCONF_SCHEMAS`:: List all the gconf schema files. The macro will add the schema files to the port plist and will handle their registration on install and deinstall. + GConf is the XML-based database that virtually all GNOME applications use for storing their settings. These files are installed into the [.filename]#etc/gconf/schemas# directory. This database is defined by installed schema files that are used to generate [.filename]#%gconf.xml# key files. For each schema file installed by the port, there must be an entry in the [.filename]#Makefile#: + [.programlisting] .... GCONF_SCHEMAS=my_app.schemas my_app2.schemas my_app3.schemas .... + [NOTE] ==== Gconf schemas are listed in the `GCONF_SCHEMAS` macro rather than [.filename]#pkg-plist#. If they are listed in [.filename]#pkg-plist#, they will not be registered and the applications might not work properly. ==== `INSTALLS_OMF`:: Open Source Metadata Framework (OMF) files are commonly used by GNOME 2 applications. These files contain the application help file information, and require special processing by ScrollKeeper/rarian. To properly register OMF files when installing GNOME applications from packages, make sure that `omf` files are listed in `pkg-plist` and that the port [.filename]#Makefile# has `INSTALLS_OMF` defined: + [.programlisting] .... INSTALLS_OMF=yes .... + When set, [.filename]#bsd.gnome.mk# automatically scans [.filename]#pkg-plist# and adds appropriate `@exec` and `@unexec` directives for each [.filename]#.omf# to track in the OMF registration database. [[gnome-components]] == GNOME Components For further help with a GNOME port, look at some of the link:https://ports.FreeBSD.org[existing ports] for examples. The link:https://www.FreeBSD.org/gnome/[FreeBSD GNOME page] has contact information if more help is needed. The components are divided into GNOME components that are currently in use and legacy components. If the component supports argument, they are listed between parenthesis in the description. The first is the default. "Both" is shown if the component defaults to adding to both build and run dependencies. [[gnome-components-list]] .GNOME Components [cols="1,1,1", options="header"] |=== | Component | Associated program | Description |`atk` |accessibility/atk |Accessibility toolkit (ATK) |`atkmm` |accessibility/atkmm |c++ bindings for atk |`cairo` |graphics/cairo |Vector graphics library with cross-device output support |`cairomm` |graphics/cairomm |c++ bindings for cairo |`dconf` |devel/dconf |Configuration database system (both, build, run) |`evolutiondataserver3` |databases/evolution-data-server |Data backends for the Evolution integrated mail/PIM suite |`gdkpixbuf2` |graphics/gdk-pixbuf2 |Graphics library for GTK+ |`glib20` |devel/glib20 |GNOME core library `glib20` |`glibmm` |devel/glibmm |c++ bindings for glib20 |`gnomecontrolcenter3` |sysutils/gnome-control-center |GNOME 3 Control Center |`gnomedesktop3` |x11/gnome-desktop |GNOME 3 desktop UI library |`gsound` |audio/gsound |GObject library for playing system sounds (both, build, run) |`gtk-update-icon-cache` |graphics/gtk-update-icon-cache |Gtk-update-icon-cache utility from the Gtk+ toolkit |`gtk20` |x11-toolkits/gtk20 |Gtk+ 2 toolkit |`gtk30` |x11-toolkits/gtk30 |Gtk+ 3 toolkit |`gtkmm20` |x11-toolkits/gtkmm20 |c++ bindings 2.0 for the gtk20 toolkit |`gtkmm24` |x11-toolkits/gtkmm24 |c++ bindings 2.4 for the gtk20 toolkit |`gtkmm30` |x11-toolkits/gtkmm30 |c++ bindings 3.0 for the gtk30 toolkit |`gtksourceview2` |x11-toolkits/gtksourceview2 |Widget that adds syntax highlighting to GtkTextView |`gtksourceview3` |x11-toolkits/gtksourceview3 |Text widget that adds syntax highlighting to the GtkTextView widget |`gtksourceviewmm3` |x11-toolkits/gtksourceviewmm3 |c++ bindings for the gtksourceview3 library |`gvfs` |devel/gvfs |GNOME virtual file system |`intltool` |textproc/intltool |Tool for internationalization (also see intlhack) |`introspection` |devel/gobject-introspection |Basic introspection bindings and tools to generate introspection bindings. Most of the time :build is enough, :both/:run is only need for applications that use introspection bindings. (both, build, run) |`libgda5` |databases/libgda5 |Provides uniform access to different kinds of data sources |`libgda5-ui` |databases/libgda5-ui |UI library from the libgda5 library |`libgdamm5` |databases/libgdamm5 |c++ bindings for the libgda5 library |`libgsf` |devel/libgsf |Extensible I/O abstraction for dealing with structured file formats |`librsvg2` |graphics/librsvg2 |Library for parsing and rendering SVG vector-graphic files |`libsigc++20` |devel/libsigc++20 |Callback Framework for C++ |`libxml++26` |textproc/libxml++26 |c++ bindings for the libxml2 library |`libxml2` |textproc/libxml2 |XML parser library (both, build, run) |`libxslt` |textproc/libxslt |XSLT C library (both, build, run) |`metacity` |x11-wm/metacity |Window manager from GNOME |`nautilus3` |x11-fm/nautilus |GNOME file manager |`pango` |x11-toolkits/pango |Open-source framework for the layout and rendering of i18n text |`pangomm` |x11-toolkits/pangomm |c++ bindings for the pango library |`py3gobject3` |devel/py3-gobject3 |Python 3, GObject 3.0 bindings |`pygobject3` |devel/py-gobject3 |Python 2, GObject 3.0 bindings |`vte3` |x11-toolkits/vte3 |Terminal widget with improved accessibility and I18N support |=== [[gnome-components-macro]] .GNOME Macro Components [cols="1,1", options="header"] |=== | Component | Description |`gnomeprefix` |Supply `configure` with some default locations. |`intlhack` |Same as intltool, but patches to make sure [.filename]#share/locale/# is used. Please only use when `intltool` alone is not enough. |`referencehack` |This macro is there to help splitting of the API or reference documentation into its own port. |=== [[gnome-components-legacy]] .GNOME Legacy Components [cols="1,1,1", options="header"] |=== | Component | Associated program | Description |`atspi` |accessibility/at-spi |Assistive Technology Service Provider Interface |`esound` |audio/esound |Enlightenment sound package |`gal2` |x11-toolkits/gal2 |Collection of widgets taken from GNOME 2 gnumeric |`gconf2` |devel/gconf2 |Configuration database system for GNOME 2 |`gconfmm26` |devel/gconfmm26 |c++ bindings for gconf2 |`gdkpixbuf` |graphics/gdk-pixbuf |Graphics library for GTK+ |`glib12` |devel/glib12 |glib 1.2 core library |`gnomedocutils` |textproc/gnome-doc-utils |GNOME doc utils |`gnomemimedata` |misc/gnome-mime-data |MIME and Application database for GNOME 2 |`gnomesharp20` |x11-toolkits/gnome-sharp20 |GNOME 2 interfaces for the .NET runtime |`gnomespeech` |accessibility/gnome-speech |GNOME 2 text-to-speech API |`gnomevfs2` |devel/gnome-vfs |GNOME 2 Virtual File System |`gtk12` |x11-toolkits/gtk12 |Gtk+ 1.2 toolkit |`gtkhtml3` |www/gtkhtml3 |Lightweight HTML rendering/printing/editing engine |`gtkhtml4` |www/gtkhtml4 |Lightweight HTML rendering/printing/editing engine |`gtksharp20` |x11-toolkits/gtk-sharp20 |GTK+ and GNOME 2 interfaces for the .NET runtime |`gtksourceview` |x11-toolkits/gtksourceview |Widget that adds syntax highlighting to GtkTextView |`libartgpl2` |graphics/libart_lgpl |Library for high-performance 2D graphics |`libbonobo` |devel/libbonobo |Component and compound document system for GNOME 2 |`libbonoboui` |x11-toolkits/libbonoboui |GUI frontend to the libbonobo component of GNOME 2 |`libgda4` |databases/libgda4 |Provides uniform access to different kinds of data sources |`libglade2` |devel/libglade2 |GNOME 2 glade library |`libgnome` |x11/libgnome |Libraries for GNOME 2, a GNU desktop environment |`libgnomecanvas` |graphics/libgnomecanvas |Graphics library for GNOME 2 |`libgnomekbd` |x11/libgnomekbd |GNOME 2 keyboard shared library |`libgnomeprint` |print/libgnomeprint |Gnome 2 print support library |`libgnomeprintui` |x11-toolkits/libgnomeprintui |Gnome 2 print support library |`libgnomeui` |x11-toolkits/libgnomeui |Libraries for the GNOME 2 GUI, a GNU desktop environment |`libgtkhtml` |www/libgtkhtml |Lightweight HTML rendering/printing/editing engine |`libgtksourceviewmm` |x11-toolkits/libgtksourceviewmm |c++ binding of GtkSourceView |`libidl` |devel/libIDL |Library for creating trees of CORBA IDL file |`libsigc++12` |devel/libsigc++12 |Callback Framework for C++ |`libwnck` |x11-toolkits/libwnck |Library used for writing pagers and taskslists |`libwnck3` |x11-toolkits/libwnck3 |Library used for writing pagers and taskslists |`orbit2` |devel/ORBit2 |High-performance CORBA ORB with support for the C language |`pygnome2` |x11-toolkits/py-gnome2 |Python bindings for GNOME 2 |`pygobject` |devel/py-gobject |Python 2, GObject 2.0 bindings |`pygtk2` |x11-toolkits/py-gtk2 |Set of Python bindings for GTK+ |`pygtksourceview` |x11-toolkits/py-gtksourceview |Python bindings for GtkSourceView 2 |`vte` |x11-toolkits/vte |Terminal widget with improved accessibility and I18N support |=== [[gnome-components-deprecated]] .Deprecated Components: Do Not Use [cols="1,1", options="header"] |=== | Component | Description |`pangox-compat` |pangox-compat has been deprecated and split off from the pango package. |=== [[using-qt]] == Using Qt [NOTE] ==== For ports that are part of Qt itself, see crossref:uses[uses-qt-dist,`qt-dist`]. ==== [[qt-common]] === Ports That Require Qt The Ports Collection provides support for Qt 5 and Qt 6 with `USES+=qt:5` and `USES+=qt:6` respectively. Set `USE_QT` to the list of required Qt components (libraries, tools, plugins). The Qt framework exports a number of variables which can be used by ports, some of them listed below: [[using-qt-variables]] .Variables Provided to Ports That Use Qt [cols="1,1", frame="none"] |=== |`QMAKE` |Full path to `qmake` binary. |`LRELEASE` |Full path to `lrelease` utility. |`MOC` |Full path to `moc`. |`RCC` |Full path to `rcc`. |`UIC` |Full path to `uic`. |`QT_INCDIR` |Qt include directory. |`QT_LIBDIR` |Qt libraries path. |`QT_PLUGINDIR` |Qt plugins path. |=== [[qt-components]] === Component Selection Individual Qt tool and library dependencies must be specified in `USE_QT`. Every component can be suffixed with `_build` or `_run`, the suffix indicating whether the dependency on the component is at buildtime or runtime. If unsuffixed, the component will be depended on at both build- and runtime. Usually, library components are specified unsuffixed, tool components are mostly specified with the `_build` suffix and plugin components are specified with the `_run` suffix. The most commonly used components are listed below (all available components are listed in `_USE_QT_ALL`, which is generated from `_USE_QT_COMMON` and `_USE_QT[56]_ONLY` in [.filename]#/usr/ports/Mk/Uses/qt.mk#): [[using-qt-library-list]] .Available Qt Library Components [cols="1,1", frame="none", options="header"] |=== | Name | Description |`3d` |Qt3D module |`5compat` |Qt 5 compatibility module for Qt 6 |`assistant` |Qt 5 documentation browser |`base` |Qt 6 base module |`canvas3d` |Qt canvas3d module |`charts` |Qt 5 charts module |`concurrent` |Qt multi-threading module |`connectivity` |Qt connectivity (Bluetooth/NFC) module |`core` |Qt core non-graphical module |`datavis3d` |Qt 5 3D data visualization module |`dbus` |Qt D-Bus inter-process communication module |`declarative` |Qt declarative framework for dynamic user interfaces |`designer` |Qt 5 graphical user interface designer |`diag` |Tool for reporting diagnostic information about Qt and its environment |`doc` |Qt 5 documentation |`examples` |Qt 5 examples sourcecode |`gamepad` |Qt 5 Gamepad Module |`graphicaleffects` |Qt Quick graphical effects |`gui` |Qt graphical user interface module |`help` |Qt online help integration module |`l10n` |Qt localized messages |`languageserver` |Qt 6 Language Server Protocol implementation |`linguist` |Qt 5 translation tool |`location` |Qt location module |`lottie` |Qt 6 QML API for rendering graphics and animations |`multimedia` |Qt audio, video, radio and camera support module |`network` |Qt network module |`networkauth` |Qt network auth module |`opengl` |Qt 5-compatible OpenGL support module |`paths` |Command line client to QStandardPaths |`phonon4` |KDE multimedia framework |`pixeltool` |Qt 5 screen magnifier |`plugininfo` |Qt 5 plugin metadata dumper |`positioning` |Qt 6 positioning API from sources such as satellite, wifi or text files. |`printsupport` |Qt print support module |`qdbus` |Qt command-line interface to D-Bus |`qdbusviewer` |Qt 5 graphical interface to D-Bus |`qdoc` |Qt documentation generator |`qdoc-data` |QDoc configuration files |`qev` |Qt QWidget events introspection tool |`qmake` |Qt Makefile generator |`quickcontrols` |Set of controls for building complete interfaces in Qt Quick |`quickcontrols2` |Set of controls for building complete interfaces in Qt Quick |`remoteobjects` |Qt 5 SXCML module |`script` |Qt 4-compatible scripting module |`scripttools` |Qt Script additional components |`scxml` |Qt 5 SXCML module |`sensors` |Qt sensors module |`serialbus` |Qt functions to access industrial bus systems |`serialport` |Qt functions to access serial ports |`shadertools` |Qt 6 tools for the cross-platform Qt shader pipeline |`speech` |Accessibility features for Qt5 |`sql` |Qt SQL database integration module |`sql-ibase` |Qt InterBase/Firebird database plugin |`sql-mysql` |Qt MySQL database plugin |`sql-odbc` |Qt Open Database Connectivity plugin |`sql-pgsql` |Qt PostgreSQL database plugin |`sql-sqlite2` |Qt SQLite 2 database plugin |`sql-sqlite3` |Qt SQLite 3 database plugin |`sql-tds` |Qt TDS Database Connectivity database plugin |`svg` |Qt SVG support module |`testlib` |Qt unit testing module |`tools` |Qt 6 assorted tools |`translations` |Qt 6 translation module |`uiplugin` |Custom Qt widget plugin interface for Qt Designer |`uitools` |Qt Designer UI forms support module |`virtualkeyboard` |Qt 5 Virtual Keyboard Module |`wayland` |Qt 5 wrapper for Wayland |`webchannel` |Qt 5 library for integration of C++/QML with HTML/js clients |`webengine` |Qt 5 library to render web content |`webkit` |QtWebKit with a more modern WebKit code base |`websockets` |Qt implementation of WebSocket protocol |`websockets-qml` |Qt implementation of WebSocket protocol (QML bindings) |`webview` |Qt component for displaying web content |`widgets` |Qt C++ widgets module |`x11extras` |Qt platform-specific features for X11-based systems |`xml` |Qt SAX and DOM implementations |`xmlpatterns` |Qt support for XPath, XQuery, XSLT and XML Schema |=== To determine the libraries an application depends on, run `ldd` on the main executable after a successful compilation. [[using-qt-tools-list]] .Available Qt Tool Components [cols="1,1", frame="none", options="header"] |=== | Name | Description |`buildtools` |build tools (`moc`, `rcc`), needed for almost every Qt application. |`linguisttools` |localization tools: `lrelease`, `lupdate` |`qmake` |Makefile generator/build utility |=== [[using-qt-plugins-list]] .Available Qt Plugin Components [cols="1,1", frame="none", options="header"] |=== | Name | Description |`imageformats` |plugins for TGA, TIFF, and MNG image formats |=== [[qt5-components-example]] .Selecting Qt 5 Components [example] ==== In this example, the ported application uses the Qt 5 graphical user interface library, the Qt 5 core library, all of the Qt 5 code generation tools and Qt 5's Makefile generator. Since the `gui` library implies a dependency on the core library, `core` does not need to be specified. The Qt 5 code generation tools `moc`, `uic` and `rcc`, as well as the Makefile generator `qmake` are only needed at buildtime, thus they are specified with the `_build` suffix: [.programlisting] .... USES= qt:5 USE_QT= gui buildtools_build qmake_build .... ==== [[using-qmake]] === Using `qmake` If the application provides a qmake project file ([.filename]#*.pro#), define `USES= qmake` along with `USE_QT`. `USES= qmake` already implies a build dependency on qmake, therefore the qmake component can be omitted from `USE_QT`. Similar to crossref:special[using-cmake,CMake], qmake supports out-of-source builds, which can be enabled by specifying the `outsource` argument (see crossref:special[using-qmake-example,`USES= qmake` example]). -Also see crossref:special[using-qmake-arguments]. +Also see crossref:special[using-qmake-arguments,.Possible Arguments for `USES qmake`]. [[using-qmake-arguments]] .Possible Arguments for `USES= qmake` [cols="1,1", frame="none", options="header"] |=== | Variable | Description |`no_configure` |Do not add the configure target. This is implied by `HAS_CONFIGURE=yes` and `GNU_CONFIGURE=yes`. It is required when the build only needs the environment setup from `USES= qmake`, but otherwise runs `qmake` on its own. |`no_env` |Suppress modification of the configure and make environments. It is only required when `qmake` is used to configure the software and the build fails to understand the environment setup by `USES= qmake`. |`norecursive` |Do not pass the `-recursive` argument to `qmake`. |`outsource` |Perform an out-of-source build. |=== [[using-qmake-variables]] .Variables for Ports That Use `qmake` [cols="1,1", frame="none", options="header"] |=== | Variable | Description |`QMAKE_ARGS` |Port specific qmake flags to be passed to the `qmake` binary. |`QMAKE_ENV` |Environment variables to be set for the `qmake` binary. The default is `${CONFIGURE_ENV}`. |`QMAKE_SOURCE_PATH` |Path to qmake project files ([.filename]#.pro#). The default is `${WRKSRC}` if an out-of-source build is requested, empty otherwise. |=== When using `USES= qmake`, these settings are deployed: [.programlisting] .... CONFIGURE_ARGS+= --with-qt-includes=${QT_INCDIR} \ --with-qt-libraries=${QT_LIBDIR} \ --with-extra-libs=${LOCALBASE}/lib \ --with-extra-includes=${LOCALBASE}/include CONFIGURE_ENV+= QTDIR="${QT_PREFIX}" QMAKE="${QMAKE}" \ MOC="${MOC}" RCC="${RCC}" UIC="${UIC}" \ QMAKESPEC="${QMAKESPEC}" PLIST_SUB+= QT_INCDIR=${QT_INCDIR_REL} \ QT_LIBDIR=${QT_LIBDIR_REL} \ QT_PLUGINDIR=${QT_PLUGINDIR_REL} .... Some configure scripts do not support the arguments above. To suppress modification of `CONFIGURE_ENV` and `CONFIGURE_ARGS`, set `USES= qmake:no_env`. [[using-qmake-example]] .`USES= qmake` Example [example] ==== This snippet demonstrates the use of qmake for a Qt 5 port: [.programlisting] .... USES= qmake:outsource qt:5 USE_QT= buildtools_build .... ==== Qt applications are often written to be cross-platform and often X11/Unix is not the platform they are developed on, which in turn leads to certain loose ends, like: * _Missing additional include paths._ Many applications come with system tray icon support, but neglect to look for includes and/or libraries in the X11 directories. To add directories to `qmake`'s include and library search paths via the command line, use: + [.programlisting] .... QMAKE_ARGS+= INCLUDEPATH+=${LOCALBASE}/include \ LIBS+=-L${LOCALBASE}/lib .... * _Bogus installation paths._ Sometimes data such as icons or .desktop files are by default installed into directories which are not scanned by XDG-compatible applications. package:editors/texmaker[] is an example for this - look at [.filename]#patch-texmaker.pro# in the [.filename]#files# directory of that port for a template on how to remedy this directly in the `qmake` project file. [[using-kde]] == Using KDE [[kde5-variables]] === KDE Variable Definitions If the application depends on KDE, set `USES+=kde:5` and `USE_KDE` to the list of required components. `_build` and `_run` suffixes can be used to force components dependency type (for example, `baseapps_run`). If no suffix is set, a default dependency type will be used. To force both types, add the component twice with both suffixes (for example, `ecm_build ecm_run`). Available components are listed below (up-to-date components are also listed in [.filename]#/usr/ports/Mk/Uses/kde.mk#): [[using-kde-components]] .Available KDE Components [cols="1,1", frame="none", options="header"] |=== | Name | Description |`activities` |KF5 runtime and library to organize work in separate activities |`activities-stats` |KF5 statistics for activities |`activitymanagerd` |System service to manage user's activities, track the usage patterns |`akonadi` |Storage server for KDE-Pim |`akonadicalendar` |Akonadi Calendar Integration |`akonadiconsole` |Akonadi management and debugging console |`akonadicontacts` |Libraries and daemons to implement Contact Management in Akonadi |`akonadiimportwizard` |Import data from other mail clients to KMail |`akonadimime` |Libraries and daemons to implement basic email handling |`akonadinotes` |KDE library for accessing mail storages in MBox format |`akonadisearch` |Libraries and daemons to implement searching in Akonadi |`akregator` |A Feed Reader by KDE |`alarmcalendar` |KDE API for KAlarm alarms |`apidox` |KF5 API Documentation Tools |`archive` |KF5 library that provides classes for handling archive formats |`attica` |Open Collaboration Services API library KDE5 version |`attica5` |Open Collaboration Services API library KDE5 version |`auth` |KF5 abstraction to system policy and authentication features |`baloo` |KF5 Framework for searching and managing user metadata |`baloo-widgets` |BalooWidgets library |`baloo5` |KF5 Framework for searching and managing user metadata |`blog` |KDE API for weblogging access |`bookmarks` |KF5 library for bookmarks and the XBEL format |`breeze` |Plasma5 artwork, styles and assets for the Breeze visual style |`breeze-gtk` |Plasma5 Breeze visual style for Gtk |`breeze-icons` |Breeze icon theme for KDE |`calendarcore` |KDE calendar access library |`calendarsupport` |Calendar support libraries for KDEPim |`calendarutils` |KDE utility and user interface functions for accessing calendar |`codecs` |KF5 library for string manipulation |`completion` |KF5 text completion helpers and widgets |`config` |KF5 widgets for configuration dialogs |`configwidgets` |KF5 widgets for configuration dialogs |`contacts` |KDE api to manage contact information |`coreaddons` |KF5 addons to QtCore |`crash` |KF5 library to handle crash analysis and bug report from apps |`dbusaddons` |KF5 addons to QtDBus |`decoration` |Plasma5 library to create window decorations |`designerplugin` |KF5 integration of Frameworks widgets in Qt Designer/Creator |`discover` |Plasma5 package management tools |`dnssd` |KF5 abstraction to system DNSSD features |`doctools` |KF5 documentation generation from docbook |`drkonqi` |Plasma5 crash handler |`ecm` |Extra modules and scripts for CMake |`emoticons` |KF5 library to convert emoticons |`eventviews` |Event view libriares for KDEPim |`filemetadata` |KF5 library for extracting file metadata |`frameworkintegration` |KF5 workspace and cross-framework integration plugins |`gapi` |KDE based library to access google services |`globalaccel` |KF5 library to add support for global workspace shortcuts |`grantlee-editor` |Editor for Grantlee themes |`grantleetheme` |KDE PIM grantleetheme |`gravatar` |Library for gravatar support |`guiaddons` |KF5 addons to QtGui |`holidays` |KDE library for calendar holidays |`hotkeys` |Plasma5 library for hotkeys |`i18n` |KF5 advanced internationalization framework |`iconthemes` |KF5 library for handling icons in applications |`identitymanagement` |KDE pim identities |`idletime` |KF5 library for monitoring user activity |`imap` |KDE API for IMAP support |`incidenceeditor` |Incidence editor libriares for KDEPim |`infocenter` |Plasma5 utility providing system information |`init` |KF5 process launcher to speed up launching KDE applications |`itemmodels` |KF5 models for Qt Model/View system |`itemviews` |KF5 widget addons for Qt Model/View |`jobwidgets` |KF5 widgets for tracking KJob instance |`js` |KF5 library providing an ECMAScript interpreter |`jsembed` |KF5 library for binding JavaScript objects to QObjects |`kaddressbook` |KDE contact manager |`kalarm` |Personal alarm scheduler |`kalarm` |Personal alarm scheduler |`kate` |Basic editor framework for the KDE system |`kcmutils` |KF5 utilities for working with KCModules |`kde-cli-tools` |Plasma5 non-interactive system tools |`kde-gtk-config` |Plasma5 GTK2 and GTK3 configurator |`kdeclarative` |KF5 library providing integration of QML and KDE Frameworks |`kded` |KF5 extensible daemon for providing system level services |`kdelibs4support` |KF5 porting aid from KDELibs4 |`kdepim-addons` |KDE PIM addons |`kdepim-apps-libs` |KDE PIM mail related libraries |`kdepim-runtime5` |KDE PIM tools and services |`kdeplasma-addons` |Plasma5 addons to improve the Plasma experience |`kdesu` |KF5 integration with su for elevated privileges |`kdewebkit` |KF5 library providing integration of QtWebKit |`kgamma5` |Plasma5 monitor's gamma settings |`khtml` |KF5 KTHML rendering engine |`kimageformats` |KF5 library providing support for additional image formats |`kio` |KF5 resource and network access abstraction |`kirigami2` |QtQuick based components set |`kitinerary` |Data Model and Extraction System for Travel Reservation information |`kmail` |KDE mail client |`kmail` |KDE mail client |`kmail-account-wizard` |KDE mail account wizard |`kmenuedit` |Plasma5 menu editor |`knotes` |Popup notes |`kontact` |KDE Personal Information Manager |`kontact` |KDE Personal Information Manager |`kontactinterface` |KDE glue for embedding KParts into Kontact |`korganizer` |Calendar and scheduling Program |`kpimdav` |A DAV protocol implementation with KJobs |`kpkpass` |Library to deal with Apple Wallet pass files |`kross` |KF5 multi-language application scripting |`kscreen` |Plasma5 screen management library |`kscreenlocker` |Plasma5 secure lock screen architecture |`ksmtp` |Job-based library to send email through an SMTP server |`ksshaskpass` |Plasma5 ssh-add frontend |`ksysguard` |Plasma5 utility to track and control the running processes |`kwallet-pam` |Plasma5 KWallet PAM Integration |`kwayland-integration` |Integration plugins for a Wayland-based desktop |`kwin` |Plasma5 window manager |`kwrited` |Plasma5 daemon listening for wall and write messages |`ldap` |LDAP access API for KDE |`libkcddb` |KDE CDDB library |`libkcompactdisc` |KDE library for interfacing with audio CDs |`libkdcraw` |LibRaw interface for KDE |`libkdegames` |Libraries used by KDE games |`libkdepim` |KDE PIM Libraries |`libkeduvocdocument` |Library for reading and writing vocabulary files |`libkexiv2` |Exiv2 library interface for KDE |`libkipi` |KDE Image Plugin Interface |`libkleo` |Certificate manager for KDE |`libksane` |SANE library interface for KDE |`libkscreen` |Plasma5 screen management library |`libksieve` |Sieve libriares for KDEPim |`libksysguard` |Plasma5 library to track and control running processes |`mailcommon` |Common libriares for KDEPim |`mailimporter` |Import mbox files to KMail |`mailtransport` |KDE library to managing mail transport |`marble` |Virtual globe and world atlas for KDE |`mbox` |KDE library for accessing mail storages in MBox format |`mbox-importer` |Import mbox files to KMail |`mediaplayer` |KF5 plugin interface for media player features |`messagelib` |Library for handling messages |`milou` |Plasma5 Plasmoid for search |`mime` |Library for handling MIME data |`newstuff` |KF5 library for downloading application assets from the network |`notifications` |KF5 abstraction for system notifications |`notifyconfig` |KF5 configuration system for KNotify |`okular` |KDE universal document viewer |`oxygen` |Plasma5 Oxygen style |`oxygen-icons5` |The Oxygen icon theme for KDE |`package` |KF5 library to load and install packages |`parts` |KF5 document centric plugin system |`people` |KF5 library providing access to contacts |`pim-data-exporter` |Import and export KDE PIM settings |`pimcommon` |Common libriares for KDEPim |`pimtextedit` |KDE library for PIM-specific text editing utilities |`plasma-browser-integration` |Plasma5 components to integrate browsers into the desktop |`plasma-desktop` |Plasma5 plasma desktop |`plasma-framework` |KF5 plugin based UI runtime used to write user interfaces |`plasma-integration` |Qt Platform Theme integration plugins for the Plasma workspaces |`plasma-pa` |Plasma5 Plasma pulse audio mixer |`plasma-sdk` |Plasma5 applications useful for Plasma development |`plasma-workspace` |Plasma5 Plasma workspace |`plasma-workspace-wallpapers` |Plasma5 wallpapers |`plotting` |KF5 lightweight plotting framework |`polkit-kde-agent-1` |Plasma5 daemon providing a polkit authentication UI |`powerdevil` |Plasma5 tool to manage the power consumption settings |`prison` |API to produce barcodes |`pty` |KF5 pty abstraction |`purpose` |Offers available actions for a specific purpose |`qqc2-desktop-style` |Qt QuickControl2 style for KDE |`runner` |KF5 parallelized query system |`service` |KF5 advanced plugin and service introspection |`solid` |KF5 hardware integration and detection |`sonnet` |KF5 plugin-based spell checking library |`syndication` |KDE RSS feed handling library |`syntaxhighlighting` |KF5 syntax highlighting engine for structured text and code |`systemsettings` |Plasma5 system settings |`texteditor` |KF5 advanced embeddable text editor |`textwidgets` |KF5 advanced text editing widgets |`threadweaver` |KF5 addons to QtDBus |`tnef` |KDE API for the handling of TNEF data |`unitconversion` |KF5 library for unit conversion |`user-manager` |Plasma5 user manager |`wallet` |KF5 secure and unified container for user passwords |`wayland` |KF5 Client and Server library wrapper for the Wayland libraries |`widgetsaddons` |KF5 addons to QtWidgets |`windowsystem` |KF5 library for access to the windowing system |`xmlgui` |KF5 user configurable main windows |`xmlrpcclient` |KF5 interaction with XMLRPC services |=== [[kde5-components-example]] .`USE_KDE` Example [example] ==== This is a simple example for a KDE port. `USES= cmake` instructs the port to utilize CMake, a configuration tool widely -used by KDE projects (see crossref:special[using-cmake] for detailed usage). +used by KDE projects (see crossref:special[using-cmake, Using `cmake`] for detailed usage). `USE_KDE` brings dependency on KDE libraries. Required KDE components and other dependencies can be determined through the configure log. `USE_KDE` does not imply `USE_QT`. If a port requires some Qt components, specify them in `USE_QT`. [.programlisting] .... USES= cmake kde:5 qt:5 USE_KDE= ecm USE_QT= core buildtools_build qmake_build .... ==== [[using-lxqt]] == Using LXQt Applications depending on LXQt should set `USES+= lxqt` and set `USE_LXQT` to the list of required components from the table below [[using-lxqt-components]] .Available LXQt Components [cols="1,1", frame="none", options="header"] |=== | Name | Description |`buildtools` |Helpers for additional CMake modules |`libfmqt` |Libfm Qt bindings |`lxqt` |LXQt core library |`qtxdg` |Qt implementation of freedesktop.org XDG specifications |=== [[lxqt-components-example]] .`USE_LXQT` Example [example] ==== This is a simple example, `USE_LXQT` adds a dependency on LXQt libraries. Required LXQt components and other dependencies can be determined from the configure log. [.programlisting] .... USES= cmake lxqt qt:5 tar:xz USE_QT= core dbus widgets buildtools_build qmake_build USE_LXQT= buildtools libfmqt .... ==== [[using-java]] == Using Java [[java-variables]] === Variable Definitions If the port needs a Java(TM) Development Kit (JDK(TM)) to either build, run or even extract the distfile, then define `USE_JAVA`. There are several JDKs in the ports collection, from various vendors, and in several versions. If the port must use a particular version, specify it using the `JAVA_VERSION` variable. The most current version is package:java/openjdk18[], with package:java/openjdk17[], package:java/openjdk16[], package:java/openjdk15[], package:java/openjdk14[], package:java/openjdk13[], package:java/openjdk12[], package:java/openjdk11[], package:java/openjdk8[], and package:java/openjdk7[] also available. [[using-java-variables]] .Variables Which May be Set by Ports That Use Java [cols="1,1", frame="none", options="header"] |=== | Variable | Means |`USE_JAVA` |Define for the remaining variables to have any effect. |`JAVA_VERSION` |List of space-separated suitable Java versions for the port. An optional `\+` allows specifying a range of versions (allowed values: `8[+] 11[\+] 17[+] 18[\+] 19[+] 20[\+] 21[+]`). |`JAVA_OS` |List of space-separated suitable JDK port operating systems for the port (allowed values: `native linux`). |`JAVA_VENDOR` |List of space-separated suitable JDK port vendors for the port (allowed values: `openjdk oracle`). |`JAVA_BUILD` |When set, add the selected JDK port to the build dependencies. |`JAVA_RUN` |When set, add the selected JDK port to the run dependencies. |`JAVA_EXTRACT` |When set, add the selected JDK port to the extract dependencies. |=== Below is the list of all settings a port will receive after setting `USE_JAVA`: [[using-java-variables2]] .Variables Provided to Ports That Use Java [cols="1,1", frame="none", options="header"] |=== | Variable | Value |`JAVA_PORT` |The name of the JDK port (for example, `java/openjdk6`). |`JAVA_PORT_VERSION` |The full version of the JDK port (for example, `1.6.0`). Only the first two digits of this version number are needed, use `${JAVA_PORT_VERSION:C/^([0-9])\.([0-9])(.*)$/\1.\2/}`. |`JAVA_PORT_OS` |The operating system used by the JDK port (for example, `'native'`). |`JAVA_PORT_VENDOR` |The vendor of the JDK port (for example, `'openjdk'`). |`JAVA_PORT_OS_DESCRIPTION` |Description of the operating system used by the JDK port (for example, `'Native'`). |`JAVA_PORT_VENDOR_DESCRIPTION` |Description of the vendor of the JDK port (for example, `'OpenJDK BSD Porting Team'`). |`JAVA_HOME` |Path to the installation directory of the JDK (for example, [.filename]#'/usr/local/openjdk6'#). |`JAVAC` |Path to the Java compiler to use (for example, [.filename]#'/usr/local/openjdk6/bin/javac'#). |`JAR` |Path to the `jar` tool to use (for example, [.filename]#'/usr/local/openjdk6/bin/jar'# or [.filename]#'/usr/local/bin/fastjar'#). |`APPLETVIEWER` |Path to the `appletviewer` utility (for example, [.filename]#'/usr/local/openjdk6/bin/appletviewer'#). |`JAVA` |Path to the `java` executable. Use this for executing Java programs (for example, [.filename]#'/usr/local/openjdk6/bin/java'#). |`JAVADOC` |Path to the `javadoc` utility program. |`JAVAH` |Path to the `javah` program. |`JAVAP` |Path to the `javap` program. |`JAVA_KEYTOOL` |Path to the `keytool` utility program. |`JAVA_N2A` |Path to the `native2ascii` tool. |`JAVA_POLICYTOOL` |Path to the `policytool` program. |`JAVA_SERIALVER` |Path to the `serialver` utility program. |`RMIC` |Path to the RMI stub/skeleton generator, `rmic`. |`RMIREGISTRY` |Path to the RMI registry program, `rmiregistry`. |`RMID` |Path to the RMI daemon program `rmid`. |`JAVA_CLASSES` |Path to the archive that contains the JDK class files, [.filename]#${JAVA_HOME}/jre/lib/rt.jar#. |=== Use the `java-debug` make target to get information for debugging the port. It will display the value of many of the previously listed variables. Additionally, these constants are defined so all Java ports may be installed in a consistent way: [[using-java-constants]] .Constants Defined for Ports That Use Java [cols="1,1", frame="none", options="header"] |=== | Constant | Value |`JAVASHAREDIR` |The base directory for everything related to Java. Default: [.filename]#${PREFIX}/share/java#. |`JAVAJARDIR` |The directory where JAR files is installed. Default: [.filename]#${JAVASHAREDIR}/classes#. |`JAVALIBDIR` |The directory where JAR files installed by other ports are located. Default: [.filename]#${LOCALBASE}/share/java/classes#. |=== The related entries are defined in both `PLIST_SUB` (documented in crossref:plist[plist-sub,Changing pkg-plist Based on Make Variables]) and `SUB_LIST`. [[java-building-with-ant]] === Building with Ant When the port is to be built using Apache Ant, it has to define `USE_ANT`. Ant is thus considered to be the sub-make command. When no `do-build` target is defined by the port, a default one will be set that runs Ant according to `MAKE_ENV`, `MAKE_ARGS` and `ALL_TARGET`. -This is similar to the `USES= gmake` mechanism, which is documented in crossref:special[building]. +This is similar to the `USES= gmake` mechanism, which is documented in crossref:special[building, Building Mechanisms]. [[java-best-practices]] === Best Practices When porting a Java library, the port has to install the JAR file(s) in [.filename]#${JAVAJARDIR}#, and everything else under [.filename]#${JAVASHAREDIR}/${PORTNAME}# (except for the documentation, see below). To reduce the packing file size, reference the JAR file(s) directly in the [.filename]#Makefile#. Use this statement (where [.filename]#myport.jar# is the name of the JAR file installed as part of the port): [.programlisting] .... PLIST_FILES+= ${JAVAJARDIR}/myport.jar .... When porting a Java application, the port usually installs everything under a single directory (including its JAR dependencies). The use of [.filename]#${JAVASHAREDIR}/${PORTNAME}# is strongly encouraged in this regard. It is up the porter to decide whether the port installs the additional JAR dependencies under this directory or uses the already installed ones (from [.filename]#${JAVAJARDIR}#). When porting a Java(TM) application that requires an application server such as package:www/tomcat7[] to run the service, it is quite common for a vendor to distribute a [.filename]#.war#. A [.filename]#.war# is a Web application ARchive and is extracted when called by the application. Avoid adding a [.filename]#.war# to [.filename]#pkg-plist#. It is not considered best practice. An application server will expand war archive, but not clean it up properly if the port is removed. A more desirable way of working with this file is to extract the archive, then install the files, and lastly add these files to [.filename]#pkg-plist#. [.programlisting] .... TOMCATDIR= ${LOCALBASE}/apache-tomcat-7.0 WEBAPPDIR= myapplication post-extract: @${MKDIR} ${WRKDIR}/${PORTDIRNAME} @${TAR} xf ${WRKDIR}/myapplication.war -C ${WRKDIR}/${PORTDIRNAME} do-install: cd ${WRKDIR} && \ ${INSTALL} -d -o ${WWWOWN} -g ${WWWGRP} ${TOMCATDIR}/webapps/${PORTDIRNAME} cd ${WRKDIR}/${PORTDIRNAME} && ${COPYTREE_SHARE} \* ${WEBAPPDIR}/${PORTDIRNAME} .... Regardless of the type of port (library or application), the additional documentation is installed in the crossref:makefiles[install-documentation,same location] as for any other port. The Javadoc tool is known to produce a different set of files depending on the version of the JDK that is used. For ports that do not enforce the use of a particular JDK, it is therefore a complex task to specify the packing list ([.filename]#pkg-plist#). This is one reason why porters are strongly encouraged to use `PORTDOCS`. Moreover, even if the set of files that will be generated by `javadoc` can be predicted, the size of the resulting [.filename]#pkg-plist# advocates for the use of `PORTDOCS`. The default value for `DATADIR` is [.filename]#${PREFIX}/share/${PORTNAME}#. It is a good idea to override `DATADIR` to [.filename]#${JAVASHAREDIR}/${PORTNAME}# for Java ports. Indeed, `DATADIR` is automatically added to `PLIST_SUB` (documented in crossref:plist[plist-sub,Changing pkg-plist Based on Make Variables]) so use `%%DATADIR%%` directly in [.filename]#pkg-plist#. As for the choice of building Java ports from source or directly installing them from a binary distribution, there is no defined policy at the time of writing. However, people from the https://www.freebsd.org/java/[FreeBSD Java Project] encourage porters to have their ports built from source whenever it is a trivial task. All the features that have been presented in this section are implemented in [.filename]#bsd.java.mk#. If the port needs more sophisticated Java support, please first have a look at the https://cgit.FreeBSD.org/ports/tree/Mk/bsd.java.mk[bsd.java.mk Git log] as it usually takes some time to document the latest features. Then, if the needed support that is lacking would be beneficial to many other Java ports, feel free to discuss it on the freebsd-java. Although there is a `java` category for PRs, it refers to the JDK porting effort from the FreeBSD Java project. Therefore, submit the Java port in the `ports` category as for any other port, unless the issue is related to either a JDK implementation or [.filename]#bsd.java.mk#. Similarly, there is a defined policy regarding the `CATEGORIES` of a Java port, which is detailed in crossref:makefiles[makefile-categories,Categorization]. [[using-php]] == Web Applications, Apache and PHP [[using-apache]] === Apache [[using-apache-variables]] .Variables for Ports That Use Apache [cols="1,1", frame="none"] |=== |`USE_APACHE` |The port requires Apache. Possible values: `yes` (gets any version), `22`, `24`, `22-24`, `22+`, etc. The default APACHE version is `22`. More details are available in [.filename]#ports/Mk/bsd.apache.mk# and at https://wiki.freebsd.org/Apache/[wiki.freebsd.org/Apache/]. |`APXS` |Full path to the `apxs` binary. Can be overridden in the port. |`HTTPD` |Full path to the `httpd` binary. Can be overridden in the port. |`APACHE_VERSION` |The version of present Apache installation (read-only variable). This variable is only available after inclusion of [.filename]#bsd.port.pre.mk#. Possible values: `22`, `24`. |`APACHEMODDIR` |Directory for Apache modules. This variable is automatically expanded in [.filename]#pkg-plist#. |`APACHEINCLUDEDIR` |Directory for Apache headers. This variable is automatically expanded in [.filename]#pkg-plist#. |`APACHEETCDIR` |Directory for Apache configuration files. This variable is automatically expanded in [.filename]#pkg-plist#. |=== [[using-apache-modules]] .Useful Variables for Porting Apache Modules [cols="1,1", frame="none"] |=== |`MODULENAME` |Name of the module. Default value is `PORTNAME`. Example: `mod_hello` |`SHORTMODNAME` |Short name of the module. Automatically derived from `MODULENAME`, but can be overridden. Example: `hello` |`AP_FAST_BUILD` |Use `apxs` to compile and install the module. |`AP_GENPLIST` |Also automatically creates a [.filename]#pkg-plist#. |`AP_INC` |Adds a directory to a header search path during compilation. |`AP_LIB` |Adds a directory to a library search path during compilation. |`AP_EXTRAS` |Additional flags to pass to `apxs`. |=== [[web-apps]] === Web Applications Web applications must be installed into [.filename]#PREFIX/www/appname#. This path is available both in [.filename]#Makefile# and in [.filename]#pkg-plist# as `WWWDIR`, and the path relative to `PREFIX` is available in [.filename]#Makefile# as `WWWDIR_REL`. The user and group of web server process are available as `WWWOWN` and `WWWGRP`, in case the ownership of some files needs to be changed. The default values of both are `www`. Use `WWWOWN?= myuser` and `WWWGRP?= mygroup` if the port needs different values. This allows the user to override them easily. [IMPORTANT] ==== Use `WWWOWN` and `WWWGRP` sparingly. Remember that every file the web server can write to is a security risk waiting to happen. ==== Do not depend on Apache unless the web app explicitly needs Apache. Respect that users may wish to run a web application on a web server other than Apache. [[php-variables]] === PHP PHP web applications declare their dependency on it with `USES=php`. See crossref:uses[uses-php,`php`] for more information. [[php-pear]] === PEAR Modules Porting PEAR modules is a very simple process. Add `USES=pear` to the port's [.filename]#Makefile#. The framework will install the relevant files in the right places and automatically generate the plist at install time. [[pear-makefile]] .Example Makefile for PEAR Class [example] ==== [.programlisting] .... PORTNAME= Date DISTVERSION= 1.4.3 CATEGORIES= devel www pear MAINTAINER= someone@example.org COMMENT= PEAR Date and Time Zone Classes WWW= https://pear.php.net/package/Date/ USES= pear .include .... ==== [TIP] ==== PEAR modules will automatically be flavorized using crossref:flavors[flavors-auto-php,PHP flavors]. ==== [NOTE] ==== If a non default `PEAR_CHANNEL` is used, the build and run-time dependencies will automatically be added. ==== [IMPORTANT] ==== PEAR modules do not need to defined `PKGNAMESUFFIX` it is automatically filled in using `PEAR_PKGNAMEPREFIX`. If a port needs to add to `PKGNAMEPREFIX`, it must also use `PEAR_PKGNAMEPREFIX` to differentiate between different flavors. ==== [[php-horde]] ==== Horde Modules In the same way, porting Horde modules is a simple process. Add `USES=horde` to the port's [.filename]#Makefile#. The framework will install the relevant files in the right places and automatically generate the plist at install time. The `USE_HORDE_BUILD` and `USE_HORDE_RUN` variables can be used to add buildtime and runtime dependencies on other Horde modules. See [.filename]#Mk/Uses/horde.mk# for a complete list of available modules. [[horde-Makefile]] .Example Makefile for Horde Module [example] ==== [.programlisting] .... PORTNAME= Horde_Core DISTVERSION= 2.14.0 CATEGORIES= devel www pear MAINTAINER= horde@FreeBSD.org COMMENT= Horde Core Framework libraries WWW= https://pear.horde.org/ OPTIONS_DEFINE= KOLAB SOCKETS KOLAB_DESC= Enable Kolab server support SOCKETS_DESC= Depend on sockets PHP extension USES= horde USE_PHP= session USE_HORDE_BUILD= Horde_Role USE_HORDE_RUN= Horde_Role Horde_History Horde_Pack \ Horde_Text_Filter Horde_View KOLAB_USE= HORDE_RUN=Horde_Kolab_Server,Horde_Kolab_Session SOCKETS_USE= PHP=sockets .include .... ==== [TIP] ==== As Horde modules are also PEAR modules they will also automatically be flavorized using crossref:flavors[flavors-auto-php,PHP flavors]. ==== [[using-python]] == Using Python The Ports Collection supports parallel installation of multiple Python versions. Ports must use a correct `python` interpreter, according to the user-settable `PYTHON_VERSION`. Most prominently, this means replacing the path to `python` executable in scripts with the value of `PYTHON_CMD`. Ports that install files under `PYTHON_SITELIBDIR` must use the `pyXY-` package name prefix, so their package name embeds the version of Python they are installed into. [.programlisting] .... PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX} .... [[using-python-variables]] .Most Useful Variables for Ports That Use Python [cols="1,1", frame="none"] |=== |`USES=python` |The port needs Python. The minimal required version can be specified with values such as `3.10+`. Version ranges can also be specified by separating two version numbers with a dash: `USES=python:3.8-3.9`. Note that `USES=python` does _not_ cover Python 2.7, it needs to be requested explicitly with `USES=python:2.7+`. |`USE_PYTHON=distutils` |Use Python distutils for configuring, compiling, and installing. This is required when the port comes with [.filename]#setup.py#. This overrides the `do-build` and `do-install` targets and may also override `do-configure` if `GNU_CONFIGURE` is not defined. Additionally, it implies `USE_PYTHON=flavors`. |`USE_PYTHON=autoplist` |Create the packaging list automatically. This also requires `USE_PYTHON=distutils` to be set. |`USE_PYTHON=concurrent` |The port will use an unique prefix, typically `PYTHON_PKGNAMEPREFIX` for certain directories, such as `EXAMPLESDIR` and `DOCSDIR` and also will append a suffix, the python version from `PYTHON_VER`, to binaries and scripts to be installed. This allows ports to be installed for different Python versions at the same time, which otherwise would install conflicting files. |`USE_PYTHON=flavors` |The port does not use distutils but still supports multiple Python versions. `FLAVORS` will be set to the supported Python versions. See crossref:flavors[flavors-auto-python,`USES`=python and Flavors] for more information. |`USE_PYTHON=optsuffix` |If the current Python version is not the default version, the port will gain `PKGNAMESUFFIX=${PYTHON_PKGNAMESUFFIX}`. Only useful with flavors. |`PYTHON_PKGNAMEPREFIX` |Used as a `PKGNAMEPREFIX` to distinguish packages for different Python versions. Example: `py27-` |`PYTHON_SITELIBDIR` |Location of the site-packages tree, that contains installation path of Python (usually `LOCALBASE`). `PYTHON_SITELIBDIR` can be very useful when installing Python modules. |`PYTHONPREFIX_SITELIBDIR` |The PREFIX-clean variant of PYTHON_SITELIBDIR. Always use `%%PYTHON_SITELIBDIR%%` in [.filename]#pkg-plist# when possible. The default value of `%%PYTHON_SITELIBDIR%%` is `lib/python%%PYTHON_VERSION%%/site-packages` |`PYTHON_CMD` |Python interpreter command line, including version number. |=== [[using-python-variables-helpers]] .Python Module Dependency Helpers [cols="1,1", frame="none"] |=== |`PYNUMERIC` |Dependency line for numeric extension. |`PYNUMPY` |Dependency line for the new numeric extension, numpy. (PYNUMERIC is deprecated by upstream vendor). |`PYXML` |Dependency line for XML extension (not needed for Python 2.0 and higher as it is also in base distribution). |`PY_ENUM34` |Conditional dependency on package:devel/py-enum34[] depending on the Python version. |`PY_ENUM_COMPAT` |Conditional dependency on package:devel/py-enum-compat[] depending on the Python version. |`PY_PATHLIB` |Conditional dependency on package:devel/py-pathlib[] depending on the Python version. |`PY_IPADDRESS` |Conditional dependency on package:net/py-ipaddress[] depending on the Python version. |`PY_FUTURES` |Conditional dependency on package:devel/py-futures[] depending on the Python version. |=== A complete list of available variables can be found in [.filename]#/usr/ports/Mk/Uses/python.mk#. [IMPORTANT] ==== All dependencies to Python ports using crossref:flavors[flavors-auto-python,Python flavors] (either with `USE_PYTHON=distutils` or `USE_PYTHON=flavors`) must have the Python flavor appended to their origin using `@${PY_FLAVOR}`. -See crossref:special[python-Makefile]. +See crossref:special[python-Makefile,.Makefile for a Simple Python Module]. ==== [[python-Makefile]] .Makefile for a Simple Python Module [example] ==== [.programlisting] .... PORTNAME= sample DISTVERSION= 1.2.3 CATEGORIES= devel MAINTAINER= fred.bloggs@example.com COMMENT= Python sample module WWW= https://example.com/project/sample/ RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}six>0:devel/py-six@${PY_FLAVOR} USES= python USE_PYTHON= autoplist distutils .include .... ==== Some Python applications claim to have `DESTDIR` support (which would be required for staging) but it is broken (Mailman up to 2.1.16, for instance). This can be worked around by recompiling the scripts. This can be done, for example, in the `post-build` target. Assuming the Python scripts are supposed to reside in `PYTHONPREFIX_SITELIBDIR` after installation, this solution can be applied: [.programlisting] .... (cd ${STAGEDIR}${PREFIX} \ && ${PYTHON_CMD} ${PYTHON_LIBDIR}/compileall.py \ -d ${PREFIX} -f ${PYTHONPREFIX_SITELIBDIR:S;${PREFIX}/;;}) .... This recompiles the sources with a path relative to the stage directory, and prepends the value of `PREFIX` to the file name recorded in the byte-compiled output file by `-d`. `-f` is required to force recompilation, and the `:S;${PREFIX}/;;` strips prefixes from the value of `PYTHONPREFIX_SITELIBDIR` to make it relative to `PREFIX`. [[using-tcl]] == Using Tcl/Tk The Ports Collection supports parallel installation of multiple Tcl/Tk versions. Ports should try to support at least the default Tcl/Tk version and higher with `USES=tcl`. It is possible to specify the desired version of `tcl` by appending `:_xx_`, for example, `USES=tcl:85`. [[using-tcl-variables]] .The Most Useful Read-Only Variables for Ports That Use Tcl/Tk [cols="1,1", frame="none"] |=== |`TCL_VER` | chosen major.minor version of Tcl |`TCLSH` | full path of the Tcl interpreter |`TCL_LIBDIR` | path of the Tcl libraries |`TCL_INCLUDEDIR` | path of the Tcl C header files |`TK_VER` | chosen major.minor version of Tk |`WISH` | full path of the Tk interpreter |`TK_LIBDIR` | path of the Tk libraries |`TK_INCLUDEDIR` | path of the Tk C header files |=== See the crossref:uses[uses-tcl,`USES=tcl`] and crossref:uses[uses-tk,`USES=tk`] of crossref:uses[uses,Using `USES` Macros] for a full description of those variables. A complete list of those variables is available in [.filename]#/usr/ports/Mk/Uses/tcl.mk#. [[using-sdl]] == Using SDL `USE_SDL` is used to autoconfigure the dependencies for ports which use an SDL based library like package:devel/sdl12[] and package:graphics/sdl_image[]. These SDL libraries for version 1.2 are recognized: * sdl: package:devel/sdl12[] * console: package:devel/sdl_console[] * gfx: package:graphics/sdl_gfx[] * image: package:graphics/sdl_image[] * mixer: package:audio/sdl_mixer[] * mm: package:devel/sdlmm[] * net: package:net/sdl_net[] * pango: package:x11-toolkits/sdl_pango[] * sound: package:audio/sdl_sound[] * ttf: package:graphics/sdl_ttf[] These SDL libraries for version 2.0 are recognized: * sdl: package:devel/sdl20[] * gfx: package:graphics/sdl2_gfx[] * image: package:graphics/sdl2_image[] * mixer: package:audio/sdl2_mixer[] * net: package:net/sdl2_net[] * ttf: package:graphics/sdl2_ttf[] Therefore, if a port has a dependency on package:net/sdl_net[] and package:audio/sdl_mixer[], the syntax will be: [.programlisting] .... USE_SDL= net mixer .... The dependency package:devel/sdl12[], which is required by package:net/sdl_net[] and package:audio/sdl_mixer[], is automatically added as well. Using `USE_SDL` with entries for SDL 1.2, it will automatically: * Add a dependency on sdl12-config to `BUILD_DEPENDS` * Add the variable `SDL_CONFIG` to `CONFIGURE_ENV` * Add the dependencies of the selected libraries to `LIB_DEPENDS` Using `USE_SDL` with entries for SDL 2.0, it will automatically: * Add a dependency on sdl2-config to `BUILD_DEPENDS` * Add the variable `SDL2_CONFIG` to `CONFIGURE_ENV` * Add the dependencies of the selected libraries to `LIB_DEPENDS` [[using-wx]] == Using wxWidgets This section describes the status of the wxWidgets libraries in the ports tree and its integration with the ports system. [[wx-introduction]] === Introduction There are many versions of the wxWidgets libraries which conflict between them (install files under the same name). In the ports tree this problem has been solved by installing each version under a different name using version number suffixes. The obvious disadvantage of this is that each application has to be modified to find the expected version. Fortunately, most of the applications call the `wx-config` script to determine the necessary compiler and linker flags. The script is named differently for every available version. Majority of applications respect an environment variable, or accept a configure argument, to specify which `wx-config` script to call. Otherwise they have to be patched. [[wx-version]] === Version Selection To make the port use a specific version of wxWidgets there are two variables available for defining (if only one is defined the other will be set to a default value): [[wx-ver-sel-table]] .Variables to Select wxWidgets Versions [cols="1,1,1", frame="none", options="header"] |=== | Variable | Description | Default value |`USE_WX` |List of versions the port can use |All available versions |`USE_WX_NOT` |List of versions the port cannot use |None |=== The available wxWidgets versions and the corresponding ports in the tree are: [[wx-widgets-versions-table]] .Available wxWidgets Versions [cols="1,1", frame="none", options="header"] |=== | Version | Port |`2.8` |package:x11-toolkits/wxgtk28[] |`3.0` |package:x11-toolkits/wxgtk30[] |=== -The variables in crossref:special[wx-ver-sel-table] can be set to one or more of these combinations separated by spaces: +The variables in crossref:special[wx-ver-sel-table,.Variables to Select wxWidgets Versions] can be set to one or more of these combinations separated by spaces: [[wx-widgets-versions-specification]] .wxWidgets Version Specifications [cols="1,1", frame="none", options="header"] |=== | Description | Example |Single version |`2.8` |Ascending range |`2.8+` |Descending range |`3.0-` |Full range (must be ascending) |`2.8-3.0` |=== There are also some variables to select the preferred versions from the available ones. They can be set to a list of versions, the first ones will have higher priority. [[wx-widgets-preferred-version]] .Variables to Select Preferred wxWidgets Versions [cols="1,1", frame="none", options="header"] |=== | Name | Designed for |`WANT_WX_VER` |the port |`WITH_WX_VER` |the user |=== [[wx-components]] === Component Selection There are other applications that, while not being wxWidgets libraries, are related to them. These applications can be specified in `WX_COMPS`. These components are available: [[wx-widgets-components-table]] .Available wxWidgets Components [cols="1,1,1", frame="none", options="header"] |=== | Name | Description | Version restriction |`wx` |main library |none |`contrib` |contributed libraries |`none` |`python` |wxPython (Python bindings) |`2.8-3.0` |=== The dependency type can be selected for each component by adding a suffix separated by a semicolon. -If not present then a default type will be used (see crossref:special[wx-def-dep-types]). +If not present then a default type will be used (see crossref:special[wx-def-dep-types,.Default wxWidgets Dependency Types]). These types are available: [[wx-widgets-dependency-table]] .Available wxWidgets Dependency Types [cols="1,1", frame="none", options="header"] |=== | Name | Description |`build` |Component is required for building, equivalent to `BUILD_DEPENDS` |`run` |Component is required for running, equivalent to `RUN_DEPENDS` |`lib` |Component is required for building and running, equivalent to `LIB_DEPENDS` |=== The default values for the components are detailed in this table: [[wx-def-dep-types]] .Default wxWidgets Dependency Types [cols="1,1", frame="none", options="header"] |=== | Component | Dependency type |`wx` |`lib` |`contrib` |`lib` |`python` |`run` |`mozilla` |`lib` |`svg` |`lib` |=== [[wx-components-example]] .Selecting wxWidgets Components [example] ==== This fragment corresponds to a port which uses wxWidgets version `2.4` and its contributed libraries. [.programlisting] .... USE_WX= 2.8 WX_COMPS= wx contrib .... ==== [[wx-version-detection]] === Detecting Installed Versions To detect an installed version, define `WANT_WX`. If it is not set to a specific version then the components will have a version suffix. `HAVE_WX` will be filled after detection. [[wx-ver-det-example]] .Detecting Installed wxWidgets Versions and Components [example] ==== This fragment can be used in a port that uses wxWidgets if it is installed, or an option is selected. [.programlisting] .... WANT_WX= yes .include .if defined(WITH_WX) || !empty(PORT_OPTIONS:MWX) || !empty(HAVE_WX:Mwx-2.8) USE_WX= 2.8 CONFIGURE_ARGS+= --enable-wx .endif .... This fragment can be used in a port that enables wxPython support if it is installed or if an option is selected, in addition to wxWidgets, both version `2.8`. [.programlisting] .... USE_WX= 2.8 WX_COMPS= wx WANT_WX= 2.8 .include .if defined(WITH_WXPYTHON) || !empty(PORT_OPTIONS:MWXPYTHON) || !empty(HAVE_WX:Mpython) WX_COMPS+= python CONFIGURE_ARGS+= --enable-wxpython .endif .... ==== [[wx-defined-variables]] === Defined Variables -These variables are available in the port (after defining one from crossref:special[wx-ver-sel-table]). +These variables are available in the port (after defining one from crossref:special[wx-ver-sel-table,.Variables to Select wxWidgets Versions]). [[wx-widgets-variables]] .Variables Defined for Ports That Use wxWidgets [cols="1,1", frame="none", options="header"] |=== | Name | Description |`WX_CONFIG` |The path to the wxWidgets`wx-config` script (with different name) |`WXRC_CMD` |The path to the wxWidgets`wxrc` program (with different name) |`WX_VERSION` |The wxWidgets version that is going to be used (for example, `2.6`) |=== [[wx-premk]] === Processing in [.filename]#bsd.port.pre.mk# Define `WX_PREMK` to be able to use the variables right after including [.filename]#bsd.port.pre.mk#. [IMPORTANT] ==== When defining `WX_PREMK`, then the version, dependencies, components and defined variables will not change if modifying the wxWidgets port variables _after_ including [.filename]#bsd.port.pre.mk#. ==== [[wx-premk-example]] .Using wxWidgets Variables in Commands [example] ==== This fragment illustrates the use of `WX_PREMK` by running the `wx-config` script to obtain the full version string, assign it to a variable and pass it to the program. [.programlisting] .... USE_WX= 2.8 WX_PREMK= yes .include .if exists(${WX_CONFIG}) VER_STR!= ${WX_CONFIG} --release PLIST_SUB+= VERSION="${VER_STR}" .endif .... ==== [NOTE] ==== The wxWidgets variables can be safely used in commands when they are inside targets without the need of `WX_PREMK`. ==== [[wx-additional-config-args]] === Additional `configure` Arguments Some GNU `configure` scripts cannot find wxWidgets with just the `WX_CONFIG` environment variable set, requiring additional arguments. `WX_CONF_ARGS` can be used for provide them. [[wx-conf-args-values]] .Legal Values for `WX_CONF_ARGS` [cols="1,1", frame="none", options="header"] |=== | Possible value | Resulting argument |`absolute` |`--with-wx-config=${WX_CONFIG}` |`relative` |`--with-wx=${LOCALBASE} --with-wx-config=${WX_CONFIG:T}` |=== [[using-lua]] == Using Lua This section describes the status of the Lua libraries in the ports tree and its integration with the ports system. [[lua-introduction]] === Introduction There are many versions of the Lua libraries and corresponding interpreters, which conflict between them (install files under the same name). In the ports tree this problem has been solved by installing each version under a different name using version number suffixes. The obvious disadvantage of this is that each application has to be modified to find the expected version. But it can be solved by adding some additional flags to the compiler and linker. Applications that use Lua should normally build for just one version. However, loadable modules for Lua are built in a separate flavor for each Lua version that they support, and dependencies on such modules should specify the flavor using the `@${LUA_FLAVOR}` suffix on the port origin. [[lua-version]] === Version Selection A port using Lua should have a line of this form: [.programlisting] .... USES= lua .... If a specific version of Lua, or range of versions, is needed, it can be specified as a parameter in the form `XY` (which may be used multiple times), `XY+`, `-XY`, or `XY-ZA`. The default version of Lua as set via `DEFAULT_VERSIONS` will be used if it falls in the requested range, otherwise the closest requested version to the default will be used. For example: [.programlisting] .... USES= lua:52-53 .... Note that no attempt is made to adjust the version selection based on the presence of any already-installed Lua version. [NOTE] ==== The `XY+` form of version specification should not be used without careful consideration; the Lua API changes to some extent in every version, and configuration tools like CMake or Autoconf will often fail to work on future versions of Lua until updated to do so. ==== [[lua-version-config]] === Configuration and Compiler flags Software that uses Lua may have been written to auto-detect the Lua version in use. In general ports should override this assumption, and force the use of the specific Lua version selected as described above. Depending on the software being ported, this might require any or all of: * Using `LUA_VER` as part of a parameter to the software's configuration script via `CONFIGURE_ARGS` or `CONFIGURE_ENV` (or equivalent for other build systems); * Adding `-I${LUA_INCDIR}`, `-L${LUA_LIBDIR}`, and `-llua-${LUA_VER}` to `CFLAGS`, `LDFLAGS`, `LIBS` respectively as appropriate; * Patch the software's configuration or build files to select the correct version. [[lua-version-flavors]] === Version Flavors A port which installs a Lua module (rather than an application that simply makes use of Lua) should build a separate flavor for each supported Lua version. This is done by adding the `module` parameter: [.programlisting] .... USES= lua:module .... A version number or range of versions can be specified as well; use a comma to separate parameters. Since each flavor must have a different package name, the variable `LUA_PKGNAMEPREFIX` is provided which will be set to an appropriate value; the intended usage is: [.programlisting] .... PKGNAMEPREFIX= ${LUA_PKGNAMEPREFIX} .... Module ports should normally install files only to `LUA_MODLIBDIR`, `LUA_MODSHAREDIR`, `LUA_DOCSDIR`, and `LUA_EXAMPLESDIR`, all of which are set up to refer to version-specific subdirectories. Installing any other files must be done with care to avoid conflicts between versions. A port (other than a Lua module) which wishes to build a separate package for each Lua version should use the `flavors` parameter: [.programlisting] .... USES= lua:flavors .... This operates the same way as the `module` parameter described above, but without the assumption that the package should be documented as a Lua module (so `LUA_DOCSDIR` and `LUA_EXAMPLESDIR` are not defined by default). However, the port may choose to define `LUA_DOCSUBDIR` as a suitable subdirectory name (usually the port's `PORTNAME` as long as this does not conflict with the `PORTNAME` of any module), in which case the framework will define both `LUA_DOCSDIR` and `LUA_EXAMPLESDIR`. As with module ports, a flavored port should avoid installing files that would conflict between versions. Typically this is done by adding `LUA_VER_STR` as a suffix to program names (e.g. using crossref:uses[uses-uniquefiles,`uniquefiles`]), and otherwise using either `LUA_VER` or `LUA_VER_STR` as part of any other files or subdirectories used outside of `LUA_MODLIBDIR` and `LUA_MODSHAREDIR`. [[lua-defined-variables]] === Defined Variables These variables are available in the port. [[using-lua-variables-ports]] .Variables Defined for Ports That Use Lua [cols="1,1", frame="none", options="header"] |=== | Name | Description |`LUA_VER` |The Lua version that is going to be used (for example, `5.4`) |`LUA_VER_STR` |The Lua version without the dots (for example, `54`) |`LUA_FLAVOR` |The flavor name corresponding to the selected Lua version, to be used for specifying dependencies |`LUA_BASE` |The prefix that should be used to locate Lua (and components) that are already installed |`LUA_PREFIX` |The prefix where Lua (and components) are to be installed by this port |`LUA_INCDIR` |The directory where Lua header files are installed |`LUA_LIBDIR` |The directory where Lua libraries are installed |`LUA_REFMODLIBDIR` |The directory where Lua module libraries ([.filename]#.so#) that are already installed are to be found |`LUA_REFMODSHAREDIR` |The directory where Lua modules ([.filename]#.lua#) that are already installed are to be found |`LUA_MODLIBDIR` |The directory where Lua module libraries ([.filename]#.so#) are to be installed by this port |`LUA_MODSHAREDIR` |The directory where Lua modules ([.filename]#.lua#) are to be installed by this port |`LUA_PKGNAMEPREFIX` |The package name prefix used by Lua modules |`LUA_CMD` |The name of the Lua interpreter (e.g. `lua54`) |`LUAC_CMD` |The name of the Lua compiler (e.g. `luac54`) |=== These additional variables are available for ports that specified the `module` parameter: [[using-lua-variables-modules]] .Variables Defined for Lua Module Ports [cols="1,1", frame="none", options="header"] |=== | Name | Description |`LUA_DOCSDIR` |the directory to which the module's documentation should be installed. |`LUA_EXAMPLESDIR` |the directory to which the module's example files should be installed. |=== [[lua-examples]] === Examples [[lua-app-Makefile]] .Makefile for an application using Lua [example] ==== This example shows how to reference a Lua module required at run time. Notice that the reference must specify a flavor. [.programlisting] .... PORTNAME= sample DISTVERSION= 1.2.3 CATEGORIES= whatever MAINTAINER= fred.bloggs@example.com COMMENT= Sample WWW= https://example.com/lua_sample/sample/ RUN_DEPENDS= ${LUA_REFMODLIBDIR}/lpeg.so:devel/lua-lpeg@${LUA_FLAVOR} USES= lua .include .... ==== [[lua-mod-Makefile]] .Makefile for a simple Lua module [example] ==== [.programlisting] .... PORTNAME= sample DISTVERSION= 1.2.3 CATEGORIES= whatever PKGNAMEPREFIX= ${LUA_PKGNAMEPREFIX} MAINTAINER= fred.bloggs@example.com COMMENT= Sample WWW= https://example.com/lua_sample/sample/ USES= lua:module DOCSDIR= ${LUA_DOCSDIR} .include .... ==== [[using-guile]] == Using Guile This section describes the status of Guile in the ports tree and its integration with the ports system. [[guile-introduction]] === Introduction There are multiple versions of the Guile libraries and corresponding interpreters, which conflict between them (install files under the same name). In the ports tree this problem has been solved by installing each version under a different name using version number suffixes. In most cases, applications should detect the correct version from the configuration variables provided and use `pkg-config` to determine the name and associated paths. However, some applications (especially those using their own configuration rules for `cmake` or `meson`) will always try to use the latest available version. In this case, either patch the port or declare a build conflict (see the `conflicts` option below) to ensure that the correct dependency is generated when building outside of poudriere. Applications that use Guile should normally build for just one version, preferably the one specified in `DEFAULT_VERSIONS`, or failing that the latest version that they support. However, Guile or Scheme libraries, or extension modules for Guile are built in a separate flavor for each Guile version that they support, and dependencies on such ports should specify the flavor using the `@${GUILE_FLAVOR}` suffix on the port origin. [[guile-version]] === Version Selection A port using Guile should define `USES=guile:__arg,arg...__` with appropriate arguments as follows: [[guile-defined-uses-args]] .Arguments Defined for Ports That Use Guile [cols="1m,4", frame="none", options="header"] |=== | Name | Description |_X.Y_ |Declare compatibility with Guile version `X.Y`. Currently available versions are `1.8` (obsolete), `2.2` and `3.0`. Multiple versions may be specified. |flavors |Create a flavor for every Guile version specified. The version specified by `DEFAULT_VERSIONS` will become the default flavor. Flavor names are of the form `guileXY`. |build |Add the Guile interpreter as a build dependency only, rather than a library dependency. `build` and `run` may both be specified. |run |Add the Guile interpreter as a runtime dependency only, rather than a library dependency. `build` and `run` may both be specified. |alias |Add `BINARY_ALIAS` values for the interpreter and tools. |conflicts |Declare `CONFLICTS_BUILD` for Guile versions newer than the one selected. Use this when the port cannot be configured to use a specific Guile version. |=== Some additional arguments are available for handling unusual cases; see `Mk/Uses/guile.mk` for details. Unless `build` or `run` is specified, then `LIB_DEPENDS` receives both the `libguile` library dependency and also any additional dependencies required by the guile version, e.g. `libgc`. Normally the port should not need any additional dependencies related to its use of Guile. [[guile-version-config]] === Configuration flags Software that uses Guile should be using the `pkg-config` mechanism to obtain compiler and linker flags. Some older or esoteric ports may be using `guile-config` or obtaining values directly from `guile` instead, which should also work (the `alias` argument may be useful in some of these cases). The framework tries to inform the port of the desired Guile version using the following methods: * `GUILE_EFFECTIVE_VERSION` is added to `CONFIGURE_ENV`; * The full path to the Guile binary is specified in the `GUILE` variable in `CONFIGURE_ENV` and `MAKE_ENV`; * If the `alias` option is used, the desired Guile version's binaries are the ones aliased; * If the `alias` option is not used, paths to the desired Guile version's tools (`guild`, `guile-config`, etc.) are added to `CONFIGURE_ENV` and `MAKE_ENV` as variables `GUILD`, `GUILE_CONFIG`, etc. For some ports, it may be necessary to specify the version in additional ways, such as via `CONFIGURE_ARGS` or `MESON_ARGS`, depending on the port. If none of these methods cause the port to select the specified Guile version when other versions are present, then preferably patch it to do so. If that is not feasible, specify the `conflicts` option to prevent building the port under conditions where it will detect the wrong version. [[guile-version-flavors]] === Version Flavors A port which installs a Guile extension or library, or a Scheme library that precompiles for Guile, should build a separate flavor for each supported Guile version. This is done by adding the `flavors` option. Since each flavor must have a different package name, such ports must set `PKGNAMESUFFIX`, typically: [.programlisting] .... PKGNAMESUFFIX= -${FLAVOR} .... Such ports must install Scheme files to `GUILE_SITE_DIR` rather than to `GUILE_GLOBAL_SITE_DIR` even when the files are not version-specific. This often requires patching the port. Additionally, if such a port installs a `.pc` file, it must be placed in `GUILE_PKGCONFIG_PATH` rather than in the global `pkgconfig` directory. This allows dependent ports to find a correct configuration for the specific Guile version in use. If a Guile extension port installs a `.so` file, then it must usually be placed in the Guile-version-specific `extensions` directory. `USE_LDCONFIG` should usually not be used. Any other files installed by a flavored port must likewise be in version-specific directories or use version-specific filenames. For documentation and examples, `GUILE_DOCS_DIR` and `GUILE_EXAMPLES_DIR` specify suitable locations in which the port should create a subdirectory, see below. [[guile-defined-variables]] === Defined Variables These variables are available in the port. [[using-guile-variables-ports]] .Variables Defined for Ports That Use Guile [cols="1,3m,6", frame="none", options="header"] |=== | Name | Sample Value | Description |`GUILE_VER` |3.0 |Guile version in use. |`GUILE_SFX` |3 |Short suffix used on some names. Use only with care; may be non-unique or may change in the future. |`GUILE_FLAVOR` |guile30 |Flavor name corresponding to the selected version. |`GUILE_PORT` |lang/guile3 |Port origin of the specified Guile version. |`GUILE_PREFIX` |${PREFIX} |Directory prefix to be used for installation. |`GUILE_CMD` |guile-3.0 |Name of the Guile interpreter, with version suffix. |`GUILE_CMDPATH` |${LOCALBASE}/bin/guile-3.0 |Full path to the Guile interpreter. |`GUILD_CMD` |guild-3.0 |Name of the Guild tool, with version suffix. |`GUILD_CMDPATH` |${LOCALBASE}/bin/guild-3.0 |Full path to the Guild tool. |`++GUILE_*_CMD++` + `++GUILE_*_CMDPATH++` | |Like `GUILE_CMD` and `GUILE_CMDPATH`, but for other tool binaries. |`GUILE_PKGCONFIG_PATH` |${LOCALBASE}/libdata/pkgconfig/guile/3.0 |Where packages using `flavors` should install `.pc` files. |`GUILE_INFO_PATH` |share/info/guile3 |A suitable value for `INFO_PATH` for ports using the `flavors` option. |=== The following are defined as variables and as `PLIST_SUB` entries. The variable form is suffixed with `_DIR` and is a full path (prefixed with `GUILE_PREFIX`). [[using-guile-path-variables-ports]] .Path Substitutions Defined for Ports That Use Guile [cols="1m,3m,6", frame="none", options="header"] |=== | Name | Sample Value | Description |GUILE_GLOBAL_SITE |share/guile/site |Site directory shared by all guile versions; this should not usually be used. |GUILE_SITE |share/guile/3.0/site |Site directory for the selected Guile version. |GUILE_SITE_CCACHE |lib/guile/3.0/site-ccache |Directory for compiled bytecode files. |GUILE_DOCS |share/doc/guile30 |Parent directory for version-specific documentation. |GUILE_EXAMPLES |share/examples/guile30 |Parent directory for version-specific examples. |=== [[guile-examples]] === Examples [[guile-app-Makefile]] .Makefile for an application using Guile [example] ==== This example shows how to reference a Guile library required at build and run time. Notice that the reference must specify a flavor. This example assumes that the application is using `pkg-config` to locate dependencies. [.programlisting] .... PORTNAME= sample DISTVERSION= 1.2.3 CATEGORIES= whatever MAINTAINER= fred.bloggs@example.com COMMENT= Sample WWW= https://example.com/guile_sample/sample/ BUILD_DEPENDS= guile-lib-${GUILE_FLAVOR}>=0.2.5:devel/guile-lib@${GUILE_FLAVOR} RUN_DEPENDS= guile-lib-${GUILE_FLAVOR}>=0.2.5:devel/guile-lib@${GUILE_FLAVOR} USES= guile:2.2,3.0 pkgconfig .include .... ==== [[using-iconv]] == Using `iconv` FreeBSD has a native `iconv` in the operating system. For software that needs `iconv`, define `USES=iconv`. When a port defines `USES=iconv`, these variables will be available: [.informaltable] [cols="1,1,1,1", frame="none", options="header"] |=== | Variable name | Purpose | Port iconv (when using WCHAR_T or //TRANSLIT extensions) | Base iconv |`ICONV_CMD` |Directory where the `iconv` binary resides |`${LOCALBASE}/bin/iconv` |[.filename]#/usr/bin/iconv# |`ICONV_LIB` |`ld` argument to link to [.filename]#libiconv# (if needed) |`-liconv` |(empty) |`ICONV_PREFIX` |Directory where the `iconv` implementation resides (useful for configure scripts) |`${LOCALBASE}` |[.filename]#/usr# |`ICONV_CONFIGURE_ARG` |Preconstructed configure argument for configure scripts |`--with-libiconv-prefix=${LOCALBASE}` |(empty) |`ICONV_CONFIGURE_BASE` |Preconstructed configure argument for configure scripts |`--with-libiconv=${LOCALBASE}` |(empty) |=== These two examples automatically populate the variables with the correct value for systems using package:converters/libiconv[] or the native `iconv` respectively: [[iconv-simple-use]] .Simple `iconv` Usage [example] ==== [.programlisting] .... USES= iconv LDFLAGS+= -L${LOCALBASE}/lib ${ICONV_LIB} .... ==== [[iconv-configure-use]] .`iconv` Usage with `configure` [example] ==== [.programlisting] .... USES= iconv CONFIGURE_ARGS+=${ICONV_CONFIGURE_ARG} .... ==== As shown above, `ICONV_LIB` is empty when a native `iconv` is present. This can be used to detect the native `iconv` and respond appropriately. Sometimes a program has an `ld` argument or search path hardcoded in a [.filename]#Makefile# or configure script. This approach can be used to solve that problem: [[iconv-reinplace]] .Fixing Hardcoded `-liconv` [example] ==== [.programlisting] .... USES= iconv post-patch: @${REINPLACE_CMD} -e 's/-liconv/${ICONV_LIB}/' ${WRKSRC}/Makefile .... ==== In some cases it is necessary to set alternate values or perform operations depending on whether there is a native `iconv`. [.filename]#bsd.port.pre.mk# must be included before testing the value of `ICONV_LIB`: [[iconv-conditional]] .Checking for Native `iconv` Availability [example] ==== [.programlisting] .... USES= iconv .include post-patch: .if empty(ICONV_LIB) # native iconv detected @${REINPLACE_CMD} -e 's|iconv||' ${WRKSRC}/Config.sh .endif .include .... ==== [[using-xfce]] == Using Xfce Ports that need Xfce libraries or applications set `USES=xfce`. Specific Xfce library and application dependencies are set with values assigned to `USE_XFCE`. They are defined in [.filename]#/usr/ports/Mk/Uses/xfce.mk#. The possible values are: .Values of `USE_XFCE` garcon:: package:sysutils/garcon[] libexo:: package:x11/libexo[] libgui:: package:x11-toolkits/libxfce4gui[] libmenu:: package:x11/libxfce4menu[] libutil:: package:x11/libxfce4util[] panel:: package:x11-wm/xfce4-panel[] thunar:: package:x11-fm/thunar[] xfconf:: package:x11/xfce4-conf[] [[use-xfce]] .`USES=xfce` Example [example] ==== [.programlisting] .... USES= xfce USE_XFCE= libmenu .... ==== [[use-xfce-gtk2]] .Using Xfce's Own GTK2 Widgets [example] ==== In this example, the ported application uses the GTK2-specific widgets package:x11/libxfce4menu[] and package:x11/xfce4-conf[]. [.programlisting] .... USES= xfce:gtk2 USE_XFCE= libmenu xfconf .... ==== [TIP] ==== Xfce components included this way will automatically include any dependencies they need. It is no longer necessary to specify the entire list. If the port only needs package:x11-wm/xfce4-panel[], use: [.programlisting] .... USES= xfce USE_XFCE= panel .... There is no need to list the components package:x11-wm/xfce4-panel[] needs itself like this: [.programlisting] .... USES= xfce USE_XFCE= libexo libmenu libutil panel .... However, Xfce components and non-Xfce dependencies of the port must be included explicitly. Do not count on an Xfce component to provide a sub-dependency other than itself for the main port. ==== [[using-budgie]] == Using Budgie Applications or libraries depending on the Budgie desktop should set `USES= budgie` and set `USE_BUDGIE` to the list of required components. [cols="1,1", frame="none", options="header"] |=== | Name | Description | `libbudgie` | Desktop core (library) | `libmagpie` | Budgie's X11 window manager and compositor library | `raven` | All-in-one center in panel for accessing different applications widgets | `screensaver` | Desktop-specific screensaver |=== [NOTE] ==== All application widgets communicate through the *org.budgie_desktop.Raven* service. The default dependency is lib- and run-time, it can be changed with `:build` or `:run`, for example: [.programlisting] .... USES= budgie USE_BUDGIE= screensaver:build .... ==== [[budgie-components-example]] .`USE_BUDGIE` Example [example] ==== [.programlisting] .... USES= budgie gettext gnome meson pkgconfig USE_BUDGIE= libbudgie .... ==== [[using-databases]] == Using Databases -Use one of the `USES` macros from crossref:special[using-databases-uses] to add a dependency on a database. +Use one of the `USES` macros from crossref:special[using-databases-uses,.Database `USES` Macros] to add a dependency on a database. [[using-databases-uses]] .Database `USES` Macros [cols="1,1", frame="none", options="header"] |=== | Database | USES Macro |Berkeley DB |crossref:uses[uses-bdb,`bdb`] |MariaDB, MySQL, Percona |crossref:uses[uses-mysql,`mysql`] |PostgreSQL |crossref:uses[uses-pgsql,`pgsql`] |SQLite |crossref:uses[uses-sqlite,`sqlite`] |=== [[using-databases-bdb-ex1]] .Using Berkeley DB 6 [example] ==== [.programlisting] .... USES= bdb:6 .... See crossref:uses[uses-bdb,`bdb`] for more information. ==== [[using-databases-mysql-ex1]] .Using MySQL [example] ==== When a port needs the MySQL client library add [.programlisting] .... USES= mysql .... See crossref:uses[uses-mysql,`mysql`] for more information. ==== [[using-databases-pgsql-ex1]] .Using PostgreSQL [example] ==== When a port needs the PostgreSQL server version 9.6 or later add [.programlisting] .... USES= pgsql:9.6+ WANT_PGSQL= server .... See crossref:uses[uses-pgsql,`pgsql`] for more information. ==== [[using-databases-sqlite-ex1]] .Using SQLite 3 [example] ==== [.programlisting] .... USES= sqlite:3 .... See crossref:uses[uses-sqlite,`sqlite`] for more information. ==== [[rc-scripts]] == Starting and Stopping Services (`rc` Scripts) [.filename]#rc.d# scripts are used to start services on system startup, and to give administrators a standard way of stopping, starting and restarting the service. Ports integrate into the system [.filename]#rc.d# framework. Details on its usage can be found in extref:{handbook}[the rc.d Handbook chapter, configtuning-rcd]. Detailed explanation of the available commands is provided in man:rc[8] and man:rc.subr[8]. Finally, there is extref:{rc-scripting}[an article] on practical aspects of [.filename]#rc.d# scripting. With a mythical port called _doorman_, which needs to start a _doormand_ daemon. Add the following to the [.filename]#Makefile#: [.programlisting] .... USE_RC_SUBR= doormand .... Multiple scripts may be listed and will be installed. Scripts must be placed in the [.filename]#files# subdirectory and a `.in` suffix must be added to their filename. Standard `SUB_LIST` expansions will be ran against this file. Use of the `%%PREFIX%%` and `%%LOCALBASE%%` expansions is strongly encouraged as well. More on `SUB_LIST` in crossref:pkg-files[using-sub-files,the relevant section]. As of FreeBSD 6.1-RELEASE, local [.filename]#rc.d# scripts (including those installed by ports) are included in the overall man:rcorder[8] of the base system. An example simple [.filename]#rc.d# script to start the doormand daemon: [.programlisting] .... #!/bin/sh # PROVIDE: doormand # REQUIRE: LOGIN # KEYWORD: shutdown # # Add these lines to /etc/rc.conf.local or /etc/rc.conf # to enable this service: # # doormand_enable (bool): Set to NO by default. # Set it to YES to enable doormand. # doormand_config (path): Set to %%PREFIX%%/etc/doormand/doormand.cf # by default. . /etc/rc.subr name=doormand rcvar=doormand_enable load_rc_config $name : ${doormand_enable:="NO"} : ${doormand_config="%%PREFIX%%/etc/doormand/doormand.cf"} command=%%PREFIX%%/sbin/${name} pidfile=/var/run/${name}.pid command_args="-p $pidfile -f $doormand_config" run_rc_command "$1" .... Unless there is a very good reason to start the service earlier, or it runs as a particular user (other than root), all ports scripts must use: [.programlisting] .... REQUIRE: LOGIN .... If the startup script launches a daemon that must be shutdown, the following will trigger a stop of the service on system shutdown: [.programlisting] .... KEYWORD: shutdown .... If the script is not starting a persistent service this is not necessary. For optional configuration elements the "=" style of default variable assignment is preferable to the ":=" style here, since the former sets a default value only if the variable is unset, and the latter sets one if the variable is unset _or_ null. A user might very well include something like: [.programlisting] .... doormand_flags="" .... in their [.filename]#rc.conf.local#, and a variable substitution using ":=" would inappropriately override the user's intention. The `_enable` variable is not optional, and must use the ":" for the default. [IMPORTANT] ==== Ports _must not_ start and stop their services when installing and deinstalling. Do not abuse the [.filename]#plist# keywords described in crossref:plist[plist-keywords-base-exec, "the @preexec command,@postexec command,@preunexec command,@postunexec command section"] by running commands that modify the currently running system, including starting or stopping services. ==== [[rc-scripts-checklist]] === Pre-Commit Checklist Before contributing a port with an [.filename]#rc.d# script, and more importantly, before committing one, please consult this checklist to be sure that it is ready. The package:devel/rclint[] port can check for most of these, but it is not a substitute for proper review. [.procedure] . If this is a new file, does it have a [.filename]#.sh# extension? If so, that must be changed to just [.filename]#file.in# since [.filename]#rc.d# files may not end with that extension. . Do the name of the file (minus [.filename]#.in#), the `PROVIDE` line, and `$` _name_ all match? The file name matching `PROVIDE` makes debugging easier, especially for man:rcorder[8] issues. Matching the file name and `$`_name_ makes it easier to figure out which variables are relevant in [.filename]#rc.conf[.local]#. It is also a policy for all new scripts, including those in the base system. . Is the `REQUIRE` line set to `LOGIN`? This is mandatory for scripts that run as a non-root user. If it runs as root, is there a good reason for it to run prior to `LOGIN`? If not, it must run after so that local scrips can be loosely grouped to a point in man:rcorder[8] after most everything in the base is already running. . Does the script start a persistent service? If so, it must have `KEYWORD: shutdown`. . Make sure there is no `KEYWORD: FreeBSD` present. This has not been necessary nor desirable for years. It is also an indication that the new script was copy/pasted from an old script, so extra caution must be given to the review. . If the script uses an interpreted language like `perl`, `python`, or `ruby`, make certain that `command_interpreter` is set appropriately, for example, for Perl, by adding `PERL=${PERL}` to `SUB_LIST` and using `%%PERL%%`. Otherwise, + [source,shell] .... # service name stop .... + will probably not work properly. See man:service[8] for more information. . Have all occurrences of [.filename]#/usr/local# been replaced with `%%PREFIX%%`? . Do the default variable assignments come after `load_rc_config`? . Are there default assignments to empty strings? They should be removed, but double-check that the option is documented in the comments at the top of the file. . Are things that are set in variables actually used in the script? . Are options listed in the default _name_`_flags` things that are actually mandatory? If so, they must be in `command_args`. `-d` is a red flag (pardon the pun) here, since it is usually the option to "daemonize" the process, and therefore is actually mandatory. . `_name__flags` must never be included in `command_args` (and vice versa, although that error is less common). . Does the script execute any code unconditionally? This is frowned on. Usually these things must be dealt with through a `start_precmd`. . All boolean tests must use the `checkyesno` function. No hand-rolled tests for `[Yy][Ee][Ss]`, etc. . If there is a loop (for example, waiting for something to start) does it have a counter to terminate the loop? We do not want the boot to be stuck forever if there is an error. . Does the script create files or directories that need specific permissions, for example, a [.filename]#pid# that needs to be owned by the user that runs the process? Rather than the traditional man:touch[1]/man:chown[8]/man:chmod[1] routine, consider using man:install[1] with the proper command line arguments to do the whole procedure with one step. [[users-and-groups]] == Adding Users and Groups Some ports require a particular user account to be present, usually for daemons that run as that user. For these ports, choose a _unique_ UID from 50 to 999 and register it in [.filename]#ports/UIDs# (for users) and [.filename]#ports/GIDs# (for groups). The unique identification should be the same for users and groups. Please include a patch against these two files when requiring a new user or group to be created for the port. Then use `USERS` and `GROUPS` in [.filename]#Makefile#, and the user will be automatically created when installing the port. [.programlisting] .... USERS= pulse GROUPS= pulse pulse-access pulse-rt .... The current list of reserved UIDs and GIDs can be found in [.filename]#ports/UIDs# and [.filename]#ports/GIDs#. [[requiring-kernel-sources]] == Ports That Rely on Kernel Sources Some ports (such as kernel loadable modules) need the kernel source files so that the port can compile. Here is the correct way to determine if the user has them installed: [.programlisting] .... USES= kmod .... Apart from this check, the `kmod` feature takes care of most items that these ports need to take into account. [[go-libs]] == Go Libraries Ports must not package or install Go libs or source code. Go ports must fetch the required deps at the normal fetch time and should only install the programs and things users need, not the things Go developers would need. Ports should (in order of preference): * Use vendored dependencies included with the package source. * Fetch the versions of deps specified by upstream (in the case of go.mod, vendor.json or similar). * As a last resort (deps are not included nor versions specified exactly) fetch versions of dependencies available at the time of upstream development/release. [[haskell-libs]] == Haskell Libraries Just like in case of Go language, Ports must not package or install Haskell libraries. Haskell ports must link statically to their dependencies and fetch all distribution files on fetch stage. [[shell-completion]] == Shell Completion Files Many modern shells (including bash, fish, tcsh and zsh) support parameter and/or option tab-completion. This support usually comes from completion files, which contain the definitions for how tab completion will work for a certain command. Ports sometimes ship with their own completion files, or porters may have created them themselves. When available, completion files should always be installed. It is not necessary to make an option for it. If an option is used, though, always enable it in `OPTIONS_DEFAULT`. [[shell-completion-paths]] .Full shell completion file names [cols="1,1,1", frame="none"] |=== |`bash` |[.filename]#${PREFIX}/etc/bash_completion.d# or [.filename]#${PREFIX}/share/bash-completion/completions# |(any unique file names in one of these folders) |`fish` |[.filename]#${PREFIX}/share/fish/completions/${PORTNAME}.fish# | |`zsh` |[.filename]#${PREFIX}/share/zsh/site-functions/_${PORTNAME}# | |=== Do not register any dependencies on the shells themselves. diff --git a/documentation/content/en/books/porters-handbook/testing/_index.adoc b/documentation/content/en/books/porters-handbook/testing/_index.adoc index 7ac46b3a4e..f49e02caa7 100644 --- a/documentation/content/en/books/porters-handbook/testing/_index.adoc +++ b/documentation/content/en/books/porters-handbook/testing/_index.adoc @@ -1,670 +1,670 @@ --- title: Chapter 10. Testing the Port prev: books/porters-handbook/pkg-files next: books/porters-handbook/upgrading description: Testing a FreeBSD Port tags: ["testing", "port", "Portclippy", "Portfmt", "Portlint", "poudriere", "sets"] showBookMenu: true weight: 10 path: "/books/porters-handbook/testing/" --- [[testing]] = Testing the Port :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 10 :partnums: :source-highlighter: rouge :experimental: :images-path: books/porters-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[make-describe]] == Running `make describe` Several of the FreeBSD port maintenance tools, such as man:portupgrade[1], rely on a database called [.filename]#/usr/ports/INDEX# which keeps track of such items as port dependencies. [.filename]#INDEX# is created by the top-level [.filename]#ports/Makefile# via `make index`, which descends into each port subdirectory and executes `make describe` there. Thus, if `make describe` fails in any port, no one can generate [.filename]#INDEX#, and many people will quickly become unhappy. [NOTE] ==== It is important to be able to generate this file no matter what options are present in [.filename]#make.conf#, so please avoid doing things such as using `.error` statements when (for instance) a dependency is not satisfied. (See crossref:porting-dads[dads-dot-error,Avoid Use of the `.error` Construct].) ==== If `make describe` produces a string rather than an error message, everything is probably safe. See [.filename]#bsd.port.mk# for the meaning of the string produced. Also note that running a recent version of `portlint` (as specified in the next section) will cause `make describe` to be run automatically. [[make-test]] == Running `make test` Even if the port builds fine, it is a good idea to ensure that the software correctly does what it is supposed to do. If the original upstream project provides tests along with the software, it is a good idea to run them and check everything works as expected. A port can enable tests automatically by using the `TEST_TARGET` variable. When set, this variable contains the name of the testing target of the port. This is usually just `test` but other names include `tests`, `check` or for specific cases things like `run_tests.py`. In addition to the `TEST_TARGET` variable the framework provides the following variables to control the tests execution: * `TEST_WRKSRC` is the directory to do the tests in. * `TEST_ENV` contains additional variables to be passed to the test stage. * `TEST_ARGS` contains any extra arguments passed to the test stage. Examples of use of these variables can be found in package:cad/xyce[], package:www/libjwt[] and others. [NOTE] ==== Please make sure that tests do not break when updating a port. ==== [[testing-portclippy]] == Portclippy / Portfmt Those tools come from package:ports-mgmt/portfmt[]. Portclippy is a linter that checks if variables in the [.filename]#Makefile# are in the correct order according to crossref:order[porting-order,Order of Variables in Port Makefiles]. Portfmt is a tool for automatically formatting [.filename]#Makefile#. [[testing-portlint]] == Portlint Do check the port with crossref:quick-porting[porting-portlint,`portlint`] before submitting or committing it. `portlint` warns about many common errors, both functional and stylistic. For a new port, `portlint -A` is the most thorough; for an existing port, `portlint -C` is sufficient. Since `portlint` uses heuristics to try to figure out errors, it can produce false positive warnings. In addition, occasionally something that is flagged as a problem really cannot be done in any other way due to limitations in the ports framework. pass:[] When in doubt, the best thing to do is ask on {freebsd-ports}. pass:[] [[testing-porttools]] == Port Tools The package:ports-mgmt/porttools[] program is part of the Ports Collection. `port` is the front-end script, which can help simplify the testing job. Whenever a new port or an update to an existing one needs testing, use `port test` to test the port, including the crossref:testing[testing-portlint,`portlint`] checking. This command also detects and lists any files that are not listed in [.filename]#pkg-plist#. For example: [source,shell] .... # port test /usr/ports/net/csup .... [[porting-prefix]] == `PREFIX` and `DESTDIR` `PREFIX` determines where the port will be installed. It defaults to [.filename]#/usr/local#, but can be set by the user to a custom path like [.filename]#/opt#. The port must respect the value of this variable. `DESTDIR`, if set by the user, determines the complete alternative environment, usually a jail or an installed system mounted somewhere other than [.filename]#/#. A port will actually install into [.filename]#DESTDIR/PREFIX#, and register with the package database in [.filename]#DESTDIR/var/db/pkg#. `DESTDIR` is handled automatically by the ports infrastructure with man:chroot[8]. There is no need for modifications or any extra care to write `DESTDIR`-compliant ports. The value of `PREFIX` will be set to `LOCALBASE` (defaulting to [.filename]#/usr/local#). If `USE_LINUX_PREFIX` is set, `PREFIX` will be `LINUXBASE` (defaulting to [.filename]#/compat/linux#). Avoiding hard-coded [.filename]#/usr/local# paths in the source makes the port much more flexible and able to cater to the needs of other sites. Often, this can be accomplished by replacing occurrences of [.filename]#/usr/local# in the port's various [.filename]##Makefile##s with `${PREFIX}`. This variable is automatically passed down to every stage of the build and install processes. Make sure the application is not installing things in [.filename]#/usr/local# instead of `PREFIX`. A quick test for such hard-coded paths is: [source,shell] .... % make clean; make package PREFIX=/var/tmp/`make -V PORTNAME` .... If anything is installed outside of `PREFIX`, the package creation process will complain that it cannot find the files. In addition, it is worth checking the same with the stage directory support (see crossref:special[staging,Staging]): [source,shell] .... % make stage && make check-plist && make stage-qa && make package .... * `check-plist` checks for files missing from the plist, and files in the plist that are not installed by the port. * `stage-qa` checks for common problems like bad shebang, symlinks pointing outside the stage directory, setuid files, and non-stripped libraries... These tests will not find hard-coded paths inside the port's files, nor will it verify that `LOCALBASE` is being used to correctly refer to files from other ports. The temporarily installed port in [.filename]#/var/tmp/`make -V PORTNAME`# must be tested for proper operation to make sure there are no problems with paths. `PREFIX` must not be set explicitly in a port's [.filename]#Makefile#. Users installing the port may have set `PREFIX` to a custom location, and the port must respect that setting. Refer to programs and files from other ports with the variables mentioned above, not explicit pathnames. For instance, if the port requires a macro `PAGER` to have the full pathname of `less`, do not use a literal path of [.filename]#/usr/local/bin/less#. Instead, use `${LOCALBASE}`: [.programlisting] .... -DPAGER=\"${LOCALBASE}/bin/less\" .... The path with `LOCALBASE` is more likely to still work if the system administrator has moved the whole [.filename]#/usr/local# tree somewhere else. [TIP] ==== All these tests are done automatically when running `poudriere testport` or `poudriere bulk -t`. It is highly recommended that every ports contributor install and test their ports with it. -See crossref:testing[testing-poudriere] for more information. +See crossref:testing[testing-poudriere, poudriere] for more information. ==== [[testing-poudriere]] == poudriere For a ports contributor, poudriere is one of the most important and helpful testing and build tools. Its main features include: * Bulk building of the entire ports tree, specific subsets of the ports tree, or a single port including its dependencies * Automatic packaging of build results * Generation of build log files per port * Providing a signed man:pkg[8] repository * Testing of port builds before submitting a patch to the FreeBSD bug tracker or committing to the ports tree * Testing for successful ports builds using different options Because poudriere performs its building in a clean man:jail[8] environment and uses man:zfs[8] features, it has several advantages over traditional testing on the host system: * No pollution of the host environment: No leftover files, no accidental removals, no changes of existing configuration files. * Verify [.filename]#pkg-plist# for missing or superfluous entries * Ports committers sometimes ask for a poudriere log alongside a patch submission to assess whether the patch is ready for integration into the ports tree It is also quite straightforward to set up and use, has no dependencies, and will run on any supported FreeBSD release. This section shows how to install, configure, and run poudriere as part of the normal workflow of a ports contributor. The examples in this section show a default file layout, as standard in FreeBSD. Substitute any local changes accordingly. The ports tree, represented by `${PORTSDIR}`, is located in [.filename]#/usr/ports#. Both `${LOCALBASE}` and `${PREFIX}` are [.filename]#/usr/local# by default. [[testing-poudriere-installing]] === Installing poudriere poudriere is available in the ports tree in package:ports-mgmt/poudriere[]. It can be installed using man:pkg[8] or from ports: [source,shell] .... # pkg install poudriere .... or [source,shell] .... # make -C /usr/ports/ports-mgmt/poudriere install clean .... There is also a work-in-progress version of poudriere which will eventually become the next release. It is available in package:ports-mgmt/poudriere-devel[]. This development version is used for the official FreeBSD package builds, so it is well tested. It often has newer interesting features. A ports committer will want to use the development version because it is what is used in production, and has all the new features that will make sure everything is exactly right. A contributor will not necessarily need those as the most important fixes are backported to released version. The main reason for the use of the development version to build the official package is because it is faster, in a way that will shorten a full build from 18 hours to 17 hours when using a high end 32 CPU server with 128GB of RAM. Those optimizations will not matter a lot when building ports on a desktop machine. [[testing-poudriere-setup]] === Setting Up poudriere The port installs a default configuration file, [.filename]#/usr/local/etc/poudriere.conf#. Each parameter is documented in the configuration file. Here is a minimal example config file: [.programlisting] .... ZPOOL=zroot BASEFS=/usr/local/poudriere DISTFILES_CACHE=/usr/ports/distfiles RESOLV_CONF=/etc/resolv.conf .... `ZPOOL`:: The name of the ZFS storage pool which poudriere shall use. Must be listed in the output of `zpool status`. `BASEFS`:: The root mount point for poudriere file systems. This entry will cause poudriere to mount `tank/poudriere` to `/poudriere`. `DISTFILES_CACHE`:: Defines where distfiles are stored. In this example, poudriere and the host share the distfiles storage directory. This avoids downloading tarballs which are already present on the system. Please create this directory if it does not already exist so that poudriere can find it. `RESOLV_CONF`:: Use the host [.filename]#/etc/resolv.conf# inside jails for DNS. This is needed so jails can resolve the URLs of distfiles when downloading. It is not needed when using a proxy. Refer to the default configuration file for proxy configuration. [[testing-poudriere-create-jails]] === Creating poudriere Jails Create the base jails which poudriere will use for building: [source,shell] .... # poudriere jail -c -j 131Ramd64 -v 13.1-RELEASE -a amd64 .... Fetch a `13.1-RELEASE` for `amd64` from the FTP server given by `FREEBSD_HOST` in [.filename]#poudriere.conf#, create the zfs file system `tank/poudriere/jails/131Ramd64`, mount it on [.filename]#/poudriere/jails/131Ramd64# and extract the `13.1-RELEASE` tarballs into this file system. [source,shell] .... # poudriere jail -c -j 12i386 -v stable/12 -a i386 -m git+https .... Create `tank/poudriere/jails/12i386`, mount it on [.filename]#/poudriere/jails/12i386#, then check out the tip of the Git branch of `FreeBSD-12-STABLE` from `GIT_HOST` in [.filename]#poudriere.conf# or the default `git.freebsd.org` into [.filename]#/poudriere/jails/12i386/usr/src#, then complete a `buildworld` and install it into [.filename]#/poudriere/jails/12i386#. [NOTE] ==== While it is possible to build a newer version of FreeBSD on an older version, most of the time it will not run. For example, if a `stable/13` jail is needed, the host will have to run `stable/13` too. Running `13.1-RELEASE` is not enough. ==== [NOTE] ==== To create a poudriere jail for `14.0-CURRENT`: [source,shell] .... # poudriere jail -c -j 14amd64 -v main -a amd64 -m git+https .... In order to run a `14.0-CURRENT` poudriere jail the host must be running `14.0-CURRENT`. In general, newer kernels can build and run older jails. For instance, a `14.0-CURRENT` kernel can build and run a `12.4-STABLE` if the `COMPAT_FREEBSD12` kernel option was compiled in (on by default in `14.0-CURRENT`[.filename]#GENERIC# kernel config). ==== A list of jails currently known to poudriere can be shown with `poudriere jail -l`: [source,shell] .... # poudriere jail -l JAILNAME VERSION ARCH METHOD 131Ramd64 13.1-RELEASE amd64 ftp 12i386 12.4-STABLE i386 git+https .... [[testing-poudriere-maintaining-jails]] === Keeping poudriere Jails Updated Managing updates is very straightforward. The command: [source,shell] .... # poudriere jail -u -j JAILNAME .... updates the specified jail to the latest version available. pass:[] For FreeBSD releases, update to the latest patchlevel with man:freebsd-update[8]. pass:[] For FreeBSD versions built from source, update to the latest git revision in the branch. [TIP] ==== For jails employing a `git+*` method, it is helpful to add `-J _NumberOfParallelBuildJobs_` to speed up the build by increasing the number of parallel compile jobs used. For example, if the building machine has 6 CPUs, use: [source,shell] .... # poudriere jail -u -J 6 -j JAILNAME .... ==== [[testing-poudriere-ports-tree]] === Setting Up Ports Trees for Use with poudriere There are multiple ways to use ports trees in poudriere. The most straightforward way is to have poudriere create a default ports tree for itself, using link:{handbook}mirrors/#git[Git]: [source,shell] .... # poudriere ports -c -m git+https -B main .... These commands create `tank/poudriere/ports/default`, mount it on [.filename]#/poudriere/ports/default#, and populate it using Git. Afterward it is included in the list of known ports trees: [source,shell] .... # poudriere ports -l PORTSTREE METHOD TIMESTAMP PATH default git+https 2020-07-20 04:23:56 /poudriere/ports/default .... [NOTE] ==== Note that the "default" ports tree is special. Each of the build commands explained later will implicitly use this ports tree unless specifically specified otherwise. To use another tree, add `-p _treename_` to the commands. ==== The best way to deal with local modifications for a ports contributor is to use link:{handbook}mirrors/#git[Git]. As with the creation of jails, it is possible to use a different method for creating the ports tree. To add an additional ports tree for testing local modifications and ports development, checking out the tree via git (as described above) is preferable. [[testing-poudriere-ports-tree-manual]] === Using Manually Managed Ports Trees with poudriere Depending on the workflow, it can be extremely helpful to use ports trees which are maintained manually. For instance, if there is a local copy of the ports tree in [.filename]#/work/ports#, point poudriere to the location: [source,shell] .... # poudriere ports -c -m null -M /work/ports -p development .... This will be listed in the table of known trees: [source,shell] .... # poudriere ports -l PORTSTREE METHOD TIMESTAMP PATH development null 2020-07-20 05:06:33 /work/ports .... [NOTE] ==== The dash or `null` in the `METHOD` column means that poudriere will not update or change this ports tree, ever. It is completely up to the user to maintain this tree, including all local modifications that may be used for testing new ports and submitting patches. ==== [[testing-poudriere-ports-tree-updating]] === Keeping poudriere Ports Trees Updated As straightforward as with jails described earlier: [source,shell] .... # poudriere ports -u -p PORTSTREE .... Will update the given _PORTSTREE_, one tree given by the output of `poudriere -l`, to the latest revision available on the official servers. [NOTE] ==== Ports trees without a method, see -crossref:testing[testing-poudriere-ports-tree-manual], cannot be updated like this and must be updated manually by the porter. +crossref:testing[testing-poudriere-ports-tree-manual, Using Manually Managed Ports Trees with poudriere], cannot be updated like this and must be updated manually by the porter. ==== [[testing-poudriere-testing-ports]] === Testing Ports After jails and ports trees have been set up, the result of a contributor's modifications to the ports tree can be tested. For example, local modifications to the package:www/firefox[] port located in [.filename]#/work/ports/www/firefox# can be tested in the previously created 13.1-RELEASE jail: [source,shell] .... # poudriere testport -j 131Ramd64 -p development -o www/firefox .... This will build all dependencies of Firefox. If a dependency has been built previously and is still up-to-date, the pre-built package is installed. If a dependency has no up-to-date package, one will be built with default options in a jail. Then Firefox itself is built. The complete build of every port is logged to [.filename]#/poudriere/data/logs/bulk/131Ri386-development/build-time/logs#. The directory name `131Ri386-development` is derived from the arguments to `-j` and `-p`, respectively. For convenience, a symbolic link [.filename]#/poudriere/data/logs/bulk/131Ri386-development/latest# is also maintained. The link points to the latest _build-time_ directory. Also in this directory is an [.filename]#index.html# for observing the build process with a web browser. By default, poudriere cleans up the jails and leaves log files in the directories mentioned above. To ease investigation, jails can be kept running after the build by adding `-i` to `testport`: [source,shell] .... # poudriere testport -j 131Ramd64 -p development -i -o www/firefox .... After the build completes, and regardless of whether it was successful, a shell is provided within the jail. The shell is used to investigate further. poudriere can be told to leave the jail running after the build finishes with `-I`. poudriere will show the command to run when the jail is no longer needed. It is then possible to man:jexec[8] into it: [source,shell] .... # poudriere testport -j 131Ramd64 -p development -I -o www/firefox [...] ====>> Installing local Pkg repository to /usr/local/etc/pkg/repos ====>> Leaving jail 131Ramd64-development-n running, mounted at /poudriere/data/.m/131Ramd64-development/ref for interactive run testing ====>> To enter jail: jexec 131Ramd64-development-n env -i TERM=$TERM /usr/bin/login -fp root ====>> To stop jail: poudriere jail -k -j 131Ramd64 -p development # jexec 131Ramd64-development-n env -i TERM=$TERM /usr/bin/login -fp root # [do some stuff in the jail] # exit # poudriere jail -k -j 131Ramd64 -p development ====>> Umounting file systems .... An integral part of the FreeBSD ports build infrastructure is the ability to tweak ports to personal preferences with options. These can be tested with poudriere as well. Adding the `-c`: [source,shell] .... # poudriere testport -c -o www/firefox .... Presents the port configuration dialog before the port is built. The ports given after `-o` in the format `_category_/_portname_` will use the specified options, all dependencies will use the default options. Testing dependent ports with non-default options can be accomplished using sets, -see crossref:testing[testing-poudriere-sets]. +see crossref:testing[testing-poudriere-sets, Using Sets]. [TIP] ==== When testing ports where [.filename]#pkg-plist# is altered during build depending on the selected options, it is recommended to perform a test run with all options selected _and_ one with all options deselected. ==== [[testing-poudriere-sets]] === Using Sets For all actions involving builds, a so-called _set_ can be specified using `-z _setname_`. A set refers to a fully independent build. This allows, for instance, usage of `testport` with non-standard options for the dependent ports. To use sets, poudriere expects an existing directory structure similar to `PORT_DBDIR`, defaults to [.filename]#/var/db/ports# in its configuration directory. This directory is then man:nullfs[5]-mounted into the jails where the ports and their dependencies are built. Usually a suitable starting point can be obtained by recursively copying the existing `PORT_DBDIR` to [.filename]#/usr/local/etc/poudriere.d/jailname-portname-setname-options#. This is described in detail in man:poudriere[8]. For instance, testing package:www/firefox[] in a specific set named `devset`, add the `-z devset` parameter to the `testport` command: [source,shell] .... # poudriere testport -j 131Ramd64 -p development -z devset -o www/firefox .... This will look for the existence of these directories in this order: * [.filename]#/usr/local/etc/poudriere.d/131Ramd64-development-devset-options# * [.filename]#/usr/local/etc/poudriere.d/131Ramd64-devset-options# * [.filename]#/usr/local/etc/poudriere.d/131Ramd64-development-options# * [.filename]#/usr/local/etc/poudriere.d/devset-options# * [.filename]#/usr/local/etc/poudriere.d/development-options# * [.filename]#/usr/local/etc/poudriere.d/131Ramd64-options# * [.filename]#/usr/local/etc/poudriere.d/options# From this list, poudriere man:nullfs[5]-mounts the _first existing_ directory tree into the [.filename]#/var/db/ports# directory of the build jails. Hence, all custom options are used for all the ports during this run of `testport`. After the directory structure for a set is provided, the options for a particular port can be altered. For example: [source,shell] .... # poudriere options -c www/firefox -z devset .... The configuration dialog for package:www/firefox[] is shown, and options can be edited. The selected options are saved to the `devset` set. [NOTE] ==== poudriere is very flexible in the option configuration. poudriere can be set for particular jails, ports trees, and for multiple ports by one command. Refer to man:poudriere[8] for details. ==== [[testing-poudriere-make-conf]] === Providing a Custom [.filename]#make.conf# File Similar to using sets, poudriere will also use a custom [.filename]#make.conf# if it is provided. No special command line argument is necessary. Instead, poudriere looks for existing files matching a name scheme derived from the command line. For instance: [source,shell] .... # poudriere testport -j 131Ramd64 -p development -z devset -o www/firefox .... causes poudriere to check for the existence of these files in this order: * [.filename]#/usr/local/etc/poudriere.d/make.conf# * [.filename]#/usr/local/etc/poudriere.d/devset-make.conf# * [.filename]#/usr/local/etc/poudriere.d/development-make.conf# * [.filename]#/usr/local/etc/poudriere.d/131Ramd64-make.conf# * [.filename]#/usr/local/etc/poudriere.d/131Ramd64-development-make.conf# * [.filename]#/usr/local/etc/poudriere.d/131Ramd64-devset-make.conf# * [.filename]#/usr/local/etc/poudriere.d/131Ramd64-development-devset-make.conf# Unlike with sets, all of the found files will be appended, _in that order_, into one [.filename]#make.conf# inside the build jails. It is hence possible to have general make variables, intended to affect all builds in [.filename]#/usr/local/etc/poudriere.d/make.conf#. Special variables, intended to affect only certain jails or sets can be set in specialised [.filename]#make.conf# files, such as [.filename]#/usr/local/etc/poudriere.d/131Ramd64-development-devset-make.conf#. [[testing-poudriere-sets-perl]] .Using [.filename]#make.conf# to Change Default Perl [example] ==== To build a set with a non default Perl version, for example, `5.20`, using a set named `perl5-20`, create a [.filename]#perl5-20-make.conf# with this line: [.programlisting] .... DEFAULT_VERSIONS+= perl=5.20 .... [NOTE] **** Note the use of `+=` so that if the variable is already set in the default [.filename]#make.conf# its content will not be overwritten. **** ==== [[testing-poudriere-pruning-distfiles]] === Pruning no Longer Needed Distfiles poudriere comes with a built-in mechanism to remove outdated distfiles that are no longer used by any port of a given tree. The command [source,shell] .... # poudriere distclean -p portstree .... will scan the distfiles folder, `DISTFILES_CACHE` in [.filename]#poudriere.conf#, versus the ports tree given by the `-p _portstree_` argument and prompt for removal of those distfiles. To skip the prompt and remove all unused files unconditionally, the `-y` argument can be added: [source,shell] .... # poudriere distclean -p portstree -y .... [[testing-debugging-ports]] == Debugging ports Sometimes things go wrong and the port fails at run time. The framework provides some facilities to help in debugging ports. These helpers are limited since the way of debugging a port heavily depends on the technology used. The following variables help with debugging ports: * `WITH_DEBUG`. If set, ports are built with debugging symbols. * `WITH_DEBUG_PORTS`. Specifies a list of ports to be built with `WITH_DEBUG` set. * `DEBUG_FLAGS`. Used to specify additional flags to `CFLAGS`. Defaults to `-g`. When `WITH_DEBUG` is set, either globally or for a list of ports, the resulting binaries are not stripped. These variables can be specified in [.filename]#make.conf# or in the command line: [source,shell] .... # cd category/port && make -DWITH_DEBUG DEBUG_FLAGSS="-g -O0" .... [NOTE] ==== If the port is built using package:ports-mgmt/poudriere[] the debugging variables must be specified in poudriere's [.filename]#make.conf# and not in [.filename]#/etc/make.conf#. Refer to package:ports-mgmt/poudriere[] documentation for details. ==== Please refer to the debugging information in the extref:{developers-handbook}tools[Developer's Handbook, debugging] for more details about the debugging tools available. diff --git a/documentation/content/en/books/porters-handbook/uses/_index.adoc b/documentation/content/en/books/porters-handbook/uses/_index.adoc index 599256e11b..d2005f5ba8 100644 --- a/documentation/content/en/books/porters-handbook/uses/_index.adoc +++ b/documentation/content/en/books/porters-handbook/uses/_index.adoc @@ -1,2414 +1,2414 @@ --- title: Chapter 17. Using USES Macros prev: books/porters-handbook/keeping-up next: books/porters-handbook/versions description: USES macros make it easy to declare requirements and settings for a FreeBSD Port tags: ["uses", "macros", "introduction", "guide"] showBookMenu: true weight: 17 path: "/books/porters-handbook/uses/" --- [[uses]] = Using `USES` Macros :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 17 :partnums: :source-highlighter: rouge :experimental: :images-path: books/porters-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[uses-intro]] == An Introduction to `USES` `USES` macros make it easy to declare requirements and settings for a port. They can add dependencies, change building behavior, add metadata to packages, and so on, all by selecting simple, preset values. Each section in this chapter describes a possible value for `USES`, along with its possible arguments. Arguments are appended to the value after a colon (`:`). Multiple arguments are separated by commas (`,`). [[uses-intro-ex1]] .Using Multiple Values [example] ==== [.programlisting] .... USES= bison perl .... ==== [[uses-intro-ex2]] .Adding an Argument [example] ==== [.programlisting] .... USES= tar:xz .... ==== [[uses-intro-ex3]] .Adding Multiple Arguments [example] ==== [.programlisting] .... USES= drupal:7,theme .... ==== [[uses-intro-ex4]] .Mixing it All Together [example] ==== [.programlisting] .... USES= pgsql:9.3+ cpe python:2.7,build .... ==== [[uses-7z]] == `7z` Possible arguments: (none), `p7zip`, `partial` Extract using man:7z[1] instead of man:bsdtar[1] and sets `EXTRACT_SUFX=.7z`. The `p7zip` option forces a dependency on the `7z` from package:archivers/p7zip[] if the one from the base system is not able to extract the files. `EXTRACT_SUFX` is not changed if the `partial` option is used, this can be used if the main distribution file does not have a [.filename]#.7z# extension. [[uses-ada]] == `ada` Possible arguments: (none), `6`, `12`, `(run)` Depends on an Ada-capable compiler, and sets `CC` accordingly. Defaults to use `gcc6-aux` from ports. [[uses-autoreconf]] == `autoreconf` Possible arguments: (none), `build` Runs `autoreconf`. It encapsulates the `aclocal`, `autoconf`, `autoheader`, `automake`, `autopoint`, and `libtoolize` commands. Each command applies to [.filename]#${AUTORECONF_WRKSRC}/configure.ac# or its old name, [.filename]#${AUTORECONF_WRKSRC}/configure.in#. If [.filename]#configure.ac# defines subdirectories with their own [.filename]#configure.ac# using `AC_CONFIG_SUBDIRS`, `autoreconf` will recursively update those as well. The `:build` argument only adds build time dependencies on those tools but does not run `autoreconf`. A port can set `AUTORECONF_WRKSRC` if `WRKSRC` does not contain the path to [.filename]#configure.ac#. [[uses-blaslapack]] == `blaslapack` Possible arguments: (none), `atlas`, `netlib` (default), `gotoblas`, `openblas` Adds dependencies on Blas / Lapack libraries. [[uses-bdb]] == `bdb` Possible arguments: (none), `48`, `5` (default), `6` Add dependency on the Berkeley DB library. Default to package:databases/db5[]. It can also depend on package:databases/db48[] when using the `:48` argument or package:databases/db6[] with `:6`. It is possible to declare a range of acceptable values, `:48+` finds the highest installed version, and falls back to 4.8 if nothing else is installed. `INVALID_BDB_VER` can be used to specify versions which do not work with this port. The framework exposes the following variables to the port: `BDB_LIB_NAME`:: The name of the Berkeley DB library. For example, when using package:databases/db5[], it contains `db-5.3`. `BDB_LIB_CXX_NAME`:: The name of the Berkeley DBC++ library. For example, when using package:databases/db5[], it contains `db_cxx-5.3`. `BDB_INCLUDE_DIR`:: The location of the Berkeley DB include directory. For example, when using package:databases/db5[], it will contain `${LOCALBASE}/include/db5`. `BDB_LIB_DIR`:: The location of the Berkeley DB library directory. For example, when using package:databases/db5[], it contains `${LOCALBASE}/lib`. `BDB_VER`:: The detected Berkeley DB version. For example, if using `USES=bdb:48+` and Berkeley DB 5 is installed, it contains `5`. [IMPORTANT] ==== package:databases/db48[] is deprecated and unsupported. It must not be used by any port. ==== [[uses-bison]] == `bison` Possible arguments: (none), `build`, `run`, `both` Uses package:devel/bison[] By default, with no arguments or with the `build` argument, it implies `bison` is a build-time dependency, `run` implies a run-time dependency, and `both` implies both run-time and build-time dependencies. [[uses-budgie]] == `budgie` Possible arguments: (none) Provide support for the Budgie desktop environment. Use `USE_BUDGIE` to select the components needed for the port. See crossref:special[using-budgie,Using Budgie] for more information. [[uses-cabal]] == `cabal` [IMPORTANT] ==== Ports should not be created for Haskell libraries, see crossref:special[haskell-libs,Haskell Libraries] for more information. ==== Possible arguments: (none), `hpack`, `nodefault` Sets default values and targets used to build Haskell software using Cabal. A build dependency on the Haskell compiler port (package:lang/ghc[]) is added. If there is some other version of GHC already listed in the `BUILD_DEPENDS` variable (for example, package:lang/ghc810[]), it would be used instead. If the `hpack` argument is given, a build dependency on package:devel/hs-hpack[] is added and `hpack` is invoked at configuration step to generate .cabal file. If the `nodefault` argument is given, the framework will not try to pull the main distribution file from the Hackage. This argument is implicitly added if `USE_GITHUB` or `USE_GITLAB` is present. The framework provides the following variables: `CABAL_REVISION`:: Haskell packages hosted on Hackage may have revisions. Set this knob to an integer number to pull in revised package description. `USE_CABAL`:: If the software uses Haskell dependencies, list them in this variable. Each item should be present on Hackage and be listed in form `packagename-_0.1.2_`. Dependencies can have revisions too, which are specified after the `_` symbol. Automatic generation of the dependency list is supported, see crossref:special[using-cabal,Building Haskell Applications with `cabal`]. `CABAL_FLAGS`:: List of flags to be passed to `cabal-install` during the configuring and building stage. The flags are passed verbatim. This variable is usually used to enable or disable flags that are declared in the .cabal file. Pass `foo` to enable the `foo` flag and `-foo` to disable it. `CABAL_EXECUTABLES`:: List of executable files installed by the port. Default value: `${PORTNAME}`. Consult the .cabal file of the project being ported to get a list of possible values for this variable. Each value corresponds to an `executable` stanza in the .cabal file. Items from this list are automatically added to pkg-plist. `SKIP_CABAL_PLIST`:: If defined, do not add items from `${CABAL_EXECUTABLES}` to pkg-plist. `opt_USE_CABAL`:: Adds items to `${USE_CABAL}` depending on `opt` option. `opt_CABAL_EXECUTABLES`:: Adds items to `${CABAL_EXECUTABLES}` depending on `opt` option. `opt_CABAL_FLAGS`:: If `opt` is enabled, append the value to `${CABAL_FLAGS}`. Otherwise, append `-value` to disable the flag. Note that this behavior is slightly different from the plain `CABAL_FLAGS` as it does not accept values starting with `-`. `CABAL_WRAPPER_SCRIPTS`:: A subset of `${CABAL_EXECUTABLES}` containing Haskell programs to be wrapped into a shell script that sets `*_datadir` environment variables before running the program. This also causes the actual Haskell binary to be installed under `libexec/cabal/` directory. This knob is needed for Haskell programs that install their data files under `share/` directory. `FOO_DATADIR_VARS`:: List of extra Haskell packages, whose data files should be accessible by the executable named `FOO`. The executable should be a part of `${CABAL_WRAPPER_SCRIPTS}`. Haskell packages listed there should not have a version suffix. `CABAL_PROJECT`:: Some Haskell projects may already have a `cabal.project` file, which is also generated by the ports framework. If that is the case, use this variable to specify what to do with the original `cabal.project`. Setting this variable to `remove` will cause the original file to be removed. Setting this variable to `append` will: . Move the original file to `cabal.project.${PORTNAME}` during the `extract` stage. . Concatenate the original `cabal.project.${PORTNAME}` and the generated `cabal.project` into a single file after the `patch` stage. Using `append` makes it possible to perform patching on the original file before it gets merged. [[uses-cargo]] == `cargo` Possible arguments: (none) Uses Cargo for configuring, building, and testing. It can be used to port Rust applications that use the Cargo build system. For more information see crossref:special[using-cargo,Building Rust Applications with `cargo`]. [[uses-charsetfix]] == `charsetfix` Possible arguments: (none) Prevents the port from installing [.filename]#charset.alias#. This must be installed only by package:converters/libiconv[]. `CHARSETFIX_MAKEFILEIN` can be set to a path relative to `WRKSRC` if [.filename]#charset.alias# is not installed by [.filename]#${WRKSRC}/Makefile.in#. [[uses-cmake]] == `cmake` Possible arguments: (none), `insource`, `noninja`, `run`, `testing` Use CMake for configuring the port and generating a build system. By default an out-of-source build is performed, leaving the sources in `WRKSRC` free from build artifacts. With the `insource` argument, an in-source build will be performed instead. This argument should be an exception, used only when a regular out-of-source build does not work. By default Ninja (package:devel/ninja[]) is used for the build. In some cases this does not work correctly. With the `noninja` argument, the build will use regular `make` for builds. This argument should only be used if a Ninja-based build does not work. With the `run` argument, a run dependency is registered in addition to a build dependency. With the `testing` argument, a test-target is added that uses CTest. When running tests the port will be re-configured for testing and re-built. For more information see crossref:special[using-cmake,Using `cmake`]. [[uses-compiler]] == `compiler` Possible arguments: (none), `env` (default, implicit), `{cpp}17-lang`, `{cpp}14-lang`, `{cpp}11-lang`, `gcc-{cpp}11-lib`, `{cpp}11-lib`, `{cpp}0x`, `c11`, `nestedfct`, `features` Determines which compiler to use based on any given wishes. Use `{cpp}17-lang` if the port needs a {cpp}17-capable compiler, `{cpp}14-lang` if the port needs a {cpp}14-capable compiler, `{cpp}11-lang` if the port needs a {cpp}11-capable compiler, `gcc-{cpp}11-lib` if the port needs the `g++` compiler with a {cpp}11 library, or `{cpp}11-lib` if the port needs a {cpp}11-ready standard library. If the port needs a compiler understanding {cpp}0X, C11 or nested functions, the corresponding parameters should be used. Use `features` to request a list of features supported by the default compiler. After including [.filename]#bsd.port.pre.mk# the port can inspect the results using these variables: * `COMPILER_TYPE`: the default compiler on the system, either gcc or clang * `ALT_COMPILER_TYPE`: the alternative compiler on the system, either gcc or clang. Only set if two compilers are present in the base system. * `COMPILER_VERSION`: the first two digits of the version of the default compiler. * `ALT_COMPILER_VERSION`: the first two digits of the version of the alternative compiler, if present. * `CHOSEN_COMPILER_TYPE`: the chosen compiler, either gcc or clang * `COMPILER_FEATURES`: the features supported by the default compiler. It currently lists the {cpp} library. [[uses-cpe]] == `cpe` Possible arguments: (none) Include Common Platform Enumeration (CPE) information in package manifest as a CPE 2.3 formatted string. See the https://scap.nist.gov/specifications/cpe/[CPE specification] for details. To add CPE information to a port, follow these steps: [.procedure] . Search for the official CPE entry for the software product either by using the NVD's https://web.nvd.nist.gov/view/cpe/search[CPE search engine] or in the https://nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz[official CPE dictionary] (warning, very large XML file). _Do not ever make up CPE data._ . Add `cpe` to `USES` and compare the result of `make -V CPE_STR` to the CPE dictionary entry. Continue one step at a time until `make -V CPE_STR` is correct. . If the product name (second field, defaults to `PORTNAME`) is incorrect, define `CPE_PRODUCT`. . If the vendor name (first field, defaults to `CPE_PRODUCT`) is incorrect, define `CPE_VENDOR`. . If the version field (third field, defaults to `PORTVERSION`) is incorrect, define `CPE_VERSION`. . If the update field (fourth field, defaults to empty) is incorrect, define `CPE_UPDATE`. . If it is still not correct, check [.filename]#Mk/Uses/cpe.mk# for additional details, or contact the {ports-secteam}. . Derive as much as possible of the CPE name from existing variables such as `PORTNAME` and `PORTVERSION`. Use variable modifiers to extract the relevant portions from these variables rather than hardcoding the name. . _Always_ run `make -V CPE_STR` and check the output before committing anything that changes `PORTNAME` or `PORTVERSION` or any other variable which is used to derive `CPE_STR`. [[uses-cran]] == `cran` Possible arguments: (none), `auto-plist`, `compiles` Uses the Comprehensive R Archive Network. Specify `auto-plist` to automatically generate [.filename]#pkg-plist#. Specify `compiles` if the port has code that need to be compiled. [[uses-desktop-file-utils]] == `desktop-file-utils` Possible arguments: (none) Uses update-desktop-database from package:devel/desktop-file-utils[]. An extra post-install step will be run without interfering with any post-install steps already in the port [.filename]#Makefile#. A line with crossref:plist[plist-keywords-desktop-file-utils,`@desktop-file-utils`] will be added to the plist. Only use this macro if the port provides a `.desktop` file which contains a `MimeType` entry. [[uses-desthack]] == `desthack` Possible arguments: (none) Changes the behavior of GNU configure to properly support `DESTDIR` in case the original software does not. [[uses-display]] == `display` Possible arguments: (none), _ARGS_ Set up a virtual display environment. If the environment variable `DISPLAY` is not set, then Xvfb is added as a build dependency, and `CONFIGURE_ENV` is extended with the port number of the currently running instance of Xvfb. The _ARGS_ parameter defaults to `install` and controls the phase around which to start and stop the virtual display. [[uses-dos2unix]] == `dos2unix` Possible arguments: (none) The port has files with line endings in DOS format which need to be converted. Several variables can be set to control which files will be converted. The default is to convert _all_ files, including binaries. See crossref:slow-porting[slow-patch-automatic-replacements,Simple Automatic Replacements] for examples. * `DOS2UNIX_REGEX`: match file names based on a regular expression. * `DOS2UNIX_FILES`: match literal file names. * `DOS2UNIX_GLOB`: match file names based on a glob pattern. * `DOS2UNIX_WRKSRC`: the directory from which to start the conversions. Defaults to `${WRKSRC}`. [[uses-drupal]] == `drupal` Possible arguments: `7`, `module`, `theme` Automate installation of a port that is a Drupal theme or module. Use with the version of Drupal that the port is expecting. For example, `USES=drupal:7,module` says that this port creates a Drupal 7 module. A Drupal 7 theme can be specified with `USES=drupal:7,theme`. [[uses-ebur128]] == `ebur128` Possible arguments: (none), `build`, `lib`, `run`, `test` Adds a dependency on package:audio/ebur128[]. It allows to transparently depend on the `rust` or `legacy` variants by using `DEFAULT_VERSIONS` in [.filename]#make.conf#. For instance, to use the legacy version, use `DEFAULT_VERSIONS+=ebur128=legacy` When no arguments are used, the behavior is the same as if the `lib` argument was provided. The rest of the arguments provide the corresponding category of dependency. [[uses-eigen]] == `eigen` Possible arguments: 2, 3, build (default), run Add dependency on package:math/eigen[]. [[uses-elfctl]] == `elfctl` Possible arguments: (none) Change an ELF binary's feature control note by setting ELF_FEATURES. [[uses-elfct-ex1]] .Uses=elfctl [example] ==== [.programlisting] .... USES= elfctl ELF_FEATURES= featurelist:path/to/file1 \ featurelist:path/to/file1 \ featurelist:path/to/file2 .... ==== The format of `featurelist` is described in man:elfctl[1]. The file paths are relative to ${BUILD_WRKSRC}. [[uses-erlang]] == `erlang` Possible arguments: (none), `enc`, `rebar`, `rebar3` Adds a build and run time dependency on package:lang/erlang[]. Depending on the argument, it adds additional build dependencies. `enc` adds a dependency on package:devel/erlang-native-compiler[], `rebar` adds a dependency on package:devel/rebar[] and `rebar3` adds a dependency on package:devel/rebar3[]. In addition, the following variables are available to the port: * `ERL_APP_NAME`: Erlang app name as installed in Erlang's lib dir (minus version) * `ERL_APP_ROOT`: Root directory for this Erlang app * `REBAR_CMD`: Path to the "rebar" command * `REBAR3_CMD`: Path to the "rebar3" command * `REBAR_PROFILE`: Rebar profile * `REBAR_TARGETS`: Rebar target list (usually compile, maybe escriptize) * `ERL_BUILD_NAME`: Build name for rebar3 * `ERL_BUILD_DEPS`: List of BUILD_DEPENDS in category/portname format * `ERL_RUN_DEPS`: List of RUN_DEPENDS in category/portname format * `ERL_DOCS`: List of documentation files and directories [[uses-fakeroot]] == `fakeroot` Possible arguments: (none) Changes some default behavior of build systems to allow installing as a user. See https://wiki.debian.org/FakeRoot[] for more information on `fakeroot`. [[uses-fam]] == `fam` Possible arguments: (none), `fam`, `gamin` Uses a File Alteration Monitor as a library dependency, either package:devel/fam[] or package:devel/gamin[]. End users can set WITH_FAM_SYSTEM to specify their preference. [[uses-firebird]] == `firebird` Possible arguments: (none), `25` Add a dependency to the client library of the Firebird database. [[uses-fonts]] == `fonts` Possible arguments: (none), `fc`, `fontsdir` (default), `none` Adds a runtime dependency on tools needed to register fonts. Depending on the argument, add a `crossref:plist[plist-keywords-fc,@fc] ${FONTSDIR}` line, `crossref:plist[plist-keywords-fontsdir,@fontsdir] ${FONTSDIR}` line, or no line if the argument is `none`, to the plist. `FONTSDIR` defaults to [.filename]#${PREFIX}/share/fonts/${FONTNAME}# and `FONTNAME` to `${PORTNAME}`. Add `FONTSDIR` to `PLIST_SUB` and `SUB_LIST` [[uses-fortran]] == `fortran` Possible arguments: `gcc` (default) Uses the GNU Fortran compiler. [[uses-fuse]] == `fuse` Possible arguments: `2` (default), `3` The port will depend on the FUSE library and handle the dependency on the kernel module depending on the version of FreeBSD. [[uses-gem]] == `gem` Possible arguments: (none), `noautoplist` Handle building with RubyGems. If `noautoplist` is used, the packing list is not generated automatically. This implies `USES=ruby`. [[uses-gettext]] == `gettext` Possible arguments: (none) Deprecated. Will include both crossref:uses[uses-gettext-runtime,`gettext-runtime`] and crossref:uses[uses-gettext-tools,`gettext-tools`]. [[uses-gettext-runtime]] == `gettext-runtime` Possible arguments: (none), `lib` (default), `build`, `run` Uses package:devel/gettext-runtime[]. By default, with no arguments or with the `lib` argument, implies a library dependency on [.filename]#libintl.so#. `build` and `run` implies, respectively a build-time and a run-time dependency on [.filename]#gettext#. [[uses-gettext-tools]] == `gettext-tools` Possible arguments: (none), `build` (default), `run` Uses package:devel/gettext-tools[]. By default, with no argument, or with the `build` argument, a build time dependency on [.filename]#msgfmt# is registered. With the `run` argument, a run-time dependency is registered. [[uses-ghostscript]] == `ghostscript` Possible arguments: _X_, `build`, `run`, `nox11` A specific version _X_ can be used. Possible versions are `7`, `8`, `9`, and `agpl` (default). `nox11` indicates that the `-nox11` version of the port is required. `build` and `run` add build- and run-time dependencies on Ghostscript. The default is both build- and run-time dependencies. [[uses-gl]] == `gl` Possible arguments: (none) Provides an easy way to depend on GL components. The components should be listed in `USE_GL`. The available components are: `egl`:: add a library dependency on [.filename]#libEGL.so# from package:graphics/libglvnd[] `gbm`:: Add a library dependency on [.filename]#libgbm.so# from package:graphics/mesa-libs[] `gl`:: Add a library dependency on [.filename]#libGL.so# from package:graphics/libglvnd[] `glesv2`:: Add a library dependency on [.filename]#libGLESv2.so# from package:graphics/libglvnd[] `glew`:: Add a library dependency on [.filename]#libGLEW.so# from package:graphics/glew[] `glu`:: Add a library dependency on [.filename]#libGLU.so# from package:graphics/libGLU[] `glut`:: Add a library dependency on [.filename]#libglut.so# from package:graphics/freeglut[] `opengl`:: Add a library dependency on [.filename]#libOpenGL.so# from package:graphics/libglvnd[] [[uses-gmake]] == `gmake` Possible arguments: (none) Uses package:devel/gmake[] as a build-time dependency and sets up the environment to use `gmake` as the default `make` for the build. [[uses-gnome]] == `gnome` Possible arguments: (none) Provides an easy way to depend on GNOME components. The components should be listed in `USE_GNOME`. The available components are: * `atk` * `atkmm` * `cairo` * `cairomm` * `dconf` * `esound` * `evolutiondataserver3` * `gconf2` * `gconfmm26` * `gdkpixbuf` * `gdkpixbuf2` * `glib12` * `glib20` * `glibmm` * `gnomecontrolcenter3` * `gnomedesktop3` * `gnomedocutils` * `gnomemenus3` * `gnomemimedata` * `gnomeprefix` * `gnomesharp20` * `gnomevfs2` * `gsound` * `gtk-update-icon-cache` * `gtk12` * `gtk20` * `gtk30` * `gtkhtml3` * `gtkhtml4` * `gtkmm20` * `gtkmm24` * `gtkmm30` * `gtksharp20` * `gtksourceview` * `gtksourceview2` * `gtksourceview3` * `gtksourceviewmm3` * `gvfs` * `intlhack` * `intltool` * `introspection` * `libartlgpl2` * `libbonobo` * `libbonoboui` * `libgda5` * `libgda5-ui` * `libgdamm5` * `libglade2` * `libgnome` * `libgnomecanvas` * `libgnomekbd` * `libgnomeprint` * `libgnomeprintui` * `libgnomeui` * `libgsf` * `libgtkhtml` * `libgtksourceviewmm` * `libidl` * `librsvg2` * `libsigc++12` * `libsigc++20` * `libwnck` * `libwnck3` * `libxml++26` * `libxml2` * `libxslt` * `metacity` * `nautilus3` * `orbit2` * `pango` * `pangomm` * `pangox-compat` * `py3gobject3` * `pygnome2` * `pygobject` * `pygobject3` * `pygtk2` * `pygtksourceview` * `referencehack` * `vte` * `vte3` The default dependency is build- and run-time, it can be changed with `:build` or `:run`. For example: [.programlisting] .... USES= gnome USE_GNOME= gnomemenus3:build intlhack .... See crossref:special[using-gnome,Using GNOME] for more information. [[uses-go]] == `go` [IMPORTANT] ==== Ports should not be created for Go libs, see crossref:special[go-libs,Go Libraries] for more information. ==== Possible arguments: (none), `N.NN`, `N.NN-devel`, `modules`, `no_targets`, `run` Sets default values and targets used to build Go software. A build dependency on the Go compiler port is added, port maintainers can set version required. By default the build is performed in GOPATH mode. If Go software uses modules, the modules-aware mode can be switched on with `modules` argument. `no_targets` will setup build environment like `GO_ENV`, `GO_BUILDFLAGS` but skip creating extract and build targets. `run` will also add a run dependency on the Go compiler port. The build process is controlled by several variables: `GO_MODULE`:: The name of the application module as specified by the `module` directive in `go.mod`. In most cases, this is the only required variable for ports that use Go modules. `GO_PKGNAME`:: The name of the Go package when building in GOPATH mode. This is the directory that will be created in `${GOPATH}/src`. If not set explicitly and `GH_SUBDIR` or `GL_SUBDIR` is present, `GO_PKGNAME` will be inferred from it. It is not needed when building in modules-aware mode. `GO_TARGET`:: The packages to build. The default value is `${GO_PKGNAME}`. `GO_TARGET` can also be a tuple in the form `package:path` where path can be either a simple filename or a full path starting with `${PREFIX}`. `GO_TESTTARGET`:: The packages to test. The default value is `./...` (the current package and all subpackages). `CGO_CFLAGS`:: Additional `CFLAGS` values to be passed to the C compiler by `go`. `CGO_LDFLAGS`:: Additional `LDFLAGS` values to be passed to the C compiler by `go`. `GO_BUILDFLAGS`:: Additional build arguments to be passed to `go build`. `GO_TESTFLAGS`:: Additional build arguments to be passed to `go test`. See crossref:special[using-go,Building Go Applications] for usage examples. [[uses-gperf]] == `gperf` Possible arguments: (none) Add a buildtime dependency on package:devel/gperf[] if `gperf` is not present in the base system. [[uses-grantlee]] == `grantlee` Possible arguments: `5`, `selfbuild` Handle dependency on Grantlee. Specify `5` to depend on the Qt5 based version, package:devel/grantlee5[]. `selfbuild` is used internally by package:devel/grantlee5[] to get their versions numbers. [[uses-groff]] == `groff` Possible arguments: `build`, `run`, `both` Registers a dependency on package:textproc/groff[] if not present in the base system. [[uses-gssapi]] == `gssapi` Possible arguments: (none), `base` (default), `heimdal`, `mit`, `flags`, `bootstrap` Handle dependencies needed by consumers of the GSS-API. Only libraries that provide the Kerberos mechanism are available. By default, or set to `base`, the GSS-API library from the base system is used. Can also be set to `heimdal` to use package:security/heimdal[], or `mit` to use package:security/krb5[]. When the local Kerberos installation is not in `LOCALBASE`, set `HEIMDAL_HOME` (for `heimdal`) or `KRB5_HOME` (for `krb5`) to the location of the Kerberos installation. These variables are exported for the ports to use: * `GSSAPIBASEDIR` * `GSSAPICPPFLAGS` * `GSSAPIINCDIR` * `GSSAPILDFLAGS` * `GSSAPILIBDIR` * `GSSAPILIBS` * `GSSAPI_CONFIGURE_ARGS` The `flags` option can be given alongside `base`, `heimdal`, or `mit` to automatically add `GSSAPICPPFLAGS`, `GSSAPILDFLAGS`, and `GSSAPILIBS` to `CFLAGS`, `LDFLAGS`, and `LDADD`, respectively. For example, use `base,flags`. The `bootstrap` option is a special prefix only for use by package:security/krb5[] and package:security/heimdal[]. For example, use `bootstrap,mit`. [[uses-gssapi-ex1]] .Typical Use [example] ==== [.programlisting] .... OPTIONS_SINGLE= GSSAPI OPTIONS_SINGLE_GSSAPI= GSSAPI_BASE GSSAPI_HEIMDAL GSSAPI_MIT GSSAPI_NONE GSSAPI_BASE_USES= gssapi GSSAPI_BASE_CONFIGURE_ON= --with-gssapi=${GSSAPIBASEDIR} ${GSSAPI_CONFIGURE_ARGS} GSSAPI_HEIMDAL_USES= gssapi:heimdal GSSAPI_HEIMDAL_CONFIGURE_ON= --with-gssapi=${GSSAPIBASEDIR} ${GSSAPI_CONFIGURE_ARGS} GSSAPI_MIT_USES= gssapi:mit GSSAPI_MIT_CONFIGURE_ON= --with-gssapi=${GSSAPIBASEDIR} ${GSSAPI_CONFIGURE_ARGS} GSSAPI_NONE_CONFIGURE_ON= --without-gssapi .... ==== [[uses-gstreamer]] == `gstreamer` Possible arguments: (none) Provides an easy way to depend on GStreamer components. The components should be listed in `USE_GSTREAMER`. The available components are: * `a52dec` * `aalib` * `amrnb` * `amrwbdec` * `aom` * `assrender` * `bad` * `bs2b` * `cairo` * `cdio` * `cdparanoia` * `chromaprint` * `curl` * `dash` * `dtls` * `dts` * `dv` * `dvd` * `dvdread` * `editing-services` * `faac` * `faad` * `flac` * `flite` * `gdkpixbuf` * `gl` * `gme` * `gnonlin` * `good` * `gsm` * `gtk4` * `gtk` * `hal` * `hls` * `jack` * `jpeg` * `kate` * `kms` * `ladspa` * `lame` * `libav` * `libcaca` * `libde265` * `libmms` * `libvisual` * `lv2` * `mm` * `modplug` * `mpeg2dec` * `mpeg2enc` * `mpg123` * `mplex` * `musepack` * `neon` * `ogg` * `opencv` * `openexr` * `openh264` * `openjpeg` * `openmpt` * `opus` * `pango` * `png` * `pulse` * `qt` * `resindvd` * `rsvg` * `rtmp` * `shout2` * `sidplay` * `smoothstreaming` * `sndfile` * `sndio` * `soundtouch` * `soup` * `spandsp` * `speex` * `srtp` * `taglib` * `theora` * `ttml` * `twolame` * `ugly` * `v4l2` * `vorbis` * `vpx` * `vulkan` * `wavpack` * `webp` * `webrtcdsp` * `x264` * `x265` * `x` * `ximagesrc` * `zbar` [[uses-guile]] == `guile` Possible arguments: (none), `_X.Y_`, `flavors`, `build`, `run`, `alias`, `conflicts` Adds a dependency on Guile. By default this is a library dependency on the appropriate `libguile*.so`, unless overridden by the `build` and/or `run` option. The `alias` option configures `BINARY_ALIAS` appropriately (see crossref:makefiles[binary-alias,Use `BINARY_ALIAS`]). The default version is set by the usual `DEFAULT_VERSIONS` mechanism; if the default version is not one of the listed versions, then the latest available listed version is used. Applications using Guile are normally built for only a single Guile version. However, extension or library modules should use the `flavors` option to build with multiple flavors. For more information see crossref:special[using-guile,Using Guile]. [[uses-horde]] == `horde` Possible arguments: (none) Add buildtime and runtime dependencies on package:devel/pear-channel-horde[]. Other Horde dependencies can be added with `USE_HORDE_BUILD` and `USE_HORDE_RUN`. See crossref:special[php-horde,Horde Modules] for more information. [[uses-iconv]] == `iconv` Possible arguments: (none), `lib`, `build`, `patch`, `translit`, `wchar_t` Uses `iconv` functions, either from the port package:converters/libiconv[] as a build-time and run-time dependency, or from the base system. By default, with no arguments or with the `lib` argument, implies `iconv` with build-time and run-time dependencies. `build` implies a build-time dependency, and `patch` implies a patch-time dependency. If the port uses the `WCHAR_T` or `//TRANSLIT` iconv extensions, add the relevant arguments so that the correct iconv is used. For more information see crossref:special[using-iconv,Using `iconv`]. [[uses-imake]] == `imake` Possible arguments: (none), `env`, `notall`, `noman` Add package:devel/imake[] as a build-time dependency and run `xmkmf -a` during the `configure` stage. If the `env` argument is given, the `configure` target is not set. If the `-a` flag is a problem for the port, add the `notall` argument. If `xmkmf` does not generate a `install.man` target, add the `noman` argument. [[uses-kde]] == `kde` Possible arguments: `5` Add dependency on KDE components. See crossref:special[using-kde,Using KDE] for more information. [[uses-kmod]] == `kmod` Possible arguments: (none), `debug` Fills in the boilerplate for kernel module ports, currently: * Add `kld` to `CATEGORIES`. * Set `SSP_UNSAFE`. * Set `IGNORE` if the kernel sources are not found in `SRC_BASE`. * Define `KMODDIR` to [.filename]#/boot/modules# by default, add it to `PLIST_SUB` and `MAKE_ENV`, and create it upon installation. If `KMODDIR` is set to [.filename]#/boot/kernel#, it will be rewritten to [.filename]#/boot/modules#. This prevents breaking packages when upgrading the kernel due to [.filename]#/boot/kernel# being renamed to [.filename]#/boot/kernel.old# in the process. * Handle cross-referencing kernel modules upon installation and deinstallation, using crossref:plist[plist-keywords-kld,`@kld`]. * If the `debug` argument is given, the port can install a debug version of the module into [.filename]#KERN_DEBUGDIR#/[.filename]#KMODDIR#. By default, `KERN_DEBUGDIR` is copied from `DEBUGDIR` and set to [.filename]#/usr/lib/debug#. The framework will take care of creating and removing any required directories. [[uses-ldap]] == `ldap` Possible arguments: (none), , client, server Registers a dependency on package:net/openldap[]. It uses the specific `` (without the dot notation) if set. Otherwise it tries to find the currently installed version. If necessary it falls back to the default version found in `bsd.default-versions.mk`. `client` specifies a runtime dependency on the client library. This is also the default. `server` specifies a runtime dependency on the server. The following variables can be accessed by the port: `IGNORE_WITH_OPENLDAP`:: This variable can be defined if the ports does not support one or more versions of OpenLDAP. `WITH_OPENLDAP_VER`:: User defined variable to set OpenLDAP version. `OPENLDAP_VER`:: Detected OpenLDAP version. [[uses-lha]] == `lha` Possible arguments: (none) Set `EXTRACT_SUFX` to `.lzh` [[uses-libarchive]] == `libarchive` Possible arguments: (none) Registers a dependency on package:archivers/libarchive[]. Any ports depending on libarchive must include `USES=libarchive`. [[uses-libedit]] == `libedit` Possible arguments: (none) Registers a dependency on package:devel/libedit[]. Any ports depending on libedit must include `USES=libedit`. [[uses-libtool]] == `libtool` Possible arguments: (none), `keepla`, `build` Patches `libtool` scripts. This must be added to all ports that use `libtool`. The `keepla` argument can be used to keep [.filename]#.la# files. Some ports do not ship with their own copy of libtool and need a build time dependency on package:devel/libtool[], use the `:build` argument to add such dependency. [[uses-linux]] == `linux` Possible arguments: `c6`, `c7` Ports Linux compatibility framework. Specify `c6` to depend on CentOS 6 packages. Specify `c7` to depend on CentOS 7 packages. The available packages are: * `allegro` * `alsa-plugins-oss` * `alsa-plugins-pulseaudio` * `alsalib` * `atk` * `avahi-libs` * `base` * `cairo` * `cups-libs` * `curl` * `cyrus-sasl2` * `dbusglib` * `dbuslibs` * `devtools` * `dri` * `expat` * `flac` * `fontconfig` * `gdkpixbuf2` * `gnutls` * `graphite2` * `gtk2` * `harfbuzz` * `jasper` * `jbigkit` * `jpeg` * `libasyncns` * `libaudiofile` * `libelf` * `libgcrypt` * `libgfortran` * `libgpg-error` * `libmng` * `libogg` * `libpciaccess` * `libsndfile` * `libsoup` * `libssh2` * `libtasn1` * `libthai` * `libtheora` * `libv4l` * `libvorbis` * `libxml2` * `mikmod` * `naslibs` * `ncurses-base` * `nspr` * `nss` * `openal` * `openal-soft` * `openldap` * `openmotif` * `openssl` * `pango` * `pixman` * `png` * `pulseaudio-libs` * `qt` * `qt-x11` * `qtwebkit` * `scimlibs` * `sdl12` * `sdlimage` * `sdlmixer` * `sqlite3` * `tcl85` * `tcp_wrappers-libs` * `tiff` * `tk85` * `ucl` * `xorglibs` [[uses-llvm]] == `llvm` Possible arguments: (none), `_XY_`, min=`_XY_`, max=`_XY_`, build, run, lib Adds a dependency on LLVM. By default this is a build dependency unless overridden by the `run` or `lib` options. The default version is the one set in `LLVM_DEFAULT`. A specific version can be specified as well. The minimum and maximum versions can be specified with the `min` and `max` parameters respectively. The ports framework export the following variables to the port: `LLVM_VERSION`:: Version chosen from the arguments to llvm.mk `LLVM_PORT`:: Chosen llvm port `LLVM_CONFIG`:: llvm-config of the chosen port `LLVM_LIBLLVM`:: libLLVM.so of the chosen port `LLVM_PREFIX`:: Installation prefix of the chosen port [[uses-localbase]] == `localbase` Possible arguments: (none), `ldflags` Ensures that libraries from dependencies in `LOCALBASE` are used instead of the ones from the base system. Specify `ldflags` to add `-L${LOCALBASE}/lib` to `LDFLAGS` instead of `LIBS`. Ports that depend on libraries that are also present in the base system should use this. It is also used internally by a few other `USES`. [[uses-lua]] == `lua` Possible arguments: (none), `_XY_`, `_XY_+`, `-_XY_`, `_XY_-_ZA_`, `module`, `flavors`, `build`, `run`, `env` Adds a dependency on Lua. By default this is a library dependency, unless overridden by the `build` and/or `run` option. The `env` option prevents the addition of any dependency, while still defining all the usual variables. The default version is set by the usual `DEFAULT_VERSIONS` mechanism, unless a version or range of versions is specified as an argument, for example, `51` or `51-54`. Applications using Lua are normally built for only a single Lua version. However, library modules intended to be loaded by Lua code should use the `module` option to build with multiple flavors. For more information see crossref:special[using-lua,Using Lua]. [[uses-luajit]] == `luajit` Possible arguments: (none), `_X_` Adds a dependency on luajit runtime. A specific version _X_ can be used. Possible versions are `luajit`, `luajit-devel`, `luajit-openresty` After including [.filename]#bsd.port.options.mk# or [.filename]#bsd.port.pre.mk# the port can inspect these variables: `LUAJIT_VER`:: The selected luajit version `LUAJIT_INCDIR`:: The path to luajit's header files `LUAJIT_LUAVER`:: Which luajit spec version is selected (2.0 for luajit, else 2.1) For more information see crossref:special[using-lua,Using Lua]. [[uses-lxqt]] == `lxqt` Possible arguments: (none) Handle dependencies for the LXQt Desktop Environment. Use `USE_LXQT` to select the components needed for the port. See crossref:special[using-lxqt,Using LXQt] for more information. [[uses-magick]] == `magick` Possible arguments: (none), `_X_`, `build`, `nox11`, `run`, `test` Add a library dependency on `ImageMagick`. A specific version _X_ can be used. Possible versions are `6` and `7` (default). `nox11` indicates that the `-nox11` version of the port is required. `build`, `run` and `test` add build-, run-time and test dependencies on ImageMagick. [[uses-makeinfo]] == `makeinfo` Possible arguments: (none) Add a build-time dependency on `makeinfo` if it is not present in the base system. [[uses-makeself]] == `makeself` Possible arguments: (none) Indicates that the distribution files are makeself archives and sets the appropriate dependencies. [[uses-mate]] == `mate` Possible arguments: (none) Provides an easy way to depend on MATE components. The components should be listed in `USE_MATE`. The available components are: * `autogen` * `caja` * `common` * `controlcenter` * `desktop` * `dialogs` * `docutils` * `icontheme` * `intlhack` * `intltool` * `libmatekbd` * `libmateweather` * `marco` * `menus` * `notificationdaemon` * `panel` * `pluma` * `polkit` * `session` * `settingsdaemon` The default dependency is build- and run-time, it can be changed with `:build` or `:run`. For example: [.programlisting] .... USES= mate USE_MATE= menus:build intlhack .... [[uses-meson]] == `meson` Possible arguments: (none) Provide support for Meson based projects. For more information see crossref:special[using-meson,Using `meson`]. [[uses-metaport]] == `metaport` Possible arguments: (none) Sets the following variables to make it easier to create a metaport: `MASTER_SITES`, `DISTFILES`, `EXTRACT_ONLY`, `NO_BUILD`, `NO_INSTALL`, `NO_MTREE`, `NO_ARCH`. [[uses-minizip]] == `minizip` Possible arguments: (none), `ng` Adds a library dependency on package:archivers/minizip[] or package:archivers/minizip-ng[] respectively. [[uses-mysql]] == `mysql` Possible arguments: (none), `_version_`, `client` (default), `server`, `embedded` Provide support for MySQL If no version is given, try to find the current installed version. Fall back to the default version, MySQL-5.6. The possible versions are `55`, `55m`, `55p`, `56`, `56p`, `56w`, `57`, `57p`, `80`, `100m`, `101m`, and `102m`. The `m` and `p` suffixes are for the MariaDB and Percona variants of MySQL. `server` and `embedded` add a build- and run-time dependency on the MySQL server. When using `server` or `embedded`, add `client` to also add a dependency on [.filename]#libmysqlclient.so#. A port can set `IGNORE_WITH_MYSQL` if some versions are not supported. The framework sets `MYSQL_VER` to the detected MySQL version. [[uses-mono]] == `mono` Possible arguments: (none), `nuget` Adds a dependency on the Mono (currently only C#) framework by setting the appropriate dependencies. Specify `nuget` when the port uses nuget packages. `NUGET_DEPENDS` needs to be set with the names and versions of the nuget packages in the format `_name_=_version_`. An optional package origin can be added using `_name_=_version_:_origin_`. The helper target, `buildnuget`, will output the content of the `NUGET_DEPENDS` based on the provided [.filename]#packages.config#. [[uses-motif]] == `motif` Possible arguments: (none) Uses package:x11-toolkits/open-motif[] as a library dependency. End users can set `WANT_LESSTIF` in [.filename]#make.conf# to use package:x11-toolkits/lesstif[] as dependency instead of package:x11-toolkits/open-motif[]. Similarly setting `WANT_OPEN_MOTIF_DEVEL` in [.filename]#make.conf# will add a dependency on package:x11-toolkits/open-motif-devel[] [[uses-ncurses]] == `ncurses` Possible arguments: (none), `base`, `port` Uses ncurses, and causes some useful variables to be set. [[uses-nextcloud]] == `nextcloud` Possible arguments: (none) Adds support for Nextcloud applications by adding a run time dependency on package:www/nextcloud[]. [[uses-ninja]] == `ninja` Possible arguments: (none), `build`, `make` (default), `run` If `build` or `run` arguments are specify, it respectively adds a build or run time dependency on package:devel/ninja[]. If `make` or no arguments are provided, use ninja to build the port instead of make. `make` implies `build`. If the variable `NINJA_DEFAULT` is set to `samurai`, then the dependencies are set on package:devel/samurai[] instead. [[uses-nodejs]] == `nodejs` Possible arguments: (none), `build`, `run`, `current`, `lts`, `10`, `14`, `16`, `17`. Uses nodejs. Adds a dependency on package:www/node*[]. If a supported version is specified then `run` and/or `build` must be specified too. [[uses-objc]] == `objc` Possible arguments: (none) Add objective C dependencies (compiler, runtime library) if the base system does not support it. [[uses-octave]] == `octave` Possible arguments: (none), env Uses package:math/octave[]. `env` loads only one `OCTAVE_VERSION` environmental variable. [[uses-openal]] == `openal` Possible arguments: `al`, `soft` (default), `si`, `alut` Uses OpenAL. The backend can be specified, with the software implementation as the default. The user can specify a preferred backend with `WANT_OPENAL`. Valid values for this knob are `soft` (default) and `si`. [[uses-pathfix]] == `pathfix` Possible arguments: (none) Look for [.filename]#Makefile.in# and [.filename]#configure# in `PATHFIX_WRKSRC` (defaults to `WRKSRC`) and fix common paths to make sure they respect the FreeBSD hierarchy. For example, it fixes the installation directory of `pkgconfig`'s [.filename]#.pc# files to [.filename]#${PREFIX}/libdata/pkgconfig#. If the port uses `USES=autoreconf`, [.filename]#Makefile.am# will be added to `PATHFIX_MAKEFILEIN` automatically. If the port crossref:uses[uses-cmake,`USES=cmake`] it will look for [.filename]#CMakeLists.txt# in `PATHFIX_WRKSRC`. If needed, that default filename can be changed with `PATHFIX_CMAKELISTSTXT`. [[uses-pear]] == `pear` Possible arguments: `env` Adds a dependency on package:devel/pear[]. It will setup default behavior for software using the PHP Extension and Application Repository. Using the `env` arguments only sets up the PEAR environment variables. See crossref:special[php-pear,PEAR Modules] for more information. [[uses-perl5]] == `perl5` Possible arguments: (none) Depends on Perl. The configuration is done using `USE_PERL5`. `USE_PERL5` can contain the phases in which to use Perl, can be `extract`, `patch`, `build`, `run`, or `test`. `USE_PERL5` can also contain `configure`, `modbuild`, or `modbuildtiny` when [.filename]#Makefile.PL#, [.filename]#Build.PL#, or Module::Build::Tiny's flavor of [.filename]#Build.PL# is required. `USE_PERL5` defaults to `build run`. When using `configure`, `modbuild`, or `modbuildtiny`, `build` and `run` are implied. See crossref:special[using-perl,Using Perl] for more information. [[uses-pgsql]] == `pgsql` Possible arguments: (none), `_X.Y_`, `_X.Y_+`, `_X.Y_-`, `_X.Y_-_Z.A_` Provide support for PostgreSQL. Port maintainer can set version required. Minimum and maximum versions or a range can be specified; for example, `9.0-`, `8.4+`, `8.4-9.2.` By default, the added dependency will be the client, but if the port requires additional components, this can be done using `WANT_PGSQL=_component[:target]_`; for example, `WANT_PGSQL=server:configure pltcl plperl`. The available components are: * `client` * `contrib` * `docs` * `pgtcl` * `plperl` * `plpython` * `pltcl` * `server` [[uses-php]] == `php` Possible arguments: (none), `phpize`, `ext`, `zend`, `build`, `cli`, `cgi`, `mod`, `web`, `embed`, `pecl`, `flavors`, `noflavors` Provide support for PHP. Add a runtime dependency on the default PHP version, package:lang/php81[]. `phpize`:: Use to build a PHP extension. Enables flavors. `ext`:: Use to build, install and register a PHP extension. Enables flavors. `zend`:: Use to build, install and register a Zend extension. Enables flavors. `build`:: Set PHP also as a build-time dependency. `cli`:: Needs the CLI version of PHP. `cgi`:: Needs the CGI version of PHP. `mod`:: Needs the Apache module for PHP. `web`:: Needs the Apache module or the CGI version of PHP. `embed`:: Needs the embedded library version of PHP. `pecl`:: Provide defaults for fetching PHP extensions from the PECL repository. Enables flavors. `flavors`:: Enable automatic crossref:flavors[flavors-auto-php,PHP flavors] generation. Flavors will be generated for all PHP versions, except the ones present in crossref:uses[uses-php-ignore,`IGNORE_WITH_PHP`]. `noflavors`:: Disable automatic PHP flavors generation. _Must only_ be used with extensions provided by PHP itself. Variables are used to specify which PHP modules are required, as well as which version of PHP are supported. `USE_PHP`:: The list of required PHP extensions at run-time. Add `:build` to the extension name to add a build-time dependency. Example: `pcre xml:build gettext` [[uses-php-ignore]] `IGNORE_WITH_PHP`:: The port does not work with PHP of the given version. For possible values look at the content of `_ALL_PHP_VERSIONS` in [.filename]#Mk/Uses/php.mk#. When building a PHP or Zend extension with `:ext` or `:zend`, these variables can be set: `PHP_MODNAME`:: The name of the PHP or Zend extension. Default value is `${PORTNAME}`. `PHP_HEADER_DIRS`:: A list of subdirectories from which to install header files. The framework will always install the header files that are present in the same directory as the extension. `PHP_MOD_PRIO`:: The priority at which to load the extension. It is a number between `00` and `99`. + For extensions that do not depend on any extension, the priority is automatically set to `20`, for extensions that depend on another extension, the priority is automatically set to `30`. Some extensions may need to be loaded before every other extension, for example package:www/php56-opcache[]. Some may need to be loaded after an extension with a priority of `30`. In that case, add `PHP_MOD_PRIO=_XX_` in the port's Makefile. For example: + [.programlisting] .... USES= php:ext USE_PHP= wddx PHP_MOD_PRIO= 40 .... These variables are available to use in `PKGNAMEPREFIX` or `PKGNAMESUFFIX`: `PHP_PKGNAMEPREFIX`:: Contains `php_XY_-` where _XY_ is the current flavor's PHP version. Use with PHP extensions and modules. `PHP_PKGNAMESUFFIX`:: Contains `-php_XY_` where _XY_ is the current flavor's PHP version. Use with PHP applications. `PECL_PKGNAMEPREFIX`:: Contains `php_XY_-pecl-` where _XY_ is the current flavor's PHP version. Use with PECL modules. [IMPORTANT] ==== With flavors, all PHP extensions, PECL extensions, PEAR modules _must have_ a different package name, so they must all use one of these three variables in their `PKGNAMEPREFIX` or `PKGNAMESUFFIX`. ==== [[uses-pkgconfig]] == `pkgconfig` Possible arguments: (none), `build` (default), `run`, `both` Uses package:devel/pkgconf[]. With no arguments or with the `build` argument, it implies `pkg-config` as a build-time dependency. `run` implies a run-time dependency and `both` implies both run-time and build-time dependencies. [[uses-pure]] == `pure` Possible arguments: (none), `ffi` Uses package:lang/pure[]. Largely used for building related pure ports. With the `ffi` argument, it implies package:devel/pure-ffi[] as a run-time dependency. [[uses-pyqt]] == `pyqt` Possible arguments: (none), `4`, `5` Uses PyQt. If the port is part of PyQT itself, set `PYQT_DIST`. Use `USE_PYQT` to select the components the port needs. The available components are: * `core` * `dbus` * `dbussupport` * `demo` * `designer` * `designerplugin` * `doc` * `gui` * `multimedia` * `network` * `opengl` * `qscintilla2` * `sip` * `sql` * `svg` * `test` * `webkit` * `xml` * `xmlpatterns` These components are only available with PyQT4: * `assistant` * `declarative` * `help` * `phonon` * `script` * `scripttools` These components are only available with PyQT5: * `multimediawidgets` * `printsupport` * `qml` * `serialport` * `webkitwidgets` * `widgets` The default dependency for each component is build- and run-time, to select only build or run, add `_build` or `_run` to the component name. For example: [.programlisting] .... USES= pyqt USE_PYQT= core doc_build designer_run .... [[uses-pytest]] == `pytest` Possible arguments: (none), 4 Introduces a new dependency on package:devel/pytest[]. It defines a `do-test` target which will run the tests properly. Use the argument to depend on a specific package:devel/pytest[] version. For ports using package:devel/pytest[] consider using this instead of a specific `do-test` target. The framework exposes the following variables to the port: `PYTEST_ARGS`:: Additional arguments to pytest (defaults to empty). `PYTEST_IGNORED_TESTS`:: lists of `pytest -k` patterns of tests to ignore (defaults to empty). For tests which are not expected to pass, such as ones requiring a database access. `PYTEST_BROKEN_TESTS`:: lists of `pytest -k` patterns of tests to ignore (defaults to empty). For broken tests which require fixing. In addition the following variables may be set by the user: `PYTEST_ENABLE_IGNORED_TESTS`:: Enable tests which are otherwise ignored by `PYTEST_IGNORED_TESTS`. `PYTEST_ENABLE_BROKEN_TESTS`:: Enable tests which are otherwise ignored by `PYTEST_BROKEN_TESTS`. `PYTEST_ENABLE_ALL_TESTS`:: Enable tests which are otherwise ignored by `PYTEST_IGNORED_TESTS` and `PYTEST_BROKEN_TESTS`. [[uses-python]] == `python` Possible arguments: (none), `_X.Y_`, `_X.Y+_`, `_-X.Y_`, `_X.Y-Z.A_`, `patch`, `build`, `run`, `test` Uses Python. A supported version or version range can be specified. If Python is only needed at build time, run time or for the tests, it can be set as a build, run or test dependency with `build`, `run`, or `test`. If Python is also needed during the patch phase, use `patch`. See crossref:special[using-python, Using Python] for more information. `USES=python:env` can be used when the variables exported by the framework are needed but a dependency on Python is not. It can happen when using with crossref:uses[uses-shebangfix,`USES=shebangfix`], and the goal is only to fix the shebangs but not add a dependency on Python. [[uses-qmail]] == `qmail` Possible arguments: (none), `build`, `run`, `both`, `vars` Uses package:mail/qmail[]. With the `build` argument, it implies `qmail` as a build-time dependency. `run` implies a run-time dependency. Using no argument or the `both` argument implies both run-time and build-time dependencies. `vars` will only set QMAIL variables for the port to use. [[uses-qmake]] == `qmake` Possible arguments: (none), `norecursive`, `outsource`, `no_env`, `no_configure` Uses QMake for configuring. For more information see crossref:special[using-qmake,Using `qmake`]. [[uses-qt]] == `qt` Possible arguments: `5`, `6`, `no_env` Add dependency on Qt components. `no_env` is passed directly to `USES= qmake`. See crossref:special[using-qt,Using Qt] for more information. [[uses-qt-dist]] == `qt-dist` Possible arguments: (none) or `5` and (none) or `6` and (none) or one of `3d`, `5compat`, `base`, `charts`, `connectivity`, `datavis3d`, `declarative`, `doc` `languageserver`, `gamepad`, `graphicaleffects`, `imageformats`, `locat ion`, `lottie`, `multimedia`, `networkauth`, `positioning`, `quick3d`, `quickcontrols2`, `quickcontrols`, `quicktimeline`, `remoteobjects`, `script`, `scxml `, `sensors`, `serialbus`, `serialport`, `shadertools`, `speech`, `svg`, `tools`, `translations`, `virtualkeyboard`, `wayland`, `webchannel`, `webengine`, `webglplugin`, `websockets`, `webview`, `x11extras`, `xmlpatterns`. Provides support for building Qt 5 and Qt 6 components. It takes care of setting up the appropriate configuration environment for the port to build. [[qt5-dist-example]] .Building Qt 5 Components [example] ==== The port is Qt 5's `networkauth` component, which is part of the `networkauth` distribution file. [.programlisting] .... PORTNAME= networkauth DISTVERSION= ${QT5_VERSION} USES= qt-dist:5 .... ==== [[qt6-dist-example]] .Building Qt 6 Components [example] ==== The port is Qt 6's `websockets` component, which is part of the `websockets` distribution file. [.programlisting] .... PORTNAME= websockets PORTVERSION= ${QT6_VERSION} USES= qt-dist:6 .... ==== If `PORTNAME` does not match the component name, it can be passed as an argument to `qt-dist`. [[qt5-dist-example-explicit]] .Building Qt 5 Components with Different Names [example] ==== The port is Qt 5's `gui` component, which is part of the `base` distribution file. [.programlisting] .... PORTNAME= gui DISTVERSION= ${QT5_VERSION} USES= qt-dist:5,base .... ==== [[uses-readline]] == `readline` Possible arguments: (none), `port` Uses readline as a library dependency, and sets `CPPFLAGS` and `LDFLAGS` as necessary. If the `port` argument is used or if readline is not present in the base system, add a dependency on package:devel/readline[] [[uses-ruby]] == `ruby` Possible arguments: (none), `build`, `extconf`, `run`, `setup` Provide support for Ruby related ports. `(none)` without arguments adds runtime dependency on package:lang/ruby[]. `build` adds a dependency on package:lang/ruby[] at build time. `extconf` states that the port uses extconf.rb to configure. `run` adds a dependency on package:lang/ruby[] at run time. This is also the default. `setup` states that the port uses setup.rb to configure and build. The user may have the following variables defined: `RUBY_VER`:: Alternative short version of ruby in the form of `x.y'. `RUBY_DEFAULT_VER`:: Set to (e.g.) `2.7` to use `ruby27` as the default version. `RUBY_ARCH`:: Set the architecture name (e.g. i386-freebsd7). The following variables are exported to be used by the port: `RUBY`:: Set to full path of ruby. If set, the values of the following variables are automatically obtained from the ruby executable: `RUBY_ARCH`, `RUBY_ARCHLIBDIR`, `RUBY_LIBDIR`, `RUBY_SITEARCHLIBDIR`, `RUBY_SITELIBDIR`, `RUBY_VER` and `RUBY_VERSION` `RUBY_VER`:: Set to the alternative short version of ruby in the form of `x.y'. `RUBY_EXTCONF`:: Set to the alternative name of extconf.rb (default: extconf.rb). `RUBY_EXTCONF_SUBDIRS`:: Set to list of subdirectories, if multiple modules are included. `RUBY_SETUP`:: Set to the alternative name of setup.rb (default: setup.rb). [[uses-samba]] == `samba` Possible arguments: `build`, `env`, `lib`, `run` Handle dependency on Samba. `env` will not add any dependency and only set up the variables. `build` and `run` will add build-time and run-time dependency on [.filename]#smbd#. `lib` will add a dependency on [.filename]#libsmbclient.so#. The variables that are exported are: `SAMBA_PORT`:: The origin of the default Samba port. `SAMBA_INCLUDEDIR`:: The location of the Samba header files. `SAMBA_LIBS`:: The directory where the Samba shared libraries are available. `SAMBA_LDB_PORT`:: The origin of the ldb port used by the selected Samba version (e.g., package:databases/ldb28[]). It should be used if a port needs to depend on the same ldb version as the selected Samba version. [[uses-scons]] == `scons` Possible arguments: (none) Provide support for the use of package:devel/scons[]. See crossref:special[using-scons,Using `scons`] for more information. [[uses-shared-mime-info]] == `shared-mime-info` Possible arguments: (none) Uses update-mime-database from package:misc/shared-mime-info[]. This uses will automatically add a post-install step in such a way that the port itself still can specify there own post-install step if needed. It also add an crossref:plist[plist-keywords-shared-mime-info,`@shared-mime-info`] entry to the plist. [[uses-shebangfix]] == `shebangfix` Possible arguments: (none) A lot of software uses incorrect locations for script interpreters, most notably [.filename]#/usr/bin/perl# and [.filename]#/bin/bash#. The shebangfix macro fixes shebang lines in scripts listed in `SHEBANG_REGEX`, `SHEBANG_GLOB`, or `SHEBANG_FILES`. `SHEBANG_REGEX`:: Contains _one_ extended regular expressions, and is used with the `-iregex` argument of man:find[1]. -See crossref:uses[uses-shebangfix-ex-regex]. +See crossref:uses[uses-shebangfix-ex-regex,.`USESshebangfix` with `SHEBANG_REGEX`]. `SHEBANG_GLOB`:: Contains a list of patterns used with the `-name` argument of man:find[1]. -See crossref:uses[uses-shebangfix-ex-glob]. +See crossref:uses[uses-shebangfix-ex-glob,.`USESshebangfix` with `SHEBANG_GLOB`]. `SHEBANG_FILES`:: Contains a list of files or man:sh[1] globs. The shebangfix macro is run from `${WRKSRC}`, so `SHEBANG_FILES` can contain paths that are relative to `${WRKSRC}`. It can also deal with absolute paths if files outside of `${WRKSRC}` require patching. -See crossref:uses[uses-shebangfix-ex-files]. +See crossref:uses[uses-shebangfix-ex-files,.`USESshebangfix` with `SHEBANG_FILES`]. Currently Bash, Java, Ksh, Lua, Perl, PHP, Python, Ruby, Tcl, and Tk are supported by default. There are three configuration variables: `SHEBANG_LANG`:: The list of supported interpreters. `_interp__CMD`:: The path to the command interpreter on FreeBSD. The default value is `${LOCALBASE}/bin/_interp_`. `_interp__OLD_CMD`:: The list of wrong invocations of interpreters. These are typically obsolete paths, or paths used on other operating systems that are incorrect on FreeBSD. They will be replaced by the correct path in `_interp__CMD`. + [NOTE] ==== These will _always_ be part of `_interp__OLD_CMD`: `"/usr/bin/env _interp_" /bin/_interp_ /usr/bin/_interp_ /usr/local/bin/_interp_`. ==== + [TIP] ==== `_interp__OLD_CMD` contain multiple values. Any entry with spaces must be quoted. -See crossref:uses[uses-shebangfix-ex-ksh]. +See crossref:uses[uses-shebangfix-ex-ksh,.Specifying all the Paths When Adding an Interpreter to `USESshebangfix`]. ==== [IMPORTANT] ==== The fixing of shebangs is done during the `patch` phase. If scripts are created with incorrect shebangs during the `build` phase, the build process (for example, the [.filename]#configure# script, or the [.filename]#Makefiles#) must be patched or given the right path (for example, with `CONFIGURE_ENV`, `CONFIGURE_ARGS`, `MAKE_ENV`, or `MAKE_ARGS`) to generate the right shebangs. Correct paths for supported interpreters are available in `_interp__CMD`. ==== [TIP] ==== When used with crossref:uses[uses-python,`USES=python`], and the aim is only to fix the shebangs but a dependency on Python itself is not wanted, use `USES=python:env` instead. ==== [[uses-shebangfix-ex-lua]] .Adding Another Interpreter to `USES=shebangfix` [example] ==== To add another interpreter, set `SHEBANG_LANG`. For example: [.programlisting] .... SHEBANG_LANG= lua .... ==== [[uses-shebangfix-ex-ksh]] .Specifying all the Paths When Adding an Interpreter to `USES=shebangfix` [example] ==== If it was not already defined, and there were no default values for `_interp__OLD_CMD` and `_interp__CMD` the Ksh entry could be defined as: [.programlisting] .... SHEBANG_LANG= ksh ksh_OLD_CMD= "/usr/bin/env ksh" /bin/ksh /usr/bin/ksh ksh_CMD= ${LOCALBASE}/bin/ksh .... ==== [[uses-shebangfix-ex-strange]] .Adding a Strange Location for an Interpreter [example] ==== Some software uses strange locations for an interpreter. For example, an application might expect Python to be located in [.filename]#/opt/bin/python2.7#. The strange path to be replaced can be declared in the port [.filename]#Makefile#: [.programlisting] .... python_OLD_CMD= /opt/bin/python2.7 .... ==== [[uses-shebangfix-ex-regex]] .`USES=shebangfix` with `SHEBANG_REGEX` [example] ==== To fix all the files in `${WRKSRC}/scripts` ending in [.filename]#.pl#, [.filename]#.sh#, or [.filename]#.cgi# do: [.programlisting] .... USES= shebangfix SHEBANG_REGEX= ./scripts/.*\.(sh|pl|cgi) .... [NOTE] ====== `SHEBANG_REGEX` is used by running `find -E`, which uses modern regular expressions also known as extended regular expressions. See man:re_format[7] for more information. ====== ==== [[uses-shebangfix-ex-glob]] .`USES=shebangfix` with `SHEBANG_GLOB` [example] ==== To fix all the files in `${WRKSRC}` ending in [.filename]#.pl# or [.filename]#.sh#, do: [.programlisting] .... USES= shebangfix SHEBANG_GLOB= *.sh *.pl .... ==== [[uses-shebangfix-ex-files]] .`USES=shebangfix` with `SHEBANG_FILES` [example] ==== To fix the files [.filename]#script/foobar.pl# and [.filename]#script/*.sh# in `${WRKSRC}`, do: [.programlisting] .... USES= shebangfix SHEBANG_FILES= scripts/foobar.pl scripts/*.sh .... ==== [[uses-sqlite]] == `sqlite` Possible arguments: (none), `2`, `3` Add a dependency on SQLite. The default version used is 3, but version 2 is also possible using the `:2` modifier. [[uses-ssl]] == `ssl` Possible arguments: (none), `build`, `run` Provide support for OpenSSL. A build- or run-time only dependency can be specified using `build` or `run`. These variables are available for the port's use, they are also added to `MAKE_ENV`: `OPENSSLBASE`:: Path to the OpenSSL installation base. `OPENSSLDIR`:: Path to OpenSSL's configuration files. `OPENSSLLIB`:: Path to the OpenSSL libraries. `OPENSSLINC`:: Path to the OpenSSL includes. `OPENSSLRPATH`:: If defined, the path the linker needs to use to find the OpenSSL libraries. [TIP] ==== If a port does not build with an OpenSSL flavor, set the `BROKEN_SSL` variable, and possibly the `BROKEN_SSL_REASON__flavor_`: [.programlisting] .... BROKEN_SSL= libressl BROKEN_SSL_REASON_libressl= needs features only available in OpenSSL .... ==== [[uses-tar]] == `tar` Possible arguments: (none), `Z`, `bz2`, `bzip2`, `lzma`, `tbz`, `tbz2`, `tgz`, `txz`, `xz`, `zst`, `zstd` Set `EXTRACT_SUFX` to `.tar`, `.tar.Z`, `.tar.bz2`, `.tar.bz2`, `.tar.lzma`, `.tbz`, `.tbz2`, `.tgz`, `.txz`, `.tar.xz`, `.tar.zst` or `.tar.zstd` respectively. [[uses-tcl]] == `tcl` Possible arguments: _version_, `wrapper`, `build`, `run`, `tea` Add a dependency on Tcl. A specific version can be requested using _version_. The version can be empty, one or more exact version numbers (currently `84`, `85`, or `86`), or a minimal version number (currently `84+`, `85+` or `86+`). To only request a non version specific wrapper, use `wrapper`. A build- or run-time only dependency can be specified using `build` or `run`. To build the port using the Tcl Extension Architecture, use `tea`. After including [.filename]#bsd.port.pre.mk# the port can inspect the results using these variables: * `TCL_VER`: chosen major.minor version of Tcl * `TCLSH`: full path of the Tcl interpreter * `TCL_LIBDIR`: path of the Tcl libraries * `TCL_INCLUDEDIR`: path of the Tcl C header files * `TK_VER`: chosen major.minor version of Tk * `WISH`: full path of the Tk interpreter * `TK_LIBDIR`: path of the Tk libraries * `TK_INCLUDEDIR`: path of the Tk C header files [[uses-terminfo]] == `terminfo` Possible arguments: (none) Adds crossref:plist[plist-keywords-terminfo,`@terminfo`] to the [.filename]#plist#. Use when the port installs [.filename]#*.terminfo# files in [.filename]#${PREFIX}/share/misc#. [[uses-tex]] == `tex` Possible arguments: (none) Provide support for tex. Loads all the default variables for TEX related ports and does not add any dependency on any ports. Variables are used to specify which TEX modules are required. `USE_TEX`:: The list of required TEX extensions at run-time. Add `:build` to the extension name to add a build-time dependency, `:run` to add runtime dependency, `:test` for test time dependency, `:extract` for extract time dependency. Example: `base texmf:build source:run` Current possible arguments are as follows: * `base` * `texmf` * `source` * `docs` * `web2c` * `kpathsea` * `ptexenc` * `basic` * `tlmgr` * `texlua` * `texluajit` * `synctex` * `xpdfopen` * `dvipsk` * `dvipdfmx` * `xdvik` * `gbklatex` * `formats` * `tex` * `latex` * `pdftex` * `jadetex` * `luatex` * `ptex` * `xetex` * `xmltex` * `texhash` * `updmap` * `fmtutil` [[uses-tk]] == `tk` Same as arguments for `tcl` Small wrapper when using both Tcl and Tk. The same variables are returned as when using Tcl. [[uses-uidfix]] == `uidfix` Possible arguments: (none) Changes some default behavior (mostly variables) of the build system to allow installing this port as a normal user. Try this in the port before using crossref:uses[uses-fakeroot,USES=fakeroot] or patching. [[uses-uniquefiles]] == `uniquefiles` Possible arguments: (none), `dirs` Make files or directories 'unique', by adding a prefix or suffix. If the `dirs` argument is used, the port needs a prefix (and only a prefix) based on `UNIQUE_PREFIX` for standard directories `DOCSDIR`, `EXAMPLESDIR`, `DATADIR`, `WWWDIR`, `ETCDIR`. These variables are available for ports: * `UNIQUE_PREFIX`: The prefix to be used for directories and files. Default: `${PKGNAMEPREFIX}`. * `UNIQUE_PREFIX_FILES`: A list of files that need to be prefixed. Default: empty. * `UNIQUE_SUFFIX`: The suffix to be used for files. Default: `${PKGNAMESUFFIX}`. * `UNIQUE_SUFFIX_FILES`: A list of files that need to be suffixed. Default: empty. [[uses-vala]] == `vala` Possible arguments: `build`, `lib`, `no_depend` Adds build or library dependencies on package:lang/vala[]. The `no_depend` argument is reserved for package:lang/vala[] itself. [[uses-varnish]] == `varnish` Possible arguments: `4` (default), `6`, `7` Handle dependencies on Varnish Cache. Adds a dependency on package:www/varnish*[]. [[uses-webplugin]] == `webplugin` Possible arguments: (none), `ARGS` Automatically create and remove symbolic links for each application that supports the webplugin framework. `ARGS` can be one of: * `gecko`: support plug-ins based on Gecko * `native`: support plug-ins for Gecko, Opera, and WebKit-GTK * `linux`: support Linux plug-ins * `all` (default, implicit): support all plug-in types * (individual entries): support only the browsers listed These variables can be adjusted: * `WEBPLUGIN_FILES`: No default, must be set manually. The plug-in files to install. * `WEBPLUGIN_DIR`: The directory to install the plug-in files to, default [.filename]#PREFIX/lib/browser_plugins/WEBPLUGIN_NAME#. Set this if the port installs plug-in files outside of the default directory to prevent broken symbolic links. * `WEBPLUGIN_NAME`: The final directory to install the plug-in files into, default `PKGBASE`. [[uses-xfce]] == `xfce` Possible arguments: (none), `gtk2` Provide support for Xfce related ports. See crossref:special[using-xfce,Using Xfce] for details. The `gtk2` argument specifies that the port requires GTK2 support. It adds additional features provided by some core components, for example, package:x11/libxfce4menu[] and package:x11-wm/xfce4-panel[]. [[uses-xorg]] == `xorg` Possible arguments: (none) Provides an easy way to depend on X.org components. The components should be listed in `USE_XORG`. The available components are: [[using-x11-components]] .Available X.Org Components [cols="1,1", frame="none", options="header"] |=== | Name | Description |`dmx` |DMX extension library |`fontenc` |The fontenc Library |`fontutil` |Create an index of X font files in a directory |`ice` |Inter Client Exchange library for X11 |`libfs` |The FS library |`pciaccess` |Generic PCI access library |`pixman` |Low-level pixel manipulation library |`sm` |Session Management library for X11 |`x11` |X11 library |`xau` |Authentication Protocol library for X11 |`xaw` |X Athena Widgets library |`xaw6` |X Athena Widgets library |`xaw7` |X Athena Widgets library |`xbitmaps` |X.Org bitmaps data |`xcb` |The X protocol C-language Binding (XCB) library |`xcomposite` |X Composite extension library |`xcursor` |X client-side cursor loading library |`xdamage` |X Damage extension library |`xdmcp` |X Display Manager Control Protocol library |`xext` |X11 Extension library |`xfixes` |X Fixes extension library |`xfont` |X font library |`xfont2` |X font library |`xft` |Client-sided font API for X applications |`xi` |X Input extension library |`xinerama` |X11 Xinerama library |`xkbfile` |XKB file library |`xmu` |X Miscellaneous Utilities libraries |`xmuu` |X Miscellaneous Utilities libraries |`xorg-macros` |X.Org development aclocal macros |`xorg-server` |X.Org X server and related programs |`xorgproto` |xorg protocol headers |`xpm` |X Pixmap library |`xpresent` |X Present Extension library |`xrandr` |X Resize and Rotate extension library |`xrender` |X Render extension library |`xres` |X Resource usage library |`xscrnsaver` |The XScrnSaver library |`xshmfence` |Shared memory 'SyncFence' synchronization primitive |`xt` |X Toolkit library |`xtrans` |Abstract network code for X |`xtst` |X Test extension |`xv` |X Video Extension library |`xvmc` |X Video Extension Motion Compensation library |`xxf86dga` |X DGA Extension |`xxf86vm` |X Vidmode Extension |=== [[uses-xorg-cat]] == `xorg-cat` Possible arguments: `app`, `data`, `doc`, `driver`, `font`, `lib`, `proto`, `util`, `xserver` and (none) or one off `autotools` (default), `meson` Provide support for building Xorg components. It takes care of setting up common dependencies and an appropriate configuration environment needed. This is intended only for Xorg components. The category has to match upstream categories. The second argument is the build system to use. autotools is the default, but meson is also supported. [[uses-zip]] == `zip` Possible arguments: (none), `infozip` Indicates that the distribution files use the ZIP compression algorithm. For files using the InfoZip algorithm the `infozip` argument must be passed to set the appropriate dependencies.