-
Notifications
You must be signed in to change notification settings - Fork 12
/
DIFFERENCES
689 lines (521 loc) · 24.5 KB
/
DIFFERENCES
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
Porting these FreeBSD utilities to Linux systems exposes some notable
differences. This file attempts to summarize the major differences
and what option was taken for the port.
copyright[] and sccsid[]
------------------------
These static strings are unused in the code and cause compiler
warnings. We disable them by passing -Dlint to the compiler. Some
source files have these strings disabled anyway in FreeBSD by wrapping
them in #if 0/#endif.
__FBSDID()
----------
We disable this by passing -D'__FBSDID(x)=' to the compiler.
MAXPHYS
-------
The maximum raw I/O size is defined in <sys/param.h>, but that define
does not exist on Linux. MAXPHYS has history in the Unix world and
nearly all commercial Unix variants provide this information in a
header file. But Linux is more flexible and having a hardcoded
default does not necessarily work for all supported hardware. I am
not sure what the best corresponding value is to use on Linux, so for
now I just copied the MAXPHYS definition from FreeBSD and am using
that where it is used. It defaults to 1 megabyte on 64-bit systems,
so whatever.
S_ISTXT
-------
The FreeBSD macro to test st_mode to see if the sticky bit is set is
named S_ISTXT while Linux spells it S_ISVTX. For our purposes we will
just change these in the code to S_ISVTX.
reallocarray() and recallocarray()
----------------------------------
reallocarray() is a thin wrapper around realloc(). glibc offers it
though there is currently no man page for it on typical Linux systems.
We will use the glibc reallocarray() but copy over recallocarray.c
since glibc lacks that. recallocarray() is reallocarray() but in
calloc() style.
glibc makes reallocarray available with _DEFAULT_SOURCE defined, but
in versions prior to 2.28 it was part of _GNU_SOURCE. Programs using
reallocarray() have _DEFAULT_SOURCE added to their Makefile.
__libc_sigprocmask()
--------------------
We have <signal.h> on Linux and can replace calls to
__libc_sigprocmask() with _sigprocmask().
REG_BASIC
---------
FreeBSD defines REG_BASIC for regcomp(3). This is not defined in
glibc on Linux because it is the default behavior. There is
REG_EXTENDED to enable POSIX Extended Regular Expressions. Where
REG_BASIC appears in regcomp() calls, we remove it.
IOV_MAX
-------
This is defined in glibc if you define _XOPEN_SOURCE.
SIZE_T_MAX
----------
glibc does not offer this. Where it is used, we will use SIZE_MAX
from stdint.h.
getline()
---------
glibc has this if you define _GNU_SOURCE when building.
fgetln()
--------
The FreeBSD function to read a line of input from a file stream is not
portable, except to other BSD variants. On glibc and defined by POSIX
we have getline(), which is similar but slightly different. We can't
easily port the FreeBSD fgetln() function because of the way it works.
It's easier to just rewrite code to use getline() instead, which is
what we will do. Used in loops, you can change this:
char *cp = NULL;
size_t readlen = 0;
while ((cp = fgetln(fp, &readlen)) != NULL)
to:
char *cp = NULL;
size_t buflen = 0;
ssize_t readlen;
while ((readlen = getline(&cp, &buflen, fp)) >= 0)
It is important to differentiate between the buffer size and the number
of characters read, as getline may be called multiple times in a row
and the buffer and its size should be preserved (so that getline can
properly reallocate it if needed). The actual number of characters
read from the line is returned by the function. It is also important
to take care of properly initializing the buffer and the length before
the first time getline is called.
asprintf()
----------
glibc has this if you define _GNU_SOURCE.
SIGINFO
-------
The SIGINFO signal is custom to the BSDs, and not present on Linux in
any form. However, there are the user signals SIGUSR1 and SIGUSR2,
which can serve the same purpose in our case. All instances of SIGINFO
have been replaced with SIGUSR1, so to e.g. get the current status from
'dd', you can use 'kill -USR1 PID_OF_DD'.
login_cap.h and related functions
---------------------------------
FreeBSD has a concept of login capabilities and user classes. We
don't have that on Linux, so code that makes use of this has been
removed. For example, on FreeBSD the env(1) command has the -L and -U
options for specifying the user name to operate under (-U) and the
login class (-L). These have been removed from the code as well as
the man page since the functionality is not present under Linux.
Other commands that offer login_cap functionality have had it removed.
major() and minor()
-------------------
These macros are for use with st_rdev members of a struct stat. They
are available from the <sys/sysmacros.h> header on Linux.
makedev()
---------
This is defined in the <sys/sysmacros.h> header on Linux.
NL_TEXTMAX
----------
Linux has this when __USE_XOPEN is defined. You can get this through
_GNU_SOURCE or _XOPEN_SOURCE or _POSIX_C_SOURCE. For us, _GNU_SOURCE
tends to be the better option so we don't accidentally turn off other
definitions.
wcwidth() and wchar.h functions
-------------------------------
Available in glibc by defining _XOPEN_SOURCE. Programs requiring this
have it added to their Makefile.am file. Note that _GNU_SOURCE also
implies _XOPEN_SOURCE.
nextwctype()
------------
This is not available on Linux or in POSIX, and used in tr. Since it
cannot be reimplemented (to do it efficiently enough to be useful, one
needs access to the actual ctype ranges in the current character encoding),
tr lacks support for non-ASCII character ranges (an emulation is provided
that only considers a single byte range). This is actually in line with
the GNU implementation, which does not support Unicode character ranges
either.
D_MD_ORDER
----------
This is a local extension on FreeBSD in langinfo.h for nl_langinfo().
If you call nl_langinfo() with D_MD_ORDER, it will give you a
locale-appropriate format string suitable for strftime() to print the
date. The purpose is to order the output correctly for the locale and
print the month before the day or the day before the month. glibc
lacks the D_MD_ORDER extension, but we can get the same effect by
using D_FMT and looking at the second character in the returned
string. If the second character is 'd' it means order with the day
first, otherwise order with the month first.
UID_MAX and GID_MAX
-------------------
Defined in /etc/login.defs on Linux. Using INT_MAX here to keep
things simple. Might need a better solution in the future. Passing
them with -D options to the compiler.
'chmod -h' and lchmod()
-----------------------
FreeBSD and other BSD systems offer an lchmod() call that is like
chmod(), but it changes permissions on a symlink instead of what the
symlink points to. Think about stat() vs. lstat(). Likewise, the
chmod command offers the -h option to do the same thing. Linux does
not have lchmod() nor has it had the 'chmod -h' functionality. It's
possible to implement the functionality with fchmodat(), but we are
not doing that because the -h functionality has not been present on
Linux in the past. Support for -h in chmod.c has been removed and it
has been removed from the chmod.1 man page (though the historical
information and BSD-specification information remove).
lchmod() is also used in cp(1) from FreeBSD, but that functionality
has been removed from this port.
lpathconf()
-----------
Linux does not have lpathconf(). It does have pathconf(). On both
FreeBSD and Linux the pathconf() function returns configuration values
for files. The lpathconf() function does the same thing for symlinks,
but of the actual link itself and not what it points to. Use of
lpathconf() is either removed or replaced as necessary. In chmod.c,
it is used to request the value of _PC_ACL_NFS4, but since that value
name doesn't appear on Linux the use of lpathconf() is dropped. Also
the corresponding NFS4 stuff in chmod.c is dropped.
struct passwd
-------------
As defined in pwd.h, this is mostly similar on Linux from FreeBSD but
FreeBSD does include some things beyond what a standard Unix system
has. Notably their pw_class attribute which defines the user class.
This is a thing specific to FreeBSD and is not present on other
systems. At least it's not present on Linux. For our port, we are
removing the pw_class support in code that uses it.
You may also see code that uses pw_change or pw_expire. These members
are not available on Linux either and have been removed from the code
in this port.
<sys/mac.h> and related functions
---------------------------------
Code for FreeBSD's MAC (Mandatory Access Control) is not available on
Linux and has been removed. This could, arguably, be swapped out with
SELinux functionality. Patches welcome.
The ls(1) command has the -Z option removed from the command and man
page.
<sys/acl.h> and related functions
---------------------------------
Code for FreeBSD's ACL subsystem is not available on Linux. Linux
only supports POSIX draft ACLs, not NFSv4 ACLs, and there is libacl
to manipulate them.
We implement support for libacl where possible (and therefore for
POSIX draft ACLs), but not for NFSv4 ACLs (the code is ignored).
Additionally, we implement support for extended attributes in specific
places such as mv(1) as well as cp(1) in archive mode, using Linux
API.
strtonum()
----------
This is a BSD extension meant as a more flexible alternative to atoi()
and strtol(). It converts a string to a long long in base 10. The
main advantage it offers is accounting for arbitrary whitespace
followed by an optional '+' or '-' before the number begins. But
glibc's strtoll() already does this plus it offers the ability to
specify the base for conversion. In instances where strtonum() is
used, we will convert it to use strtoll() and handle errno results.
user_from_uid() and group_from_gid()
------------------------------------
Where user_from_uid() is used, we will replace it with a call to
getpwnam() and then using the pw_name member of the struct passwd
returned from that function. Where group_from_gid() is used, we will
replace it with a call to getgrgid() and then use the gr_name member
of the struct group returned from that function.
fflagstostr(), fchflags(), stat.st_flags, and related things
------------------------------------------------------------
Files in BSD have various flags that can be set. Make it immutable,
for instance. In Linux we have the chattr and lsattr commands for the
same type functionality. These are filesystem-specific. In BSD,
everything is implemented in the same source tree and they only have
the one main filesystem, so this is implemented in the main API for
the operating system.
Linux doesn't have a generic way to do this, so the functionality has
been removed from commands that try to use it.
The stat(1) command has the st_flags handling code removed as well.
The ls(1) command has the -U and -o options removed from the code and
from the man page. The du(1) command has the -n option removed from
the code and from the man page.
'ls -o'
-------
The ls(1) command has the -o option to show the file flags in the long
listing output. Flags come from st_flags on struct stat structures
and is specific to BSD operating systems. This option has been
removed from ls in this port.
struct stat (st_birthtim and other things)
----------------------------------------------------
There are a number of differences between the stat structures on Linux
and FreeBSD.
The st_birthtim member is not present on Linux because this is
filesystem specific and there is not a generic way to handle it. Even
FreeBSD has this problem for some filesystems. In those cases, the
st_btime output is undefined if the filesystem lacks support for it.
GNU stat works this way too. For consistency with the other stuff we
are doing, our code removes the st_birthtime code whenever it appears
in the code.
S_IFWHT and S_ISWHT
-------------------
Linux does not support whiteouts as a struct stat member. Where
S_IFWHT or S_ISWHT is used or checked, it is removed from the code.
fts_open()
----------
The compare function uses a different prototype on Linux. On FreeBSD,
the expectation is:
int (*compar)(const FTSENT * const *, const FTSENT * const *);
while on Linux it is:
int (*compar)(const FTSENT **, const FTSENT **);
Our port removes the second 'const' in the prototype.
FIODTYPE and D_DISK/D_TAPE/etc
------------------------------
These appear in the dd(1) command. This ioctl() is not available on
Linux. Remove the checks against D_DISK/D_TAPE/etc as well. Only
make the determination based on S_ISCHR() or S_ISBLK() and leave it at
that.
OFF_MAX
-------
FreeBSD defines this as the maximum value for an off_t. On Linux we
don't have this, but an off_t is a long int, so we can use LONG_MAX
instead.
check_utility_compat()
----------------------
The check_utility_compat() function checks whether utility should
behave in a traditional (FreeBSD 4.7-compatible) manner, or in
accordance with IEEE Std 1003.1-2001 (“POSIX.1”). The configuration
is given as a comma- separated list of utility names; if the list is
present but empty, all supported utilities assume their most
compatible mode. The check_utility_compat() function first checks for
an environment variable named _COMPAT_FreeBSD_4. If that environment
variable does not exist, then check_utility_compat() will attempt to
read the contents of a symbolic link named /etc/compat-FreeBSD-4-util.
If no configuration is found, compatibility mode is disabled.
We don't have this function on Linux so calls to it have been removed.
QUAD_MAX
--------
This is defined on FreeBSD as LONG_MAX, so we'll just call it LONG_MAX
via CFLAGS.
MAXLOGNAME
----------
The maximum login name length is defined as LOGIN_NAME_MAX on Linux.
Linux has both the POSIX limit and the Linux limit. The POSIX limit
is 9 while the Linux limit is 256. We're building with _GNU_SOURCE,
so we're getting the Linux limit.
struct statfs
-------------
This is available on Linux in the <sys/vfs.h> header. Not all of the
struct members are the same as the ones in FreeBSD. For instance,
Linux has .f_bsize whereas FreeBSD has .f_iosize. The statfs
structures are OS-specific and the similarly named struct statvfs is
defined to be the portable one. We will use the statvfs structure and
functions where statfs is used. The statvfs struct and functions are
defined in <sys/statvfs.h>.
The struct statvfs on Linux does not have the f_mntonname member, so
uses of that in these tools has been removed.
_PATH_CP and _PATH_RM
---------------------
These are defined as /bin/cp and /bin/rm, respectively. Where we need
them we will just define them in CFLAGS and move on.
MAXBSIZE
--------
Defined in the <sys/param.h> header from the FreeBSD kernel as 65536.
This is the maximum filesystem block size. Linux lacks a generic
definition for this as it is per-filesystem dependent. We lift the
FreeBSD definition from their <sys/param.h> and use it.
undelete()
----------
The rm(1) command offers the -W option to try to undelete files marked
as whiteout on a unionfs volume. This is FreeBSD-specific and has
been removed.
vis.h functions
---------------
Starting with 4.4BSD, the C library gained a header called vis.h that
defined a number of functions to "visually encode characters".
Functions such as strvis(). These functions are present in FreeBSD
and are used by some programs, such as install(1). Linux with glibc
lacks the vis.h functions. BSD systems tend to have a source file in
libc called vis.c which provides strvis(), but we provide them in the
local libcompat library. The header file is available in include/ and
programs are patched to include "vis.h" instead of <vis.h>.
EPROCLIM
--------
This is a FreeBSD specific error code that means "too many processes".
Linux does not provide this so it is removed from the code where it
appears.
getbsize()
----------
The FreeBSD standard C library includes the getbsize() function which
returns a formatted string based on the value in the BLOCKSIZE
environment variable. This appears to be a standard BSD thing as it
claims to have originated with 4.4 BSD. We take the one from the
FreeBSD source tree and put it in our compat library.
EFTYPE
------
This is an errno value from FreeBSD that we do not have on Linux. It
means "invalid file type". Where we need to use EFTYPE for reporting,
we will use EINVAL instead.
MD5 and SHA API differences
---------------------------
We use libcrypto from OpenSSL for MD5 and SHA message digest
algorithms. The API is mostly the same, but some types and functions
are spelled differently. For example, in FreeBSD they have SHA1_CTX
and OpenSSL provides SHA_CTX. FreeBSD has MD5Init and OpenSSL
provides MD5_Init. Our port patches these instances in the code.
FreeBSD also provides *_File() functions that compute the named
message digest given a filename. OpenSSL does not provide this.
Where the function is used in install(1), we have rewritten
digest_file() to compute the digest with an open/read loop.
The *_End() function calls have been replaced with *_Final() function
calls.
st_atimespec, st_ctimespec, and st_mtimespec
--------------------------------------------
Linux does not have the st_{a,c,m}timespec members. Linux has
st_atim, st_mtim, and st_ctim (note the lack of the trailing 'e')
which are all struct timespec structures. There is st_atime,
st_mtime, and st_ctime which are the .tv_sec members of the timespec
structures. You can get the nanoseconds from the .tv_nsec member on
the timespec structures. Code using these stat(2) struct members, we
patch it to use the Linux struct syntax. So st_atimespec becomes
st_atim.
st_birthtime
------------
The st_birthtime member in struct stat is not present on Linux because
this is filesystem specific and there is not a generic way to handle
it. Even FreeBSD has this problem for some filesystems. In those
cases, the st_btime output is undefined if the filesystem lacks
support. GNU stat works this way too. For consistency with the other
stuff we are doing, our code removes the st_birthtime code whenever it
appears in code.
st_gen
------
The st_gen struct stat member is the file generation number and this
is not present on Linux, so it has been removed from the code.
SPECNAMELEN
-----------
FreeBSD defines SPECNAMELEN as 255. We change this to MAXPATHLEN on
Linux (also 255). This is used in stat(1) and relates to path name
limits.
ishexdigit()
------------
Present on FreeBSD but not on Linux. We change this to isxdigit()
which we have via ctype.h on glibc.
'stat -H'
---------
The fhandle_t type and fhstat() function are not available on Linux,
so the special handling of NFS handles in stat(1) via the -H option
has been removed.
getmntinfo()
------------
FreeBSD provides a function called getmntinfo() which returns an array
of mounted filesystems. This includes the device node name, directory
mounted on, filesystem stats, and other information. Linux has no
equivalent to this. The combined structure in FreeBSD contains
information that you would get from getmntent() and statvfs() on
Linux. The first thing you have to do on Linux is loop over the
mounted filesystems using getmntent(). Later you can open the mounted
filesystem to get a FILE * and then call statvfs() on that to get data
like free space and size and such.
To make df(1) easier to port, we have implemented a getmntinfo() with
a combined data type called struct mntinfo. The new getmntinfo()
function creates an array of struct mntinfo entries of mounted
filesystems containing the combined data from both getmntent() and
statvfs() on Linux. There is also a corresponding freemntinfo() call
to free the memory allocated for the array.
This change does make df(1) the most different command in the port,
but there is no other easy way under Linux to get the mounted
filesystem information.
MNT_WAIT, MNT_NOWAIT, MNT_LOCAL
-------------------------------
These flags are not available through the corresponding Linux APIs.
These have been dropped from function calls trying to use them.
MNAMELEN
--------
This constant does not exist on Linux, but filesystem names are
NUL-terminated strings anyway so we can use strcmp(). Where MNAMELEN
is used, it has been removed.
df(1)
-----
df(1) has an internal function called makenetvfslist() which reads a
setting via sysctlbyname(), which Linux does not have. The df.c
source has removed this function and defined NETVFSLIST as a static
string of the information likely to come from makenetvfslist() were it
to work on Linux. What this function does is return a list of network
filesystems with "no" prefixed and the list comma-delimited. We can
define this for now in df.c and implement a function later if desired.
Another change in df(1) is how it handles a specific list of
filesystems to report information for. In FreeBSD the command
allocates a mntbuf array large enough for the number of filesystems
specified, then collects the info via statfs() calls and builds the
array. Since we have to implement getmntinfo(), we run that instead
for all df(1) invocations and then iterate over that list and set
f_selected to 0 for unselected filesystems.
ALTWERASE
---------
Alternate word erase is a BSD thing. glibc offers WERASE and VWERASE
and has inconsistent documentation alluding to VWERASE being ALTWERASE
as you expect on FreeBSD. Our patches use VWERASE where ALTWERASE was
used.
TTYDISC and other *DISC macros
------------------------------
tty line discipline macro names are entirely different between Linux
and FreeBSD. TTYDISC is '0' and that maps to N_TTY on Linux. The
Linux names tend to be N_*, so PPPDISC is N_PPP. FreeBSD has some
that Linux doesn't have, like NMEADISC, and in those cases the
FreeBSD-specific code is removed.
Missing stty(1) Control Modes
-----------------------------
Some modes for stty(1) just don't exist on Linux. These are mdmbuf,
kerninfo, onoeot, ctsflow, and rtsflow. In those cases, the support
for them is removed from stty(1).
VDSUSP
------
This is called CDSUSP on Linux. In fact, on FreeBSD the VDSUSP name
appears to be legacy. Linux doesn't carry the old name, only the new
name.
VSTATUS
-------
This is called CSTATUS on Linux, similar to the VDSUSP vs. CDSUSP
difference.
TIOCEXT
-------
This is handled via tcgetattr() and tcsetattr() on Linux, whereas it's
an ioctl on BSD. The f_extproc function in stty.c has been altered to
do things the Linux way.
tty headers
-----------
Fortunately Linux and FreeBSD systems do things very differently here.
On Linux, you generally want to include termios.h and pty.h. BSD
doesn't have the latter. Avoid directly including sys or linux
headers because those are pulled in by the glibc headers. In stty,
these headers are included in stty.h.
getopt()
--------
The semantics of a dash at the beginning of optstring differ between
BSD and GNU variants. On BSD, it simply means to permit the literal
option -, while GNU style implementations have it result in every
non-option parameter being treated as an option parameter with the
value 1. Therefore, this is removed in the ports and reimplemented in
other ways.
howmany()
---------
This macro is available in <sys/param.h> on Linux.
sys_signame[]
-------------
This array contains strings describing the signal number. The array
index is the signal number. There is no portable way to do this, so
the projects brings in some public domain code from util-linux.
sys_nsig
--------
This is the maximum number of signals defined. On a Linux system
this is spelld NSIG.
sysctl()
--------
Linux frowns on using sysctl() to gather information about the system.
There is an alternative function called sysconf() which supports a
limited subset of things. We use this where sysctl() was used and
there is no other way to obtain the required information, such as
computing the amount of physical memory in the system. In some cases
it's just not possible on Linux so we have to open and read data from
files in /proc.
kqueue
------
The tail(1) command on FreeBSD uses kqueue to monitor for events on
files and then take action. This is a BSD-specific API and not
available on Linux. When it comes to monitoring files, the equivalent
Linux API is inotify, which can be used together with event handling
mechanisms such as poll/epoll (the actual Linux alternative to kqueue
is epoll, but it doesn't work on regular files, while kqueue does).
procctl()
---------
The FreeBSD procctl() function has a different API than the prctl()
function on Linux. We replace procctl() calls with prctl().
`diff -l` and `diff3`
---------------------
The `-l` (paginate) flag is not supported in `diff` as it was too
hard to port. The `diff3` tool comes from OpenBSD rather than FreeBSD,
as I have not managed to port the FreeBSD one yet.