Add modules

This commit is contained in:
Tobias Happ 2019-11-24 00:37:40 +01:00 committed by Alexander Sosedkin
parent 5cc656fffc
commit f40362898a
19 changed files with 1045 additions and 0 deletions

View file

@ -0,0 +1,112 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.build;
# Programs that always should be available on the activation
# script's PATH.
activationBinPaths = lib.makeBinPath [
pkgs.bash
pkgs.coreutils
pkgs.findutils
pkgs.gnused
pkgs.ncurses # For `tput`.
pkgs.nix
];
activationCmds = concatStringsSep "\n" (
mapAttrsToList (name: value: ''
noteEcho "Activating ${name}"
${value}
'') cfg.activation
);
activationScript = pkgs.writeScript "activation-script" ''
#!${pkgs.runtimeShell}
set -eu
set -o pipefail
cd $HOME
export PATH="${activationBinPaths}"
${builtins.readFile ../lib-bash/color-echo.sh}
${builtins.readFile ../lib-bash/activation-init.sh}
${activationCmds}
'';
in
{
###### interface
options = {
build = {
activation = mkOption {
default = {};
type = types.attrs;
description = ''
Activation scripts for the nix-on-droid environment.
</para><para>
Any script should respect the <varname>DRY_RUN</varname>
variable, if it is set then no actual action should be taken.
The variable <varname>DRY_RUN_CMD</varname> is set to
<code>echo</code> if dry run is enabled. Thus, many cases you
can use the idiom <code>$DRY_RUN_CMD rm -rf /</code>.
'';
};
activationPackage = mkOption {
type = types.package;
readOnly = true;
internal = true;
description = "Derivation with activation script.";
};
etc = mkOption {
type = types.package;
internal = true;
description = "Package containing /etc files.";
};
};
};
###### implementation
config = {
build.activationPackage =
pkgs.runCommand
"nix-on-droid-generation"
{
preferLocalBuild = true;
allowSubstitutes = false;
}
''
mkdir --parents $out/filesystem/{bin,usr/{bin,lib}}
cp ${activationScript} $out/activate
ln --symbolic ${config.build.etc}/etc $out/etc
ln --symbolic ${config.environment.path} $out/nix-on-droid-path
ln --symbolic ${config.environment.files.login} $out/filesystem/bin/login
ln --symbolic ${config.environment.files.loginInner} $out/filesystem/usr/lib/login-inner
ln --symbolic ${config.environment.binSh} $out/filesystem/bin/sh
ln --symbolic ${config.environment.usrBinEnv} $out/filesystem/usr/bin/env
'';
};
}

45
modules/build/config.nix Normal file
View file

@ -0,0 +1,45 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, ... }:
with lib;
{
###### interface
options = {
build = {
initialBuild = mkOption {
type = types.bool;
default = false;
internal = true;
description = ''
Whether this is the initial build for the bootstrap zip ball.
Should not be enabled manually, see
<filename>initial-build.nix</filename>.
'';
};
installationDir = mkOption {
type = types.path;
internal = true;
readOnly = true;
description = "Path to installation directory.";
};
};
};
###### implementation
config = {
build.installationDir = "/data/data/com.termux.nix/files/usr";
};
}

View file

@ -0,0 +1,54 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, ... }:
with lib;
{
###### interface
options = {
build = {
arch = mkOption {
type = types.enum [ "aarch64" "i686" ];
description = "Destination arch.";
};
channel = {
nixpkgs = mkOption {
type = types.str;
default = "https://nixos.org/channels/nixos-19.09";
description = "Channel URL for nixpkgs.";
};
nix-on-droid = mkOption {
type = types.str;
default = "https://github.com/t184256/nix-on-droid-bootstrap/archive/master.tar.gz";
description = "Channel URL for nix-on-droid.";
};
};
};
};
###### implementation
config = {
build.initialBuild = true;
# /etc/group and /etc/passwd need to be build on target machine because
# uid and gid need to be determined.
environment.etc = {
"group".enable = false;
"nix-on-droid.nix.default".text = builtins.readFile ./nix-on-droid.nix.default;
"passwd".enable = false;
};
};
}

View file

