From 917628b22ce3f57c13bc4adb0780a7c167f3cd28 Mon Sep 17 00:00:00 2001 From: eureka-cpu Date: Mon, 16 Feb 2026 23:07:45 -0800 Subject: [PATCH 1/5] fix: inherit the login shell from the user --- lib/util.ml | 8 ++------ test/test_ns.rs | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/util.ml b/lib/util.ml index 13b3479..85171c1 100644 --- a/lib/util.ml +++ b/lib/util.ml @@ -22,12 +22,8 @@ module Util = struct Error.handle_ns_error "%s" (Error.sprintf_unix_error e path) ;; - (** Get the user's shell from the environment *) - let shell = - match Sys.getenv_opt "SHELL" with - | Some s -> s - | None -> "/bin/sh" - ;; + (** Get the user's login shell *) + let shell = (Unix.getpwuid (Unix.getuid ())).Unix.pw_shell (** Whether a flake.nix file exists at the given directory *) let flake_exists_at dir = Sys.file_exists (Filename.concat dir "flake.nix") diff --git a/test/test_ns.rs b/test/test_ns.rs index edaa50b..cf45895 100644 --- a/test/test_ns.rs +++ b/test/test_ns.rs @@ -6,6 +6,7 @@ static ENV_SHELL: sync::OnceLock = sync::OnceLock::new(); fn dune_test_dir() -> &'static path::PathBuf { DUNE_TEST_DIR.get_or_init(|| env::current_dir().expect("failed to get test directory")) } +// TODO: Use libc to get the login shell of the user. fn env_shell() -> &'static String { ENV_SHELL.get_or_init(|| env::var("SHELL").expect("failed to get shell from environment")) } From c9b0658e75324cdf3642cdb72d2d7dbe6b19910f Mon Sep 17 00:00:00 2001 From: eureka-cpu Date: Thu, 5 Mar 2026 14:22:37 -0800 Subject: [PATCH 2/5] add unit context to shell function --- lib/cmd.ml | 6 +++--- lib/util.ml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cmd.ml b/lib/cmd.ml index a8b3e7c..f103e5b 100644 --- a/lib/cmd.ml +++ b/lib/cmd.ml @@ -19,14 +19,14 @@ module Cmd = struct Bos.Cmd.v "nix" |>+ [ "develop" ] @ [ Uri.sprintf_uri_attr_opt entrypoint attribute ] |>+ Option.value ~default:[] force_experimental_features - |>+ [ "--command"; Unix.shell ] + |>+ [ "--command"; Unix.shell () ] ;; let legacy_nix_shell_from_entrypoint entrypoint attribute = Bos.Cmd.v "nix-shell" |>+ Option.value ~default:[] (Option.map (fun attr -> [ "--attr"; attr ]) attribute) |>+ [ entrypoint ] - |>+ [ "--command"; Unix.shell ] + |>+ [ "--command"; Unix.shell () ] ;; let nix_shell installables force_experimental_features = @@ -40,7 +40,7 @@ module Cmd = struct (* Need to combine/validate that the installables given are all Nixpkgs *) Bos.Cmd.v "nix-shell" |>+ [ "--packages" ] @ installables - |>+ [ "--command"; Unix.shell ] + |>+ [ "--command"; Unix.shell () ] ;; let print_strategy ({ workdir; primary; fallback } : strategy) = diff --git a/lib/util.ml b/lib/util.ml index 85171c1..5b420f9 100644 --- a/lib/util.ml +++ b/lib/util.ml @@ -23,7 +23,7 @@ module Util = struct ;; (** Get the user's login shell *) - let shell = (Unix.getpwuid (Unix.getuid ())).Unix.pw_shell + let shell () = (Unix.getpwuid (Unix.getuid ())).Unix.pw_shell (** Whether a flake.nix file exists at the given directory *) let flake_exists_at dir = Sys.file_exists (Filename.concat dir "flake.nix") From 5e96e986dab184fd8beab923b1c77010921b2690 Mon Sep 17 00:00:00 2001 From: eureka-cpu Date: Thu, 5 Mar 2026 14:23:09 -0800 Subject: [PATCH 3/5] bump to 0.4.3 --- dune-project | 2 +- ns.opam | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dune-project b/dune-project index 9477af7..525cce3 100644 --- a/dune-project +++ b/dune-project @@ -2,7 +2,7 @@ (name ns) -(version 0.4.2) +(version 0.4.3) (generate_opam_files true) diff --git a/ns.opam b/ns.opam index b29416a..7603df2 100644 --- a/ns.opam +++ b/ns.opam @@ -1,6 +1,6 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -version: "0.4.2" +version: "0.4.3" synopsis: "A unified interface for nix shell." description: "An intuitive nix shell interface that unifies the `nix shell`, `nix develop` and `nix-shell` commands." From 3ca2a832f75f246c7c222e41795e8cd37ab15907 Mon Sep 17 00:00:00 2001 From: eureka-cpu Date: Thu, 5 Mar 2026 14:50:38 -0800 Subject: [PATCH 4/5] use system libc bindings to get user shell --- test/dune | 2 +- test/test_ns.rs | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/test/dune b/test/dune index 3acffcd..29c44e5 100644 --- a/test/dune +++ b/test/dune @@ -16,4 +16,4 @@ (targets test_ns) ; the Dune target name (deps test_ns.rs) ; path relative to this dune file (action - (run rustc --test %{deps} -o %{targets} --allow warnings))) + (run rustc --test %{deps} -o %{targets} -A warnings -l c))) diff --git a/test/test_ns.rs b/test/test_ns.rs index cf45895..dfa2164 100644 --- a/test/test_ns.rs +++ b/test/test_ns.rs @@ -1,4 +1,4 @@ -use std::{env, path, process, sync}; +use std::{env, ffi, path, process, sync}; static DUNE_TEST_DIR: sync::OnceLock = sync::OnceLock::new(); static ENV_SHELL: sync::OnceLock = sync::OnceLock::new(); @@ -6,9 +6,41 @@ static ENV_SHELL: sync::OnceLock = sync::OnceLock::new(); fn dune_test_dir() -> &'static path::PathBuf { DUNE_TEST_DIR.get_or_init(|| env::current_dir().expect("failed to get test directory")) } -// TODO: Use libc to get the login shell of the user. -fn env_shell() -> &'static String { - ENV_SHELL.get_or_init(|| env::var("SHELL").expect("failed to get shell from environment")) + +/// Minimal bindings to dynamically linked libc, used for getting the shell of the logged in user. +mod libc { + unsafe extern "C" { + pub fn getuid() -> u32; + pub fn getpwuid(uid: u32) -> *mut Passwd; + } + + #[repr(C)] + pub struct Passwd { + pub pw_name: *mut i8, + pub pw_passwd: *mut i8, + pub pw_uid: u32, + pub pw_gid: u32, + #[cfg(target_os = "macos")] + pub pw_change: i64, + #[cfg(target_os = "macos")] + pub pw_class: *mut i8, + pub pw_gecos: *mut i8, + pub pw_dir: *mut i8, + pub pw_shell: *mut i8, + #[cfg(target_os = "macos")] + pub pw_expire: i64, + } +} + +fn env_shell() -> &'static str { + ENV_SHELL.get_or_init(|| unsafe { + let uid = libc::getuid(); + let pw = libc::getpwuid(uid); + assert!(!pw.is_null()); + ffi::CStr::from_ptr((*pw).pw_shell) + .to_string_lossy() + .into_owned() + }) } fn ns() -> path::PathBuf { From b5ff69b59b2bef0a94d3507efb0b53b55627c809 Mon Sep 17 00:00:00 2001 From: eureka-cpu Date: Thu, 5 Mar 2026 15:03:51 -0800 Subject: [PATCH 5/5] fix readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e7b253..770069d 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ nix run github:eureka-cpu/ns -- # Add or remove it from your user profile: ```sh -nix profile install github:eureka-cpu/ns +nix profile add github:eureka-cpu/ns nix profile remove ns ```