Compare commits

...

184 commits

Author SHA1 Message Date
Filippo Squillace
0037f96e15 Add warning box for Ubuntu restriction 2024-10-12 11:53:52 +02:00
Filippo Squillace
0242749f8e Replace yay with yay-git 2024-10-12 11:34:38 +02:00
Filippo Squillace
e2d9517a92 Test enabling back the check scripts 2024-10-08 19:47:29 +02:00
Filippo Squillace
452a69cff3 Do not remove gzip during build 2024-10-08 01:10:24 +02:00
Filippo Squillace
7af01ba481 Fix pacman 7 usage during build 2024-10-08 01:04:11 +02:00
Filippo Squillace
e68c24dec6 7.4.9 2024-08-01 20:29:07 +02:00
Filippo Squillace
fd44972137 Disable the checks and fix shellcheck 2024-08-01 20:21:34 +02:00
Filippo Squillace
4d2d0fcb84 7.4.8 2024-01-09 16:41:45 +01:00
Filippo Squillace
c91e013cd4 Copy pacman.conf file if does not exist 2024-01-09 16:32:29 +01:00
Filippo Squillace
2eaf739a29
Merge pull request #339 from cosmojg/patch-2
Explain installation before quickstart/setup
2023-11-15 22:33:52 +01:00
Cosmo
e680325f5a
Explain installation before quickstart/setup
This should clear up some of the confusion that new users experience when discovering JuNest for the first time
2023-11-13 15:29:05 -05:00
Filippo Squillace
6ae9f72dd5 Add Readme update 2023-07-22 16:34:44 +02:00
Filippo Squillace
d19d2f07b6 Add buymeacoffee badge 2023-07-22 16:26:21 +02:00
Filippo Squillace
2dd84efecb 7.4.7 2023-05-31 15:07:39 +02:00
Filippo Squillace
cc1287825d
Merge pull request #332 from fsquillace/userns-check
#328 Check if `user` file exist in `ns` directory
2023-05-31 15:06:25 +02:00
Filippo Squillace
b3565e093d #328 Check if user file exist in ns directory 2023-05-31 14:57:57 +02:00
Filippo Squillace
9a06d47f76 Add shellcheck disable 2023-05-29 12:00:15 +02:00
Filippo Squillace
daa60b05e3 Fix PATH when running trap 2023-05-29 11:47:18 +02:00
Filippo Squillace
507502dc1a 7.4.5 2023-05-07 16:27:17 +02:00
Filippo Squillace
c440252f2a
Merge pull request #326 from fsquillace/wrapper-custom-path
Wrapper custom path
2023-05-07 16:26:22 +02:00
Filippo Squillace
3742c16ce0 Add documentation and unit test 2023-05-07 16:13:10 +02:00
Filippo Squillace
c2dae9021d Add integ test 2023-05-07 14:15:55 +02:00
Filippo Squillace
39508ca8a9 First commit 2023-05-07 13:59:00 +02:00
Filippo Squillace
ae365215fb 7.4.4 2023-05-06 01:38:52 +02:00
Filippo Squillace
874f52f0f8 Remove PATH setting for chroot mode 2023-05-06 00:47:14 +02:00
Filippo Squillace
71397b942b
Merge pull request #325 from escape0707/patch-1
Update README.md to accommodate that sudo-fake provides sudo
2023-05-06 00:27:47 +02:00
Escape0707
296c9e47b4 Update README.md to accommodate that sudo-fake provides sudo
Since junest/sudo-fake now provides sudo, users don't need to ignore core/sudo during the installation of base-devel. They only need to make sure not to install core/sudo manually.
2023-05-06 00:58:20 +09:00
Filippo Squillace
9b00c5c4c5 Reduce PATH when accessing to Junest session 2023-04-30 13:20:54 +02:00
Filippo Squillace
ba0ddcc524 7.4.3 2023-02-18 23:47:20 +01:00
Filippo Squillace
4db85bcf1f #318: Use multi-call wrapper 2023-02-18 00:49:54 +01:00
Filippo Squillace
369cda8dc6 7.4.2 2023-02-18 00:03:19 +01:00
Filippo Squillace
b976f767d5 Add checks for fakeroot chown 2023-02-17 23:49:06 +01:00
Filippo Squillace
95f97a62b7 #305: Add fakeroot variable to bypass chown commands 2023-02-17 18:26:13 +01:00
Filippo Squillace
6048b43218 7.4.1 2023-01-31 22:09:43 +01:00
Filippo Squillace
3fb7676277 Merge branch 'master' into dev 2023-01-31 22:08:36 +01:00
Filippo Squillace
978f64ea0a
Merge pull request #316 from cosmojg/patch-2
Fix deprecated find -perm syntax
2023-01-31 21:51:08 +01:00
Filippo Squillace
48b20848c8
Merge pull request #317 from cosmojg/patch-3
Fix grammar and improve style
2023-01-31 21:50:52 +01:00
Cosmo
632b416955
Fix grammar and improve style 2023-01-31 00:30:41 -05:00
Cosmo
0b34458fb5
Fix deprecated find -perm syntax 2023-01-30 23:51:50 -05:00
Filippo Squillace
2492583877 7.4.0 2023-01-15 23:08:40 +01:00
Filippo Squillace
a9174267b3 Add unit tests 2023-01-15 22:28:08 +01:00
Filippo Squillace
65c45517e1 Bind /run/user directory 2023-01-15 22:03:27 +01:00
Filippo Squillace
20f42f6cb7 7.3.20 2022-12-31 11:17:45 +00:00
Filippo Squillace
76c1644c63 Add discord server link 2022-12-31 11:13:25 +00:00
Filippo Squillace
1c16425b88 7.3.19 2022-12-19 23:15:38 +00:00
Filippo Squillace
fab5b0df2e Remove arch-travis and directly use docker 2022-12-19 23:12:02 +00:00
Filippo Squillace
c052e660ee 7.3.18 2022-12-18 13:43:00 +00:00
Filippo Squillace
30967bc15f Remove -d option in pacstrap 2022-12-18 13:24:29 +00:00
Filippo Squillace
60c7d1c5d0 Update keyring 2022-12-18 12:43:56 +00:00
Filippo Squillace
91f95ae4b5 Change URL to CloudFlare provider 2022-12-18 10:51:00 +00:00
Filippo Squillace
2f6e137e7e 7.3.17 2022-11-05 13:02:35 +01:00
Filippo Squillace
991aa5d7fe
Merge pull request #302 from schance995/extend-path
Extend $PATH in common.sh with system $PATH.
2022-11-05 12:53:53 +01:00
Spencer Skylar Chan
e5f14c3735 Extend $PATH in common.sh with system $PATH.
This lets junest work on non-FHS systems such as GNU Guix.
2022-10-30 00:18:58 -04:00
Filippo Squillace
f0e82bf8bf 7.3.16 2022-10-15 12:50:44 +02:00
Filippo Squillace
56761f6e63 Change url 2022-10-15 12:49:49 +02:00
Filippo Squillace
77acbf5214 7.3.15 2022-08-05 18:06:47 +02:00
Filippo Squillace
799d3bdd42 Install keyring first during the build preparation 2022-08-05 18:06:29 +02:00
Filippo Squillace
a9f5304279 #297 Create bin wrapper for symlinks 2022-08-05 18:06:29 +02:00
Filippo Squillace
df2fec0a36 7.3.14 2022-04-24 20:14:12 +00:00
Filippo Squillace
73b8bec8db Fix wrapper when passing multiple arguments and add unit tests
This change come from the PR #289
2022-04-24 19:54:32 +00:00
Filippo Squillace
98775b538f
Merge pull request #294 from fsquillace/sudoj
Default to ns mode (not fakeroot) for bin wrappers and add sudoj command
2022-04-23 19:32:10 +02:00
Filippo Squillace
0e6aa260ad Default to ns mode (not fakeroot) for bin wrappers and add sudoj command
This is related to #292
2022-04-23 17:11:55 +00:00
Filippo Squillace
21b5e3fabb 7.3.13 2022-03-01 00:43:02 +01:00
Filippo Squillace
0295f37758 Add shellcheck 2022-03-01 00:05:09 +01:00
Filippo Squillace
e7d7056e9c
Merge pull request #291 from fsquillace/create-wrappers
Create wrappers
2022-02-17 00:27:52 +01:00
Filippo Squillace
e794a6150c Add more unit tests 2022-02-16 22:55:40 +01:00
Filippo Squillace
2b9f1839f1 Add create-bin-wrappers command 2022-02-13 20:07:13 +01:00
Filippo Squillace
5630a0f035
Merge pull request #287 from neiser/master
Fix quoting in wrapper script
2022-02-13 11:06:05 +01:00
Andreas Grub
bc543a9285 Fix quoting in wrapper script
The 'eval' introduced in #262 unfortunately breaks command
invocations were a parameter contains spaces, such as

rg "my pattern with spaces"

as it would be called as `rg my pattern with
spaces`. This can be fixed using printf. Using
parameter extension quoting with ${@@Q} only
works with bash >4.4 (but only >4.0 is required).

At least the above invocation then works correctly!
2022-02-12 06:31:18 +01:00
Filippo Squillace
5f7eaff50e 7.3.12 2022-01-08 11:57:53 +01:00
Filippo Squillace
7d8c619ee0 #284 Fix copy command 2022-01-05 23:47:55 +01:00
Filippo Squillace
e6bae0647c Merge branch 'dev' into master 2021-12-31 18:21:42 +01:00
Filippo Squillace
6efc4d0f52 Update VERSION 2021-12-31 18:20:27 +01:00
Filippo Squillace
de63bdf96a Change url main repo 2021-12-31 18:09:10 +01:00
Filippo Squillace
4a1c11d4ed Fix deploy script 2021-12-20 21:19:54 +00:00
Filippo Squillace
a9d11fb4d5
Merge pull request #280 from fsquillace/dev
Dev
2021-12-20 21:57:42 +01:00
Filippo Squillace
5e97524338 Update README with proot updates 2021-12-20 18:49:22 +00:00
Filippo Squillace
14d51d9856 Merge branch 'master' into dev 2021-12-20 18:07:00 +00:00
Filippo Squillace
46cc4aad48
Merge pull request #274 from ayaka14732/patch-2
Fix installation guide in README
2021-11-03 10:34:52 +01:00
Ayaka Mikazuki
4036a7737b
Update README.md 2021-11-03 11:18:42 +08:00
Filippo Squillace
6e872c5f26 Update version and README 2021-10-13 22:33:09 +02:00
Filippo Squillace
7fe9c0e9ec Fix the --backend-command option 2021-10-13 12:23:41 +02:00
Filippo Squillace
38ab252f98 Enable all capabilities in ns fakeroot mode 2021-09-21 14:21:48 +02:00
Filippo Squillace
9ecabcd524 Change mirrorlist, update the initial message, do not inherit PATH variable and use precompiled yay during build phase 2021-09-11 14:44:35 +02:00
Filippo Squillace
86277fd589 Put the original mirror back 2021-09-11 14:44:35 +02:00
Filippo Squillace
e45d76651e First commit 2021-09-11 14:44:33 +02:00
Filippo Squillace
fc3b54e97f Authenticate to Docker hub 2021-06-19 16:46:04 +02:00
Filippo Squillace
e9406123b9 Test travis 2021-06-19 16:08:49 +02:00
Filippo Squillace
08553a447e Remove @ from wrapper 2021-03-24 11:54:17 +01:00
Filippo Squillace
6af7bae418 Fix wrappers using eval #262 2021-03-24 11:49:28 +01:00
Filippo Squillace
700b809fbe 7.3.6 2021-02-16 18:18:24 +01:00
Filippo Squillace
8e560b4a8a Make namespace check more robust and update README 2021-02-16 18:13:27 +01:00
Filippo Squillace
79e4107196 Update VERSION 2021-01-10 13:26:07 +01:00
Filippo Squillace
b8ad2182be Update README 2021-01-10 13:25:49 +01:00
Filippo Squillace
6548e19eb5 Use proper proc,dev,sys binds for ns mode 2021-01-10 13:16:48 +01:00
Filippo Squillace
8d4217492a 7.3.4 2021-01-04 21:10:31 +01:00
Filippo Squillace
f0b6f0962e Use true fakechroot/fakeroot in ns fakeroot mode 2021-01-04 19:21:07 +01:00
Filippo Squillace
4527297be1 Remove warnings when using pacman 2020-12-31 12:57:33 +01:00
Filippo Squillace
6291e5cc83 Use the Junest repo to install package deps 2020-12-30 13:35:21 +01:00
Filippo Squillace
f98fa897bf 7.3.1 2020-12-30 00:59:00 +01:00
Filippo Squillace
d3f9f13ccd Fix deploy 2020-12-30 00:58:24 +01:00
Filippo Squillace
2242585778 Merge branch 'master' into dev 2020-12-29 19:04:38 +01:00
Filippo Squillace
8844f7b5d8
Merge pull request #258 from fsquillace/archlinux-travis
Archlinux travis
2020-12-29 19:03:05 +01:00
Filippo Squillace
d25ae30158 Update README 2020-12-29 19:02:14 +01:00
Filippo Squillace
2aeb23b882 Add tests for wrappers 2020-12-29 13:09:35 +01:00
Filippo Squillace
3d16ee2583 First commit for wrappers 2020-12-29 10:46:59 +01:00
Filippo Squillace
9d2e6e4bbf Add deploy feature 2020-12-28 12:07:19 +01:00
Filippo Squillace
b75faac48f Add remaining junest tests in travis 2020-12-27 18:59:08 +01:00
Filippo Squillace
95479ba41f Use arch-travis in CI 2020-12-26 12:23:11 +01:00
Filippo Squillace
78c4f72bc1
Merge pull request #257 from hodapp512/patch-1
Update README.md for updated bind usage
2020-12-11 11:00:46 +01:00
hodapp512
26e58aaeec
Update README.md for updated bind usage 2020-12-10 11:27:15 -06:00
Filippo Squillace
8609300b20
Merge pull request #254 from fsquillace/zst
Zst
2020-09-15 19:43:07 +02:00
Filippo Squillace
440dde6564 7.2.2 2020-09-15 19:40:16 +02:00
Filippo Squillace
84f4d20370 Disable integ test for ARM 2020-09-15 19:31:24 +02:00
Filippo Squillace
98107ac07f Change format package from xz 2020-09-15 14:06:03 +02:00
Filippo Squillace
7b3685941d 7.2.1 2020-03-28 18:48:51 +01:00
Filippo Squillace
6d7bc4efa4 Add all arch in proot-static package 2020-03-28 16:54:46 +01:00
Filippo Squillace
b0169a8e5f 7.2.0 2020-03-28 15:55:08 +01:00
Filippo Squillace
12e6f6214e Add arm arch to proot 2020-03-28 13:16:40 +01:00
Filippo Squillace
500546a0e2 Fix build and proot 2020-03-28 12:57:03 +01:00
Filippo Squillace
09b9c644d9 Add option to specify location of backend command 2020-03-27 18:39:58 +01:00
Filippo Squillace
348b73ce73 Remove groot content 2020-03-24 21:18:25 +01:00
Filippo Squillace
6592bc9bd2 Separate proot, qemu, groot into packages 2020-03-22 17:53:47 +01:00
Filippo Squillace
d1285908ae
Merge pull request #240 from fsquillace/dev
Fix travis for ARM tests
2020-03-17 14:54:12 +01:00
Filippo Squillace
1580ba9c8e Fix travis for ARM tests 2020-03-16 21:34:29 +01:00
Filippo Squillace
628ac3c655 7.1.0 2020-03-16 20:12:27 +01:00
Filippo Squillace
4b5b7b300b Add test for bwrap command 2020-03-16 18:59:01 +01:00
Filippo Squillace
385dd8c68c Add script to check all tests 2020-03-15 23:49:45 +01:00
Filippo Squillace
6e55e0c648 See mirror URL only for non arm arch 2020-03-15 23:26:25 +01:00
Filippo Squillace
121f2c74f6 Improve build for ARM arch 2020-03-15 17:10:49 +01:00
Filippo Squillace
9bfd7e047d Add bwrap as backend for ns 2020-03-15 13:41:06 +01:00
Filippo Squillace
538e87f036 Add FUNDING file 2020-02-21 23:07:59 +01:00
Filippo Squillace
5b60382ca4
Merge pull request #237 from fsquillace/dev
Dev
2019-12-15 15:46:40 +01:00
Filippo Squillace
7acf16cc73
Merge pull request #236 from fsquillace/fix
Remove interface lo when checking iftop
2019-12-15 15:46:20 +01:00
Filippo Squillace
11a439499b Remove interface lo when checking iftop 2019-12-15 14:31:11 +00:00
Filippo Squillace
e0dd3257a8 Add support for ARM arch during build and check 2019-12-15 11:55:27 +00:00
Filippo Squillace
4bb9b60638 Merge branch 'dev' 2019-12-01 17:11:10 +01:00
Filippo Squillace
606353047c 7.0.2 2019-12-01 17:10:01 +01:00
Filippo Squillace
493b105faa Remove socket filename for gpg agent during build check 2019-12-01 17:06:12 +01:00
Filippo Squillace
85aeda4ac9 Update the check for building image 2019-12-01 17:06:12 +01:00
Filippo Squillace
2e8f5905c7 7.0.1 2019-12-01 17:06:12 +01:00
Filippo Squillace
82b146a57e Add rw permission to files in image 2019-12-01 17:06:12 +01:00
Filippo Squillace
e12cd8d8ff
Merge pull request #233 from soraxas/master
Fix typos in --help message
2019-11-17 10:01:52 +01:00
Oscar Lai
8d91e18ab0 fixed typos in --help message 2019-11-10 02:22:42 +11:00
Filippo Squillace
c5847b8583 7.0.1 2019-10-25 20:48:20 +02:00
Filippo Squillace
27f92d0b3f Add rw permission to files in image 2019-10-25 20:46:27 +02:00
Filippo Squillace
97d19da268
Merge pull request #231 from fsquillace/new-junest
New junest
2019-10-22 22:27:52 +02:00
Filippo Squillace
632aad46bd Small fixes 2019-10-22 22:23:12 +02:00
Filippo Squillace
de0bec9bc5 Remove yaourt package and allow not to copy common etc files 2019-10-20 22:45:40 +02:00
Filippo Squillace
3341187cf6 Change the CLI and make ns the default backend 2019-10-20 16:15:31 +02:00
Filippo Squillace
ef4bf7cd79 6.0.10 2019-08-09 23:59:18 +10:00
Filippo Squillace
00c60118fb Enable AUR tests 2019-08-09 23:42:55 +10:00
Filippo Squillace
30b743cb1b Fix keyring setup for ARM arch 2019-08-09 22:11:49 +10:00
Filippo Squillace
313ef30662 Add aurutils to the check build script 2019-08-09 21:19:37 +10:00
Filippo Squillace
691369068d Update README and change order for PATH variable 2019-06-10 17:33:31 +10:00
Filippo Squillace
fbe49acc01 6.0.9 2018-10-31 21:51:23 +11:00
Filippo Squillace
98c97ddfa7 Merge branch 'dev' 2018-10-31 21:50:34 +11:00
Filippo Squillace
6361522e40 Fix aur validation tests and include sudo-fake in codebase 2018-10-31 20:53:08 +11:00
Filippo Squillace
cc351f419d Add check for disabled unprivileged user namespace 2018-10-28 17:34:45 +11:00
Filippo Squillace
bca7e565ca
Merge pull request #210 from DroidFreak32/patch-1
Fix JuNest image URL
2018-08-11 10:26:31 +10:00
DroidFreak32
34f3458335
Fix JuNest image URL 2018-07-21 18:04:43 +05:30
Filippo Squillace
5172093fe2 6.0.8 2017-09-23 22:35:35 +10:00
Filippo Squillace
5bc4cd245a :doc: x86 (32 bit) is deprecated 2017-09-23 22:33:46 +10:00
Filippo Squillace
0d7468b516 Merge pull request #200 from fsquillace/docs_and_nested_envs
Docs and nested envs
2017-09-18 17:02:06 +02:00
Filippo Squillace
d858d577c8 Fix checks for updating Arch Linux keyrings 2017-09-18 16:59:35 +02:00
Filippo Squillace
f60bbb5c2a Issue #195: Check presence of nested env first 2017-09-18 13:48:34 +02:00
Filippo Squillace
b2ba7f9d5b Issue #197: Differences between JuNest and other systems 2017-09-18 13:45:33 +02:00
Filippo Squillace
4b6fd63cf8 Inform with a warn in case SECCOMP gets disabled 2017-06-23 14:51:29 +02:00
Filippo Squillace
9cd13c88f6 6.0.7 2017-04-25 22:57:37 +01:00
Filippo Squillace
797853bbb4 Merge pull request #192 from fsquillace/activate_aur_test_namespac
Activate aur test namespac
2017-04-25 22:56:41 +01:00
Filippo Squillace
358f92d3e0 Remove package-query as a dependency for building JuNest Image 2017-04-25 22:53:10 +01:00
Filippo Squillace
c3610ec86a Activate the aur check for namespace mode 2017-04-25 09:17:03 +01:00
Filippo Squillace
22483b9ea9 6.0.6 2017-04-25 00:26:17 +01:00
Filippo Squillace
3eada1e4f1 Merge pull request #191 from fsquillace/issue_check_script_fix
Update the system before running checks
2017-04-25 00:25:34 +01:00
Filippo Squillace
8fe650ce87 Update the system before running checks 2017-04-25 00:22:09 +01:00
Filippo Squillace
d6d6883e82 6.0.5 2017-04-24 23:11:48 +01:00
Filippo Squillace
f9f7cbcaaa Update the check script to exclude sudo from base-devel 2017-04-24 23:10:32 +01:00
Filippo Squillace
51f6765634 6.0.4 2017-04-24 21:47:48 +01:00
Filippo Squillace
c2d5985fe3 Merge pull request #190 from fsquillace/issue_184_aur_namespace
Issue #184: Add `sudo-fake` to JuNest image
2017-04-24 09:47:50 +01:00
Filippo Squillace
7ebdf628cf Issue #184: Add sudo-fake to JuNest image 2017-04-24 09:21:40 +01:00
Filippo Squillace
35fce94c4e 6.0.3 2017-04-20 20:23:18 +01:00
Filippo Squillace
73b4b85399 Merge pull request #188 from fsquillace/issue_replace_mountpoint
Replace `mountpoint` command by checking mounts file
2017-04-20 20:20:18 +01:00
Filippo Squillace
bd0e9fbbcc Replace mountpoint command by checking mounts file
`mountpoint` does not detect some directory. By checking directly
from `/proc/self/mounts` groot can be more reliable and portable.
2017-04-20 20:19:04 +01:00
Filippo Squillace
137788a98a Groot: Do not umount directories that are not mountpoint 2017-04-19 23:52:26 +01:00
35 changed files with 2284 additions and 1392 deletions

2
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,2 @@
github: fsquillace
custom: https://github.com/fsquillace/junest/blob/master/README.md#donating

3
.gitignore vendored
View file

@ -1 +1,4 @@
*.swp
*pkg.tar.*
*.tar.gz
*.SRCINFO

View file