@ -0,0 +1,39 @@
{ pkgs, ... }:
{
# Simply install just the packages
environment.packages = with pkgs; [
# User-facing stuff that you really really want to have
vim # or some other editor, e.g. nano or neovim
# Some common stuff that people expect to have
#diffutils
#findutils
#utillinux
#tzdata
#hostname
#man
#less
#gnugrep
#gnupg
#gnused
#gnutar
#bzip2
#gzip
#xz
#zip
#unzip
];
# After installing home-manager channel like
# nix-channel --add https://github.com/rycee/home-manager/archive/master.tar.gz home-manager
# nix-channel --update
# you can configure home-manager in here like
#home-manager.config =
# { pkgs, ... }:
# {
# # insert home-manager config
# };
}
# vim: ft=nix

39
modules/default.nix Normal file
View file

@ -0,0 +1,39 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ pkgs ? import <nixpkgs> { }, initialBuild ? false, config ? { } }:
with pkgs.lib;
let
homeDir = builtins.getEnv "HOME";
configFile = homeDir + "/.config/nixpkgs/nix-on-droid.nix";
hasConfigFile = builtins.pathExists configFile;
rawModule = evalModules {
modules = [
{
_module.args = { inherit pkgs; };
}
]
++ optional (!initialBuild && hasConfigFile) configFile
++ optional (!initialBuild && !hasConfigFile && pkgs.config ? nix-on-droid) pkgs.config.nix-on-droid
++ optional initialBuild config
++ import ./module-list.nix;
};
failedAssertions = map (x: x.message) (filter (x: !x.assertion) rawModule.config.assertions);
module =
if failedAssertions != []
then throw "\nFailed assertions:\n${concatMapStringsSep "\n" (x: "- ${x}") failedAssertions}"
else showWarnings rawModule.config.warnings rawModule;
in
if initialBuild
then module.config
else {
inherit (module.config.build) activationPackage;
inherit (module.config.environment) path;
}

View file

