summaryrefslogtreecommitdiffstats
path: root/pkgs/shells/bash/5.nix
blob: 07726320556e0bd3cbe3b98ba24ac9dbe8519a0f (plain)
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
{
  lib,
  stdenv,
  buildPackages,
  fetchurl,
  updateAutotoolsGnuConfigScriptsHook,
  bison,
  util-linuxMinimal,
  coreutils,
  libredirect,
  glibcLocales,
  gnused,

  interactive ? true,
  readline,
  withDocs ? null,
  forFHSEnv ? false,

  pkgsStatic,
}:

let
  upstreamPatches = import ./bash-5.3-patches.nix (
    nr: sha256:
    fetchurl {
      url = "mirror://gnu/bash/bash-5.3-patches/bash53-${nr}";
      inherit sha256;
    }
  );
in
lib.warnIf (withDocs != null)
  ''
    bash: `.override { withDocs = true; }` is deprecated, the docs are always included.
  ''
  stdenv.mkDerivation
  (fa: {
    pname = "bash${lib.optionalString interactive "-interactive"}";
    version = "5.3${fa.patch_suffix}";
    patch_suffix = "p${toString (builtins.length upstreamPatches)}";

    src = fetchurl {
      url = "mirror://gnu/bash/bash-${lib.removeSuffix fa.patch_suffix fa.version}.tar.gz";
      hash = "sha256-DVzYaWX4aaJs9k9Lcb57lvkKO6iz104n6OnZ1VUPMbo=";
    };

    hardeningDisable = [
      "format"
    ]
    # bionic libc is super weird and has issues with fortify outside of its own libc, check this comment:
    # https://github.com/NixOS/nixpkgs/pull/192630#discussion_r978985593
    # or you can check libc/include/sys/cdefs.h in bionic source code
    ++ lib.optionals (stdenv.hostPlatform.libc == "bionic") [ "fortify" ];

    outputs = [
      "out"
      "dev"
      "man"
      "doc"
      "info"
    ];

    separateDebugInfo = true;

    env.NIX_CFLAGS_COMPILE = ''
      -DSYS_BASHRC="/etc/bashrc"
      -DSYS_BASH_LOGOUT="/etc/bash_logout"
    ''
    + lib.optionalString (!forFHSEnv) ''
      -DDEFAULT_PATH_VALUE="/no-such-path"
      -DSTANDARD_UTILS_PATH="/no-such-path"
      -DDEFAULT_LOADABLE_BUILTINS_PATH="${placeholder "out"}/lib/bash:."
    ''
    + ''
      -DNON_INTERACTIVE_LOGIN_SHELLS
      -DSSH_SOURCE_BASHRC
    ''
    # Bash's configure script assumes that CC and CC_FOR_BUILD have the
    # same default -std=... flags. But at this moment, for cross llvm and FreeBSD, we
    # have CC_FOR_BUILD that defaults to c23, and a CC that default to
    # something older, perhaps c17. This breaks the build because of
    # bash's faulty assumptions.
    #
    # To fix, we simply force the standard to be the higher for CC to
    # match CC_FOR_BUILD.
    #
    # Once FreeBSD and other contexts are built with a newer version of clang,
    # this hack should be removed.
    + lib.optionalString stdenv.cc.isClang ''
      -std=c23
    '';

    patchFlags = [ "-p0" ];

    patches = upstreamPatches ++ [
      # Enable PGRP_PIPE independently of the kernel of the build machine.
      # This doesn't seem to be upstreamed despite such a mention of in https://github.com/NixOS/nixpkgs/pull/77196,
      # which originally introduced the patch
      # Some related discussion can be found in
      # https://lists.gnu.org/archive/html/bug-bash/2015-05/msg00071.html
      ./pgrp-pipe-5.patch
    ];

    configureFlags = [
      # At least on Linux bash memory allocator has pathological performance
      # in scenarios involving use of larger memory:
      #   https://lists.gnu.org/archive/html/bug-bash/2023-08/msg00052.html
      # Various distributions default to system allocator. Let's nixpkgs
      # do the same.
      "--without-bash-malloc"
      (if interactive then "--with-installed-readline" else "--disable-readline")
    ]
    ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
      "bash_cv_job_control_missing=nomissing"
      "bash_cv_sys_named_pipes=nomissing"
      "bash_cv_getcwd_malloc=yes"
      # This check cannot be performed when cross compiling. The "yes"
      # default is fine for static linking on Linux (weak symbols?) but
      # not with BSDs, when it does clash with the regular `getenv`.
      "bash_cv_getenv_redef=${
        lib.boolToYesNo (!(with stdenv.hostPlatform; isStatic && (isOpenBSD || isFreeBSD)))
      }"
    ]
    ++ lib.optionals stdenv.hostPlatform.isCygwin [
      "bash_cv_dev_stdin=present"
      "bash_cv_dev_fd=standard"
      "gt_cv_func_printf_posix=yes"
    ]
    ++ lib.optionals (stdenv.hostPlatform.libc == "musl") [
      "--disable-nls"
    ]
    ++ lib.optionals stdenv.hostPlatform.isFreeBSD [
      # /dev/fd is optional on FreeBSD. we need it to work when built on a system
      # with it and transferred to a system without it! This includes linux cross.
      "bash_cv_dev_fd=absent"
    ];

    strictDeps = true;
    # Note: Bison is needed because the patches above modify parse.y.
    depsBuildBuild = [ buildPackages.stdenv.cc ];
    nativeBuildInputs = [
      updateAutotoolsGnuConfigScriptsHook
      bison
    ]
    ++ lib.optionals stdenv.hostPlatform.isDarwin [ stdenv.cc.bintools ];

    buildInputs = lib.optionals interactive [ readline ];

    enableParallelBuilding = true;

    doCheck = false; # Can't be enabled by default due to dependency cycle, use passthru.tests.withChecks instead

    postInstall = ''
      ln -s bash${stdenv.hostPlatform.extensions.executable} "$out/bin/sh"
      rm -f $out/lib/bash/Makefile.inc
    '';

    postFixup =
      if interactive then
        ''
          substituteInPlace "$out/bin/bashbug" \
            --replace '#!/bin/sh' "#!$out/bin/bash"
        ''
      # most space is taken by locale data
      else
        ''
          rm -rf "$out/share" "$out/bin/bashbug"
        '';

    passthru = {
      shellPath = "/bin/bash";
      tests.static = pkgsStatic.bash;
      tests.withChecks = fa.finalPackage.overrideAttrs (attrs: {
        doCheck = true;

        nativeCheckInputs = attrs.nativeCheckInputs or [ ] ++ [
          util-linuxMinimal
          libredirect.hook
          glibcLocales
          gnused
        ];

        meta = attrs.meta // {
          # Ignore Darwin for now, because the tests fail in many more ways than on Linux
          broken = attrs.meta.broken or false || stdenv.buildPlatform.isDarwin;
        };

        patches = attrs.patches or [ ] ++ [
          # See commit comment, also submitted upstream: https://lists.gnu.org/archive/html/bug-bash/2025-10/msg00054.html
          ./fail-tests.patch
          # See commit comment, also submitted upstream: https://lists.gnu.org/archive/html/bug-bash/2025-10/msg00055.html
          ./failed-tests-output.patch
          # The run-builtins test _almost_ succeeds, only has a bit of PATH trouble
          # and some odd terminal column mismatch
          ./fix-builtins-tests.patch
          # The run-invocation test _almost_ succeeds, only has a bit of PATH trouble
          ./fix-invocation-tests.patch
        ];

        preCheck = attrs.preCheck or "" + ''
          # Allows looking at actual outputs for failed tests
          export BASH_TSTOUT_KEEPDIR=$(mktemp -d)
          export HOME=$(mktemp -d)
          export NIX_REDIRECTS=${
            lib.concatMapAttrsStringSep ":" (name: value: "${name}=${value}") {
              "/bin/echo" = lib.getExe' coreutils "echo";
              "/bin/cat" = lib.getExe' coreutils "cat";
              "/bin/rm" = lib.getExe' coreutils "rm";
              "/usr" = "$(mktemp -d)";
            }
          }

          disabled_checks=(
            # Unsets PATH and breaks, not clear
            run-execscript

            # Fails on ZFS & needs a ja_JP.SJIS locale, which glibcLocales doesn't have
            run-intl

            # These error with "echo: write error: Broken pipe"
            run-histexpand
            run-lastpipe
            run-comsub
            run-comsub2

            # For some reason has an extra 'declare -x version="5.2p37"'
            run-nameref

            # These print some extra 'trap -- ''' SIGPIPE'
            run-trap
            run-varenv

            # These rely on /dev/tty
            run-read
            run-test
            run-vredir

            # Might also be related to not having a tty: "Inappropriate ioctl for device"
            run-history

            # Can be enabled in 5.4
            run-printf

            # This is probably fixable without too much trouble, but just not having a hardcoded PATH in type5.sub doesn't cut it
            # 142,143c142,147
            # < type5.sub: line 23: mkdir: command not found
            # < type5.sub: line 24: cd: /build/type-23722: No such file or directory
            # ---
            # > cat is /bin/cat
            # > cat is aliased to `echo cat'
            # > /bin/cat
            # > break is a shell builtin
            # > break is a special shell builtin
            # > ./e
            run-type
          )
          for check in "''${disabled_checks[@]}"; do
            # Exit before running the test script
            sed -i "1iecho 'Skipping test $check' >&2 && exit 0" "tests/$check"
          done
        '';
      });
    };

    __structuredAttrs = true;

    meta = {
      homepage = "https://www.gnu.org/software/bash/";
      description =
        "GNU Bourne-Again Shell, the de facto standard shell on Linux"
        + lib.optionalString interactive " (for interactive use)";
      longDescription = ''
        Bash is the shell, or command language interpreter, that will
        appear in the GNU operating system.  Bash is an sh-compatible
        shell that incorporates useful features from the Korn shell
        (ksh) and C shell (csh).  It is intended to conform to the IEEE
        POSIX P1003.2/ISO 9945.2 Shell and Tools standard.  It offers
        functional improvements over sh for both programming and
        interactive use.  In addition, most sh scripts can be run by
        Bash without modification.
      '';
      license = lib.licenses.gpl3Plus;
      platforms = lib.platforms.all;
      # https://github.com/NixOS/nixpkgs/issues/333338
      badPlatforms = [ lib.systems.inspect.patterns.isMinGW ];
      maintainers = with lib.maintainers; [ infinisil ];
      teams = [ lib.teams.security-review ];
      mainProgram = "bash";
      identifiers.cpeParts =
        let
          versionSplit = lib.split "p" fa.version;
        in
        {
          vendor = "gnu";
          product = "bash";
          version = lib.elemAt versionSplit 0;
          update = lib.elemAt versionSplit 2;
        };
    };
  })