@ -1,30 +1,62 @@
language: bash
sudo: required
os: linux
cache:
directories:
- ~/.ccache
- ~/.pkg-cache
services:
- docker
env:
matrix:
- TRAVIS_BASH_VERSION="4.0"
before_install:
- ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION"
- ./ci/install-bash.sh "$TRAVIS_BASH_VERSION"
- sudo apt-get update
- sudo apt-get -y install awscli
install:
- PATH=$PWD/bin:$PATH
- junest -- echo "Installing JuNest (\$(uname -m))"
- JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))"
# TODO: Remember to enable x86 tests when fixed
#- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))"
script:
#######################
# Unit Tests
#######################
- bash --version
- bash ./tests/checkstyle/checkstyle.sh
- bash ./tests/unit-tests/unit-tests.sh
- shellcheck bin/junest lib/**/*.sh ci/*.sh tests/**/*.sh
# Multiple tests against different execution modes:
- junest -f -- ${PWD}/lib/checks/check.sh
- junest -u -- ${PWD}/lib/checks/check.sh --skip-aur-tests
- sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh --run-root-tests
- yes | junest --delete
# ARM with qemu does seem to work properly. Disabling integ tests for ARM for now.
#- export JUNEST_HOME=~/.junest-arm
#- junest setup --arch arm
#- junest proot --fakeroot -- echo "Installing JuNest (\$(uname -m))"
#- junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests
#- junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo
#- yes | junest setup --delete
- JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh
- yes | JUNEST_HOME=~/.junest-arm junest --delete
#######################
# Build and validation
#######################
- echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin
- docker run --rm -v "$(pwd):/build" -v ~/.ccache:/home/travis/.ccache -v ~/.pkg-cache:/var/cache/pacman/pkg --privileged archlinux:latest bash /build/ci/build_image.sh
- "echo pacman pkg cache size: $(du -h ~/.pkg-cache|cut -f1) in $(ls ~/.pkg-cache|wc -l) files"
- ls -l
# Test the newly created JuNest image against Ubuntu host
- export JUNEST_HOME=~/.junest
- junest setup -i junest-x86_64.tar.gz
# TODO The check does not work at the moment: https://app.travis-ci.com/github/fsquillace/junest/builds/271706037
# Disabling it in order to avoid having stale version of junest images.
- ${PWD}/lib/checks/check_all.sh
- yes | junest setup --delete
after_success:
#######################
# Deploy and validation
#######################
- ./ci/deploy.sh ./junest-x86_64.tar.gz

435
README.md
View file

