1{
2 pkgs,
3 buildEnv,
4 runCommand,
5 lib,
6 stdenv,
7 freebsd,
8 binlore,
9}:
10
11# These are some unix tools that are commonly included in the /usr/bin
12# and /usr/sbin directory under more normal distributions. Along with
13# coreutils, these are commonly assumed to be available by build
14# systems, but we can't assume they are available. In Nix, we list
15# each program by name directly through this unixtools attribute.
16
17# You should always try to use single binaries when available. For
18# instance, if your program needs to use "ps", just list it as a build
19# input, not "procps" which requires Linux.
20
21let
22 inherit (lib)
23 getBin
24 getOutput
25 mapAttrs
26 platforms
27 ;
28
29 version = "1003.1-2008";
30
31 singleBinary =
32 cmd: providers:
33 let
34 provider = providers.${stdenv.hostPlatform.parsed.kernel.name} or providers.linux;
35 bin = "${getBin provider}/bin/${cmd}";
36 manDir = "${getOutput "man" provider}/share/man";
37 in
38 runCommand "${cmd}-${provider.name}"
39 {
40 meta = {
41 mainProgram = cmd;
42 priority = 10;
43 platforms = platforms.${stdenv.hostPlatform.parsed.kernel.name} or platforms.all;
44 };
45 passthru = {
46 inherit provider;
47 inherit (provider) version;
48 }
49 // lib.optionalAttrs (builtins.hasAttr "binlore" providers) {
50 binlore.out = (binlore.synthesize (getBin bins.${cmd}) providers.binlore);
51 };
52 preferLocalBuild = true;
53 }
54 ''
55 if ! [ -x ${bin} ]; then
56 echo Cannot find command ${cmd}
57 exit 1
58 fi
59
60 mkdir -p $out/bin
61 ln -s ${bin} $out/bin/${cmd}
62
63 if [ -d ${manDir} ]; then
64 manpages=($(cd ${manDir} ; find . -name '${cmd}*'))
65 for manpage in "''${manpages[@]}"; do
66 mkdir -p $out/share/man/$(dirname $manpage)
67 ln -s ${manDir}/$manpage $out/share/man/$manpage
68 done
69 fi
70 '';
71
72 # more is unavailable in darwin
73 # so we just use less
74 more_compat = runCommand "more-${pkgs.less.name}" { } ''
75 mkdir -p $out/bin
76 ln -s ${pkgs.less}/bin/less $out/bin/more
77 '';
78
79 bins = mapAttrs singleBinary {
80 # singular binaries
81 arp = {
82 linux = pkgs.net-tools;
83 darwin = pkgs.darwin.network_cmds;
84 freebsd = pkgs.freebsd.arp;
85 };
86 col = {
87 linux = pkgs.util-linux;
88 darwin = pkgs.darwin.text_cmds;
89 };
90 column = {
91 linux = pkgs.util-linux;
92 darwin = pkgs.darwin.text_cmds;
93 };
94 eject = {
95 linux = pkgs.util-linux;
96 };
97 getconf = {
98 linux = if stdenv.hostPlatform.libc == "glibc" then pkgs.libc else pkgs.netbsd.getconf;
99 darwin = pkgs.darwin.system_cmds;
100 # I don't see any obvious arg exec in the doc/manpage
101 binlore = ''
102 execer cannot bin/getconf
103 '';
104 };
105 getent = {
106 linux = if stdenv.hostPlatform.libc == "glibc" then pkgs.libc.getent else pkgs.netbsd.getent;
107 darwin = pkgs.netbsd.getent;
108 freebsd = pkgs.freebsd.getent;
109 openbsd = pkgs.openbsd.getent;
110 };
111 getopt = {
112 linux = pkgs.util-linux;
113 darwin = pkgs.getopt;
114 };
115 fdisk = {
116 linux = pkgs.util-linux;
117 darwin = pkgs.darwin.diskdev_cmds;
118 freebsd = pkgs.freebsd.fdisk;
119 };
120 fsck = {
121 linux = pkgs.util-linux;
122 darwin = pkgs.darwin.diskdev_cmds;
123 };
124 hexdump = {
125 linux = pkgs.util-linuxMinimal;
126 darwin = pkgs.darwin.shell_cmds;
127 };
128 hostname = {
129 linux = pkgs.hostname-debian;
130 darwin = pkgs.darwin.shell_cmds;
131 freebsd = pkgs.freebsd.bin;
132 openbsd = pkgs.openbsd.hostname;
133 };
134 ifconfig = {
135 linux = pkgs.net-tools;
136 darwin = pkgs.darwin.network_cmds;
137 freebsd = pkgs.freebsd.ifconfig;
138 openbsd = pkgs.openbsd.ifconfig;
139 };
140 killall = {
141 linux = pkgs.psmisc;
142 darwin = pkgs.darwin.shell_cmds;
143 };
144 locale = {
145 linux = pkgs.glibc;
146 darwin = pkgs.darwin.adv_cmds;
147 freebsd = pkgs.freebsd.locale;
148 # technically just targeting glibc version
149 # no obvious exec in manpage
150 binlore = ''
151 execer cannot bin/locale
152 '';
153 };
154 logger = {
155 linux = pkgs.util-linux;
156 };
157 more = {
158 linux = pkgs.util-linux;
159 darwin = more_compat;
160 };
161 mount = {
162 linux = pkgs.util-linux;
163 darwin = pkgs.darwin.diskdev_cmds;
164 freebsd = freebsd.mount;
165 openbsd = pkgs.openbsd.mount;
166 # technically just targeting the darwin version; binlore already
167 # ids the util-linux copy as 'cannot'
168 # no obvious exec in manpage args; I think binlore flags 'can'
169 # on the code to run `mount_<filesystem>` variants
170 binlore = ''
171 execer cannot bin/mount
172 '';
173 };
174 netstat = {
175 linux = pkgs.net-tools;
176 darwin = pkgs.darwin.network_cmds;
177 freebsd = pkgs.freebsd.netstat;
178 };
179 ping = {
180 linux = pkgs.iputils;
181 darwin = pkgs.darwin.network_cmds;
182 freebsd = freebsd.ping;
183 };
184 ps = {
185 linux = pkgs.procps;
186 darwin = pkgs.darwin.ps;
187 freebsd = pkgs.freebsd.bin;
188 openbsd = pkgs.openbsd.ps;
189 # technically just targeting procps ps (which ids as can)
190 # but I don't see obvious exec in args; have yet to look
191 # for underlying cause in source
192 binlore = ''
193 execer cannot bin/ps
194 '';
195 };
196 quota = {
197 linux = pkgs.linuxquota;
198 darwin = pkgs.darwin.diskdev_cmds;
199 };
200 route = {
201 linux = pkgs.net-tools;
202 darwin = pkgs.darwin.network_cmds;
203 freebsd = pkgs.freebsd.route;
204 openbsd = pkgs.openbsd.route;
205 };
206 script = {
207 linux = pkgs.util-linux;
208 darwin = pkgs.darwin.shell_cmds;
209 };
210 sysctl = {
211 linux = pkgs.procps;
212 darwin = pkgs.darwin.system_cmds;
213 freebsd = pkgs.freebsd.sysctl;
214 openbsd = pkgs.openbsd.sysctl;
215 };
216 top = {
217 linux = pkgs.procps;
218 darwin = pkgs.darwin.top;
219 freebsd = pkgs.freebsd.top;
220 openbsd = pkgs.openbsd.top;
221 # technically just targeting procps top; haven't needed this in
222 # any scripts so far, but overriding it for consistency with ps
223 # override above and in procps. (procps also overrides 'free',
224 # but it isn't included here.)
225 binlore = ''
226 execer cannot bin/top
227 '';
228 };
229 umount = {
230 linux = pkgs.util-linux;
231 darwin = pkgs.darwin.diskdev_cmds;
232 };
233 whereis = {
234 linux = pkgs.util-linux;
235 darwin = pkgs.darwin.shell_cmds;
236 };
237 wall = {
238 linux = pkgs.util-linux;
239 };
240 watch = {
241 linux = pkgs.procps;
242
243 # watch is the only command from procps that builds currently on
244 # Darwin/FreeBSD. Unfortunately no other implementations exist currently!
245 darwin = pkgs.callPackage ../os-specific/linux/procps-ng { };
246 freebsd = pkgs.callPackage ../os-specific/linux/procps-ng { };
247 openbsd = pkgs.callPackage ../os-specific/linux/procps-ng { };
248 };
249 write = {
250 linux = pkgs.util-linux;
251 darwin = pkgs.darwin.basic_cmds;
252 };
253 xxd = {
254 linux = pkgs.tinyxxd;
255 darwin = pkgs.tinyxxd;
256 freebsd = pkgs.tinyxxd;
257 };
258 };
259
260 makeCompat =
261 pname: paths:
262 buildEnv {
263 name = "${pname}-${version}";
264 inherit paths;
265 };
266
267 # Compatibility derivations
268 # Provided for old usage of these commands.
269 compat =
270 with bins;
271 mapAttrs makeCompat {
272 procps = [
273 ps
274 sysctl
275 top
276 watch
277 ];
278 util-linux = [
279 fsck
280 fdisk
281 getopt
282 hexdump
283 mount
284 script
285 umount
286 whereis
287 write
288 col
289 column
290 ];
291 net-tools = [
292 arp
293 hostname
294 ifconfig
295 netstat
296 route
297 ];
298 };
299in
300bins // compat