@ -0,0 +1,108 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, ... }:
with lib;
let
etc' = filter (f: f.enable) (attrValues config.environment.etc);
etc = pkgs.stdenvNoCC.mkDerivation {
name = "etc";
builder = ./make-etc.sh;
preferLocalBuild = true;
allowSubstitutes = false;
sources = map (x: x.source) etc';
targets = map (x: x.target) etc';
};
fileType = types.submodule (
{ name, config, ... }:
{
options = {
enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether this /etc file should be generated. This
option allows specific /etc files to be disabled.
'';
};
target = mkOption {
type = types.str;
description = ''
Name of symlink (relative to <filename>/etc</filename>).
Defaults to the attribute name.
'';
};
text = mkOption {
type = types.nullOr types.lines;
default = null;
description = "Text of the file.";
};
source = mkOption {
type = types.path;
description = "Path of the source file.";
};
};
config = {
target = mkDefault name;
source = mkIf (config.text != null) (
let name' = "etc-" + baseNameOf name;
in mkDefault (pkgs.writeText name' config.text));
};
}
);
in
{
###### interface
options = {
environment.etc = mkOption {
type = types.loaOf fileType;
default = {};
example = literalExample ''
{
example-configuration-file = {
source = "/nix/store/.../etc/dir/file.conf.example";
};
"default/useradd".text = "GROUP=100 ...";
}
'';
description = ''
Set of files that have to be linked in <filename>/etc</filename>.
'';
};
};
###### implementation
config = {
build = {
inherit etc;
activation.setUpEtc = ''
$DRY_RUN_CMD bash ${./setup-etc.sh} /etc ${etc}/etc
'';
};
};
}

View file

@ -0,0 +1,41 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
# inspired by https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/etc/make-etc.sh
source $stdenv/setup
mkdir -p $out
set -f
sources_=($sources)
targets_=($targets)
set +f
for ((i = 0; i < ${#targets_[@]}; i++)); do
source="${sources_[$i]}"
target="${targets_[$i]}"
if [[ "$source" =~ '*' ]]; then
# If the source name contains '*', perform globbing.
mkdir -p $out/etc/$target
for fn in $source; do
ln -s "$fn" $out/etc/$target/
done
else
mkdir -p $out/etc/$(dirname $target)
if ! [ -e $out/etc/$target ]; then
ln -s $source $out/etc/$target
else
echo "duplicate entry $target -> $source"
if test "$(readlink $out/etc/$target)" != "$source"; then
echo "mismatched duplicate entry $(readlink $out/etc/$target) <-> $source"
exit 1
fi
fi
fi
done

View file

@ -0,0 +1,85 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
# inspired by https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/etc/setup-etc.pl
etc="${1}"
static="/etc/static"
new_etc="${2}"
function atomic_symlink() {
local source="${1}"
local target="${2}"
local target_tmp="${target}.tmp"
mkdir -p "$(dirname "${target_tmp}")"
ln -sf "${source}" "${target_tmp}"
mv -T "${target_tmp}" "${target}"
}
# Remove dangling symlinks that point to /etc/static. These are
# configuration files that existed in a previous configuration but not
# in the current one.
function cleanup() {
local file
for file in $(find "${etc}" -xtype l); do
local target="$(readlink "${file}")"
if [[ ! -L "${target}" ]]; then
echo "removing obsolete symlink '${file}'..."
rm "${file}"
fi
done
}
# Returns 0 if the argument points to the files in /etc/static. That
# means either argument is a symlink to a file in /etc/static or a
# directory with all children being static.
function is_static() {
local path="${1}"
if [[ -L "${path}" ]]; then
[[ "$(readlink "${path}")" == ${static}/* ]]
return
fi
if [[ -d "${path}" ]]; then
local file
for file in "${path}"/*; do
is_static "${file}" || return
done
fi
false
}
function link() {
if [[ ! -d "${new_etc}" ]]; then
return
fi
local name
for name in $(find "${new_etc}/" -type l | sed -e "s,^${new_etc}/,,"); do
local target="${etc}/${name}"
mkdir -p "$(dirname "${target}")"
if [[ -e "${target}" ]] && ! is_static "${target}"; then
echo "Linking of ${target} failed. Please remove this file."
else
atomic_symlink "${static}/${name}" "${target}"
fi
done
}
# On initial build /etc/static is a directory instead of a symlink
if [[ -d "${etc}/static" ]]; then
rm --recursive "${etc}/static"
fi
# Atomically update /etc/static to point at the etc files of the
# current configuration.
atomic_symlink "${new_etc}" "${etc}/static"
cleanup
link

View file

@ -0,0 +1,36 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, ... }:
with lib;
{
###### interface
options = {
};
###### implementation
config = {
environment.etc = {
"nix/nix.conf".text = ''
sandbox = false
substituters = https://cache.nixos.org https://nix-on-droid.cachix.org
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nix-on-droid.cachix.org-1:56snoMJTXmDRC1Ei24CmKoUqvHJ9XCp+nidK7qkMQrU=
'';
"resolv.conf".text = ''
nameserver 1.1.1.1
nameserver 8.8.8.8
'';
};
};
}

View file

@ -0,0 +1,60 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.environment;
in
{
###### interface
options = {
environment = {
binSh = mkOption {
type = types.str;
readOnly = true;
description = "Path to /bin/sh executable.";
};
usrBinEnv = mkOption {
type = types.str;
readOnly = true;
description = "Path to /usr/bin/env executable.";
};
};
};
###### implementation
config = {
build.activation = {
linkBinSh = ''
$DRY_RUN_CMD mkdir $VERBOSE_ARG --parents /bin
$DRY_RUN_CMD ln $VERBOSE_ARG --symbolic --force ${cfg.binSh} /bin/.sh.tmp
$DRY_RUN_CMD mv $VERBOSE_ARG /bin/.sh.tmp /bin/sh
'';
linkUsrBinEnv = ''
$DRY_RUN_CMD mkdir $VERBOSE_ARG --parents /usr/bin
$DRY_RUN_CMD ln $VERBOSE_ARG --symbolic --force ${cfg.usrBinEnv} /usr/bin/.env.tmp
$DRY_RUN_CMD mv $VERBOSE_ARG /usr/bin/.env.tmp /usr/bin/env
'';
};
environment = {
binSh = "${pkgs.bashInteractive}/bin/sh";
usrBinEnv = "${pkgs.coreutils}/bin/env";
};
};
}

View file

@ -0,0 +1,55 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, customPkgs, ... }:
with lib;
let
login = pkgs.callPackage ./login.nix { inherit config; };
loginInner = pkgs.callPackage ./login-inner.nix { inherit config customPkgs; };
in
{
###### interface
options = {
environment.files = {
login = mkOption {
type = types.package;
readOnly = true;
description = "Login script.";
};
loginInner = mkOption {
type = types.package;
readOnly = true;
description = "Login-inner script.";
};
};
};
###### implementation
config = {
build.activation.installLoginScripts = ''
$DRY_RUN_CMD mkdir $VERBOSE_ARG --parents /bin /usr/lib
$DRY_RUN_CMD cp $VERBOSE_ARG ${login} /bin/login
$DRY_RUN_CMD cp $VERBOSE_ARG ${loginInner} /usr/lib/login-inner
'';
environment.files = {
inherit login loginInner;
};
};
}

View file

@ -0,0 +1,70 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, customPkgs, writeText }:
let
inherit (customPkgs.packageInfo) cacert coreutils nix;
in
writeText "login-inner" ''
set -e
[ "$#" -gt 0 ] || echo "Welcome to Nix-on-Droid!"
[ "$#" -gt 0 ] || echo "If nothing works, use the rescue shell and read ${config.build.installationDir}/usr/lib/login-inner"
[ "$#" -gt 0 ] || echo "If it does not help, report bugs at https://github.com/t184256/nix-on-droid-bootstrap/issues"
export USER="${config.user.userName}"
export HOME="${config.user.home}"
${lib.optionalString config.build.initialBuild ''
[ "$#" -gt 0 ] || echo "Sourcing Nix environment..."
. ${nix}/etc/profile.d/nix.sh
export NIX_SSL_CERT_FILE=${cacert}
echo "Installing and updating nix-channels..."
${nix}/bin/nix-channel --add ${config.build.channel.nixpkgs} nixpkgs
${nix}/bin/nix-channel --update nixpkgs
${nix}/bin/nix-channel --add ${config.build.channel.nix-on-droid} nix-on-droid
${nix}/bin/nix-channel --update nix-on-droid
echo "Copy default nix-on-droid config..."
${coreutils}/bin/mkdir --parents $HOME/.config/nixpkgs
${coreutils}/bin/cp /etc/nix-on-droid.nix.default $HOME/.config/nixpkgs/nix-on-droid.nix
echo "Installing first nix-on-droid generation..."
${nix}/bin/nix build --no-link --file "<nix-on-droid>" nix-on-droid
$(${nix}/bin/nix path-info --file "<nix-on-droid>" nix-on-droid)/bin/nix-on-droid switch
echo
echo "Congratulations! Now you have Nix installed with some default packages like bashInteractive, \
coreutils, cacert and most important nix-on-droid itself to manage local configuration, see"
echo " nix-on-droid help"
echo "or in the config file"
echo " ~/.config/nixpkgs/nix-on-droid.nix"
echo
echo "You can go for the bare nix-on-droid setup or you can configure your phone via home-manager. See \
config file for further information."
echo
''}
[ "$#" -gt 0 ] || echo "Sourcing Nix environment..."
. $HOME/.nix-profile/etc/profile.d/nix.sh
if [ -e "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh" ]; then
[ "$#" -gt 0 ] || echo "Sourcing home-manager environment..."
export NIX_PATH=$HOME/.nix-defexpr/channels''${NIX_PATH:+:}$NIX_PATH
. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"
fi
# Workaround for https://github.com/NixOS/nix/issues/1865
export NIX_PATH=nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs/:$NIX_PATH
if [ "$#" -eq 0 ]; then
exec /usr/bin/env bash
else
exec /usr/bin/env "$@"
fi
''

View file

@ -0,0 +1,23 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, writeScript }:
writeScript "login" ''
#!/system/bin/sh
set -e
export USER="${config.user.userName}"
export PROOT_TMP_DIR=${config.build.installationDir}/tmp
export PROOT_L2S_DIR=${config.build.installationDir}/.l2s
exec "${config.build.installationDir}/bin/proot-static" \
-b ${config.build.installationDir}/nix:/nix \
-b ${config.build.installationDir}/bin:/bin \
-b ${config.build.installationDir}/etc:/etc \
-b ${config.build.installationDir}/tmp:/tmp \
-b ${config.build.installationDir}/usr:/usr \
-b /:/android \
--link2symlink \
${config.build.installationDir}/bin/sh ${config.build.installationDir}/usr/lib/login-inner "$@"
''

View file

@ -0,0 +1,67 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.environment;
in
{
###### interface
options = {
environment = {
packages = mkOption {
type = types.listOf types.package;
default = [];
description = "List of packages to be installed as user packages.";
};
path = mkOption {
type = types.package;
readOnly = true;
internal = true;
description = "Derivation for installing user packages.";
};
};
};
###### implementation
config = {
build.activation.installPackages = ''
$DRY_RUN_CMD nix-env --install ${cfg.path}
'';
environment = {
packages = [
(pkgs.callPackage ../../nix-on-droid { })
pkgs.bashInteractive
pkgs.cacert
pkgs.coreutils
pkgs.less # since nix tools really want a pager available, #27
pkgs.nix
];
path = pkgs.buildEnv {
name = "nix-on-droid-path";
paths = cfg.packages;
meta = {
description = "Environment of packages installed through nix-on-droid.";
};
};
};
};
}

59
modules/home-manager.nix Normal file
View file

@ -0,0 +1,59 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.home-manager;
hmModule = types.submodule ({ name, ... }: {
imports = import <home-manager/modules/modules.nix> { inherit lib pkgs; };
config = {
submoduleSupport.enable = true;
submoduleSupport.externalPackageInstall = cfg.useUserPackages;
home.username = config.user.userName;
home.homeDirectory = config.user.home;
};
});
in
{
###### interface
options = {
home-manager = {
config = mkOption {
type = types.nullOr hmModule;
default = null;
description = "Home Manager configuration.";
};
useUserPackages = mkEnableOption ''
installation of user packages through the
<option>environment.packages</option> option.
'';
};
};
###### implementation
config = mkIf (cfg.config != null) {
inherit (config) assertions warnings;
build.activation.homeManager = ''
${cfg.config.home.activationPackage}/activate
'';
environment.packages = mkIf cfg.useUserPackages cfg.config.home.packages;
};
}

View file

@ -0,0 +1,20 @@
if [[ -v VERBOSE ]]; then
export VERBOSE_ECHO=echo
export VERBOSE_ARG="--verbose"
else
export VERBOSE_ECHO=true
export VERBOSE_ARG=""
fi
if [[ -v DRY_RUN ]] ; then
echo "This is a dry run"
export DRY_RUN_CMD=echo
else
$VERBOSE_ECHO "This is a live run"
export DRY_RUN_CMD=""
fi
if [[ -v VERBOSE ]]; then
echo -n "Using Nix version: "
nix --version
fi

View file

@ -0,0 +1,37 @@
# The check for terminal output and color support is heavily inspired
# by https://unix.stackexchange.com/a/10065.
function setupColors() {
normalColor=""
errorColor=""
warnColor=""
noteColor=""
# Check if stdout is a terminal.
if [[ -t 1 ]]; then
# See if it supports colors.
local ncolors
ncolors=$(tput colors)
if [[ -n "$ncolors" && "$ncolors" -ge 8 ]]; then
normalColor="$(tput sgr0)"
errorColor="$(tput bold)$(tput setaf 1)"
warnColor="$(tput setaf 3)"
noteColor="$(tput bold)$(tput setaf 6)"
fi
fi
}
setupColors
function errorEcho() {
echo "${errorColor}$*${normalColor}"
}
function warnEcho() {
echo "${warnColor}$*${normalColor}"
}
function noteEcho() {
echo "${noteColor}$*${normalColor}"
}

14
modules/module-list.nix Normal file
View file

@ -0,0 +1,14 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
[
./build/activation.nix
./build/config.nix
./environment/etc
./environment/files.nix
./environment/login
./environment/links.nix
./environment/path.nix
./user.nix
<nixpkgs/nixos/modules/misc/assertions.nix>
]

81
modules/user.nix Normal file
View file

@ -0,0 +1,81 @@
# Licensed under GNU Lesser General Public License v3 or later, see COPYING.
# Copyright (c) 2019 Alexander Sosedkin and other contributors, see AUTHORS.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.user;
idsDerivation = pkgs.runCommand "ids.nix" {} ''
cat > $out <<EOF
{
gid = "$(${pkgs.coreutils}/bin/id -g)";
uid = "$(${pkgs.coreutils}/bin/id -u)";
}
EOF
'';
ids = import idsDerivation;
in
{
###### interface
options = {
user = {
group = mkOption {
type = types.str;
default = "nix-on-droid";
description = "Group name.";
};
home = mkOption {
type = types.path;
readOnly = true;
description = "Path to home directory.";
};
shell = mkOption {
type = types.path;
readOnly = true;
description = "Path to login shell.";
};
userName = mkOption {
type = types.str;
default = "nix-on-droid";
description = "User name.";
};
};
};
###### implementation
config = {
environment.etc = {
"group".text = ''
root:x:0:
${cfg.group}:x:${ids.gid}:${cfg.userName}
'';
"passwd".text = ''
root:x:0:0:System administrator:${config.build.installationDir}/root:/bin/sh
${cfg.userName}:x:${ids.uid}:${ids.gid}:${cfg.userName}:${cfg.home}:${cfg.shell}
'';
};
user = {
home = "/data/data/com.termux.nix/files/home";
shell = "/bin/sh";
};
};
}