@ -1,6 +1,13 @@
JuNest
======
The Arch Linux based distro that runs upon any Linux distros without root access.
> [!IMPORTANT]
> Starting from Ubuntu 23.10+, [unprivileged user namespaces has been restricted](https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces).
> If using JuNest within Ubuntu, you may need root privileges in order to enable it.
> Alternatively, you can access JuNest using the `proot` mode as described
> [below](#Proot-based).
The lightweight Arch Linux based distro that runs, without root privileges, on top of any other Linux distro.
<h1 align="center">
<a href="https://github.com/fsquillace/junest"><img
@ -11,7 +18,7 @@ The Arch Linux based distro that runs upon any Linux distros without root access
|Project Status|Donation|Communication|
|:------------:|:------:|:-----------:|
| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Gratipay](https://img.shields.io/badge/Gratipay-Donate%20to%20JuNest-green.svg)](https://gratipay.com/junest/) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/GoogleGroups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) |
| [![Build status](https://api.travis-ci.com/fsquillace/junest.png?branch=master)](https://app.travis-ci.com/github/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![Github Sponsors](https://img.shields.io/badge/GitHub-Sponsors-orange.svg)](https://github.com/sponsors/fsquillace) [![PayPal](https://img.shields.io/badge/PayPal-Donation-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Buy me a coffee](https://www.buymeacoffee.com/assets/img/custom_images/yellow_img.png)](https://www.buymeacoffee.com/fsquillace) | [![Join the Discord server at https://discord.gg/ttfBT7MKve](https://img.shields.io/badge/Discord-Server-blueviolet.svg)](https://discord.gg/ttfBT7MKve) |
**Table of Contents**
- [Description](#description)
@ -23,48 +30,45 @@ The Arch Linux based distro that runs upon any Linux distros without root access
- [Troubleshooting](#troubleshooting)
- [More documentation](#more-documentation)
- [Contributing](#contributing)
- [Author](#author)
- [Donating](#donating)
- [Authors](#authors)
Description
===========
**JuNest** (Jailed User NEST) is a lightweight Arch Linux based distribution that allows to have
an isolated GNU/Linux environment inside any generic host GNU/Linux OS
and without the need to have root privileges for installing packages.
**JuNest** (Jailed User Nest) is a lightweight Arch Linux based distribution
that allows the creation of disposable and partially isolated GNU/Linux environments
within any generic GNU/Linux host OS and without requiring root
privileges to install packages.
JuNest contains mainly the package managers (called [pacman](https://wiki.archlinux.org/index.php/Pacman)
and a simple wrapper of [yaourt](https://wiki.archlinux.org/index.php/Yaourt) called yogurt) that allows to access
JuNest is built around [pacman](https://wiki.archlinux.org/index.php/Pacman),
the Arch Linux package manager, which allows access
to a wide range of packages from the Arch Linux repositories.
The main advantages on using JuNest are:
The main advantages of using JuNest include:
- Install packages without root privileges.
- Isolated environment in which you can install packages without affecting a production system.
- Access to a wide range of packages in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat).
- Available for x86\_64, x86 and ARM architectures but you can build your own image from scratch too!
- Run on a different architecture from the host OS via QEMU
- All Arch Linux lovers can have their favourite distro everywhere!
- Create partially isolated environments in which you can install packages without risking mishaps on production systems.
- Access a wider range of packages, particularly on GNU/Linux distros with comparatively limited repositories (such as CentOS and Red Hat).
- Run on a different architecture from the host OS via QEMU.
- Available for `x86_64` and `arm` architectures but you can build your own image from scratch too!
- All Arch Linux lovers can enjoy their favourite distro everywhere!
JuNest follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/The_Arch_Way).
Quickstart
==========
The basic way to run JuNest is via the [Proot](https://wiki.archlinux.org/index.php/Proot) as the backend program:
How different is JuNest from Docker and Vagrant?
------------------------------------------------
Although JuNest sounds similar to a virtualisation/Linux container-like system,
JuNest is quite different from solutions like Docker or Vagrant.
In fact, the purpose of JuNest is **not** to
build a completely isolated environment but, conversely, to provide the ability to run
programs as if they were running natively from the host OS. Almost everything is shared
between the host OS and the JuNest sandbox (kernel, process subtree, network, mounting, etc)
and only the root filesystem gets isolated
(since the programs installed in JuNest need to reside elsewhere).
- As normal user - Allow to make basic operations: ```junest```
- As fakeroot - Allow to install/remove packages: ```junest -f```
To know more about the JuNest execution modes depending on the backend program
used, see the [Usage](#usage) section below.
After running JuNest
--------------------
If the JuNest image has not been downloaded yet, the script will download
the image from the repository and will place it to the default directory `~/.junest`.
You can change the default directory by changing the environment variable `JUNEST_HOME`.
If you are new on Arch Linux and you are not familiar with `pacman` package manager
visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta).
This allows interaction between processes belonging to both host OS and JuNest.
For example, you can install the `top` command in JuNest and use it to monitor
processes belonging to the host OS.
Installation
============
@ -77,83 +81,208 @@ Before installing JuNest be sure that all dependencies are properly installed in
- [bash (>=4.0)](https://www.gnu.org/software/bash/)
- [GNU coreutils](https://www.gnu.org/software/coreutils/)
The minimum recommended Linux kernel of the host OS is 2.6.32 on x86 (32-bit
and 64 bit) and ARM architectures. It is still possible to run JuNest on lower
2.6.x host OS kernels but errors may appear, and some applications may
crash. For further information, read the [Troubleshooting](#troubleshooting)
section below.
## Method one (Recommended) ##
## Installation from git repository ##
Just clone the JuNest repo somewhere (for example in ~/.local/share/junest):
git clone git://github.com/fsquillace/junest ~/.local/share/junest
export PATH=~/.local/share/junest/bin:$PATH
```sh
git clone https://github.com/fsquillace/junest.git ~/.local/share/junest
export PATH=~/.local/share/junest/bin:$PATH
```
Optionally you want to use the wrappers to run commands
installed in JuNest directly from host:
```sh
export PATH="$PATH:~/.junest/usr/bin_wrappers"
```
Update your `~/.bashrc` or `~/.zshrc` to get always the wrappers available.
### Installation using AUR (Arch Linux only) ###
If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/):
If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/packages/junest-git/).
JuNest will be located in `/opt/junest/`
yaourt -S junest-git
export PATH=/opt/junest/bin:$PATH
Quickstart
==========
## Method two ##
Alternatively, another installation method would be to directly download the JuNest image and place it to the default directory ~/.junest:
Setup environment
-----------------
ARCH=<one of "x86_64", "x86", "arm">
mkdir ~/.junest
curl https://s3-eu-west-1.amazonaws.com/junest-repo/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest
export PATH=~/.junest/opt/junest/bin:$PATH
The first operation required is to install the JuNest environment in the
location of your choice via `JUNEST_HOME` environment variable
(it must contain an absolute path) which by
default is `~/.junest`:
```sh
junest setup
```
The script will download the image from the repository and will place it to the default directory `~/.junest`.
Access to environment
---------------------
JuNest uses the Linux namespaces (aka `ns`) as the default backend program. To access via `ns` just type:
```sh
junest
```
You can use the command `sudo` to acquire fakeroot privileges and
install/remove packages.
Alternatively, you can access fakeroot privileges without using `sudo` all the
time with the `-f` (or `--fakeroot`) option:
```sh
junest -f
```
Another execution mode is via [Proot](https://wiki.archlinux.org/index.php/Proot):
```sh
junest proot [-f]
```
There are multiple backend programs, each with its own pros/cons.
To know more about the JuNest execution modes depending on the backend program
used, see the [Usage](#usage) section below.
Run JuNest installed programs directly from host OS
---------------------------------------
Programs installed within JuNest can be accessible directly from host machine
without entering into a JuNest session
(namely, no need to call `junest` command first).
For instance, supposing the host OS is an Ubuntu distro you can directly
run `pacman` by simply updating the `PATH` variable:
```sh
export PATH="$PATH:~/.junest/usr/bin_wrappers"
sudoj pacman -S htop
htop
```
By default the wrappers use `ns` mode. To use the `ns --fakeroot` you can use the convenient command helper `sudoj`.
For more control on backend modes you can use the `JUNEST_ARGS` environment variable too.
For instance, if you want to run `iftop` with real root privileges:
```
sudoj pacman -S iftop
sudo JUNEST_ARGS="groot" iftop
```
Bin wrappers can be always recreated (e.g. in case for some reasons they get
corrupted) with:
```
junest create-bin-wrappers -f
```
Bin wrappers are automatically generated each time they get installed inside JuNest.
This only works for executables located in `/usr/bin` path.
For executables in other locations (say `/usr/mybinpath`) you can only create
wrappers manually by executing the command:
```
junest create-bin-wrappers --bin-path /usr/mybinpath
```
Obviously, to get access to the corresponding bin wrappers you will need to
update your `PATH` variable accordingly:
```
export PATH="$PATH:~/.junest/usr/mybinpath_wrappers"
```
Install packages from AUR
-------------------------
In `ns` mode, you can easily install package from [AUR](https://aur.archlinux.org/) repository
using the already available [`yay`](https://aur.archlinux.org/packages/yay/)
command. In `proot` mode, JuNest does no longer support the building of AUR packages.
**Remember** that in order to build packages from AUR, `base-devel` package group is required
first:
```sh
pacman -S base-devel
```
JuNest uses a modified version of `sudo` provided by `junest/sudo-fake`. And the original `core/sudo`
package will be ignored **(and must not be installed)** during the installation of `base-devel`.
Have fun!
---------
If you are new on Arch Linux and you are not familiar with `pacman` package manager
visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta).
Usage
=====
There are three different ways you can run JuNest depending on the backend program you decide to use.
PRoot based
-----------
[Proot](https://wiki.archlinux.org/index.php/Proot) represents the default
program used for accessing to the JuNest environments.
The main reason to choose Proot as default backend program is because
it represents a portable solution that works well in most of GNU/Linux distros available.
One of the major drawbacks is the fact that Proot is not officially
supported anymore, therefore, Proot bugs may no longer be fixed.
In order to run JuNest via Proot:
- As normal user - Allow to make basic operations: ```junest```
- As fakeroot - Allow to install/remove packages: ```junest -f```
Linux namespaces based
----------------------
The [Linux namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html)
represents the next generation backend program for JuNest.
The major drawback about the namespace is portability, as certain requirements
need to be satisfied: 1) Only starting from Linux 3.8, unprivileged processes can
create the required user and mount namespaces.
2) Moreover, the Linux kernel distro must have the user namespace enabled.
Hopefully, in the future the major GNU/Linux distros will start enabling such feature by default.
For instance, Ubuntu (version 14.04+) already has such feature enabled.
represents the default backend program for JuNest.
The requirements for having Linux namespaces working are:
1. Kernel starting from Linux 3.8 allows unprivileged processes to create
user and mount namespaces.
1. The Linux kernel distro must have the user namespace enabled.
In the last years, the majority of GNU/Linux distros have the user namespace
enabled by default. This means that you do not need to have root privileges to
access to the JuNest environment via this method.
This
[wiki](https://github.com/fsquillace/junest/wiki/Linux-distros-with-user-namespace-enabled-by-default)
provides the state of the user namespace on several GNU/Linux distros.
In order to run JuNest via Linux namespaces:
- As fakeroot - Allow to install/remove packages: ```junest -u```
- As normal user - Allow to make basic operations or install/remove packages
with `sudo` command: `junest ns` or `junest`
- As fakeroot - Allow to install/remove packages: `junest ns -f` or `junest -f`
This mode is based on the fantastic
[`bubblewrap`](https://github.com/containers/bubblewrap) command.
PRoot based
-----------
[Proot](https://wiki.archlinux.org/index.php/Proot) represents a portable
solution which allows unprivileged users to execute programs inside a sandbox
and works well in most of GNU/Linux distros available.
In order to run JuNest via Proot:
- As normal user - Allow to make basic operations: `junest proot`
- As fakeroot - Allow to install/remove packages: `junest proot -f`
In `proot` mode, the minimum recommended Linux kernel for the host OS is 2.6.32 on x86 (64 bit)
and ARM architectures. It is still possible to run JuNest on lower
2.6.x host OS kernels but errors may appear, and some applications may
crash. For further information, read the [Troubleshooting](#troubleshooting)
section below.
Chroot based
------------
This solution suits only for privileged users. JuNest provides the possibility
to run the environment via `chroot` program.
In particular, it uses a special program called `GRoot`, an enhanced `chroot`
wrapper that allows to bind mount directories specified by the user, such as
/proc, /sys, /dev, /tmp and $HOME, before
In particular, it uses a special program called `GRoot`, a small and portable
version of
[arch-chroot](https://wiki.archlinux.org/index.php/Chroot)
wrapper, that allows to bind mount directories specified by the user, such as
`/proc`, `/sys`, `/dev`, `/tmp`, `/run/user/<id>` and `$HOME`, before
executing any programs inside the JuNest sandbox. In case the mounting will not
work, JuNest is even providing the possibility to run the environment directly via
the pure `chroot` command.
In order to run JuNest via `chroot` solutions:
- As root via `GRoot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -g```
- As root via `GRoot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): `junest groot`
- As root via `chroot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -r```
- As root via `chroot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): `junest root`
Execution modes comparison table
----------------
@ -161,8 +290,8 @@ The following table shows the capabilities that each backend program is able to
| | QEMU | Root privileges required | Manage Official Packages | Manage AUR Packages | Portability | Support | User modes |
| --- | ---- | ------------------------ | ------------------------ | ------------------- | ----------- | ------- | ---------- |
| **Proot** | YES | NO | YES | YES | YES | Poor | Normal user and `fakeroot` |
| **Linux Namespaces** | NO | NO | YES | NO | Poor | YES | `fakeroot` only |
| **Linux Namespaces** | NO | NO | YES | YES | Poor | YES | Normal user and `fakeroot` |
| **Proot** | YES | NO | YES | NO | YES | YES | Normal user and `fakeroot` |
| **Chroot** | NO | YES | YES | YES | YES | YES | `root` only |
Advanced usage
@ -170,18 +299,22 @@ Advanced usage
## Build image ##
You can build a new JuNest image from scratch by running the following command:
junest -b [-n]
```sh
junest build [-n]
```
The script will create a directory containing all the essentials
files in order to make JuNest working properly (such as pacman, yogurt and proot).
The option **-n** will skip the final validation tests if they are not needed.
files in order to make JuNest working properly (such as `pacman` and `proot`).
The option `-n` will skip the final validation tests if they are not needed.
Remember that the script to build the image must run in an Arch Linux OS with
arch-install-scripts, package-query, git and the base-devel packages installed.
arch-install-scripts and the base-devel packages installed.
To change the build directory just use the `JUNEST_TEMPDIR` (by default /tmp).
After creating the image junest-x86\_64.tar.gz you can install it by running:
After creating the image `junest-x86_64.tar.gz` you can install it by running:
junest -i junest-x86_64.tar.gz
```sh
junest setup -i junest-x86_64.tar.gz
```
For more details, you can also take a look at
[junest-builder](https://github.com/fsquillace/junest-builder)
@ -194,20 +327,34 @@ Related wiki page:
## Run JuNest using a different architecture via QEMU ##
The following command will download the ARM JuNest image and will run QEMU in
case the host OS runs on either x86\_64 or x86 architectures:
case the host OS runs on `x86_64` architecture:
$> JUNEST_HOME=~/.junest-arm junest -a arm -- uname -m
armv7l
```sh
$> export JUNEST_HOME=~/.junest-arm
$> junest setup -a arm
$> junest proot -- uname -m
armv7l
```
## Bind directories ##
To bind a host directory to a guest location, you can use proot arguments:
To bind a host directory to a guest location:
junest -p "-b /mnt/mydata:/home/user/mydata"
```sh
junest -b "--bind /home/user/mydata /mnt/mydata"
```
This will works with PRoot, Namespace and GRoot backend programs.
Or using proot arguments:
```sh
junest proot -b "-b /mnt/mydata:/home/user/mydata"
```
The option `-b` to provide options to the backend program will work with PRoot, Namespace and GRoot backend programs.
Check out the backend program options by passing `--help` option:
junest [-u|-g] -p "--help"
```sh
junest [u|g|p] -b "--help"
```
## Systemd integration ##
Although JuNest has not been designed to be a complete container, it is even possible to
@ -219,7 +366,9 @@ and the container can only be executed using root privileges.
To boot a JuNest container:
sudo systemd-nspawn -bD ~/.junest
```sh
sudo systemd-nspawn -bD ~/.junest
```
Related wiki page:
@ -228,30 +377,17 @@ Related wiki page:
Internals
=========
There are two main chroot jail used in JuNest.
The main one is [proot](https://wiki.archlinux.org/index.php/Proot) which
allows unprivileged users to execute programs inside a sandbox and
GRoot, a small and portable version of
[arch-chroot](https://wiki.archlinux.org/index.php/Chroot) which is an
enhanced chroot for privileged users that mounts the primary directories
(i.e. /proc, /sys, /dev and /run) before executing any programs inside
the sandbox.
## Automatic fallback to classic chroot ##
If GRoot fails for some reasons in the host system (i.e. it is not able to
mount one of the directories),
JuNest automatically tries to fallback to the classic chroot.
## Automatic fallback for all the dependent host OS executables ##
JuNest attempt first to run the executables in the host OS located in different
positions (/usr/bin, /bin, /usr/sbin and /sbin).
JuNest attempts first to run the executables in the host OS located in different
positions (`/usr/bin`, `/bin`, `/usr/sbin` and `/sbin`).
As a fallback it tries to run the same executable if it is available in the JuNest
image.
environment.
## Automatic building of the JuNest images ##
The JuNest images are built every week so that you can always get the most
updated package versions.
There is a periodic automation build of the JuNest images for `x86_64` arch
only.
The JuNest image for `arm` architecture may not be always up to date because
the build is performed manually.
## Static QEMU binaries ##
There are static QEMU binaries included in JuNest image that allows to run JuNest
@ -261,18 +397,35 @@ directory.
Troubleshooting
===============
For Arch Linux related FAQs take a look at the [General troubleshooting page](https://wiki.archlinux.org/index.php/General_troubleshooting).
## Cannot use AUR repository ##
> **Q**: Why do I get the following error when I try to install a package with yogurt?
> **Q**: Why do I get the following error when I try to install a package?
Cannot find the gzip binary required for compressing man and info pages.
> **A**: JuNest comes with a very basic number of packages.
> In order to install packages using yogurt you may need to install the package group **base-devel**
> that contains all the essential packages for compiling source code (such as gcc, make, patch, etc):
> In order to install AUR packages you need to install the package group `base-devel` first
> that contains all the essential packages for compiling from source code (such as gcc, make, patch, etc):
#> pacman -S base-devel
> Remember to not install `core/sudo` as it conflicts with `junest/sudo-fake` package.
## Can't set user and group as root
> **Q**: In ns mode when installing package I get the following error:
warning: warning given when extracting /usr/file... (Can't set user=0/group=0 for
/usr/file...)
> **A**: This is because as fakeroot is not possible to set the owner/group of
> files as root. The package will still be installed correctly even though this
> message is showed.
## Could not change the root directory in pacman
## No servers configured for repository ##
> **Q**: Why I cannot install packages?
@ -308,6 +461,8 @@ Troubleshooting
$> pkgfile getop
core/util-linux
> Alternatively, you can use directly `pacman` command only. Take a look [here](https://wiki.archlinux.org/index.php/General_troubleshooting#Message:_%22error_while_loading_shared_libraries%22).
## Kernel too old ##
> **Q**: Why do I get the error: "FATAL: kernel too old"?
@ -322,7 +477,7 @@ Troubleshooting
> on to PRoot when *-p* is prepended. For example, to fake a kernel version of
> 3.10, issue the following command:
$> junest -p "-k 3.10"
$> junest proot -b "-k 3.10"
> As Arch Linux ships binaries for kernel version 2.6.32, the above error is
> not unique to the precompiled package from JuNest. It will also appear when
@ -379,7 +534,7 @@ Troubleshooting
> have *suid* permission, you can list the commands from your JuNest environment
> with the following command:
$> find /usr/bin -perm +4000
$> find /usr/bin -perm /4000
## No characters are visible on a graphic application ##
@ -408,17 +563,31 @@ Troubleshooting
> since JuNest will try to preserve the JuNest environment by assigning ownership
> of the files to the real user.
## Not enabled User namespace or kernel too old ##
## Unprivileged user namespace disable at kernel compile time or kernel too old ##
> **Q**: Why do I get warning when I run JuNest via Linux namespaces?
> **Q**: Why do I get this warning when I run JuNest via Linux namespaces?
$> junest -u
User namespace is not enabled or Kernel too old (<3.8). Proceeding anyway...
$> junest ns
Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway...
> **A**: This means that JuNest detected that the host OS either
> does not have a newer kernel version or the unprivileged user namespace
> is not enabled at kernel compile time.
> JuNest does not stop the execution of the program but it attempts to run it
> anyway. Try to use Proot as backend program in case is not possible to invoke namespaces.
## Unprivileged user namespace disabled
> **Q**: Why do I get this warning when I run JuNest via Linux namespaces?
$> junest ns
Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1
> **A**: This means that JuNest detected that the host OS either
> does not have a newer Linux version or the user namespace is not enabled.
> JuNest does not stop the execution of the program but it attempts to run it
> anyway. Try to use Proot as backend program in case is not possible to invoke namespaces.
> anyway. If you have root permissions try to enable it, otherwise try to use
> Proot as backend program.
More documentation
==================
@ -427,13 +596,21 @@ There are additional tutorials in the
Contributing
============
You could help improving JuNest in the following ways:
Contributions are welcome! You could help improving JuNest in the following ways:
- [Reporting Bugs](CONTRIBUTING.md#reporting-bugs)
- [Suggesting Enhancements](CONTRIBUTING.md#suggesting-enhancements)
- [Writing Code](CONTRIBUTING.md#your-first-code-contribution)
Author
======
Filippo Squillace <feel.sqoox@gmail.com>
Donating
========
To sustain the project please consider funding by donations through
the [GitHub Sponsors page](https://github.com/sponsors/fsquillace/).
Authors
=======
JuNest was originally created in late 2014 by [Filippo Squillace (feel.sqoox@gmail.com)](https://github.com/fsquillace).
Here is a list of [**really appreciated contributors**](https://github.com/fsquillace/junest/graphs/contributors)!
[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/0)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/0)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/1)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/1)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/2)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/2)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/3)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/3)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/4)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/4)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/5)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/5)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/6)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/6)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/7)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/7)

View file

@ -1 +1 @@
6.0.2
7.4.10

234
bin/groot
View file

@ -1,234 +0,0 @@
#!/bin/bash
#
# This script is the simplified and portable version of arch-chroot
# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot)
#
set -e
# JUNEST_BASE can be overridden for testing purposes.
# There is no need for doing it for normal usage.
JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/..)}"
NAME='GRoot'
CMD='groot'
DESCRIPTION="I am $NAME!"
CHROOTCMD=${CHROOTCMD:-chroot}
SHELL="/bin/sh"
MOUNT=mount
UMOUNT=umount
MOUNTPOINT=mountpoint
MKDIR=mkdir
TOUCH=touch
CUT=cut
SORT=sort
UNIQ=uniq
CAT=cat
READLINK=readlink
MOUNTS_FILE=/proc/self/mounts
NOT_EXISTING_FILE=103
NOT_ABSOLUTE_PATH=111
NO_ROOT_PRIVILEGES=110
source "${JUNEST_BASE}/lib/utils/utils.sh"
################################ MAIN FUNCTIONS ###########################
function chroot_teardown() {
# Remove all mounts starting from the most nested ones.
# Suffix the CHROOTDIR with / to avoid umounting directories not belonging
# to CHROOTDIR.
local normalized_chrootdir="$($READLINK -f ${CHROOTDIR})/"
local final_res=0
for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ)
do
if [[ $mp =~ ^${normalized_chrootdir}.* ]]
then
$UMOUNT $mp || final_res=$?
fi
done
$UMOUNT ${CHROOTDIR%/}
return $final_res
}
function chroot_maybe_add_mount() {
local cond=$1
shift
if eval "$cond"; then
$MOUNT "$@"
return
fi
return 1
}
function chroot_setup() {
$OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' QUIT EXIT ABRT KILL TERM INT
if ! chroot_maybe_add_mount "! $MOUNTPOINT -q '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR"
then
warn "Failed mount of directories. $CHROOTDIR is already a mountpoint. Skipping it..."
return 0
fi
local re='(.*):(.*)'
for binds in ${BINDINGS[@]}
do
local host_path=""
local guest_path=""
if [[ $binds =~ $re ]]
then
local host_path="${BASH_REMATCH[1]}"
local guest_path="${BASH_REMATCH[2]}"
else
local host_path="$binds"
local guest_path="$binds"
fi
create_node "${host_path}" "${CHROOTDIR}${guest_path}"
mount_directory "${host_path}" "${guest_path}"
done
}
function mount_directory() {
local host_path=$($READLINK -f "$1")
local guest_path="$2"
if ! $OPT_AVOID_BIND
then
$MOUNT $OPT_BIND "${host_path}" "${CHROOTDIR}${guest_path}"
return 0
fi
case "$host_path" in
/proc) $MOUNT proc "${CHROOTDIR}${guest_path}" -t proc ;;
/sys) $MOUNT sys "${CHROOTDIR}${guest_path}" -t sysfs ;;
/dev) $MOUNT udev "${CHROOTDIR}${guest_path}" -t devtmpfs; $MOUNT devpts "${guest_path}/pts" -t devpts; $MOUNT shm "${guest_path}/shm" -t tmpfs ;;
/run) $MOUNT run "${CHROOTDIR}${guest_path}" -t tmpfs ;;
/tmp) $MOUNT tmp "${CHROOTDIR}${guest_path}" -t tmpfs ;;
*) $MOUNT $OPT_BIND "${host_path}" "${CHROOTDIR}${guest_path}" ;;
esac
return 0
}
function create_node() {
local src="$1"
local dst="$2"
if [[ ! -e $src ]]
then
die_on_status $NOT_EXISTING_FILE "${src} does not exist."
elif [[ $src != /* ]]
then
die_on_status $NOT_ABSOLUTE_PATH "${src} is not an absolute path."
elif [[ -f $src ]]
then
$TOUCH "$dst"
elif [[ -d $src ]]
then
$MKDIR -p "$dst"
fi
}
function usage() {
cat <<EOF
$NAME (v$(cat $JUNEST_BASE/VERSION)): $DESCRIPTION
Usage:
$CMD [options] [<chroot-dir> [command]]
Options:
-b, --bind <path>
Make the content of <path> accessible in the guest rootfs.
This option makes any file or directory of the host rootfs
accessible in the confined environment just as if it were part of
the guest rootfs. By default the host path is bound to the same
path in the guest rootfs but users can specify any other location
with the syntax: -b <host_path>:<guest_location>. This option can
be invoked multiple times and the paths specified must be absolutes.
-n, --no-umount
Do not umount after chroot session finished.
-r, --recursive
Use rbind instead of bind.
-i, --avoid-bind
Attempt to avoid mount --bind for common directories and use
proper mount fstype instead. Detected directories with
corresponding fstype are: /proc (proc), /sys (sysfs),
/dev (devtmpfs), /tmp (tmpfs), /run (tmpfs).
-h, --help Print this help message
-V, --version Show the $NAME version
If 'command' is unspecified, $CMD will launch $SHELL.
EOF
}
version() {
echo -e "$NAME $(cat $JUNEST_BASE/VERSION)"
}
function parse_arguments() {
BINDINGS=()
OPT_NO_UMOUNT=false
OPT_RECURSIVE=false
OPT_BIND="--bind"
OPT_AVOID_BIND=false
OPT_HELP=false
OPT_VERSION=false
for opt in "$@"
do
case "$1" in
-b|--bind) shift ; BINDINGS+=("$1") ; shift ;;
-n|--no-umount) OPT_NO_UMOUNT=true ; shift ;;
-r|--recursive) OPT_BIND="--rbind" ; shift ;;
-i|--avoid-bind) OPT_AVOID_BIND=true ; shift ;;
-h|--help) OPT_HELP=true ; shift ;;
-V|--version) OPT_VERSION=true ; shift ;;
-*) die "Invalid option $1" ;;
*) break ;;
esac
done
if [[ ! -z $1 ]]
then
CHROOTDIR="$1"
shift
fi
ARGS=()
for arg in "$@"
do
ARGS+=("$arg")
done
}
function is_user_root() {
(( EUID == 0 ))
}
function execute_operation() {
$OPT_HELP && usage && return
$OPT_VERSION && version && return
is_user_root || die_on_status $NO_ROOT_PRIVILEGES 'This script must be run with root privileges'
[[ -d $CHROOTDIR ]] || die_on_status $NOT_EXISTING_FILE "Can't create chroot on non-directory $CHROOTDIR"
chroot_setup "$CHROOTDIR" || die "Failed to setup chroot $CHROOTDIR"
$CHROOTCMD "$CHROOTDIR" "${ARGS[@]}"
}
function main() {
parse_arguments "$@"
execute_operation
}
main "$@"

View file

@ -1,4 +1,5 @@
#!/usr/bin/env bash
# shellcheck disable=SC1091
#
# This file is part of JuNest (https://github.com/fsquillace/junest).
#
@ -7,154 +8,140 @@ set -e
# JUNEST_BASE can be overridden for testing purposes.
# There is no need for doing it for normal usage.
JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/..)}"
JUNEST_BASE="${JUNEST_BASE:-$(readlink -f "$(dirname "$(readlink -f "$0")")"/..)}"
source "${JUNEST_BASE}/lib/utils/utils.sh"
source "${JUNEST_BASE}/lib/core/common.sh"
source "${JUNEST_BASE}/lib/core/build.sh"
source "${JUNEST_BASE}/lib/core/setup.sh"
source "${JUNEST_BASE}/lib/core/chroot.sh"
source "${JUNEST_BASE}/lib/core/namespace.sh"
source "${JUNEST_BASE}/lib/core/proot.sh"
source "${JUNEST_BASE}/lib/core/setup.sh"
source "${JUNEST_BASE}/lib/core/wrappers.sh"
###################################
### General functions ###
###################################
usage() {
echo -e "$NAME (v$(cat $JUNEST_BASE/VERSION)): $DESCRIPTION"
echo -e "$NAME (v$(cat "$JUNEST_BASE"/VERSION)): $DESCRIPTION"
echo
echo -e "Usage: $CMD [options] [--] [command]"
echo -e "Usage: $CMD [action] [options] [--] [command]"
echo
echo -e "Setup options:"
echo -e "-i, --setup-from-file <image> Setup the $NAME image in ${JUNEST_HOME}"
echo -e "-a, --arch <arch> $NAME architecture to download (x86_64, x86, arm)"
echo -e " Defaults to the host architecture ($ARCH)"
echo -e "-d, --delete Delete $NAME from ${JUNEST_HOME}"
echo -e "General:"
echo -e "-h, --help Show this help message"
echo -e "-V, --version Show the $NAME version"
echo
echo -e "Access options:"
echo -e "-f, --fakeroot Run $NAME with fakeroot privileges"
echo -e "-g, --groot Run $NAME with root privileges via GRoot"
echo -e "-r, --root Run $NAME with root privileges via classic chroot"
echo -e "-u, --namespace Use Linux Namespace (with GRoot) instead of PRoot"
echo -e "-p, --backend-args <args> Arguments for backend program (PRoot or GRoot)"
echo -e " ($CMD -p \"--help\" to check out the PRoot options"
echo -e " $CMD -g -p \"--help\" to check out the GRoot options"
echo -e " $CMD -r -p \"--help\" to check out the chroot options)"
echo -e "Actions and options:"
echo -e " s[etup] Setup $NAME in ${JUNEST_HOME} either from repo or from file"
echo -e " -i, --from-file <image> Setup the $NAME image in ${JUNEST_HOME}"
echo -e " -a, --arch <arch> $NAME architecture to download (x86_64, arm)"
echo -e " Defaults to the host architecture ($ARCH)"
echo -e " -d, --delete Delete $NAME from ${JUNEST_HOME}"
echo
echo -e "Building options:"
echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)"
echo -e "-n, --disable-validation Disable the $NAME image validation"
echo -e " n[s] Access via Linux Namespaces using BubbleWrap (Default action)"
echo -e " -f, --fakeroot Run $NAME with fakeroot privileges"
echo -e " --backend-command <cmd> Bwrap command to use"
echo -e " -b, --backend-args <args> Arguments for bwrap backend program"
echo -e " ($CMD ns -b \"--help\" to check out the bwrap options)"
echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment"
echo
echo -e " p[root] Access via PRoot"
echo -e " -f, --fakeroot Run $NAME with fakeroot privileges"
echo -e " --backend-command <cmd> PRoot command to use"
echo -e " -b, --backend-args <args> Arguments for PRoot backend program"
echo -e " ($CMD proot -b \"--help\" to check out the PRoot options)"
echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment"
echo
echo -e " g[root] Access with root privileges via GRoot"
echo -e " --backend-command <cmd> GRoot command to use"
echo -e " -b, --backend-args <args> Arguments for GRoot backend program"
echo -e " ($CMD groot -b \"--help\" to check out the GRoot options)"
echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment"
echo
echo -e " r[oot] Access with root privileges via classic chroot"
echo -e " --backend-command <cmd> Chroot command to use"
echo -e " -b, --backend-args <args> Arguments for chroot backend program"
echo -e " ($CMD root -b \"--help\" to check out the chroot options)"
echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment"
echo
echo -e " b[uild] Build a $NAME image (must run in ArchLinux)"
echo -e " -n, --disable-check Disable the $NAME image check"
echo
echo -e " create-bin-wrappers Create a bin wrappers directory according to --bin-path option"
echo -e " Default path is $JUNEST_HOME/usr/bin_wrappers"
echo -e " -f, --force Create the wrapper files even if they already exist"
echo -e " -p, --bin-path The source directory where executable are located in JuNest"
echo -e " Default value is: /usr/bin"
echo
echo -e "General options:"
echo -e "-h, --help Show this help message"
echo -e "-V, --version Show the $NAME version"
}
version() {
echo -e "$NAME $(cat $JUNEST_BASE/VERSION)"
echo -e "$NAME $(cat "$JUNEST_BASE"/VERSION)"
}
check_cli(){
if $OPT_BUILD_IMAGE
then
if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \
$OPT_FAKEROOT || $OPT_ROOT
then
die "The build image option must be used exclusively"
fi
fi
if $OPT_DISABLE_VALIDATION
then
if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \
$OPT_FAKEROOT || $OPT_ROOT
then
die "The disable validation option must be used with the build image option only"
fi
fi
if $OPT_DELETE
then
if $OPT_BUILD_IMAGE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \
$OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION
then
die "The $NAME delete option must be used exclusively"
fi
fi
if $OPT_HELP
then
if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \
$OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION
then
die "The $NAME help option must be used exclusively"
fi
fi
if $OPT_VERSION
then
if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \
$OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION
then
die "The $NAME version option must be used exclusively"
fi
fi
if $OPT_FAKEROOT && $OPT_ROOT
then
die "You must access to $NAME with either fakeroot or root permissions"
fi
if $OPT_BACKEND_ARGS || $OPT_ARCH
then
if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || \
$OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION
then
die "Invalid syntax: Proot and arch args are not allowed with the other options"
fi
fi
if [ "$ARGS" != "" ]
then
if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \
$OPT_VERSION || $OPT_DISABLE_VALIDATION
then
die "No arguments are needed. For the CLI syntax run: $CMD --help"
fi
fi
return 0
}
function parse_arguments(){
OPT_SETUP_FROM_FILE=false
IMAGE_FILE=""
OPT_FAKEROOT=false
OPT_ROOT=false
OPT_GROOT=false
OPT_USER_NAMESPACE=false
OPT_BACKEND_ARGS=false
# Actions
ACT_SETUP=false
ACT_BUILD=false
ACT_CREATE_WRAPPERS=false
ACT_NAMESPACE=false
ACT_PROOT=false
ACT_GROOT=false
ACT_ROOT=false
ACT_HELP=false
ACT_VERSION=false
case "$1" in
s|setup) ACT_SETUP=true ; shift ;;
b|build) ACT_BUILD=true ; shift ;;
create-bin-wrappers) ACT_CREATE_WRAPPERS=true ; shift ;;
n|ns) ACT_NAMESPACE=true ; shift ;;
p|proot) ACT_PROOT=true ; shift ;;
g|groot) ACT_GROOT=true ; shift ;;
r|root) ACT_ROOT=true ; shift ;;
-h|--help) ACT_HELP=true ; shift ;;
-V|--version) ACT_VERSION=true ; shift ;;
*) ACT_NAMESPACE=true ;;
esac
if $ACT_SETUP
then
_parse_setup_opts "$@"
elif $ACT_BUILD
then
_parse_build_opts "$@"
elif $ACT_CREATE_WRAPPERS
then
_parse_create_wrappers_opts "$@"
elif $ACT_NAMESPACE
then
_parse_ns_opts "$@"
elif $ACT_PROOT
then
_parse_proot_opts "$@"
elif $ACT_GROOT
then
_parse_root_opts "$@"
elif $ACT_ROOT
then
_parse_root_opts "$@"
fi
}
function _parse_root_opts() {
# Options:
BACKEND_ARGS=""
OPT_ARCH=false
ARCH_ARG=""
OPT_BUILD_IMAGE=false
OPT_DISABLE_VALIDATION=false
CHECK_ARG=""
OPT_DELETE=false
OPT_HELP=false
OPT_VERSION=false
for opt in "$@"
OPT_NO_COPY_FILES=false
BACKEND_COMMAND=""
while [[ -n "$1" ]]
do
case "$1" in
-i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;;
-f|--fakeroot) OPT_FAKEROOT=true ; shift ;;
-r|--root) OPT_ROOT=true ; shift ;;
-g|--groot) OPT_GROOT=true ; shift ;;
-u|--namespace) OPT_USER_NAMESPACE=true ; shift ;;
-p|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;;
-a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;;
-b|--build-image) OPT_BUILD_IMAGE=true ; shift ;;
-n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;;
-d|--delete) OPT_DELETE=true ; shift ;;
-h|--help) OPT_HELP=true ; shift ;;
-V|--version) OPT_VERSION=true ; shift ;;
-b|--backend-args) shift ; BACKEND_ARGS=$1; shift ;;
-n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;;
--backend-command) shift; BACKEND_COMMAND="$1"; shift ;;
--) shift ; break ;;
-*) die "Invalid option $1" ;;
*) break ;;
@ -168,53 +155,166 @@ function parse_arguments(){
done
}
function execute_operation(){
$OPT_HELP && usage && return
$OPT_VERSION && version && return
function _parse_ns_opts() {
# Options:
OPT_FAKEROOT=false
BACKEND_ARGS=""
OPT_NO_COPY_FILES=false
BACKEND_COMMAND=""
if $OPT_BUILD_IMAGE; then
build_image_env $OPT_DISABLE_VALIDATION
return
elif $OPT_DELETE; then
delete_env
while [[ -n "$1" ]]
do
case "$1" in
-f|--fakeroot) OPT_FAKEROOT=true ; shift ;;
-b|--backend-args) shift ; BACKEND_ARGS=$1; shift ;;
-n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;;
--backend-command) shift; BACKEND_COMMAND="$1"; shift ;;
--) shift ; break ;;
-*) die "Invalid option $1" ;;
*) break ;;
esac
done
ARGS=()
for arg in "$@"
do
ARGS+=("$arg")
done
}
function _parse_proot_opts() {
# Options:
OPT_FAKEROOT=false
BACKEND_ARGS=""
OPT_NO_COPY_FILES=false
BACKEND_COMMAND=""
while [[ -n "$1" ]]
do
case "$1" in
-f|--fakeroot) OPT_FAKEROOT=true ; shift ;;
-b|--backend-args) shift ; BACKEND_ARGS=$1; shift ;;
-n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;;
--backend-command) shift; BACKEND_COMMAND="$1"; shift ;;
--) shift ; break ;;
-*) die "Invalid option $1" ;;
*) break ;;
esac
done
ARGS=("$@")
}
function _parse_build_opts() {
OPT_DISABLE_CHECK=false
while [[ -n "$1" ]]
do
case "$1" in
-n|--disable-check) OPT_DISABLE_CHECK=true ; shift ;;
*) die "Invalid option $1" ;;
esac
done
}
function _parse_create_wrappers_opts() {
OPT_FORCE=false
OPT_BIN_PATH=""
while [[ -n "$1" ]]
do
case "$1" in
-f|--force) OPT_FORCE=true ; shift ;;
-p|--bin-path) shift ; OPT_BIN_PATH="$1" ; shift ;;
*) die "Invalid option $1" ;;
esac
done
}
function _parse_setup_opts() {
OPT_FROM_FILE=false
IMAGE_FILE=""
ARCH_ARG=""
OPT_DELETE=false
while [[ -n "$1" ]]
do
case "$1" in
-i|--from-file) OPT_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;;
-a|--arch) shift ; ARCH_ARG=$1; shift ;;
-d|--delete) OPT_DELETE=true ; shift ;;
*) die "Invalid option $1" ;;
esac
done
}
function execute_operation() {
$ACT_HELP && usage && return
$ACT_VERSION && version && return
if $ACT_BUILD; then
# shellcheck disable=SC2086
build_image_env $OPT_DISABLE_CHECK
return
fi
if $ACT_SETUP; then
if $OPT_DELETE; then
delete_env
else
if is_env_installed
then
die "Error: The image cannot be installed since $JUNEST_HOME is not empty."
fi
if $OPT_FROM_FILE; then
setup_env_from_file "$IMAGE_FILE"
else
setup_env "$ARCH_ARG"
fi
create_wrappers
fi
return
fi
if ! is_env_installed
then
if $OPT_SETUP_FROM_FILE; then
setup_env_from_file $IMAGE_FILE
else
setup_env $ARCH_ARG
unset ARCH_ARG
fi
elif $OPT_SETUP_FROM_FILE; then
die "Error: The image cannot be installed since $JUNEST_HOME is not empty."
die "Error: The image is still not installed in $JUNEST_HOME. Run this first: $CMD setup"
fi
[ -z "${ARCH_ARG}" ] || \
die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME"
if $ACT_CREATE_WRAPPERS; then
# shellcheck disable=SC2086
create_wrappers $OPT_FORCE "$OPT_BIN_PATH"
exit
fi
local run_env
if $OPT_USER_NAMESPACE; then
run_env=run_env_with_namespace
elif $OPT_FAKEROOT; then
run_env=run_env_as_fakeroot
elif $OPT_ROOT; then
run_env=run_env_as_chroot
elif $OPT_GROOT; then
if $ACT_NAMESPACE; then
if $OPT_FAKEROOT; then
run_env=run_env_as_bwrap_fakeroot
else
run_env=run_env_as_bwrap_user
fi
elif $ACT_PROOT; then
if $OPT_FAKEROOT; then
run_env=run_env_as_proot_fakeroot
else
run_env=run_env_as_proot_user
fi
elif $ACT_GROOT; then
run_env=run_env_as_groot
else
run_env=run_env_as_user
elif $ACT_ROOT; then
run_env=run_env_as_chroot
fi
$run_env "${BACKEND_ARGS}" "${ARGS[@]}"
# Call create_wrappers in case new bin files have been created
# shellcheck disable=SC2064
trap "PATH=$PATH create_wrappers" EXIT QUIT TERM
# shellcheck disable=SC2086
$run_env "$BACKEND_COMMAND" "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}"
}
function main() {
parse_arguments "$@"
check_cli
execute_operation
}

8
bin/sudoj Executable file
View file

@ -0,0 +1,8 @@
#!/usr/bin/env bash
#
# This file is part of JuNest (https://github.com/fsquillace/junest).
#
export PATH="${PATH}:${JUNEST_HOME}/usr/bin_wrappers"
JUNEST_ARGS="ns --fakeroot" "$@"

15
ci/build_image.sh Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -ex
pacman -Sy --noconfirm sudo
# Create a travis user
echo "travis ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/travis
chmod 'u=r,g=r,o=' /etc/sudoers.d/travis
groupadd --gid "2000" "travis"
useradd --create-home --uid "2000" --gid "2000" --shell /usr/bin/false "travis"
# Here do not make any validation (-n) because it will be done later on in the Ubuntu host directly
cd /build
runuser -u travis -- /build/bin/junest build -n

48
ci/deploy.sh Executable file
View file

@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -e
IMG_PATH=$1
set -ux
MAX_OLD_IMAGES=5
ENDPOINT="https://8da1bcd84e423c9b013b69fe1e8b4675.r2.cloudflarestorage.com"
# ARCH can be one of: x86, x86_64, arm
HOST_ARCH=$(uname -m)
if [ "$HOST_ARCH" == "i686" ] || [ "$HOST_ARCH" == "i386" ]
then
ARCH="x86"
elif [ "$HOST_ARCH" == "x86_64" ]
then
ARCH="x86_64"
elif [[ $HOST_ARCH =~ .*(arm).* ]]
then
ARCH="arm"
else
echo "Unknown architecture ${HOST_ARCH}" >&2
exit 11
fi
if [[ "$TRAVIS_BRANCH" == "master" ]]
then
export AWS_DEFAULT_REGION=auto
# Upload image
# The put is done via a temporary filename in order to prevent outage on the
# production file for a longer period of time.
img_name=$(basename "${IMG_PATH}")
aws s3 --endpoint-url="$ENDPOINT" cp "${IMG_PATH}" s3://junest-repo/junest/
DATE=$(date +'%Y-%m-%d-%H-%M-%S')
aws s3 --endpoint-url="$ENDPOINT" cp "${IMG_PATH}" "s3://junest-repo/junest/${img_name}.${DATE}"
# Cleanup old images
aws s3 --endpoint-url="$ENDPOINT" ls s3://junest-repo/junest/junest-${ARCH}.tar.gz. | awk '{print $4}' | head -n -${MAX_OLD_IMAGES} | xargs -I {} aws s3 --endpoint-url="$ENDPOINT" rm "s3://junest-repo/junest/{}"
# Test the newly deployed image can be downloaded correctly
junest setup
junest -- echo "Installed JuNest (\$(uname -m))"
yes | junest setup --delete
fi

13
ci/install-bash.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/sh
set -ex
VERSION=$1
cd /tmp
wget "http://ftp.gnu.org/gnu/bash/bash-$VERSION.tar.gz"
tar -zxf "bash-$VERSION.tar.gz"
cd /tmp/bash-"$VERSION"*
./configure
make
sudo make install

View file

@ -1,4 +1,5 @@
#!/usr/bin/env bash
# shellcheck disable=SC1091
#
# This modules is used for:
# - Running checks against the building JuNest image
@ -9,21 +10,32 @@
#
# vim: ft=sh
set -eu
set -ex
OPT_RUN_ROOT_TESTS=${1:-false}
RUN_ROOT_TESTS=false
[[ ${OPT_RUN_ROOT_TESTS} == "--run-root-tests" ]] && RUN_ROOT_TESTS=true
OPT_SKIP_AUR_TESTS=${1:-false}
SKIP_AUR_TESTS=false
[[ ${OPT_SKIP_AUR_TESTS} == "--skip-aur-tests" ]] && SKIP_AUR_TESTS=true
USE_SUDO=false
while [[ -n "$1" ]]
do
case "$1" in
--run-root-tests) RUN_ROOT_TESTS=true ; shift ;;
--skip-aur-tests) SKIP_AUR_TESTS=true ; shift ;;
--use-sudo) USE_SUDO=true ; shift ;;
*) die "Invalid option $1" ;;
esac
done
set -u
SUDO=""
[[ -n $USE_SUDO ]] && SUDO="sudo"
JUNEST_HOME=${JUNEST_HOME:-$HOME/.junest}
# JUNEST_BASE can be overridden for testing purposes.
# There is no need for doing it for normal usage.
JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/../..)}"
JUNEST_BASE="${JUNEST_BASE:-$(readlink -f "$(dirname "$(readlink -f "$0")")"/../..)}"
source "${JUNEST_BASE}/lib/utils/utils.sh"
source "${JUNEST_BASE}/lib/core/common.sh"
@ -31,32 +43,60 @@ source "${JUNEST_BASE}/lib/core/common.sh"
info "Validating JuNest located in ${JUNEST_HOME}..."
info "Initial JuNest setup..."
echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist
pacman --noconfirm -Syy
pacman --noconfirm -S base-devel
# The following ensures that the gpg agent gets killed (if exists)
# otherwise it is not possible to exit from the session
trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" QUIT EXIT ABRT TERM INT
info "Checking essential executables work..."
pacman -Qi pacman 1> /dev/null
yogurt -V 1> /dev/null
/opt/proot/proot-$ARCH --help 1> /dev/null
prepare_archlinux "$SUDO"
PACMAN_OPTIONS="--noconfirm --disable-download-timeout"
# shellcheck disable=SC2086
$SUDO pacman $PACMAN_OPTIONS -S grep coreutils
# shellcheck disable=SC2086
# shellcheck disable=SC2046
$SUDO pacman $PACMAN_OPTIONS -Syu --ignore sudo base-devel
info "Checking basic executables work..."
$SUDO pacman -Qi pacman 1> /dev/null
/usr/bin/groot --help 1> /dev/null
# Test FAKEROOTDONTTRYCHOWN is set to true by default
set +u
if [[ -z $FAKEROOTKEY ]]
then
fakeroot chown root /tmp
else
chown root /tmp
fi
set -u
repo_package1=tree
echo "Checking ${repo_package1} package from official repo..."
pacman --noconfirm -S ${repo_package1}
# shellcheck disable=SC2086
$SUDO pacman $PACMAN_OPTIONS -S ${repo_package1}
tree -L 1
pacman --noconfirm -Rsn ${repo_package1}
# shellcheck disable=SC2086
$SUDO pacman $PACMAN_OPTIONS -Rsn ${repo_package1}
repo_package2=iftop
info "Checking ${repo_package2} package from official repo..."
pacman --noconfirm -S ${repo_package2}
$RUN_ROOT_TESTS && iftop -t -s 5
pacman --noconfirm -Rsn ${repo_package2}
# shellcheck disable=SC2086
$SUDO pacman $PACMAN_OPTIONS -S ${repo_package2}
if $RUN_ROOT_TESTS
then
# Time it out given that sometimes it gets stuck after few seconds.
$SUDO timeout 10 iftop -t -s 5 || true
fi
# shellcheck disable=SC2086
$SUDO pacman $PACMAN_OPTIONS -Rsn ${repo_package2}
if ! $SKIP_AUR_TESTS
then
aur_package=tcptraceroute
info "Checking ${aur_package} package from AUR repo..."
yogurt -A --noconfirm -S ${aur_package}
$RUN_ROOT_TESTS && tcptraceroute localhost
pacman --noconfirm -Rsn ${aur_package}
yay --noconfirm -S ${aur_package}
# shellcheck disable=SC2086
$SUDO pacman $PACMAN_OPTIONS -Rsn ${aur_package}
fi
exit 0

31
lib/checks/check_all.sh Executable file
View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Multiple tests against different execution modes
set -ex
# JUNEST_BASE can be overridden for testing purposes.
# There is no need for doing it for normal usage.
JUNEST_BASE="${JUNEST_BASE:-$(readlink -f "$(dirname "$(readlink -f "$0")")"/../..)}"
JUNEST_SCRIPT=${JUNEST_SCRIPT:-${JUNEST_BASE}/bin/junest}
CHECK_SCRIPT=${JUNEST_BASE}/lib/checks/check.sh
$JUNEST_SCRIPT proot --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests
$JUNEST_SCRIPT proot -- "$CHECK_SCRIPT" --skip-aur-tests --use-sudo
# Test the backend command option
$JUNEST_SCRIPT proot --backend-command "$JUNEST_HOME/usr/bin/proot-x86_64" -- exit
$JUNEST_SCRIPT ns --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests
$JUNEST_SCRIPT ns -- "$CHECK_SCRIPT" --use-sudo
# Test the backend command option
$JUNEST_SCRIPT ns --backend-command "$JUNEST_HOME/usr/bin/bwrap" -- exit
sudo -E "$JUNEST_SCRIPT" groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests
# Test the wrappers work
"$JUNEST_SCRIPT" create-bin-wrappers --force
"$JUNEST_HOME"/usr/bin_wrappers/pacman --help
"$JUNEST_SCRIPT" create-bin-wrappers --force --bin-path /usr/bin/core_perl/
"$JUNEST_HOME"/usr/bin/core_perl_wrappers/shasum --help
"${JUNEST_BASE}/bin/sudoj" pacman -Syu

View file

@ -8,93 +8,134 @@
#
# vim: ft=sh
function _check_package(){
if ! pacman -Qq $1 > /dev/null
then
die "Package $1 must be installed"
fi
function _install_pkg(){
# This function allows to install packages from AUR.
# At the moment is not used.
local maindir=$1
local pkgbuilddir=$2
# Generate a working directory because sources will be downloaded to there
working_dir=$(TMPDIR=/tmp mktemp -d -t junest-wd.XXXXXXXXXX)
cp -R "$pkgbuilddir"/* "$working_dir"
builtin cd "${working_dir}" || return 1
makepkg -sfcd
makepkg --printsrcinfo > "${pkgbuilddir}"/.SRCINFO
sudo pacman --noconfirm --root "${maindir}"/root -U ./*.pkg.tar.*
}
function _install_from_aur(){
local maindir=$1
local pkgname=$2
local installname=$3
mkdir -p ${maindir}/packages/${pkgname}
builtin cd ${maindir}/packages/${pkgname}
$CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}"
[ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}"
makepkg -sfc
sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz
function _prepare() {
# ArchLinux System initialization
prepare_archlinux
# curl is used to download pacman.conf file
sudo pacman -S --noconfirm git arch-install-scripts haveged curl
}
function build_image_env(){
set -x
umask 022
# The function must runs on ArchLinux with non-root privileges.
# This is because installing AUR packages can be done by normal users only.
(( EUID == 0 )) && \
die "You cannot build with root privileges."
_check_package arch-install-scripts
_check_package gcc
_check_package package-query
_check_package git
_prepare
local disable_validation=$1
local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX)
sudo mkdir -p ${maindir}/root
trap - QUIT EXIT ABRT KILL TERM INT
trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT
local maindir
maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t "${CMD}".XXXXXXXXXX)
sudo mkdir -p "${maindir}"/root
trap - QUIT EXIT ABRT TERM INT
# shellcheck disable=SC2064
trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT TERM INT
info "Installing pacman and its dependencies..."
# The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux
# All the essential executables (ln, mkdir, chown, etc) are in coreutils
# yaourt requires sed
# localedef (called by locale-gen) requires gzip
# unshare command belongs to util-linux
sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip util-linux
sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist"
sudo mkdir -p ${maindir}/root/run/lock
# bwrap command belongs to bubblewrap
sudo pacstrap -G -M "${maindir}"/root pacman coreutils bubblewrap
# AUR packages requires non-root user to be compiled. proot fakes the user to 10
info "Compiling and installing yaourt..."
_install_from_aur ${maindir} "package-query"
_install_from_aur ${maindir} "yaourt"
if [[ ${ARCH} != "arm" ]]
then
# x86_64 does not have any mirror set by default...
sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist"
fi
sudo mkdir -p "${maindir}"/root/run/lock
info "Install ${NAME} script..."
sudo pacman --noconfirm --root ${maindir}/root -S git
_install_from_aur ${maindir} "${CMD}-git" "${CMD}.install"
sudo pacman --noconfirm --root ${maindir}/root -Rsn git
# For some reasons, pacstrap does not create the pacman.conf file,
# I could not reproduce the issue locally though:
# https://app.travis-ci.com/github/fsquillace/junest/builds/268216346
[[ -e "${maindir}"/root/etc/pacman.conf ]] || sudo curl "https://gitlab.archlinux.org/archlinux/packaging/packages/pacman/-/raw/main/pacman.conf" -o "${maindir}/root/etc/pacman.conf"
# Pacman/pacstrap bug: https://gitlab.archlinux.org/archlinux/packaging/packages/arch-install-scripts/-/issues/3
sudo sed -i '/^DownloadUser = alpm$/d' "${maindir}"/root/etc/pacman.conf
sudo tee -a "${maindir}"/root/etc/pacman.conf <<EOT
[junest]
SigLevel = Optional TrustedOnly
Server = https://raw.githubusercontent.com/fsquillace/junest-repo/master/any
EOT
info "pacman.conf being used:"
cat "${maindir}"/root/etc/pacman.conf
sudo pacman --noconfirm --config "${maindir}"/root/etc/pacman.conf --root "${maindir}"/root -Sy sudo-fake groot-git proot-static qemu-user-static-bin-alt yay-git
echo "Generating the metadata info"
sudo install -d -m 755 "${maindir}/root/etc/${CMD}"
sudo bash -c "echo 'JUNEST_ARCH=$ARCH' > ${maindir}/root/etc/${CMD}/info"
# Related to: https://github.com/fsquillace/junest/issues/305
sudo bash -c "echo 'export FAKEROOTDONTTRYCHOWN=true' > ${maindir}/root/etc/profile.d/junest.sh"
info "Generating the locales..."
# sed command is required for locale-gen
sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime
# sed command is required for locale-gen but it is required by fakeroot
# and cannot be removed
# localedef (called by locale-gen) requires gzip but it is supposed to be
# already installed as systemd already depends on it
sudo pacman --noconfirm --root "${maindir}"/root -S sed gzip
sudo ln -sf /usr/share/zoneinfo/posix/UTC "${maindir}"/root/etc/localtime
sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen"
sudo ${maindir}/root/opt/junest/bin/groot ${maindir}/root locale-gen
sudo "${maindir}"/root/bin/groot "${maindir}"/root locale-gen
sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf"
info "Setting up the pacman keyring (this might take a while!)..."
sudo ${maindir}/root/opt/junest/bin/groot -b /dev ${maindir}/root bash -c \
"pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye"
if [[ $(uname -m) == *"arm"* ]]
then
sudo pacman -S --noconfirm --root "${maindir}"/root archlinuxarm-keyring
else
sudo pacman -S --noconfirm --root "${maindir}"/root archlinux-keyring
fi
sudo mount --bind "${maindir}"/root "${maindir}"/root
sudo arch-chroot "${maindir}"/root bash -c '
set -e
pacman-key --init;
for keyring_file in /usr/share/pacman/keyrings/*.gpg;
do
keyring=$(basename $keyring_file | cut -f 1 -d ".");
pacman-key --populate $keyring;
done;'
sudo umount "${maindir}"/root
sudo rm ${maindir}/root/var/cache/pacman/pkg/*
sudo rm "${maindir}"/root/var/cache/pacman/pkg/*
# This is needed on system with busybox tar command.
# If the file does not have write permission, the tar command to extract files fails.
sudo chmod -R u+rw "${maindir}"/root/
mkdir -p ${maindir}/output
builtin cd ${maindir}/output
mkdir -p "${maindir}"/output
builtin cd "${maindir}"/output || return 1
local imagefile="${CMD}-${ARCH}.tar.gz"
info "Compressing image to ${imagefile}..."
sudo $TAR -zcpf ${imagefile} -C ${maindir}/root .
sudo "$TAR" -zcpf "${imagefile}" -C "${maindir}"/root .
if ! $disable_validation
then
mkdir -p ${maindir}/root_test
$TAR -zxpf ${imagefile} -C "${maindir}/root_test"
JUNEST_HOME="${maindir}/root_test" ${maindir}/root_test/opt/${CMD}/bin/${CMD} -f ${JUNEST_BASE}/lib/checks/check.sh
JUNEST_HOME="${maindir}/root_test" sudo -E ${maindir}/root_test/opt/${CMD}/bin/${CMD} -g ${JUNEST_BASE}/lib/checks/check.sh --run-root-tests
mkdir -p "${maindir}"/root_test
$TAR -zxpf "${imagefile}" -C "${maindir}/root_test"
JUNEST_HOME="${maindir}/root_test" "${JUNEST_BASE}"/lib/checks/check_all.sh
fi
sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD}
sudo cp "${maindir}"/output/"${imagefile}" "${ORIGIN_WD}"
builtin cd ${ORIGIN_WD}
builtin cd "${ORIGIN_WD}" || return 1
trap - QUIT EXIT ABRT KILL TERM INT
sudo rm -fr "$maindir"
set +x
}

View file

@ -11,26 +11,30 @@
function _run_env_as_xroot(){
local cmd=$1
local backend_args="$2"
shift 2
local no_copy_files="$3"
shift 3
check_same_arch
local uid=$UID
# SUDO_USER is more reliable compared to SUDO_UID
[ -z $SUDO_USER ] || uid=$SUDO_USER:$SUDO_GID
[[ -z $SUDO_USER ]] || uid=$SUDO_USER:$SUDO_GID
local main_cmd="${SH[@]}"
[ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")"
local args=()
[[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")")
# With chown the ownership of the files is assigned to the real user
trap - QUIT EXIT ABRT KILL TERM INT
trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT
# shellcheck disable=SC2064
trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT TERM INT
copy_common_files
if ! $no_copy_files
then
copy_common_files
fi
check_nested_env
JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}"
# shellcheck disable=SC2086
JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${DEFAULT_SH[@]}" "${args[@]}"
}
#######################################
@ -41,25 +45,31 @@ function _run_env_as_xroot(){
# UID (RO) : The user ID.
# SUDO_USER (RO) : The sudo user ID.
# SUDO_GID (RO) : The sudo group ID.
# SH (RO) : Contains the default command to run in JuNest.
# DEFAULT_SH (RO) : Contains the default command to run in JuNest.
# Arguments:
# backend_args ($1) : The arguments to pass to proot
# cmd ($2-?) : The command to run inside JuNest environment.
# Default command is defined by SH variable.
# backend_args ($1) : The arguments to pass to backend program
# no_copy_files ($2?) : If false it will copy some files in /etc
# from host to JuNest environment.
# cmd ($3-?) : The command to run inside JuNest environment.
# Default command is defined by DEFAULT_SH variable.
# Returns:
# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different.
# Output:
# - : The command output.
#######################################
function run_env_as_groot(){
local backend_args="$1"
shift
check_nested_env
local backend_command="${1:-$GROOT}"
local backend_args="$2"
local no_copy_files="$3"
shift 3
provide_common_bindings
local bindings=${RESULT}
unset RESULT
_run_env_as_xroot "$GROOT $bindings" "$backend_args" "$@"
_run_env_as_xroot "$backend_command $bindings" "$backend_args" "$no_copy_files" "$@"
}
#######################################
@ -70,19 +80,25 @@ function run_env_as_groot(){
# UID (RO) : The user ID.
# SUDO_USER (RO) : The sudo user ID.
# SUDO_GID (RO) : The sudo group ID.
# SH (RO) : Contains the default command to run in JuNest.
# DEFAULT_SH (RO) : Contains the default command to run in JuNest.
# Arguments:
# backend_args ($1) : The arguments to pass to proot
# cmd ($2-?) : The command to run inside JuNest environment.
# Default command is defined by SH variable.
# backend_args ($1) : The arguments to pass to backend program
# no_copy_files ($2?) : If false it will copy some files in /etc
# from host to JuNest environment.
# cmd ($3-?) : The command to run inside JuNest environment.
# Default command is defined by DEFAULT_SH variable.
# Returns:
# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different.
# Output:
# - : The command output.
#######################################
function run_env_as_chroot(){
local backend_args="$1"
shift
check_nested_env
_run_env_as_xroot chroot_cmd "$backend_args" "$@"
local backend_command="${1:-chroot_cmd}"
local backend_args="$2"
local no_copy_files="$3"
shift 3
_run_env_as_xroot "$backend_command" "$backend_args" "$no_copy_files" "$@"
}

View file

@ -1,4 +1,6 @@
#!/usr/bin/env bash
# shellcheck disable=SC2034
# shellcheck disable=SC1091
#
# This module contains all common functionalities for JuNest.
#
@ -18,30 +20,32 @@ ROOT_ACCESS_ERROR=105
NESTED_ENVIRONMENT=106
VARIABLE_NOT_SET=107
NO_CONFIG_FOUND=108
UNPRIVILEGED_USERNS_DISABLED=109
JUNEST_HOME=${JUNEST_HOME:-~/.${CMD}}
JUNEST_BASE=${JUNEST_BASE:-${JUNEST_HOME}/opt/junest}
JUNEST_TEMPDIR=${JUNEST_TEMPDIR:-/tmp}
# The update of the variable PATH ensures that the executables are
# found on different locations
PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH
PATH=/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:${HOME}/.local/bin:"$PATH"
# The executable uname is essential in order to get the architecture
# of the host system, so a fallback mechanism cannot be used for it.
UNAME=uname
UNAME="uname"
ARCH_LIST=('x86_64' 'x86' 'arm')
HOST_ARCH=$($UNAME -m)
if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ]
# To check all available architectures look here:
# https://wiki.archlinux.org/index.php/PKGBUILD#arch
if [[ $HOST_ARCH == "i686" ]] || [[ $HOST_ARCH == "i386" ]]
then
ARCH="x86"
LD_LIB="${JUNEST_HOME}/lib/ld-linux.so.2"
elif [ $HOST_ARCH == "x86_64" ]
elif [[ $HOST_ARCH == "x86_64" ]]
then
ARCH="x86_64"
LD_LIB="${JUNEST_HOME}/lib64/ld-linux-x86-64.so.2"
elif [[ $HOST_ARCH =~ .*(arm).* ]]
elif [[ $HOST_ARCH =~ .*(arm).* ]] || [[ $HOST_ARCH == "aarch64" ]]
then
ARCH="arm"
LD_LIB="${JUNEST_HOME}/lib/ld-linux-armhf.so.3"
@ -49,9 +53,11 @@ else
die "Unknown architecture ${HOST_ARCH}"
fi
MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo
MAIN_REPO=https://link.storjshare.io/s/jvb5tgarnjtt565fffa44spvyuga/junest-repo
MAIN_REPO=https://pub-a2af2344e8554f6c807bc3db355ae622.r2.dev
ENV_REPO=${MAIN_REPO}/${CMD}
DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch'
# shellcheck disable=SC2016
DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch'
ORIGIN_WD=$(pwd)
@ -62,24 +68,26 @@ ORIGIN_WD=$(pwd)
# different locations in the host OS.
# List of executables that are run inside JuNest:
SH=("/bin/sh" "--login")
DEFAULT_SH=("/bin/sh" "--login")
# List of executables that are run in the host OS:
PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}"
GROOT=${JUNEST_BASE}/bin/groot
BWRAP="${JUNEST_HOME}/usr/bin/bwrap"
PROOT="${JUNEST_HOME}/usr/bin/proot-${ARCH}"
GROOT="${JUNEST_HOME}/usr/bin/groot"
CLASSIC_CHROOT=chroot
WGET="wget --no-check-certificate"
WGET="wget --content-disposition --no-check-certificate"
CURL="curl -L -J -O -k"
TAR=tar
TAR="tar"
CHOWN="chown"
LN=ln
RM=rm
MKDIR=mkdir
GETENT=getent
CP=cp
LN="ln"
RM="rm"
MKDIR="mkdir"
GETENT="getent"
CP="cp"
ID="id"
# Used for checking user namespace in config.gz file
ZGREP=zgrep
UNSHARE=unshare
ZGREP="zgrep"
UNSHARE="unshare"
LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib"
@ -88,32 +96,32 @@ LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib"
# image.
function ln_cmd(){
$LN "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN "$@"
$LN "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$LN "$@"
}
function getent_cmd(){
$GETENT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$GETENT "$@"
$GETENT "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$GETENT "$@"
}
function cp_cmd(){
$CP "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CP "$@"
$CP "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$CP "$@"
}
function rm_cmd(){
$RM "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM "$@"
$RM "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$RM "$@"
}
function chown_cmd(){
$CHOWN "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN "$@"
$CHOWN "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$CHOWN "$@"
}
function mkdir_cmd(){
$MKDIR "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR "$@"
$MKDIR "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$MKDIR "$@"
}
function zgrep_cmd(){
# No need for LD_EXEC as zgrep is a POSIX shell script
$ZGREP "$@" || ${JUNEST_HOME}/usr/bin/$ZGREP "$@"
$ZGREP "$@" || "${JUNEST_HOME}"/usr/bin/$ZGREP "$@"
}
function download_cmd(){
@ -121,7 +129,7 @@ function download_cmd(){
}
function chroot_cmd(){
$CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@"
$CLASSIC_CHROOT "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$CLASSIC_CHROOT "$@"
}
function unshare_cmd(){
@ -129,27 +137,40 @@ function unshare_cmd(){
# with --user option available.
# Hence, give priority to the `unshare` executable in JuNest image.
# Also, unshare provides an environment in which /bin/sh maps to dash shell,
# therefore it ignores all the remaining SH arguments (i.e. --login) as
# therefore it ignores all the remaining DEFAULT_SH arguments (i.e. --login) as
# they are not supported by dash.
if $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE --user "${SH[0]}" "-c" ":"
if $LD_EXEC "${JUNEST_HOME}"/usr/bin/$UNSHARE --user "${DEFAULT_SH[0]}" "-c" ":"
then
$LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE "${@}"
elif $UNSHARE --user "${SH[0]}" "-c" ":"
$LD_EXEC "${JUNEST_HOME}"/usr/bin/$UNSHARE "${@}"
elif $UNSHARE --user "${DEFAULT_SH[0]}" "-c" ":"
then
$UNSHARE "$@"
else
die "Error: Something went wrong with unshare command. Exiting"
die "Error: Something went wrong while executing unshare command. Exiting"
fi
}
function bwrap_cmd(){
if $LD_EXEC "$BWRAP" --dev-bind / / "${DEFAULT_SH[0]}" "-c" ":"
then
$LD_EXEC "$BWRAP" "${@}"
else
die "Error: Something went wrong while executing bwrap command. Exiting"
fi
}
function proot_cmd(){
local proot_args="$1"
shift
if ${PROOT} ${proot_args} "${SH[@]}" "-c" ":"
# shellcheck disable=SC2086
if ${PROOT} ${proot_args} "${DEFAULT_SH[@]}" "-c" ":"
then
# shellcheck disable=SC2086
${PROOT} ${proot_args} "${@}"
elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":"
elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${DEFAULT_SH[@]}" "-c" ":"
then
warn "Warn: Proot is not properly working. Disabling SECCOMP and expect the application to run slowly in particular when it uses syscalls intensively."
warn "Try to use Linux namespace instead as it is more reliable: junest ns"
PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}"
else
die "Error: Something went wrong with proot command. Exiting"
@ -178,7 +199,7 @@ function check_nested_env() {
if [[ $JUNEST_ENV == "1" ]]
then
die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed"
elif [[ ! -z $JUNEST_ENV ]] && [[ $JUNEST_ENV != "0" ]]
elif [[ -n $JUNEST_ENV ]] && [[ $JUNEST_ENV != "0" ]]
then
die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set"
fi
@ -200,7 +221,7 @@ function check_nested_env() {
# None
#######################################
function check_same_arch() {
source ${JUNEST_HOME}/etc/junest/info
source "${JUNEST_HOME}"/etc/junest/info
[ "$JUNEST_ARCH" != "$ARCH" ] && \
die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH"
return 0
@ -225,7 +246,7 @@ function check_same_arch() {
function provide_common_bindings(){
RESULT=""
local re='(.*):.*'
for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME"
for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME" "/run/user/$($ID -u)"
do
if [[ $bind =~ $re ]]
then
@ -258,24 +279,26 @@ function copy_passwd_and_group(){
# is configured.
# Try to at least get the current user via `getent passwd $USER` since it uses
# a more reliable and faster system call (getpwnam(3)).
if ! getent_cmd passwd > ${JUNEST_HOME}/etc/passwd || \
! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/passwd
if ! getent_cmd passwd > "${JUNEST_HOME}"/etc/passwd || \
! getent_cmd passwd "${USER}" >> "${JUNEST_HOME}"/etc/passwd
then
warn "getent command failed or does not exist. Binding directly from /etc/passwd."
copy_file /etc/passwd ${JUNEST_HOME}/etc/passwd
copy_file /etc/passwd
fi
if ! getent_cmd group > ${JUNEST_HOME}/etc/group
if ! getent_cmd group > "${JUNEST_HOME}"/etc/group
then
warn "getent command failed or does not exist. Binding directly from /etc/group."
copy_file /etc/group ${JUNEST_HOME}/etc/group
copy_file /etc/group
fi
return 0
}
function copy_file() {
local file="${1}"
[[ -r "$file" ]] && cp_cmd "$file" "${JUNEST_HOME}/$file"
# -f option ensure to remove destination file if it cannot be opened
# https://github.com/fsquillace/junest/issues/284
[[ -r "$file" ]] && cp_cmd -f "$file" "${JUNEST_HOME}/$file"
return 0
}
@ -286,3 +309,27 @@ function copy_common_files() {
copy_file /etc/resolv.conf
return 0
}
function prepare_archlinux() {
local sudo=${1:-sudo}
local pacman_options="--noconfirm --disable-download-timeout"
# shellcheck disable=SC2086
$sudo pacman $pacman_options -Syy
$sudo pacman-key --init
if [[ $(uname -m) == *"arm"* ]]
then
# shellcheck disable=SC2086
$sudo pacman $pacman_options -S archlinuxarm-keyring
$sudo pacman-key --populate archlinuxarm
else
# shellcheck disable=SC2086
$sudo pacman $pacman_options -S archlinux-keyring
$sudo pacman-key --populate archlinux
fi
# shellcheck disable=SC2086
$sudo pacman $pacman_options -Su
}

View file

@ -1,9 +1,8 @@
#!/usr/bin/env bash
#
# This module contains all namespace functionalities for JuNest.
# This module contains functionalities for accessing to JuNest via bubblewrap.
#
# http://man7.org/linux/man-pages/man7/namespaces.7.html
# http://man7.org/linux/man-pages/man2/unshare.2.html
# https://github.com/containers/bubblewrap
#
# Dependencies:
# - lib/utils/utils.sh
@ -11,10 +10,29 @@
#
# vim: ft=sh
# shellcheck disable=SC2027
COMMON_BWRAP_OPTION="--bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --bind /sys /sys --bind /proc /proc --dev-bind-try /dev /dev --bind-try "/run/user/$($ID -u)" "/run/user/$($ID -u)" --unshare-user-try"
CONFIG_PROC_FILE="/proc/config.gz"
CONFIG_BOOT_FILE="/boot/config-$($UNAME -r)"
PROC_USERNS_CLONE_FILE="/proc/sys/kernel/unprivileged_userns_clone"
PROC_USERNS_FILE="/proc/$$/ns/user"
function _is_user_namespace_enabled() {
if [[ -L $PROC_USERNS_FILE ]]
then
return 0
fi
if [[ -e $PROC_USERNS_CLONE_FILE ]]
then
# `-q` option in zgrep may cause a gzip: stdout: Broken pipe
# Use redirect to /dev/null instead
if zgrep_cmd "1" "$PROC_USERNS_CLONE_FILE" > /dev/null
then
return 0
fi
fi
local config_file=""
if [[ -e $CONFIG_PROC_FILE ]]
then
@ -23,78 +41,125 @@ function _is_user_namespace_enabled() {
then
config_file=$CONFIG_BOOT_FILE
else
return $NOT_EXISTING_FILE
return "$NOT_EXISTING_FILE"
fi
if ! zgrep_cmd -q "CONFIG_USER_NS=y" $config_file
# `-q` option in zgrep may cause a gzip: stdout: Broken pipe
# Use redirect to /dev/null instead
if ! zgrep_cmd "CONFIG_USER_NS=y" "$config_file" > /dev/null
then
return $NO_CONFIG_FOUND
return "$NO_CONFIG_FOUND"
fi
return "$UNPRIVILEGED_USERNS_DISABLED"
}
function _check_user_namespace() {
set +e
_is_user_namespace_enabled
case $? in
$NOT_EXISTING_FILE) warn "Could not understand if user namespace is enabled. No config.gz file found. Proceeding anyway..." ;;
$NO_CONFIG_FOUND) warn "User namespace is not enabled or Kernel too old (<3.8). Proceeding anyway..." ;;
"$NOT_EXISTING_FILE") warn "Could not understand if user namespace is enabled. No config.gz file found. Proceeding anyway..." ;;
"$NO_CONFIG_FOUND") warn "Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway..." ;;
"$UNPRIVILEGED_USERNS_DISABLED") warn "Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1" ;;
esac
set -e
}
function _run_env_with_namespace(){
local backend_args="$1"
shift
check_nested_env
provide_common_bindings
local bindings=${RESULT}
unset RESULT
# Use option -n in groot because umount do not work sometimes.
# As soon as the process terminates, the namespace
# will terminate too with its own mounted directories.
if [[ "$1" != "" ]]
then
JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT --no-umount --recursive $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")"
else
JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT --no-umount --recursive $bindings $backend_args "$JUNEST_HOME" "${SH[@]}"
fi
}
#######################################
# Run JuNest as fakeroot user via user namespace.
# Run JuNest as fakeroot via bwrap
#
# Globals:
# JUNEST_HOME (RO) : The JuNest home directory.
# GROOT (RO) : The groot program.
# SH (RO) : Contains the default command to run in JuNest.
# JUNEST_HOME (RO) : The JuNest home directory.
# DEFAULT_SH (RO) : Contains the default command to run in JuNest.
# BWRAP (RO): : The location of the bwrap binary.
# Arguments:
# backend_args ($1) : The arguments to pass to proot
# cmd ($2-?) : The command to run inside JuNest environment.
# Default command is defined by SH variable.
# backend_args ($1) : The arguments to pass to bwrap
# no_copy_files ($2?) : If false it will copy some files in /etc
# from host to JuNest environment.
# cmd ($3-?) : The command to run inside JuNest environment.
# Default command is defined by DEFAULT_SH variable.
# Returns:
# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different.
# Depends on the unshare command outcome.
# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different.
# $ROOT_ACCESS_ERROR : If the user is the real root.
# Output:
# - : The command output.
# - : The command output.
#######################################
function run_env_with_namespace() {
local backend_args="$1"
shift
function run_env_as_bwrap_fakeroot(){
check_nested_env
local backend_command="${1:-$BWRAP}"
local backend_args="$2"
local no_copy_files="$3"
shift 3
_check_user_namespace
check_same_arch
copy_common_files
copy_file /etc/hosts.equiv
copy_file /etc/netgroup
copy_file /etc/networks
# No need for localtime as it is setup during the image build
#copy_file /etc/localtime
copy_passwd_and_group
if ! $no_copy_files
then
copy_common_files
fi
_run_env_with_namespace "$backend_args" "$@"
local args=()
[[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")")
# Fix PATH to /usr/bin to make sudo working and avoid polluting with host related bin paths
# shellcheck disable=SC2086
PATH="/usr/bin" BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}"
}
#######################################
# Run JuNest as normal user via bwrap.
#
# Globals:
# JUNEST_HOME (RO) : The JuNest home directory.
# DEFAULT_SH (RO) : Contains the default command to run in JuNest.
# BWRAP (RO): : The location of the bwrap binary.
# Arguments:
# backend_args ($1) : The arguments to pass to bwrap
# no_copy_files ($2?) : If false it will copy some files in /etc
# from host to JuNest environment.
# cmd ($3-?) : The command to run inside JuNest environment.
# Default command is defined by DEFAULT_SH variable.
# Returns:
# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different.
# Output:
# - : The command output.
#######################################
function run_env_as_bwrap_user() {
check_nested_env
local backend_command="${1:-$BWRAP}"
local backend_args="$2"
local no_copy_files="$3"
shift 3
_check_user_namespace
check_same_arch
if ! $no_copy_files
then
copy_common_files
copy_file /etc/hosts.equiv
copy_file /etc/netgroup
copy_file /etc/networks
# No need for localtime as it is setup during the image build
#copy_file /etc/localtime
copy_passwd_and_group
fi
local args=()
[[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")")
# Resets PATH to avoid polluting with host related bin paths
# shellcheck disable=SC2086
PATH='' BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION $backend_args "${DEFAULT_SH[@]}" "${args[@]}"
}

View file

@ -1,4 +1,5 @@
#!/usr/bin/env bash
# shellcheck disable=SC1091
#
# This module contains all proot functionalities for JuNest.
#
@ -9,36 +10,39 @@
# vim: ft=sh
function _run_env_with_proot(){
local proot_args="$1"
shift
local backend_command="${1:-$PROOT}"
local backend_args="$2"
shift 2
check_nested_env
if [ "$1" != "" ]
then
JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")"
else
JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}"
fi
local args=()
[[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")")
# Resets PATH to avoid polluting with host related bin paths
PATH='' PROOT="${backend_command}" JUNEST_ENV=1 proot_cmd "${backend_args}" "${DEFAULT_SH[@]}" "${args[@]}"
}
function _run_env_with_qemu(){
local proot_args="$1"
source ${JUNEST_HOME}/etc/junest/info
local backend_command="$1"
local backend_args="$2"
shift 2
source "${JUNEST_HOME}"/etc/junest/info
if [ "$JUNEST_ARCH" != "$ARCH" ]
then
local qemu_bin="qemu-$JUNEST_ARCH-static-$ARCH"
local qemu_symlink="/tmp/${qemu_bin}-$RANDOM"
trap - QUIT EXIT ABRT KILL TERM INT
trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT KILL TERM INT
# shellcheck disable=SC2064
trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT TERM INT
warn "Emulating $NAME via QEMU..."
[ -e ${qemu_symlink} ] || \
ln_cmd -s ${JUNEST_HOME}/opt/qemu/${qemu_bin} ${qemu_symlink}
proot_args="-q ${qemu_symlink} $proot_args"
[[ -e ${qemu_symlink} ]] || \
ln_cmd -s "${JUNEST_HOME}/bin/${qemu_bin}" "${qemu_symlink}"
backend_args="-q ${qemu_symlink} $backend_args"
fi
shift
_run_env_with_proot "$proot_args" "${@}"
_run_env_with_proot "${backend_command}" "$backend_args" "${@}"
}
#######################################
@ -47,23 +51,32 @@ function _run_env_with_qemu(){
# Globals:
# JUNEST_HOME (RO) : The JuNest home directory.
# EUID (RO) : The user ID.
# SH (RO) : Contains the default command to run in JuNest.
# DEFAULT_SH (RO) : Contains the default command to run in JuNest.
# Arguments:
# backend_args ($1) : The arguments to pass to proot
# cmd ($2-?) : The command to run inside JuNest environment.
# Default command is defined by SH variable.
# no_copy_files ($2?) : If false it will copy some files in /etc
# from host to JuNest environment.
# cmd ($3-?) : The command to run inside JuNest environment.
# Default command is defined by DEFAULT_SH variable.
# Returns:
# $ROOT_ACCESS_ERROR : If the user is the real root.
# Output:
# - : The command output.
#######################################
function run_env_as_fakeroot(){
function run_env_as_proot_fakeroot(){
(( EUID == 0 )) && \
die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead."
local backend_args="$1"
shift
die_on_status "$ROOT_ACCESS_ERROR" "You cannot access with root privileges. Use --groot option instead."
check_nested_env
copy_common_files
local backend_command="$1"
local backend_args="$2"
local no_copy_files="$3"
shift 3
if ! $no_copy_files
then
copy_common_files
fi
provide_common_bindings
local bindings=${RESULT}
@ -71,7 +84,7 @@ function run_env_as_fakeroot(){
# An alternative is via -S option:
#_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}"
_run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $backend_args" "$@"
_run_env_with_qemu "$backend_command" "-0 ${bindings} -r ${JUNEST_HOME} $backend_args" "$@"
}
#######################################
@ -80,37 +93,46 @@ function run_env_as_fakeroot(){
# Globals:
# JUNEST_HOME (RO) : The JuNest home directory.
# EUID (RO) : The user ID.
# SH (RO) : Contains the default command to run in JuNest.
# DEFAULT_SH (RO) : Contains the default command to run in JuNest.
# Arguments:
# backend_args ($1) : The arguments to pass to proot
# cmd ($2-?) : The command to run inside JuNest environment.
# Default command is defined by SH variable.
# no_copy_files ($2?) : If false it will copy some files in /etc
# from host to JuNest environment.
# cmd ($3-?) : The command to run inside JuNest environment.
# Default command is defined by DEFAULT_SH variable.
# Returns:
# $ROOT_ACCESS_ERROR : If the user is the real root.
# Output:
# - : The command output.
#######################################
function run_env_as_user(){
function run_env_as_proot_user(){
(( EUID == 0 )) && \
die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead."
local backend_args="$1"
shift
die_on_status "$ROOT_ACCESS_ERROR" "You cannot access with root privileges. Use --groot option instead."
check_nested_env
# Files to bind are visible in `proot --help`.
# This function excludes /etc/mtab file so that
# it will not give conflicts with the related
# symlink in the Arch Linux image.
copy_common_files
copy_file /etc/hosts.equiv
copy_file /etc/netgroup
copy_file /etc/networks
# No need for localtime as it is setup during the image build
#copy_file /etc/localtime
copy_passwd_and_group
local backend_command="$1"
local backend_args="$2"
local no_copy_files="$3"
shift 3
if ! $no_copy_files
then
# Files to bind are visible in `proot --help`.
# This function excludes /etc/mtab file so that
# it will not give conflicts with the related
# symlink in the Arch Linux image.
copy_common_files
copy_file /etc/hosts.equiv
copy_file /etc/netgroup
copy_file /etc/networks
# No need for localtime as it is setup during the image build
#copy_file /etc/localtime
copy_passwd_and_group
fi
provide_common_bindings
local bindings=${RESULT}
unset RESULT
_run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $backend_args" "$@"
_run_env_with_qemu "$backend_command" "${bindings} -r ${JUNEST_HOME} $backend_args" "$@"
}

View file

@ -22,7 +22,7 @@
# None
#######################################
function is_env_installed(){
[ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0
[[ -d "$JUNEST_HOME" ]] && [[ "$(ls -A "$JUNEST_HOME")" ]] && return 0
return 1
}
@ -30,7 +30,7 @@ function is_env_installed(){
function _cleanup_build_directory(){
local maindir=$1
check_not_null "$maindir"
builtin cd $ORIGIN_WD
builtin cd "$ORIGIN_WD" || return 1
trap - QUIT EXIT ABRT KILL TERM INT
rm_cmd -fr "$maindir"
}
@ -40,7 +40,8 @@ function _prepare_build_directory(){
local maindir=$1
check_not_null "$maindir"
trap - QUIT EXIT ABRT KILL TERM INT
trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT
# shellcheck disable=SC2064
trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT TERM INT
}
@ -51,11 +52,18 @@ function _setup_env(){
is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME"
mkdir_cmd -p "${JUNEST_HOME}"
$TAR -zxpf ${imagepath} -C ${JUNEST_HOME}
info "The default mirror URL is ${DEFAULT_MIRROR}."
$TAR -zxpf "${imagepath}" -C "${JUNEST_HOME}"
info "${NAME} installed successfully!"
echo
info "Default mirror URL set to: ${DEFAULT_MIRROR}"
info "You can change the pacman mirror URL in /etc/pacman.d/mirrorlist according to your location:"
info " \$EDITOR ${JUNEST_HOME}/etc/pacman.d/mirrorlist"
echo
info "Remember to refresh the package databases from the server:"
info " pacman -Syy"
info "${NAME} installed successfully"
echo
info "To install packages from AUR follow the wiki here:"
info "https://github.com/fsquillace/junest#install-packages-from-aur"
}
@ -70,7 +78,6 @@ function _setup_env(){
# the JuNest system from the image.
# ENV_REPO (RO) : URL of the site containing JuNest images.
# NAME (RO) : The JuNest name.
# DEFAULT_MIRROR (RO) : Arch Linux URL mirror.
# Arguments:
# arch ($1?) : The JuNest architecture image to download.
# Defaults to the host architecture
@ -81,21 +88,22 @@ function _setup_env(){
#######################################
function setup_env(){
local arch=${1:-$ARCH}
contains_element $arch "${ARCH_LIST[@]}" || \
die_on_status $NOT_AVAILABLE_ARCH "The architecture is not one of: ${ARCH_LIST[@]}"
contains_element "$arch" "${ARCH_LIST[@]}" || \
die_on_status "$NOT_AVAILABLE_ARCH" "The architecture is not one of: ${ARCH_LIST[*]}"
local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX)
_prepare_build_directory $maindir
local maindir
maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t "${CMD}".XXXXXXXXXX)
_prepare_build_directory "$maindir"
info "Downloading ${NAME}..."
builtin cd ${maindir}
builtin cd "${maindir}" || return 1
local imagefile=${CMD}-${arch}.tar.gz
download_cmd ${ENV_REPO}/${imagefile}
download_cmd "${ENV_REPO}/${imagefile}"
info "Installing ${NAME}..."
_setup_env ${maindir}/${imagefile}
_setup_env "${maindir}/${imagefile}"
_cleanup_build_directory ${maindir}
_cleanup_build_directory "${maindir}"
}
#######################################
@ -105,7 +113,6 @@ function setup_env(){
# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs
# to be installed.
# NAME (RO) : The JuNest name.
# DEFAULT_MIRROR (RO) : Arch Linux URL mirror.
# Arguments:
# imagefile ($1) : The JuNest image file.
# Returns:
@ -116,10 +123,10 @@ function setup_env(){
function setup_env_from_file(){
local imagefile=$1
check_not_null "$imagefile"
[ ! -e ${imagefile} ] && die_on_status $NOT_EXISTING_FILE "Error: The ${NAME} image file ${imagefile} does not exist"
[[ ! -e ${imagefile} ]] && die_on_status "$NOT_EXISTING_FILE" "Error: The ${NAME} image file ${imagefile} does not exist"
info "Installing ${NAME} from ${imagefile}..."
_setup_env ${imagefile}
_setup_env "${imagefile}"
}
#######################################
@ -136,18 +143,18 @@ function setup_env_from_file(){
#######################################
function delete_env(){
! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return
if mountpoint -q ${JUNEST_HOME}
if mountpoint -q "${JUNEST_HOME}"
then
info "There are mounted directories inside ${JUNEST_HOME}"
if ! umount --force ${JUNEST_HOME}
if ! umount --force "${JUNEST_HOME}"
then
error "Cannot umount directories in ${JUNEST_HOME}"
die "Try to delete ${NAME} using root permissions"
fi
fi
# the CA directories are read only and can be deleted only by changing the mod
chmod -R +w ${JUNEST_HOME}/etc/ca-certificates
if rm_cmd -rf ${JUNEST_HOME}/*
chmod -R +w "${JUNEST_HOME}"/etc/ca-certificates
if rm_cmd -rf "${JUNEST_HOME}"
then
info "${NAME} deleted in ${JUNEST_HOME}"
else

60
lib/core/wrappers.sh Normal file
View file

@ -0,0 +1,60 @@
#!/usr/bin/env bash
#
# Dependencies:
# None
#
# vim: ft=sh
#######################################
# Create bin wrappers
#
# Globals:
# JUNEST_HOME (RO) : The JuNest home directory.
# Arguments:
# force ($1?) : Create bin wrappers even if the bin file exists.
# Defaults to false.
# Returns:
# None
# Output:
# None
#######################################
function create_wrappers() {
local force=${1:-false}
local bin_path=${2:-/usr/bin}
bin_path=${bin_path%/}
mkdir -p "${JUNEST_HOME}${bin_path}_wrappers"
# Arguments inside a variable (i.e. `JUNEST_ARGS`) separated by quotes
# are not recognized normally unless using `eval`. More info here:
# https://github.com/fsquillace/junest/issues/262
# https://github.com/fsquillace/junest/pull/287
cat <<EOF > "${JUNEST_HOME}/usr/bin/junest_wrapper"
#!/usr/bin/env bash
eval "junest_args_array=(\${JUNEST_ARGS:-ns})"
junest "\${junest_args_array[@]}" -- \$(basename \${0}) "\$@"
EOF
chmod +x "${JUNEST_HOME}/usr/bin/junest_wrapper"
cd "${JUNEST_HOME}${bin_path}" || return 1
for file in *
do
[[ -d $file ]] && continue
# Symlinks outside junest appear as broken even though they are correct
# within a junest session. The following do not skip broken symlinks:
[[ -x $file || -L $file ]] || continue
if [[ -e ${JUNEST_HOME}${bin_path}_wrappers/$file ]] && ! $force
then
continue
fi
rm -f "${JUNEST_HOME}${bin_path}_wrappers/$file"
ln -s "${JUNEST_HOME}/usr/bin/junest_wrapper" "${JUNEST_HOME}${bin_path}_wrappers/$file"
done
# Remove wrappers no longer needed
cd "${JUNEST_HOME}${bin_path}_wrappers" || return 1
for file in *
do
[[ -e ${JUNEST_HOME}${bin_path}/$file || -L ${JUNEST_HOME}${bin_path}/$file ]] || rm -f "$file"
done
}

View file

@ -50,7 +50,7 @@ function echoerr() {
# Message printed to stderr.
#######################################
function die() {
error $@
error "$@"
exit 1
}
@ -70,8 +70,8 @@ function die() {
function die_on_status() {
status=$1
shift
error $@
exit $status
error "$@"
exit "$status"
}
#######################################
@ -87,7 +87,7 @@ function die_on_status() {
# Message printed to stderr.
#######################################
function error() {
echoerr -e "\033[1;31m$@\033[0m"
echoerr -e "\033[1;31m$*\033[0m"
}
#######################################
@ -104,7 +104,7 @@ function error() {
#######################################
function warn() {
# $@: msg (mandatory) - str: Message to print
echoerr -e "\033[1;33m$@\033[0m"
echoerr -e "\033[1;33m$*\033[0m"
}
#######################################
@ -120,7 +120,7 @@ function warn() {
# Message printed to stdout.
#######################################
function info(){
echo -e "\033[1;36m$@\033[0m"
echo -e "\033[1;36m$*\033[0m"
}
#######################################
@ -142,12 +142,12 @@ function info(){
function ask(){
local question=$1
local default_answer=$2
check_not_null $question
check_not_null "$question"
if [ ! -z "$default_answer" ]
if [ -n "$default_answer" ]
then
local answers="Y y N n"
[[ "$answers" =~ "$default_answer" ]] || { error "The default answer: $default_answer is wrong."; return $WRONG_ANSWER; }
[[ "$answers" =~ $default_answer ]] || { error "The default answer: $default_answer is wrong."; return $WRONG_ANSWER; }
fi
local default="Y"
@ -156,12 +156,13 @@ function ask(){
local other="n"
[ "$default" == "N" ] && other="y"
local prompt=$(info "$question (${default}/${other})> ")
local prompt
prompt=$(info "$question (${default}/${other})> ")
local res="none"
while [ "$res" != "Y" ] && [ "$res" != "N" ] && [ "$res" != "" ];
do
read -p "$prompt" res
read -r -p "$prompt" res
res=$(echo "$res" | tr '[:lower:]' '[:upper:]')
done
@ -170,36 +171,31 @@ function ask(){
[ "$res" == "Y" ]
}
function check_and_trap() {
local sigs="${@:2:${#@}}"
local traps="$(trap -p $sigs)"
[[ $traps ]] && die "Attempting to overwrite existing $sigs trap: $traps"
trap $@
}
function check_and_force_trap() {
local sigs="${@:2:${#@}}"
local traps="$(trap -p $sigs)"
[[ $traps ]] && warn "Attempting to overwrite existing $sigs trap: $traps"
trap $@
}
function insert_quotes_on_spaces(){
# It inserts quotes between arguments.
# Useful to preserve quotes on command
# to be used inside sh -c/bash -c
C=''
local C=""
whitespace="[[:space:]]"
for i in "$@"
do
if [[ $i =~ $whitespace ]]
then
C="$C \"$i\""
temp_C="\"$i\""
else
C="$C $i"
temp_C="$i"
fi
# Handle edge case when C is empty to avoid adding an extra space
if [[ -z $C ]]
then
C="$temp_C"
else
C="$C $temp_C"
fi
done
echo $C
echo "$C"
}
contains_element () {

View file

@ -1,6 +1,7 @@
#!/usr/bin/env bash
# shellcheck disable=SC1091
source "$(dirname $0)/../utils/utils.sh"
source "$(dirname "$0")/../utils/utils.sh"
# Disable the exiterr
set +e
@ -10,12 +11,12 @@ function oneTimeSetUp(){
}
function test_check_no_tabs(){
assertCommandFailOnStatus 1 grep -R "$(printf '\t')" $(dirname $0)/../../bin/*
assertEquals "" "$(cat $STDOUTF)"
assertEquals "" "$(cat $STDERRF)"
assertCommandFailOnStatus 1 grep -R "$(printf '\t')" $(dirname $0)/../../lib/*
assertEquals "" "$(cat $STDOUTF)"
assertEquals "" "$(cat $STDERRF)"
assertCommandFailOnStatus 1 grep -R "$(printf '\t')" "$(dirname "$0")"/../../bin/*
assertEquals "" "$(cat "$STDOUTF")"
assertEquals "" "$(cat "$STDERRF")"
assertCommandFailOnStatus 1 grep -R "$(printf '\t')" "$(dirname "$0")"/../../lib/*
assertEquals "" "$(cat "$STDOUTF")"
assertEquals "" "$(cat "$STDERRF")"
}
source $(dirname $0)/../utils/shunit2
source "$(dirname "$0")"/../utils/shunit2

View file

@ -1,13 +0,0 @@
#!/bin/sh
set -ex
VERSION=$1
cd /tmp
wget http://ftp.gnu.org/gnu/bash/bash-$VERSION.tar.gz
tar -zxf bash-$VERSION.tar.gz
cd /tmp/bash-$VERSION*
./configure
make
sudo make install

View file

@ -1,6 +1,7 @@
#!/bin/bash
# shellcheck disable=SC1091
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..)
source "$JUNEST_ROOT/tests/utils/utils.sh"
@ -28,40 +29,97 @@ function tearDown(){
function init_mocks() {
chroot_cmd() {
# shellcheck disable=SC2317
[ "$JUNEST_ENV" != "1" ] && return 1
echo "chroot_cmd $@"
# shellcheck disable=SC2317
echo "chroot_cmd $*"
}
# shellcheck disable=SC2034
GROOT=chroot_cmd
mychroot() {
# shellcheck disable=SC2317
echo mychroot "$*"
}
}
function test_run_env_as_groot_cmd(){
assertCommandSuccess run_env_as_groot "" pwd
assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_groot "" "" "false" pwd
assertEquals "chroot_cmd -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")"
}
function test_run_env_as_groot_no_cmd(){
assertCommandSuccess run_env_as_groot ""
assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_groot "" "" "false" ""
assertEquals "chroot_cmd -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat "$STDOUTF")"
}
function test_run_env_as_groot_with_backend_command(){
assertCommandSuccess run_env_as_groot "mychroot" "" "false" ""
assertEquals "mychroot -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat "$STDOUTF")"
}
function test_run_env_as_groot_no_copy(){
assertCommandSuccess run_env_as_groot "" "" "true" pwd
assertEquals "chroot_cmd -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")"
[[ ! -e ${JUNEST_HOME}/etc/hosts ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/host.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]]
assertEquals 0 $?
}
function test_run_env_as_groot_nested_env(){
JUNEST_ENV=1
assertCommandFailOnStatus 106 run_env_as_groot "" "" "false" ""
unset JUNEST_ENV
}
function test_run_env_as_groot_cmd_with_backend_args(){
assertCommandSuccess run_env_as_groot "-n -b /home/blah" pwd
assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_groot "" "-n -b /home/blah" "false" pwd
assertEquals "chroot_cmd -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")"
}
function test_run_env_as_chroot_cmd(){
assertCommandSuccess run_env_as_chroot "" pwd
assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_chroot "" "" "false" pwd
assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")"
}
function test_run_env_as_chroot_no_cmd(){
assertCommandSuccess run_env_as_chroot ""
assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_chroot "" "" "false" ""
assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login" "$(cat "$STDOUTF")"
}
function test_run_env_as_chroot_with_backend_command(){
assertCommandSuccess run_env_as_chroot "mychroot" "" "false" ""
assertEquals "mychroot $JUNEST_HOME /bin/sh --login" "$(cat "$STDOUTF")"
}
function test_run_env_as_chroot_no_copy(){
assertCommandSuccess run_env_as_chroot "" "" "true" pwd
assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")"
[[ ! -e ${JUNEST_HOME}/etc/hosts ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/host.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]]
assertEquals 0 $?
}
function test_run_env_as_choot_nested_env(){
JUNEST_ENV=1
assertCommandFailOnStatus 106 run_env_as_chroot "" "" "false" ""
unset JUNEST_ENV
}
function test_run_env_as_chroot_cmd_with_backend_args(){
assertCommandSuccess run_env_as_chroot "-n -b /home/blah" pwd
assertEquals "chroot_cmd -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_chroot "" "-n -b /home/blah" "false" pwd
assertEquals "chroot_cmd -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")"
}
source $JUNEST_ROOT/tests/utils/shunit2
source "$JUNEST_ROOT"/tests/utils/shunit2

View file

@ -1,6 +1,7 @@
#!/bin/bash
# shellcheck disable=SC1091
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..)
source "$JUNEST_ROOT/tests/utils/utils.sh"
@ -21,47 +22,59 @@ function oneTimeTearDown(){
function setUp(){
ld_exec_mock() {
echo "ld_exec $@"
# shellcheck disable=SC2317
echo "ld_exec $*"
}
# shellcheck disable=SC2317
ld_exec_mock_false() {
echo "ld_exec $@"
echo "ld_exec $*"
return 1
}
# shellcheck disable=SC2034
LD_EXEC=ld_exec_mock
unshare_mock() {
echo "unshare $@"
# shellcheck disable=SC2317
echo "unshare $*"
}
# shellcheck disable=SC2034
UNSHARE=unshare_mock
# shellcheck disable=SC2317
bwrap_mock() {
echo "bwrap $*"
}
# shellcheck disable=SC2034
BWRAP=bwrap_mock
}
function test_ln(){
LN=echo assertCommandSuccess ln_cmd -s ln_file new_file
assertEquals "-s ln_file new_file" "$(cat $STDOUTF)"
LN="echo" assertCommandSuccess ln_cmd -s ln_file new_file
assertEquals "-s ln_file new_file" "$(cat "$STDOUTF")"
LN=false assertCommandSuccess ln_cmd -s ln_file new_file
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat $STDOUTF)"
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat "$STDOUTF")"
LN=false LD_EXEC=false assertCommandFail ln_cmd
}
function test_getent(){
GETENT=echo assertCommandSuccess getent_cmd passwd
assertEquals "passwd" "$(cat $STDOUTF)"
GETENT="echo" assertCommandSuccess getent_cmd passwd
assertEquals "passwd" "$(cat "$STDOUTF")"
GETENT=false assertCommandSuccess getent_cmd passwd
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat $STDOUTF)"
GETENT="false" assertCommandSuccess getent_cmd passwd
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat "$STDOUTF")"
GETENT=false LD_EXEC=false assertCommandFail getent_cmd
}
function test_cp(){
CP=echo assertCommandSuccess cp_cmd passwd
assertEquals "passwd" "$(cat $STDOUTF)"
CP="echo" assertCommandSuccess cp_cmd passwd
assertEquals "passwd" "$(cat "$STDOUTF")"
CP=false assertCommandSuccess cp_cmd passwd
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat $STDOUTF)"
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat "$STDOUTF")"
CP=false LD_EXEC=false assertCommandFail cp_cmd
}
@ -71,7 +84,9 @@ function test_download(){
CURL=/bin/false
assertCommandSuccess download_cmd
# shellcheck disable=SC2034
WGET=/bin/false
# shellcheck disable=SC2034
CURL=/bin/true
assertCommandSuccess download_cmd
@ -79,69 +94,77 @@ function test_download(){
}
function test_rm(){
RM=echo assertCommandSuccess rm_cmd rm_file
assertEquals "rm_file" "$(cat $STDOUTF)"
RM="echo" assertCommandSuccess rm_cmd rm_file
assertEquals "rm_file" "$(cat "$STDOUTF")"
RM=false assertCommandSuccess rm_cmd rm_file
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat $STDOUTF)"
RM="false" assertCommandSuccess rm_cmd rm_file
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat "$STDOUTF")"
RM=false LD_EXEC=false assertCommandFail rm_cmd rm_file
}
function test_chown(){
local id=$(id -u)
local id
id=$(id -u)
CHOWN=echo assertCommandSuccess chown_cmd $id chown_file
assertEquals "$id chown_file" "$(cat $STDOUTF)"
CHOWN="echo" assertCommandSuccess chown_cmd "$id" chown_file
assertEquals "$id chown_file" "$(cat "$STDOUTF")"
CHOWN=false assertCommandSuccess chown_cmd $id chown_file
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat $STDOUTF)"
CHOWN="false" assertCommandSuccess chown_cmd "$id" chown_file
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat "$STDOUTF")"
CHOWN=false LD_EXEC=false assertCommandFail chown_cmd $id chown_file
CHOWN=false LD_EXEC=false assertCommandFail chown_cmd "$id" chown_file
}
function test_mkdir(){
MKDIR=echo assertCommandSuccess mkdir_cmd -p new_dir/new_dir
assertEquals "-p new_dir/new_dir" "$(cat $STDOUTF)"
MKDIR="echo" assertCommandSuccess mkdir_cmd -p new_dir/new_dir
assertEquals "-p new_dir/new_dir" "$(cat "$STDOUTF")"
MKDIR=false assertCommandSuccess mkdir_cmd -p new_dir/new_dir
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat $STDOUTF)"
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat "$STDOUTF")"
MKDIR=false LD_EXEC=false assertCommandFail mkdir_cmd -p new_dir/new_dir
}
function test_zgrep(){
ZGREP=echo assertCommandSuccess zgrep_cmd new_file
assertEquals "new_file" "$(cat $STDOUTF)"
ZGREP="echo" assertCommandSuccess zgrep_cmd new_file
assertEquals "new_file" "$(cat "$STDOUTF")"
mkdir -p ${JUNEST_HOME}/usr/bin
touch ${JUNEST_HOME}/usr/bin/false
chmod +x ${JUNEST_HOME}/usr/bin/false
mkdir -p "${JUNEST_HOME}"/usr/bin
touch "${JUNEST_HOME}"/usr/bin/false
chmod +x "${JUNEST_HOME}"/usr/bin/false
echo -e "#!/bin/bash\necho zgrep" > ${JUNEST_HOME}/usr/bin/false
echo -e "#!/bin/bash\necho zgrep" > "${JUNEST_HOME}"/usr/bin/false
ZGREP=false assertCommandSuccess zgrep_cmd new_file
assertEquals "zgrep" "$(cat $STDOUTF)"
assertEquals "zgrep" "$(cat "$STDOUTF")"
echo -e "#!/bin/bash\nexit 1" > ${JUNEST_HOME}/usr/bin/false
echo -e "#!/bin/bash\nexit 1" > "${JUNEST_HOME}"/usr/bin/false
ZGREP=false assertCommandFail zgrep_cmd new_file
}
function test_unshare(){
assertCommandSuccess unshare_cmd new_program
assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE --user /bin/sh -c :\nld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE new_program")" "$(cat $STDOUTF)"
assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE --user /bin/sh -c :\nld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE new_program")" "$(cat "$STDOUTF")"
LD_EXEC=ld_exec_mock_false assertCommandSuccess unshare_cmd new_program
assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/unshare_mock --user /bin/sh -c :\nunshare --user /bin/sh -c :\nunshare new_program")" "$(cat $STDOUTF)"
assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/unshare_mock --user /bin/sh -c :\nunshare --user /bin/sh -c :\nunshare new_program")" "$(cat "$STDOUTF")"
UNSHARE=false LD_EXEC=false assertCommandFail unshare_cmd new_program
}
function test_bwrap(){
assertCommandSuccess bwrap_cmd new_program
assertEquals "$(echo -e "ld_exec $BWRAP --dev-bind / / /bin/sh -c :\nld_exec $BWRAP new_program")" "$(cat "$STDOUTF")"
BWRAP=false LD_EXEC=false assertCommandFail bwrap_cmd new_program
}
function test_chroot(){
CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root
assertEquals "root" "$(cat $STDOUTF)"
CLASSIC_CHROOT="echo" assertCommandSuccess chroot_cmd root
assertEquals "root" "$(cat "$STDOUTF")"
CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root
assertEquals "ld_exec $JUNEST_HOME/usr/bin/false root" "$(cat $STDOUTF)"
assertEquals "ld_exec $JUNEST_HOME/usr/bin/false root" "$(cat "$STDOUTF")"
CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root
}
@ -154,39 +177,43 @@ function test_proot_cmd_compat(){
function test_proot_cmd_seccomp(){
envv(){
# shellcheck disable=SC2317
env
}
PROOT=envv
assertCommandSuccess proot_cmd cmd
assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")"
assertEquals "" "$(grep "^PROOT_NO_SECCOMP" "$STDOUTF")"
envv(){
# shellcheck disable=SC2317
env | grep "^PROOT_NO_SECCOMP"
}
# shellcheck disable=SC2034
PROOT=envv
local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP")
assertCommandSuccess proot_cmd cmd
# The variable PROOT_NO_SECCOMP will be produced
# twice due to the fallback mechanism
assertEquals "PROOT_NO_SECCOMP=1
PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")"
PROOT_NO_SECCOMP=1" "$(grep "^PROOT_NO_SECCOMP" "$STDOUTF")"
}
function test_copy_passwd_and_group(){
getent_cmd_mock() {
echo $@
# shellcheck disable=SC2317
echo "$*"
}
GETENT=getent_cmd_mock assertCommandSuccess copy_passwd_and_group
assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/passwd)"
assertEquals "group" "$(cat $JUNEST_HOME/etc/group)"
assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat "$JUNEST_HOME"/etc/passwd)"
assertEquals "group" "$(cat "$JUNEST_HOME"/etc/group)"
}
function test_copy_passwd_and_group_fallback(){
cp_cmd_mock() {
echo $@
# shellcheck disable=SC2317
echo "$*"
}
CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess copy_passwd_and_group
assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME//etc/passwd\n/etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)"
assertEquals "$(echo -e "-f /etc/passwd $JUNEST_HOME//etc/passwd\n-f /etc/group $JUNEST_HOME//etc/group")" "$(cat "$STDOUTF")"
}
function test_copy_passwd_and_group_failure(){
@ -202,14 +229,14 @@ function test_nested_env_not_set_variable(){
}
function test_check_same_arch_not_same(){
echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info
echo "JUNEST_ARCH=XXX" > "${JUNEST_HOME}"/etc/junest/info
assertCommandFailOnStatus 104 check_same_arch
}
function test_check_same_arch(){
echo "JUNEST_ARCH=$ARCH" > ${JUNEST_HOME}/etc/junest/info
echo "JUNEST_ARCH=$ARCH" > "${JUNEST_HOME}"/etc/junest/info
assertCommandSuccess check_same_arch
}
source $JUNEST_ROOT/tests/utils/shunit2
source "$JUNEST_ROOT"/tests/utils/shunit2

View file

@ -1,230 +0,0 @@
#!/bin/bash
source "$(dirname $0)/../utils/utils.sh"
JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/../..)"
# Disable the exiterr
set +e
function oneTimeSetUp(){
setUpUnitTests
}
function setUp(){
# Attempt to source the files under test to revert variable overrides
source $JUNEST_BASE/bin/groot -h &> /dev/null
set +e
cwdSetUp
mkdir -p chrootdir
init_mocks
}
function tearDown(){
cwdTearDown
}
## Mock functions ##
function init_mocks() {
function usage(){
echo "usage"
}
function is_user_root() {
return 0
}
function chroot() {
echo "chroot($@)"
}
function mountpoint() {
echo "mountpoint($@)"
# As default suppose the mountpoint does not exist
return 1
}
function mount() {
echo "mount($@)"
}
function umount() {
echo "umount($@)"
}
function check_and_trap() {
echo "check_and_trap($@)"
}
}
function test_help(){
assertCommandSuccess main -h
assertEquals "usage" "$(cat $STDOUTF)"
assertCommandSuccess main --help
assertEquals "usage" "$(cat $STDOUTF)"
}
function test_version(){
assertCommandSuccess main -V
assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)"
assertCommandSuccess main --version
assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)"
}
function test_groot_no_root(){
is_user_root() {
return 1
}
assertCommandFailOnStatus $NO_ROOT_PRIVILEGES main
}
function test_groot_no_directory(){
assertCommandFailOnStatus $NOT_EXISTING_FILE main no-directory
}
function test_groot_mountpoint_exist(){
mountpoint_mock() {
echo "mountpoint($@)"
}
MOUNTPOINT=mountpoint_mock
assertCommandSuccess main chrootdir
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_mountpoint_does_not_exist(){
assertCommandSuccess main chrootdir
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind(){
assertCommandSuccess main -b /tmp chrootdir
[[ -d chrootdir/tmp ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_file(){
touch file_src
assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir
[[ -f chrootdir/file_src ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_not_existing_node(){
assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_not_absolute_path_node(){
touch file_src
assertCommandFailOnStatus $NOT_ABSOLUTE_PATH main -b file_src:/file_src chrootdir
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_guest_host(){
assertCommandSuccess main -b /tmp:/home/tmp chrootdir
[[ -d chrootdir/home/tmp ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_multiple_bind(){
assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir
[[ -d chrootdir/home/tmp ]]
assertEquals 0 $?
[[ -d chrootdir/dev ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_command(){
assertCommandSuccess main chrootdir ls -la -h
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_and_command(){
assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir ls -la -h
[[ -d chrootdir/home/tmp ]]
assertEquals 0 $?
[[ -d chrootdir/dev ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_no_umount(){
assertCommandSuccess main -n chrootdir
assertEquals "$(echo -e "mountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_chroot_teardown(){
echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts
MOUNTS_FILE=./mounts
CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown
assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1)
umount(/home/mychroot/proc)
umount(/home/mychroot/dev/shm)
umount(/home/mychroot/dev)
umount(/home/mychroot)")" "$(cat $STDOUTF)"
}
function test_groot_with_chroot_teardown_umount_failure(){
function umount() {
echo "umount($@)"
[[ "$1" == "/home/mychroot/dev/shm" ]] && return 128
return 0
}
UMOUNT=umount
echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts
MOUNTS_FILE=./mounts
CHROOTDIR=/home/mychroot assertCommandFailOnStatus 128 chroot_teardown
assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1)
umount(/home/mychroot/proc)
umount(/home/mychroot/dev/shm)
umount(/home/mychroot/dev)
umount(/home/mychroot)")" "$(cat $STDOUTF)"
}
function test_groot_with_chroot_teardown_with_trailing_slash(){
echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts
MOUNTS_FILE=./mounts
CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown
assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1)
umount(/home/mychroot/proc)
umount(/home/mychroot/dev/shm)
umount(/home/mychroot/dev)
umount(/home/mychroot)")" "$(cat $STDOUTF)"
}
function test_groot_with_rbind(){
assertCommandSuccess main -r -b /tmp chrootdir
[[ -d chrootdir/tmp ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_proc(){
assertCommandSuccess main -i -b /proc chrootdir
[[ -d chrootdir/proc ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(proc chrootdir/proc -t proc)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_dev(){
assertCommandSuccess main -i -b /dev chrootdir
[[ -d chrootdir/dev ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(udev chrootdir/dev -t devtmpfs)\nmount(devpts /dev/pts -t devpts)\nmount(shm /dev/shm -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_sys(){
assertCommandSuccess main -i -b /sys chrootdir
[[ -d chrootdir/sys ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(sys chrootdir/sys -t sysfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_run(){
assertCommandSuccess main -i -b /run chrootdir
[[ -d chrootdir/run ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(run chrootdir/run -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_tmp(){
assertCommandSuccess main -i -b /tmp chrootdir
[[ -d chrootdir/tmp ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_combined(){
assertCommandSuccess main -i -b /tmp -b /usr chrootdir
cat $STDERRF
[[ -d chrootdir/tmp ]]
assertEquals 0 $?
[[ -d chrootdir/usr ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nmount(--bind /usr chrootdir/usr)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
source $(dirname $0)/../utils/shunit2

View file

@ -1,8 +1,10 @@
#!/bin/bash
source "$(dirname $0)/../utils/utils.sh"
# shellcheck disable=SC1091
JUNEST_BASE="$(dirname $0)/../.."
source $JUNEST_BASE/bin/junest -h &> /dev/null
source "$(dirname "$0")/../utils/utils.sh"
JUNEST_BASE="$(dirname "$0")/../.."
source "$JUNEST_BASE"/bin/junest -h &> /dev/null
# Disable the exiterr
set +e
@ -12,178 +14,370 @@ function oneTimeSetUp(){
}
function setUp(){
## Mock functions ##
# shellcheck disable=SC2317
function usage(){
echo "usage"
}
# shellcheck disable=SC2317
function version(){
echo "version"
}
# shellcheck disable=SC2317
function build_image_env(){
local disable_check=$1
echo "build_image_env($disable_check)"
}
# shellcheck disable=SC2317
function delete_env(){
echo "delete_env"
}
# shellcheck disable=SC2317
function setup_env_from_file(){
echo "setup_env_from_file($1)"
}
# shellcheck disable=SC2317
function setup_env(){
echo "setup_env($1)"
}
# shellcheck disable=SC2317
function run_env_as_proot_fakeroot(){
local backend_command="$1"
local backend_args="$2"
local no_copy_files="$3"
shift 3
echo "run_env_as_proot_fakeroot($backend_command,$backend_args,$no_copy_files,$*)"
}
# shellcheck disable=SC2317
function run_env_as_groot(){
local backend_command="$1"
local backend_args="$2"
local no_copy_files="$3"
shift 3
echo "run_env_as_groot($backend_command,$backend_args,$no_copy_files,$*)"
}
# shellcheck disable=SC2317
function run_env_as_chroot(){
local backend_command="$1"
local backend_args="$2"
local no_copy_files="$3"
shift 3
echo "run_env_as_chroot($backend_command,$backend_args,$no_copy_files,$*)"
}
# shellcheck disable=SC2317
function run_env_as_proot_user(){
local backend_command="$1"
local backend_args="$2"
local no_copy_files="$3"
shift 3
echo "run_env_as_proot_user($backend_command,$backend_args,$no_copy_files,$*)"
}
# shellcheck disable=SC2317
function run_env_as_bwrap_fakeroot(){
local backend_command="$1"
local backend_args="$2"
local no_copy_files="$3"
shift 3
echo "run_env_as_bwrap_fakeroot($backend_command,$backend_args,$no_copy_files,$*)"
}
# shellcheck disable=SC2317
function run_env_as_bwrap_user(){
local backend_command="$1"
local backend_args="$2"
local no_copy_files="$3"
shift 3
echo "run_env_as_bwrap_user($backend_command,$backend_args,$no_copy_files,$*)"
}
# shellcheck disable=SC2317
function is_env_installed(){
return 0
}
}
## Mock functions ##
function usage(){
echo "usage"
}
function version(){
echo "version"
}
function build_image_env(){
local disable_validation=$1
echo "build_image_env($disable_validation)"
}
function delete_env(){
echo "delete_env"
}
function setup_env_from_file(){
echo "setup_env_from_file($1)"
}
function setup_env(){
echo "setup_env($1)"
}
function run_env_as_fakeroot(){
local backend_args="$1"
shift
echo "run_env_as_fakeroot($backend_args,$@)"
}
function run_env_as_groot(){
echo "run_env_as_groot $@"
}
function run_env_as_chroot(){
echo "run_env_as_chroot $@"
}
function run_env_as_user(){
local backend_args="$1"
shift
echo "run_env_as_user($backend_args,$@)"
}
function run_env_with_namespace(){
local backend_args="$1"
shift
echo "run_env_with_namespace($backend_args,$@)"
# shellcheck disable=SC2317
function create_wrappers(){
:
}
}
function test_help(){
assertCommandSuccess main -h
assertEquals "usage" "$(cat $STDOUTF)"
assertEquals "usage" "$(cat "$STDOUTF")"
assertCommandSuccess main --help
assertEquals "usage" "$(cat $STDOUTF)"
assertEquals "usage" "$(cat "$STDOUTF")"
}
function test_version(){
assertCommandSuccess main -V
assertEquals "version" "$(cat $STDOUTF)"
assertEquals "version" "$(cat "$STDOUTF")"
assertCommandSuccess main --version
assertEquals "version" "$(cat $STDOUTF)"
assertEquals "version" "$(cat "$STDOUTF")"
}
function test_build_image_env(){
assertCommandSuccess main -b
assertEquals "build_image_env(false)" "$(cat $STDOUTF)"
assertCommandSuccess main --build-image
assertEquals "build_image_env(false)" "$(cat $STDOUTF)"
assertCommandSuccess main -b -n
assertEquals "build_image_env(true)" "$(cat $STDOUTF)"
assertCommandSuccess main --build-image --disable-validation
assertEquals "build_image_env(true)" "$(cat $STDOUTF)"
assertCommandSuccess main b
assertEquals "build_image_env(false)" "$(cat "$STDOUTF")"
assertCommandSuccess main build
assertEquals "build_image_env(false)" "$(cat "$STDOUTF")"
assertCommandSuccess main b -n
assertEquals "build_image_env(true)" "$(cat "$STDOUTF")"
assertCommandSuccess main build --disable-check
assertEquals "build_image_env(true)" "$(cat "$STDOUTF")"
}
function test_create_wrappers(){
# shellcheck disable=SC2317
function create_wrappers(){
local force=$1
echo "create_wrappers($force)"
}
assertCommandSuccess main create-bin-wrappers
assertEquals "create_wrappers(false)" "$(cat "$STDOUTF")"
assertCommandSuccess main create-bin-wrappers --force
assertEquals "create_wrappers(true)" "$(cat "$STDOUTF")"
}
function test_delete_env(){
assertCommandSuccess main -d
assertEquals "delete_env" "$(cat $STDOUTF)"
assertCommandSuccess main --delete
assertEquals "delete_env" "$(cat $STDOUTF)"
assertCommandSuccess main s -d
assertEquals "delete_env" "$(cat "$STDOUTF")"
assertCommandSuccess main setup --delete
assertEquals "delete_env" "$(cat "$STDOUTF")"
}
function test_setup_env_from_file(){
# shellcheck disable=SC2317
is_env_installed(){
return 1
}
assertCommandSuccess main -i myimage
assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
assertCommandSuccess main --setup-from-file myimage
assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
assertCommandSuccess main s -i myimage
assertEquals "setup_env_from_file(myimage)" "$(cat "$STDOUTF")"
assertCommandSuccess main setup --from-file myimage
assertEquals "setup_env_from_file(myimage)" "$(cat "$STDOUTF")"
# shellcheck disable=SC2317
is_env_installed(){
return 0
}
assertCommandFail main -i myimage
assertCommandFail main setup -i myimage
}
function test_setup_env(){
# shellcheck disable=SC2317
is_env_installed(){
return 1
}
assertCommandSuccess main -a arm
assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
assertCommandSuccess main --arch arm
assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
assertCommandSuccess main
assertEquals "$(echo -e "setup_env()\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
assertCommandSuccess main s
assertEquals "setup_env()" "$(cat "$STDOUTF")"
assertCommandSuccess main setup
assertEquals "setup_env()" "$(cat "$STDOUTF")"
assertCommandSuccess main s -a arm
assertEquals "setup_env(arm)" "$(cat "$STDOUTF")"
assertCommandSuccess main setup --arch arm
assertEquals "setup_env(arm)" "$(cat "$STDOUTF")"
# shellcheck disable=SC2317
is_env_installed(){
return 0
}
assertCommandFail main -a arm
assertCommandFail main setup -a arm
}
function test_run_env_as_fakeroot(){
assertCommandSuccess main -f
assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)"
assertCommandSuccess main --fakeroot
assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)"
assertCommandSuccess main -f -p "-b arg"
assertEquals "run_env_as_fakeroot(-b arg,)" "$(cat $STDOUTF)"
assertCommandSuccess main -f -p "-b arg" -- command -kv
assertEquals "run_env_as_fakeroot(-b arg,command -kv)" "$(cat $STDOUTF)"
assertCommandSuccess main -f command --as
assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)"
assertCommandFail main -a "myarch" -f command --as
function test_run_env_as_proot_fakeroot(){
assertCommandSuccess main p -f
assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot --fakeroot
assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main p -f -n
assertEquals "run_env_as_proot_fakeroot(,,true,)" "$(cat "$STDOUTF")"
assertCommandSuccess main p -f --backend-command blah
assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot -f --backend-command blah
assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot -f -b "-b arg"
assertEquals "run_env_as_proot_fakeroot(,-b arg,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot -f -b "-b arg" -- command -kv
assertEquals "run_env_as_proot_fakeroot(,-b arg,false,command -kv)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot -f command --as
assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot -f -- command --as
assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")"
# shellcheck disable=SC2317
is_env_installed(){
return 1
}
assertCommandFail main proot -f
}
function test_run_env_as_user(){
assertCommandSuccess main
assertEquals "run_env_as_user(,)" "$(cat $STDOUTF)"
assertCommandSuccess main proot
assertEquals "run_env_as_proot_user(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main p -n
assertEquals "run_env_as_proot_user(,,true,)" "$(cat "$STDOUTF")"
assertCommandSuccess main -p "-b arg"
assertEquals "run_env_as_user(-b arg,)" "$(cat $STDOUTF)"
assertCommandSuccess main -p "-b arg" -- command -ll
assertEquals "run_env_as_user(-b arg,command -ll)" "$(cat $STDOUTF)"
assertCommandSuccess main command -ls
assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)"
assertCommandSuccess main p --backend-command blah
assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot --backend-command blah
assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandFail main -a "myarch" -- command -ls
assertCommandSuccess main proot -b "-b arg"
assertEquals "run_env_as_proot_user(,-b arg,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot -b "-b arg" -- command -ll
assertEquals "run_env_as_proot_user(,-b arg,false,command -ll)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot command -ls
assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat "$STDOUTF")"
assertCommandSuccess main proot -- command -ls
assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat "$STDOUTF")"
# shellcheck disable=SC2317
is_env_installed(){
return 1
}
assertCommandFail main proot
}
function test_run_env_as_groot(){
assertCommandSuccess main -g
assertEquals "run_env_as_groot " "$(cat $STDOUTF)"
assertCommandSuccess main -g command
assertEquals "run_env_as_groot command" "$(cat $STDOUTF)"
assertCommandSuccess main g
assertEquals "run_env_as_groot(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main g -n
assertEquals "run_env_as_groot(,,true,)" "$(cat "$STDOUTF")"
assertCommandSuccess main g -b "-b arg"
assertEquals "run_env_as_groot(,-b arg,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main g --backend-command blah
assertEquals "run_env_as_groot(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main groot --backend-command blah
assertEquals "run_env_as_groot(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main groot command
assertEquals "run_env_as_groot(,,false,command)" "$(cat "$STDOUTF")"
assertCommandSuccess main groot -- command
assertEquals "run_env_as_groot(,,false,command)" "$(cat "$STDOUTF")"
# shellcheck disable=SC2317
is_env_installed(){
return 1
}
assertCommandFail main groot
}
function test_run_env_as_chroot(){
assertCommandSuccess main -r
assertEquals "run_env_as_chroot " "$(cat $STDOUTF)"
assertCommandSuccess main -r command
assertEquals "run_env_as_chroot command" "$(cat $STDOUTF)"
assertCommandSuccess main r
assertEquals "run_env_as_chroot(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main r -b "-b arg"
assertEquals "run_env_as_chroot(,-b arg,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main r --backend-command blah
assertEquals "run_env_as_chroot(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main root --backend-command blah
assertEquals "run_env_as_chroot(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main root command
assertEquals "run_env_as_chroot(,,false,command)" "$(cat "$STDOUTF")"
assertCommandSuccess main root -- command
assertEquals "run_env_as_chroot(,,false,command)" "$(cat "$STDOUTF")"
# shellcheck disable=SC2317
is_env_installed(){
return 1
}
assertCommandFail main root -f
}
function test_run_env_with_namespace(){
assertCommandSuccess main -u -f
assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)"
assertCommandSuccess main --namespace --fakeroot
assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)"
function test_run_env_as_bwrap_fakeroot(){
assertCommandSuccess main n -f
assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -f
assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -n -f
assertEquals "run_env_as_bwrap_fakeroot(,,true,)" "$(cat "$STDOUTF")"
assertCommandSuccess main -u -f -p "-b arg"
assertEquals "run_env_with_namespace(-b arg,)" "$(cat $STDOUTF)"
assertCommandSuccess main -u -f -p "-b arg" -- command -kv
assertEquals "run_env_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)"
assertCommandSuccess main -u -f command --as
assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)"
assertCommandSuccess main ns -f -b "-b arg"
assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -f -b "-b arg" -- command -kv
assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -f command --as
assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -f -- command --as
assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -f --backend-command blah
assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main -f --backend-command blah
assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main -f
assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main -f
assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main -f -b "-b arg"
assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main -f -b "-b arg" -- command -kv
assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat "$STDOUTF")"
assertCommandSuccess main -f command --as
assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")"
assertCommandSuccess main -f -- command --as
assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")"
# shellcheck disable=SC2317
is_env_installed(){
return 1
}
assertCommandFail main ns -f
}
function test_check_cli(){
assertCommandFail main -b -h
assertCommandFail main -b -c
assertCommandFail main -d -s
assertCommandFail main -n -v
assertCommandFail main -d -r
assertCommandFail main -h -f
assertCommandFail main -v -i fsd
assertCommandFail main -f -r
assertCommandFail main -p args -v
assertCommandFail main -a arch -v
assertCommandFail main -d args
function test_run_env_as_bwrap_user(){
assertCommandSuccess main n
assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns
assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -n
assertEquals "run_env_as_bwrap_user(,,true,)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -b "-b arg"
assertEquals "run_env_as_bwrap_user(,-b arg,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -b "-b arg" -- command -kv
assertEquals "run_env_as_bwrap_user(,-b arg,false,command -kv)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns command --as
assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns -- command --as
assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")"
assertCommandSuccess main ns --backend-command blah
assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main --backend-command blah
assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main
assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main
assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main -b "-b arg"
assertEquals "run_env_as_bwrap_user(,-b arg,false,)" "$(cat "$STDOUTF")"
assertCommandSuccess main -b "-b arg" -- command -kv
assertEquals "run_env_as_bwrap_user(,-b arg,false,command -kv)" "$(cat "$STDOUTF")"
assertCommandSuccess main command --as
assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")"
assertCommandSuccess main -- command --as
assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")"
# shellcheck disable=SC2317
is_env_installed(){
return 1
}
assertCommandFail main ns
}
source $(dirname $0)/../utils/shunit2
function test_invalid_option(){
assertCommandFail main --no-option
assertCommandFail main n --no-option
assertCommandFail main g --no-option
assertCommandFail main r --no-option
assertCommandFail main p --no-option
assertCommandFail main b --no-option
assertCommandFail main s --no-option
}
source "$(dirname "$0")"/../utils/shunit2

View file

@ -1,6 +1,7 @@
#!/bin/bash
# shellcheck disable=SC1091
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..)
source "$JUNEST_ROOT/tests/utils/utils.sh"
@ -15,8 +16,9 @@ function oneTimeSetUp(){
## Mock functions ##
function init_mocks() {
function unshare_cmd(){
echo "unshare $@"
# shellcheck disable=SC2317
function bwrap_cmd(){
echo "$BWRAP $*"
}
}
@ -39,16 +41,16 @@ function tearDown(){
}
function _test_copy_common_files() {
[[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)"
[[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)"
[[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)"
[[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)"
[[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat "${JUNEST_HOME}"/etc/hosts)"
[[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat "${JUNEST_HOME}"/etc/host.conf)"
[[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat "${JUNEST_HOME}"/etc/nsswitch.conf)"
[[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat "${JUNEST_HOME}"/etc/resolv.conf)"
}
function _test_copy_remaining_files() {
[[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)"
[[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)"
[[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat ${JUNEST_HOME}/etc/networks)"
[[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat "${JUNEST_HOME}"/etc/hosts.equiv)"
[[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat "${JUNEST_HOME}"/etc/netgroup)"
[[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat "${JUNEST_HOME}"/etc/networks)"
[[ -e ${JUNEST_HOME}/etc/passwd ]]
assertEquals 0 $?
@ -57,57 +59,183 @@ function _test_copy_remaining_files() {
}
function test_is_user_namespace_enabled_no_config_file(){
PROC_USERNS_FILE="blah"
PROC_USERNS_CLONE_FILE="blah"
CONFIG_PROC_FILE="blah"
CONFIG_BOOT_FILE="blah"
assertCommandFailOnStatus $NOT_EXISTING_FILE _is_user_namespace_enabled
assertCommandFailOnStatus "$NOT_EXISTING_FILE" _is_user_namespace_enabled
}
function test_is_user_namespace_enabled_no_config(){
PROC_USERNS_FILE="blah"
PROC_USERNS_CLONE_FILE="blah"
touch config
gzip config
# shellcheck disable=SC2034
CONFIG_PROC_FILE="config.gz"
# shellcheck disable=SC2034
CONFIG_BOOT_FILE="blah"
assertCommandFailOnStatus $NO_CONFIG_FOUND _is_user_namespace_enabled
assertCommandFailOnStatus "$NO_CONFIG_FOUND" _is_user_namespace_enabled
}
function test_is_user_namespace_enabled_with_config(){
echo "CONFIG_USER_NS=y" > config
gzip config
CONFIG_PROC_FILE="config.gz"
CONFIG_BOOT_FILE="blah"
function test_is_user_namespace_enabled_with_userns_clone_file_disabled(){
PROC_USERNS_FILE="blah"
PROC_USERNS_CLONE_FILE="unprivileged_userns_clone"
echo "0" > $PROC_USERNS_CLONE_FILE
assertCommandFailOnStatus "$UNPRIVILEGED_USERNS_DISABLED" _is_user_namespace_enabled
}
function test_is_user_namespace_enabled_with_userns_clone_file_enabled(){
PROC_USERNS_CLONE_FILE="unprivileged_userns_clone"
echo "1" > $PROC_USERNS_CLONE_FILE
assertCommandSuccess _is_user_namespace_enabled
}
function test_run_env_with_namespace() {
assertCommandSuccess run_env_with_namespace "" ""
assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)"
function test_is_user_namespace_enabled_with_proc_userns_file_existing(){
PROC_USERNS_FILE="user"
ln -s . $PROC_USERNS_FILE
PROC_USERNS_CLONE_FILE="blah"
assertCommandSuccess _is_user_namespace_enabled
}
function test_run_env_as_bwrap_fakeroot() {
assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "false"
assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat "$STDOUTF")"
_test_copy_common_files
}
function test_run_env_as_bwrap_fakeroot_with_backend_command() {
assertCommandSuccess run_env_as_bwrap_fakeroot "mybwrap" "" "false"
assertEquals "mybwrap $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat "$STDOUTF")"
_test_copy_common_files
}
function test_run_env_as_bwrap_user() {
assertCommandSuccess run_env_as_bwrap_user "" "" "false"
assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat "$STDOUTF")"
_test_copy_common_files
_test_copy_remaining_files
}
function test_run_env_with_namespace_with_bindings() {
assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" ""
assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)"
function test_run_env_as_bwrap_user_with_backend_command() {
assertCommandSuccess run_env_as_bwrap_user "mybwrap" "" "false"
assertEquals "mybwrap $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat "$STDOUTF")"
_test_copy_common_files
_test_copy_remaining_files
}
function test_run_env_with_namespace_with_command() {
assertCommandSuccess run_env_with_namespace "" "ls -la"
assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)"
function test_run_env_as_bwrap_fakeroot_no_copy() {
assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "true" ""
assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat "$STDOUTF")"
[[ ! -e ${JUNEST_HOME}/etc/hosts ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/host.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/hosts.equiv ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/netgroup ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/networks ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/passwd ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/group ]]
assertEquals 0 $?
}
function test_run_env_as_bwrap_user_no_copy() {
assertCommandSuccess run_env_as_bwrap_user "" "" "true" ""
assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat "$STDOUTF")"
[[ ! -e ${JUNEST_HOME}/etc/hosts ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/host.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/hosts.equiv ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/netgroup ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/networks ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/passwd ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/group ]]
assertEquals 0 $?
}
function test_run_env_as_bwrap_fakeroot_with_backend_args() {
assertCommandSuccess run_env_as_bwrap_fakeroot "" "--bind /usr /usr" "false"
assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login" "$(cat "$STDOUTF")"
_test_copy_common_files
}
function test_run_env_as_bwrap_user_with_backend_args() {
assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false"
assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login" "$(cat "$STDOUTF")"
_test_copy_common_files
_test_copy_remaining_files
}
function test_run_env_with_namespace_with_bindings_and_command() {
assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la"
assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)"
function test_run_env_as_bwrap_fakeroot_with_command() {
assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "false" "ls -la"
assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")"
_test_copy_common_files
}
function test_run_env_as_bwrap_user_with_command() {
assertCommandSuccess run_env_as_bwrap_user "" "" "false" "ls -la"
assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")"
_test_copy_common_files
_test_copy_remaining_files
}
source $JUNEST_ROOT/tests/utils/shunit2
function test_run_env_as_bwrap_fakeroot_with_backend_args_and_command() {
assertCommandSuccess run_env_as_bwrap_fakeroot "" "--bind /usr /usr" "false" "ls -la"
assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")"
_test_copy_common_files
}
function test_run_env_as_bwrap_user_with_backend_args_and_command() {
assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" "ls -la"
assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")"
_test_copy_common_files
_test_copy_remaining_files
}
function test_run_env_as_bwrap_fakeroot_nested_env(){
JUNEST_ENV=1
assertCommandFailOnStatus 106 run_env_as_bwrap_fakeroot "" "" "false" ""
unset JUNEST_ENV
}
function test_run_env_as_bwrap_user_nested_env(){
# shellcheck disable=SC2034
JUNEST_ENV=1
assertCommandFailOnStatus 106 run_env_as_bwrap_user "" "" "false" ""
unset JUNEST_ENV
}
source "$JUNEST_ROOT"/tests/utils/shunit2

View file

@ -1,6 +1,7 @@
#!/bin/bash
# shellcheck disable=SC1091
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..)
source "$JUNEST_ROOT/tests/utils/utils.sh"
@ -30,16 +31,16 @@ function tearDown(){
}
function _test_copy_common_files() {
[[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)"
[[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)"
[[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)"
[[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)"
[[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat "${JUNEST_HOME}"/etc/hosts)"
[[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat "${JUNEST_HOME}"/etc/host.conf)"
[[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat "${JUNEST_HOME}"/etc/nsswitch.conf)"
[[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat "${JUNEST_HOME}"/etc/resolv.conf)"
}
function _test_copy_remaining_files() {
[[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)"
[[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)"
[[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat ${JUNEST_HOME}/etc/networks)"
[[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat "${JUNEST_HOME}"/etc/hosts.equiv)"
[[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat "${JUNEST_HOME}"/etc/netgroup)"
[[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat "${JUNEST_HOME}"/etc/networks)"
[[ -e ${JUNEST_HOME}/etc/passwd ]]
assertEquals 0 $?
@ -47,72 +48,173 @@ function _test_copy_remaining_files() {
assertEquals 0 $?
}
function test_run_env_as_user(){
function test_run_env_as_proot_user(){
# shellcheck disable=SC2317
_run_env_with_qemu() {
echo $@
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2"
assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2"
assertEquals "-b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")"
SH=("/usr/bin/echo")
assertCommandSuccess run_env_as_user "-k 3.10"
assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false"
assertEquals "-b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")"
_test_copy_common_files
_test_copy_remaining_files
}
function test_run_env_as_fakeroot(){
function test_run_env_as_proot_user_with_backend_command(){
# shellcheck disable=SC2317
_run_env_with_qemu() {
echo $@
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2"
assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2"
assertEquals "myproot -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")"
SH=("/usr/bin/echo")
assertCommandSuccess run_env_as_fakeroot "-k 3.10"
assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false"
assertEquals "myproot -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")"
_test_copy_common_files
_test_copy_remaining_files
}
function test_run_env_as_proot_user_no_copy(){
# shellcheck disable=SC2317
_run_env_with_qemu() {
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "true" "/usr/bin/mkdir" "-v" "/newdir2"
assertEquals "-b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")"
[[ ! -e ${JUNEST_HOME}/etc/hosts ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/host.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/hosts.equiv ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/netgroup ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/networks ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/passwd ]]
assertEquals 0 $?
[[ ! -e ${JUNEST_HOME}/etc/group ]]
assertEquals 0 $?
}
function test_run_env_as_proot_user_nested_env(){
JUNEST_ENV=1
assertCommandFailOnStatus 106 run_env_as_proot_user "" "" "false"
unset JUNEST_ENV
}
function test_run_env_as_proot_fakeroot(){
# shellcheck disable=SC2317
_run_env_with_qemu() {
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
assertCommandSuccess run_env_as_proot_fakeroot "" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2"
assertEquals "-0 -b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")"
SH=("/usr/bin/echo")
assertCommandSuccess run_env_as_proot_fakeroot "" "-k 3.10" "false"
assertEquals "-0 -b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")"
_test_copy_common_files
}
function test_run_env_with_quotes(){
function test_run_env_as_proot_fakeroot_with_backend_command(){
# shellcheck disable=SC2317
_run_env_with_qemu() {
echo $@
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2"
assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
assertCommandSuccess run_env_as_proot_fakeroot "myproot" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2"
assertEquals "myproot -0 -b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")"
# shellcheck disable=SC2034
SH=("/usr/bin/echo")
assertCommandSuccess run_env_as_proot_fakeroot "myproot" "-k 3.10" "false"
assertEquals "myproot -0 -b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")"
_test_copy_common_files
}
function test_run_env_as_proot_fakeroot_nested_env(){
JUNEST_ENV=1
assertCommandFailOnStatus 106 run_env_as_proot_fakeroot "" "" "false" ""
unset JUNEST_ENV
}
function test_run_env_with_quotes(){
# shellcheck disable=SC2317
_run_env_with_qemu() {
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "bash" "-c" "/usr/bin/mkdir -v /newdir2"
assertEquals "-b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")"
}
function test_run_env_with_proot_args(){
# shellcheck disable=SC2317
proot_cmd() {
[ "$JUNEST_ENV" != "1" ] && return 1
echo $@
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
assertCommandSuccess _run_env_with_proot --help
assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)"
assertCommandSuccess _run_env_with_proot "" "--help"
assertEquals "--help /bin/sh --login" "$(cat "$STDOUTF")"
assertCommandSuccess _run_env_with_proot --help mycommand
assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)"
assertCommandSuccess _run_env_with_proot "" "--help" mycommand
assertEquals "--help /bin/sh --login -c mycommand" "$(cat "$STDOUTF")"
assertCommandFail _run_env_with_proot
}
function test_qemu() {
echo "JUNEST_ARCH=arm" > ${JUNEST_HOME}/etc/junest/info
echo "JUNEST_ARCH=arm" > "${JUNEST_HOME}"/etc/junest/info
# shellcheck disable=SC2317
rm_cmd() {
echo $@
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
# shellcheck disable=SC2317
ln_cmd() {
echo $@
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
# shellcheck disable=SC2317
_run_env_with_proot() {
echo $@
# shellcheck disable=SC2086
# shellcheck disable=SC2048
echo $*
}
RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu ""
assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)"
RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu "" ""
assertEquals "$(echo -e "-s $JUNEST_HOME/bin/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat "$STDOUTF")"
}
source $JUNEST_ROOT/tests/utils/shunit2
source "$JUNEST_ROOT"/tests/utils/shunit2

View file

@ -1,6 +1,7 @@
#!/bin/bash
# shellcheck disable=SC1091
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..)
source "$JUNEST_ROOT/tests/utils/utils.sh"
@ -26,24 +27,27 @@ function tearDown(){
}
function test_is_env_installed(){
rm -rf $JUNEST_HOME/*
rm -rf "${JUNEST_HOME:?}"/*
assertCommandFail is_env_installed
touch $JUNEST_HOME/just_file
touch "$JUNEST_HOME"/just_file
assertCommandSuccess is_env_installed
}
function test_setup_env(){
rm -rf $JUNEST_HOME/*
rm -rf "${JUNEST_HOME:?}"/*
# shellcheck disable=SC2317
wget_mock(){
# Proof that the setup is happening
# inside $JUNEST_TEMPDIR
local cwd=${PWD#${JUNEST_TEMPDIR}}
local parent_dir=${PWD%${cwd}}
local cwd=${PWD#"${JUNEST_TEMPDIR}"}
local parent_dir=${PWD%"${cwd}"}
assertEquals "$JUNEST_TEMPDIR" "${parent_dir}"
touch file
tar -czvf ${CMD}-${ARCH}.tar.gz file
tar -czvf "${CMD}-${ARCH}".tar.gz file
}
# shellcheck disable=SC2034
WGET=wget_mock
# shellcheck disable=SC2119
setup_env 1> /dev/null
assertTrue "[ -e $JUNEST_HOME/file ]"
@ -52,10 +56,10 @@ function test_setup_env(){
function test_setup_env_from_file(){
rm -rf $JUNEST_HOME/*
rm -rf "${JUNEST_HOME:?}"/*
touch file
tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null
assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz
tar -czvf "${CMD}-${ARCH}".tar.gz file 1> /dev/null
assertCommandSuccess setup_env_from_file "${CMD}-${ARCH}.tar.gz"
assertTrue "[ -e $JUNEST_HOME/file ]"
}
@ -64,10 +68,10 @@ function test_setup_env_from_file_not_existing_file(){
}
function test_setup_env_from_file_with_absolute_path(){
rm -rf $JUNEST_HOME/*
rm -rf "${JUNEST_HOME:?}"/*
touch file
tar -czf ${CMD}-${ARCH}.tar.gz file
assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz
tar -czf "${CMD}-${ARCH}".tar.gz file
assertCommandSuccess setup_env_from_file "${CMD}-${ARCH}.tar.gz"
assertTrue "[ -e $JUNEST_HOME/file ]"
}
@ -78,4 +82,4 @@ function test_delete_env(){
assertCommandFail is_env_installed
}
source $JUNEST_ROOT/tests/utils/shunit2
source "$JUNEST_ROOT"/tests/utils/shunit2

View file

@ -1,10 +1,13 @@
#!/bin/bash
source "$(dirname $0)/../utils/utils.sh"
# shellcheck disable=SC1091
source "$(dirname "$0")/../utils/utils.sh"
unset HOME
export HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX)
export HOME
HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX)
source "$(dirname $0)/../../lib/utils/utils.sh"
source "$(dirname "$0")/../../lib/utils/utils.sh"
# Disable the exiterr
set +e
@ -20,37 +23,42 @@ function test_check_not_null(){
function test_echoerr(){
assertCommandSuccess echoerr "Test"
assertEquals "Test" "$(cat $STDERRF)"
assertEquals "Test" "$(cat "$STDERRF")"
}
function test_error(){
assertCommandSuccess error "Test"
local expected=$(echo -e "\033[1;31mTest\033[0m")
assertEquals "$expected" "$(cat $STDERRF)"
local expected
expected=$(echo -e "\033[1;31mTest\033[0m")
assertEquals "$expected" "$(cat "$STDERRF")"
}
function test_warn(){
assertCommandSuccess warn "Test"
local expected=$(echo -e "\033[1;33mTest\033[0m")
assertEquals "$expected" "$(cat $STDERRF)"
local expected
expected=$(echo -e "\033[1;33mTest\033[0m")
assertEquals "$expected" "$(cat "$STDERRF")"
}
function test_info(){
assertCommandSuccess info "Test"
local expected=$(echo -e "\033[1;36mTest\033[0m")
assertEquals "$expected" "$(cat $STDOUTF)"
local expected
expected=$(echo -e "\033[1;36mTest\033[0m")
assertEquals "$expected" "$(cat "$STDOUTF")"
}
function test_die(){
assertCommandFail die "Test"
local expected=$(echo -e "\033[1;31mTest\033[0m")
assertEquals "$expected" "$(cat $STDERRF)"
local expected
expected=$(echo -e "\033[1;31mTest\033[0m")
assertEquals "$expected" "$(cat "$STDERRF")"
}
function test_die_on_status(){
assertCommandFailOnStatus 222 die_on_status 222 "Test"
local expected=$(echo -e "\033[1;31mTest\033[0m")
assertEquals "$expected" "$(cat $STDERRF)"
local expected
expected=$(echo -e "\033[1;31mTest\033[0m")
assertEquals "$expected" "$(cat "$STDERRF")"
}
function test_ask_null_question(){
@ -79,34 +87,12 @@ function test_ask_wrong_default_answer() {
assertEquals 33 $?
}
function test_check_and_trap_fail() {
trap echo EXIT
trap ls QUIT
assertCommandFailOnStatus 1 check_and_trap 'pwd' EXIT QUIT
}
function test_check_and_trap() {
trap - EXIT QUIT
assertCommandSuccess check_and_trap 'echo' EXIT QUIT
}
function test_check_and_force_trap_fail() {
trap echo EXIT
trap ls QUIT
assertCommandSuccess check_and_force_trap 'echo' EXIT QUIT
}
function test_check_and_force_trap() {
trap - EXIT QUIT
assertCommandSuccess check_and_force_trap 'echo' EXIT QUIT
}
function test_insert_quotes_on_spaces(){
assertCommandSuccess insert_quotes_on_spaces this is "a test"
assertEquals "this is \"a test\"" "$(cat $STDOUTF)"
assertEquals "this is \"a test\"" "$(cat "$STDOUTF")"
assertCommandSuccess insert_quotes_on_spaces this is 'a test'
assertEquals "this is \"a test\"" "$(cat $STDOUTF)"
assertEquals "this is \"a test\"" "$(cat "$STDOUTF")"
}
function test_contains_element(){
@ -116,4 +102,4 @@ function test_contains_element(){
assertCommandFailOnStatus 1 contains_element "blabla" "${array[@]}"
}
source $(dirname $0)/../utils/shunit2
source "$(dirname "$0")"/../utils/shunit2

139
tests/unit-tests/test-wrappers.sh Executable file
View file

@ -0,0 +1,139 @@
#!/bin/bash
# shellcheck disable=SC1091
source "$(dirname "$0")/../utils/utils.sh"
source "$(dirname "$0")/../../lib/core/wrappers.sh"
# Disable the exiterr
set +e
function oneTimeSetUp(){
setUpUnitTests
}
function setUp(){
junestSetUp
}
function tearDown(){
junestTearDown
}
function test_create_wrappers_empty_bin(){
assertCommandSuccess create_wrappers
assertEquals "" "$(cat "$STDOUTF")"
assertTrue "bin_wrappers does not exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]"
}
function test_create_wrappers_not_executable_file(){
touch "$JUNEST_HOME"/usr/bin/myfile
assertCommandSuccess create_wrappers
assertEquals "" "$(cat "$STDOUTF")"
assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]"
assertTrue "myfile wrapper should not exist" "[ ! -x $JUNEST_HOME/usr/bin_wrappers/myfile ]"
}
function test_create_wrappers_directory(){
mkdir -p "$JUNEST_HOME"/usr/bin/mydir
assertCommandSuccess create_wrappers
assertEquals "" "$(cat "$STDOUTF")"
assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]"
assertTrue "mydir wrapper should not exist" "[ ! -e $JUNEST_HOME/usr/bin_wrappers/mydir ]"
}
function test_create_wrappers_broken_link(){
ln -s /opt/myapp/bin/cmd "$JUNEST_HOME"/usr/bin/cmd
assertCommandSuccess create_wrappers
assertEquals "" "$(cat "$STDOUTF")"
assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]"
assertTrue "cmd wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/cmd ]"
}
function test_create_wrappers_executable_file(){
touch "$JUNEST_HOME"/usr/bin/myfile
chmod +x "$JUNEST_HOME"/usr/bin/myfile
assertCommandSuccess create_wrappers
assertEquals "" "$(cat "$STDOUTF")"
assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]"
assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]"
}
function test_create_wrappers_verify_content(){
# Test for:
# https://github.com/fsquillace/junest/issues/262
# https://github.com/fsquillace/junest/issues/292
touch "$JUNEST_HOME"/usr/bin/myfile
chmod +x "$JUNEST_HOME"/usr/bin/myfile
export JUNEST_ARGS="ns --fakeroot -b '--bind /run /run2'"
assertCommandSuccess create_wrappers
assertEquals "" "$(cat "$STDOUTF")"
# Mock junest command to capture the actual output generated from myfile script
# shellcheck disable=SC2317
junest(){
for arg in "$@"
do
echo "$arg"
done
}
assertEquals "ns
--fakeroot
-b
--bind /run /run2
--
test-wrappers.sh
pacman
-Rsn
neovim
new package" "$(source "$JUNEST_HOME"/usr/bin_wrappers/myfile pacman -Rsn neovim 'new package')"
}
function test_create_wrappers_already_exist(){
touch "$JUNEST_HOME"/usr/bin/myfile
chmod +x "$JUNEST_HOME"/usr/bin/myfile
mkdir -p "$JUNEST_HOME"/usr/bin_wrappers
echo "original" > "$JUNEST_HOME"/usr/bin_wrappers/myfile
chmod +x "$JUNEST_HOME"/usr/bin_wrappers/myfile
assertCommandSuccess create_wrappers false
assertEquals "" "$(cat "$STDOUTF")"
assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]"
assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]"
assertEquals "original" "$(cat "$JUNEST_HOME"/usr/bin_wrappers/myfile)"
}
function test_create_wrappers_forced_already_exist(){
echo "new" > "$JUNEST_HOME"/usr/bin/myfile
chmod +x "$JUNEST_HOME"/usr/bin/myfile
mkdir -p "$JUNEST_HOME"/usr/bin_wrappers
echo "original" > "$JUNEST_HOME"/usr/bin_wrappers/myfile
chmod +x "$JUNEST_HOME"/usr/bin_wrappers/myfile
assertCommandSuccess create_wrappers true
assertEquals "" "$(cat "$STDOUTF")"
assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]"
assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]"
assertNotEquals "original" "$(cat "$JUNEST_HOME"/usr/bin_wrappers/myfile)"
}
function test_create_wrappers_executable_no_longer_exist(){
mkdir -p "$JUNEST_HOME"/usr/bin_wrappers
touch "$JUNEST_HOME"/usr/bin_wrappers/myfile
chmod +x "$JUNEST_HOME"/usr/bin_wrappers/myfile
assertCommandSuccess create_wrappers
assertEquals "" "$(cat "$STDOUTF")"
assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]"
assertTrue "myfile wrapper should not exist" "[ ! -x $JUNEST_HOME/usr/bin_wrappers/myfile ]"
}
function test_create_wrappers_custom_bin_path(){
mkdir -p "$JUNEST_HOME"/usr/mybindir
touch "$JUNEST_HOME"/usr/mybindir/myfile
chmod +x "$JUNEST_HOME"/usr/mybindir/myfile
assertCommandSuccess create_wrappers false /usr/mybindir/
assertEquals "" "$(cat "$STDOUTF")"
assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/mybindir_wrappers ]"
assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/mybindir_wrappers/myfile ]"
}
source "$(dirname "$0")"/../utils/shunit2

View file

@ -1,6 +1,7 @@
#!/bin/bash
tests_succeded=true
for tst in $(ls $(dirname $0)/test* | grep -v $(basename $0))
# shellcheck disable=SC2010
for tst in $(ls "$(dirname "$0")"/test* | grep -v "$(basename "$0")")
do
$tst || tests_succeded=false
done

View file

@ -987,7 +987,7 @@ _shunit_extractTestFunctions()
# extract the lines with test function names, strip of anything besides the
# function name, and output everything on a single line.
_shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)'
egrep "${_shunit_regex_}" "${_shunit_script_}" \
grep -E "${_shunit_regex_}" "${_shunit_script_}" \
|sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \
|xargs

View file

@ -1,25 +1,28 @@
#!/usr/bin/env bash
OLD_CWD=${PWD}
function cwdSetUp(){
ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX)
cd $ORIGIN_CWD
cd "$ORIGIN_CWD" || return 1
}
function cwdTearDown(){
rm -rf $ORIGIN_CWD
cd $OLD_CWD
rm -rf "$ORIGIN_CWD"
cd "$OLD_CWD" || return 1
}
function junestSetUp(){
JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX)
mkdir -p ${JUNEST_HOME}/etc/junest
echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info
mkdir -p ${JUNEST_HOME}/etc/ca-certificates
mkdir -p "${JUNEST_HOME}/usr/bin"
mkdir -p "${JUNEST_HOME}/etc/junest"
echo "JUNEST_ARCH=x86_64" > "${JUNEST_HOME}/etc/junest/info"
mkdir -p "${JUNEST_HOME}/etc/ca-certificates"
}
function junestTearDown(){
# the CA directories are read only and can be deleted only by changing the mod
[ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates
rm -rf $JUNEST_HOME
[ -d "${JUNEST_HOME}/etc/ca-certificates" ] && chmod -R +w "${JUNEST_HOME}/etc/ca-certificates"
rm -rf "$JUNEST_HOME"
unset JUNEST_HOME
}
@ -31,15 +34,17 @@ function setUpUnitTests(){
}
function assertCommandSuccess(){
# shellcheck disable=SC2091
$(set -e
"$@" > $STDOUTF 2> $STDERRF
"$@" > "$STDOUTF" 2> "$STDERRF"
)
assertTrue "The command $1 did not return 0 exit status" $?
}
function assertCommandFail(){
# shellcheck disable=SC2091
$(set -e
"$@" > $STDOUTF 2> $STDERRF
"$@" > "$STDOUTF" 2> "$STDERRF"
)
assertFalse "The command $1 returned 0 exit status" $?
}
@ -49,8 +54,9 @@ function assertCommandFail(){
function assertCommandFailOnStatus(){
local status=$1
shift
# shellcheck disable=SC2091
$(set -e
"$@" > $STDOUTF 2> $STDERRF
"$@" > "$STDOUTF" 2> "$STDERRF"
)
assertEquals $status $?
assertEquals "$status" $?
}