Compare commits

...
391 Commits
Author SHA1 Message Date
Kroese 799649e78c docs: Improve low diskspace warning (#1158) 2026-05-24 14:29:17 +02:00
Kroese 12060c72b2 feat: Update warning message (#1157) 2026-05-23 20:31:37 +02:00
Kroese 6eadd1b953 fix: Timeout comparison operator (#1155) 2026-05-17 13:01:57 +02:00
Kroese 342ca4da03 fix: Wrong IP was passed to getSlirp (#1154) 2026-05-17 12:27:58 +02:00
Kroese b0b6190560 feat: Add warning when macvlan parent is a bridge (#1153)
Fixes #1152
2026-05-17 06:56:55 +02:00
Kroese 075410e4cf fix: CPU cores validation logic (#1151) 2026-05-16 20:59:57 +02:00
Kroese 2a388b434b feat: Improve Dnsmasq error handling (#1149) 2026-05-16 11:35:04 +02:00
Kroese 280c4037f3 fix: CPU cores validation logic (#1150) 2026-05-16 11:33:23 +02:00
Kroese 007bdc735d fix: Warning message for missing clock source (#1148) 2026-05-16 10:58:37 +02:00
Kroese 41fc0a6a10 fix: Undeclared variable in ConvertDisk (#1147) 2026-05-16 10:11:37 +02:00
Kroese 7753e4ac74 fix: Slirp portmapping was missing last port (#1146) 2026-05-16 02:22:44 +02:00
Kroese f74bf35202 fix: Socket detection logic (#1145) 2026-05-16 02:17:55 +02:00
Kroese aa472c96c6 feat: Use iptables multiport extension (#1144) 2026-05-15 23:28:01 +02:00
Kroese 0dcb880800 fix: Do not remove QEMU files (#1143) 2026-05-15 22:43:44 +02:00
Kroese 8daa6973b7 feat: Do not require NET_RAW for dnsmasq (#1142) 2026-05-15 21:30:16 +02:00
Kroese 3884befa56 feat: Improve memory allocation logic (#1141) 2026-05-15 17:58:41 +02:00
Kroese 85b83f8eb1 feat: Remove reliability on iptables multiport extension (#1140) 2026-05-15 17:44:35 +02:00
Kroese f395dfaa66 feat: Removed legacy code (#1139) 2026-05-14 20:59:36 +02:00
Kroese b3124075ea feat: Refactor QEMU PID variables (#1138) 2026-05-10 17:34:22 +02:00
Kroese aed909bdee fix: NFT tables detection (#1137) 2026-05-10 17:24:02 +02:00
Kroese d4cf5778e2 build: Update Passt to v2026_05_07 (#1136) 2026-05-10 17:20:26 +02:00
Kroese 48de7dd00b fix: Size comparison variables (#1135) 2026-05-10 17:16:20 +02:00
dependabot[bot] 686e64da3f build(deps): Bump docker/setup-buildx-action from 3 to 4 (#1130) 2026-05-10 17:15:02 +02:00
dependabot[bot] 7517dc8b3e build(deps): Bump docker/metadata-action from 5 to 6 (#1131) 2026-05-10 17:13:41 +02:00
renovate[bot] 660fe715e4 chore(deps): update grantbirki/json-yaml-validate action to v5 (#1134) 2026-05-10 17:06:56 +02:00
dependabot[bot] 04ea29ec77 build(deps): Bump docker/build-push-action from 6 to 7 (#1132) 2026-05-10 17:05:14 +02:00
dependabot[bot] 02c891cb16 build(deps): Bump docker/login-action from 3 to 4 (#1129) 2026-05-10 17:04:00 +02:00
Quang-Linh LE 0b5d21357e fiz: Ignore sector size for whole disk passthrough (#1121) 2026-01-13 11:40:35 +01:00
Kroese e0545b37d7 fix: Avoid duplicating dnsmasq arguments (#1113) 2025-11-22 04:28:11 +01:00
renovate[bot] 4161c21082 chore(deps): update actions/checkout action to v6 (#1112)
Update / dockerHubDescription (push) Has been cancelled
2025-11-21 12:39:39 +01:00
Kroese 48d9a1771d fix: Update Codespaces configuration (#1110) 2025-11-14 06:05:19 +01:00
Kroese 471cdbb338 fix: Workaround AppArmor profile for passt (#1108) 2025-11-12 07:03:22 +01:00
Kroese e77bca202b fix: Spelling mistake (#1105) 2025-11-06 03:46:35 +01:00
Kroese 2e6c01e934 feat: Detect if container is running in privileged mode (#1104) 2025-11-06 03:39:46 +01:00
Kroese 302c991c0c fix: Change condition for OverlayFS warning (#1103) 2025-11-06 03:22:47 +01:00
Kroese a89007ee03 build: Use Github token (#1100) 2025-10-29 14:05:53 +01:00
Kroese 8a89149d58 feat: Check for SSE4 instruction set (#1099) 2025-10-29 08:32:42 +01:00
Kroese 5e8bbc2868 fix: Remove unnecessary operation (#1097) 2025-10-24 04:30:21 +02:00
Kroese 4e48920309 fix: Do not assume Podman never has privileges (#1096) 2025-10-24 01:19:38 +02:00
Kroese 8b145924b9 fix: Reduce spare disk space threshold (#1093)
Update / dockerHubDescription (push) Has been cancelled
2025-10-22 02:47:50 +02:00
Kroese a0328e1e9c fix: Inherit owner from parent folder (#1092) 2025-10-22 02:38:57 +02:00
Kroese b7f5214a7b build: Add code quality checks (#1091) 2025-10-22 00:59:35 +02:00
Kroese b0e4c4ac5f docs: Update docker run command (#1090) 2025-10-21 23:15:31 +02:00
Kroese bbb67aac93 build: Add review workflow for shell formatting (#1089) 2025-10-21 22:39:50 +02:00
Kroese 433c83b393 fix: Kill QEMU after 5 seconds if it hangs (#1088) 2025-10-19 17:56:44 +02:00
Kroese 5577178eeb fix: Only display non-zero percentage (#1087) 2025-10-19 17:32:25 +02:00
Kroese 221b0242fa fix: Kill QEMU after 5 seconds when it hangs (#1086) 2025-10-19 16:57:51 +02:00
Kroese c05623f8af fix: Round filesize up to nearest cluster (#1085) 2025-10-19 14:38:36 +02:00
Kroese eb9884cc96 feat: Improve Github Codespaces configuration (#1084) 2025-10-19 12:48:40 +02:00
Kroese 8e2490e6bc feat: Improve Github Codespaces configuration (#1082) 2025-10-19 10:40:03 +02:00
Kroese 399243886e feat: Show directory size (#1083) 2025-10-19 09:40:45 +02:00
Kroese b0dbfcb805 feat: Improve Github Codespaces configuration (#1081) 2025-10-19 01:14:11 +02:00
Kroese dec2dc9230 feat: Check free diskspace during startup (#1080) 2025-10-17 16:47:43 +02:00
Kroese 2c44669d91 feat: Improve Codespaces configuration (#1079) 2025-10-17 13:25:02 +02:00
Kroese 175d90aad7 fix: Move order in entry file (#1078) 2025-10-17 13:04:03 +02:00
Kroese e1e5f8f91d fix: Validate status messages (#1077) 2025-10-17 12:07:13 +02:00
Kroese dff8abbe1e build: Validate JSON and YML files (#1076) 2025-10-17 10:05:52 +02:00
Kroese 0f97091e61 fix: Set network flag (#1075) 2025-10-17 01:39:49 +02:00
Kroese ea0d7ee6cd feat: Implement extra disksize preset (#1074) 2025-10-17 00:17:30 +02:00
Kroese 75daa31d36 feat: Implement extra CPU_CORES preset (#1073) 2025-10-17 00:15:56 +02:00
Kroese 8c44319c45 feat: Move memory check to own module (#1072) 2025-10-16 23:49:16 +02:00
Kroese dac574d933 feat: Automatically adjust RAM size when too high (#1071) 2025-10-16 12:36:49 +02:00
Kroese fd4c5001e8 feat: Update Github Codespaces configuration (#1070) 2025-10-16 09:43:19 +02:00
Kroese dfe0b23995 feat: Improve Github Codespaces configuration (#1069) 2025-10-15 23:58:01 +02:00
Kroese 6158372eaa fix: Remove nat option (#1068)
Update / dockerHubDescription (push) Has been cancelled
2025-10-15 14:39:28 +02:00
Kroese b1a778d7b2 docs: Readme (#1067) 2025-10-15 12:43:07 +02:00
Kroese bc0defd813 feat: Add custom .yml for Github Codespaces (#1066) 2025-10-15 11:39:36 +02:00
Kroese 48e7a9fff0 fix: Round down minimum disk size (#1065) 2025-10-15 11:37:05 +02:00
Kroese c2fa58ef27 feat: Fall back to slirp when passt fails (#1064) 2025-10-15 10:31:42 +02:00
Kroese ea49cb144b feat: Validate user port configuration (#1063) 2025-10-14 16:44:11 +02:00
Kroese b8e778a79d fix: Configure ports for Slirp networking (#1062) 2025-10-14 14:16:20 +02:00
Kroese c70e12f0a2 fix: Lower spare disk space (#1061)
Reduced spare disk space threshold from 2GB to 512MB.
2025-10-14 03:33:25 +02:00
Kroese 6281205912 feat: Add "max" setting for DISK_SIZE (#1060) 2025-10-14 01:22:44 +02:00
Kroese 1ffc5c55b2 fix: Show Passt output on error (#1059) 2025-10-13 14:11:54 +02:00
Kroese c3302e1720 fix: Rename physical to logical (#1058) 2025-10-13 09:28:25 +02:00
Kroese 25227944b5 fix: Do not reset loading animation (#1056) 2025-10-12 01:51:17 +02:00
Kroese 06650e916a build: Run check for all files (#1057)
Removed specific paths from pull request triggers.
2025-10-12 01:48:25 +02:00
Kroese 2e34dffed5 feat: Expose only selected ports with Passt (#1055) 2025-10-12 01:44:24 +02:00
Kroese 3db91f077f fix: Relay last status message (#1054) 2025-10-11 17:56:44 +02:00
Kroese fae14f4dd9 feat: Set listening interface for Passt (#1052) 2025-10-09 11:48:08 +02:00
Kroese d190b3ba87 feat: Use websocket for status messages (#1051) 2025-10-08 21:28:26 +02:00
Kroese 554f3295cb fix: Terminate tail on exit (#1049) 2025-10-08 08:13:27 +02:00
Kroese cdc4689d6a feat: Use the engine variable (#1048) 2025-10-07 12:41:42 +02:00
Kroese 21d18fd439 feat: Improve healthcheck (#1047) 2025-10-07 05:53:06 +02:00
Kroese fd5ec52226 fix: Check if logfile exists (#1046) 2025-10-07 02:21:49 +02:00
Kroese fc7ab22741 fix: Use gateway MAC for passt (#1045) 2025-10-07 02:15:26 +02:00
Kroese 59cf59faa4 feat: Improved networking implementation (#1044) 2025-10-07 00:58:34 +02:00
Kroese 705c6ce7f1 fix: Exclude 'tap' from bus check (#1043) 2025-10-05 17:06:57 +02:00
Kroese f2937ab507 feat: Allow large MTU sizes (#1042) 2025-10-04 10:35:20 +02:00
Kroese 399829cf3c feat: Make monitor port configurable (#1041) 2025-10-04 09:39:20 +02:00
xrh0905 b694d6faf8 feat: Support 8k sector sizes (#1040) 2025-10-03 12:57:08 +02:00
Kroese 7acd1f6cdb feat: Enhanced Dnsmasq logging (#1039) 2025-10-03 01:54:44 +02:00
Kroese 09ca3bf118 feat: Add debug trace option (#1038) 2025-10-02 17:18:53 +02:00
renovate[bot] 6cac45c397 chore(deps): update peter-evans/dockerhub-description action to v5 (#1037)
Update / dockerHubDescription (push) Has been cancelled
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-01 23:39:30 +02:00
Kroese f18663d840 feat: Network mode detection (#1036) 2025-10-01 13:05:13 +02:00
Kroese fefe1af9e6 fix: CPU detection (#1035)
Refactor CPU string processing to remove 'th Gen' suffix.
2025-09-30 17:18:43 +02:00
Kroese 87a8cf7513 feat: Support 32k sector sizes (#1034) 2025-09-30 10:49:07 +02:00
Kroese 7f31cb6023 fix: Detect host mode networking (#1033) 2025-09-30 10:32:00 +02:00
Kroese 138742c953 feat: Increase default disksize (#1030)
Update / dockerHubDescription (push) Has been cancelled
2025-09-28 18:22:44 +02:00
Kroese 2c6efc45f2 feat: Make webserver port configurable (#1028) 2025-09-27 11:44:13 +02:00
Kroese 24d795fbe3 buid: Add ethtool package (#1027) 2025-09-27 10:45:09 +02:00
Kroese 7fae62d286 feat: Detect host mode networking (#1026) 2025-09-27 10:44:02 +02:00
Kroese 2135df07ea docs: Additional info for user-mode networking (#1025) 2025-09-27 10:08:11 +02:00
Kroese 521beedf1c feat: Add note for MAC address availability (#1024) 2025-09-27 09:49:11 +02:00
Kroese e362c9a8a9 feat: Update error message for KVM acceleration (#1023) 2025-09-24 16:10:32 +02:00
Kroese 78817ecfc1 fix: Remove default model (#1022) 2025-09-23 16:04:44 +02:00
Kroese 8de7f56ff8 feat: Add KVM warning (#1021) 2025-09-23 16:02:42 +02:00
Kroese 2e2017470e fix: Syntax for arithmetic operations (#1020) 2025-09-22 20:24:23 +02:00
Kroese 0a0cd98de3 feat: Add "max" setting to automaticly set CPU cores and RAM (#1019) 2025-09-22 16:59:02 +02:00
renovate[bot] 17187dd23a chore(deps): update hadolint/hadolint-action action to v3.3.0 (#1018)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-22 16:56:58 +02:00
Kroese 10237b31cf revert: Simplify conditional checks (#1017)
This reverts commit 6883efb857.
2025-09-21 23:08:00 +02:00
Kroese 6883efb857 fix: Simplify conditional checks (#1016) 2025-09-21 15:09:52 +02:00
Kroese 1ca55cad8f feat: Limit CPU_CORES to amount of physical cores (#1015) 2025-09-21 13:41:20 +02:00
Kroese f841eb1ef1 fix: Simplify conditional checks (#1014) 2025-09-20 23:47:00 +02:00
Kroese 1ee49332f3 feat: Improve CPU detection (#1013) 2025-09-20 21:43:35 +02:00
Kroese 095e618785 feat: Make webserver optional (#1012) 2025-09-18 23:45:05 +02:00
Kroese 57a902ad9f feat: add UDP support to USER_PORTS (#1011)
Allow USER_PORTS entries in the form PORT or PORT/PROTO (tcp or udp). When the protocol is omitted, TCP is assumed for backward compatibility. This enables forwarding of UDP services when running the container in user‑mode networking.
2025-09-17 21:49:20 +02:00
xrh0905 a7e229aaae feat: Add IPQuery.io as additional comparison source for the country code (#1006) 2025-09-17 17:55:54 +02:00
Kroese 10466d7851 feat: Parse CPU flags (#1010) 2025-09-17 17:54:50 +02:00
Kroese 238ebd273b build: Disable automatic builds (#1009)
Removed push triggers and paths to ignore from build workflow.
2025-09-14 11:54:51 +02:00
renovate[bot] 0b08f4212e chore(deps): update hadolint/hadolint-action action to v3.2.0 (#1008)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-03 16:43:41 +02:00
Kroese 9aec5d20e3 feat: Check if storage folder is writeable (#1005)
Build / Check (push) Has been cancelled
Update / dockerHubDescription (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-08-27 22:50:23 +02:00
Kroese a19bf2f066 feat: Check if storage folder is writeable (#1004) 2025-08-27 22:48:23 +02:00
Kroese bee68ee548 feat: Add syntax parser directive (#1003) 2025-08-27 21:29:28 +02:00
xrh0905 520c70ab22 feat: Allow shutdown timeout override (#995)
Mitigation #987
2025-08-27 19:58:02 +02:00
dependabot[bot] 67a7fbc94b build(deps): Bump actions/checkout from 4 to 5 (#1001)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-27 19:56:41 +02:00
Kroese 1b8054e847 fix: Podman detection (#990)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-05-27 00:50:40 +02:00
Kroese 631a558a9f feat: Enable IPv6 support for user-mode container networking (#983)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-27 11:28:54 +02:00
Kroese d5805b4e08 feat: Check CPU vendor (#982) 2025-04-27 11:21:37 +02:00
Kroese 1dc15ce2e0 docs: Add input types (#981) 2025-04-23 12:54:22 +02:00
Kroese 4145e811df feat: Improve CPU detection (#980)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-20 21:43:02 +02:00
Kroese fe8615d7d3 docs: Add quotes around $PWD (#977)
Build / Check (push) Has been cancelled
Update / dockerHubDescription (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-16 12:10:59 +02:00
Kroese 27ea5506bc feat: Default to 2 CPU cores and 2GB of RAM (#976) 2025-04-16 11:56:02 +02:00
Kroese 394131a0d7 feat: Podman detection (#972)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-09 09:01:01 +02:00
Kroese 4d0d16023f feat: Podman detection (#971) 2025-04-09 08:58:02 +02:00
Kroese 60dd794b29 fix: Avoid pipe to head on find (#970) 2025-04-09 08:03:41 +02:00
Kroese f13d104968 build: Add root-user-action flag (#968)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-08 07:53:17 +02:00
Kroese 914099fd12 build: Add --root-user-action flag (#967)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-07 18:47:36 +02:00
Kroese 639725957d fix: Permission errors on QNAP (#966) 2025-04-07 18:36:47 +02:00
Kroese 64bbe82c4a fix: KVM warning (#965)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
Update / dockerHubDescription (push) Has been cancelled
2025-04-07 17:44:26 +02:00
Kroese 73a13e5697 fix: QNAP permission errors (#964) 2025-04-07 17:20:14 +02:00
Kroese e8ec5fb8ed feat: Support 4k sector sizes (#963) 2025-04-07 13:25:20 +02:00
Kroese 0b500ca377 docs: Disk pass-through (#960)
Update / dockerHubDescription (push) Has been cancelled
2025-04-03 10:22:26 +02:00
Kroese df58745ed8 fix: Ignore missing custom .pat after install (#959)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-03 01:13:14 +02:00
Kroese 55e8ab4930 docs: Github Codespaces (#956)
Update / dockerHubDescription (push) Has been cancelled
2025-03-27 01:48:40 +01:00
Kroese 4882fd3bf6 fix: Local file support (#955)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-03-26 19:51:58 +01:00
Kroese 3e69f4bcc9 feat: New extraction method (#954)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-26 09:24:13 +01:00
Kroese 39428909d6 docs: Installation (#953)
Update / dockerHubDescription (push) Waiting to run
2025-03-26 02:47:28 +01:00
Kroese 71d2ed40db docs: Github Codespaces (#952)
Update / dockerHubDescription (push) Waiting to run
2025-03-25 14:49:46 +01:00
Kroese 9ad21a28a6 docs: Disk pass-through (#951) 2025-03-25 12:18:38 +01:00
Kroese 0c7acd6e71 fix: Remove non-printable characters (#949)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-03-24 13:52:38 +01:00
Kroese ad26129375 docs: KVM information (#947)
Update / dockerHubDescription (push) Has been cancelled
2025-03-20 23:21:41 +01:00
Kroese 4e7822fedd docs: Compatibility chart (#946) 2025-03-20 23:07:14 +01:00
Kroese 4dfcbe4ab1 docs: Add Podman (#945) 2025-03-20 20:09:53 +01:00
Kroese 8fb6f1f9ad feat: Podman detection (#944)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-03-20 11:54:26 +01:00
Kroese 11d4fafa6d fix: User-mode networking (#943)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-20 03:07:01 +01:00
Kroese be15557798 fix: User-mode networking (#942) 2025-03-20 03:05:50 +01:00
Kroese 1e83757494 fix: Set user-mode IP address (#941)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-19 12:55:53 +01:00
Kroese fad463a439 feat: Add devcontainer (#940)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-19 09:17:48 +01:00
Kroese 608563d029 feat: Add devcontainer (#939)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-18 19:25:27 +01:00
Kroese 5fcd22b09f docs: Formatting (#938)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
Update / dockerHubDescription (push) Has been cancelled
2025-03-18 14:24:05 +01:00
Kroese 65548da2ef docs: Github Codespaces (#937) 2025-03-18 14:10:08 +01:00
Kroese 111e513dac docs: Github Codespaces (#936) 2025-03-18 14:09:10 +01:00
Kroese 7fce3a98fe feat: Refactor helper functions (#935) 2025-03-18 12:57:52 +01:00
Kroese 4018eeadb4 fix: Remove port 80 (#934)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
Update / dockerHubDescription (push) Waiting to run
2025-03-18 05:03:54 +01:00
Kroese a8e4647fa6 feat: IPv6 support (#933) 2025-03-18 03:59:58 +01:00
Kroese 36d3fca4fc fix: Fallback to POSIX fallocate (#932)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-17 11:19:04 +01:00
Kroese 89b28f36d3 docs: Disk pass-through (#930)
Update / dockerHubDescription (push) Has been cancelled
2025-03-16 12:30:06 +01:00
Kroese b4f7d70a7a docs: Readme (#929)
Update / dockerHubDescription (push) Waiting to run
2025-03-16 06:52:14 +01:00
Kroese 902bafbd0c docs: Readme (#928) 2025-03-16 06:40:38 +01:00
Kroese 7ad5c7fa70 fix: Display available memory (#926)
Update / dockerHubDescription (push) Waiting to run
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-03-15 14:09:17 +01:00
Kroese 4d29f056b7 fix: Format filesizes (#925)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-14 18:53:53 +01:00
Kroese 36af9a3483 feat: Validate configured RAM (#924)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-14 14:42:08 +01:00
Kroese 5e6f931433 feat: Detect clock source (#923) 2025-03-14 14:16:10 +01:00
Kroese beadfe720c feat: Improve CPU detection (#921)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-14 05:23:49 +01:00
Kroese 92b4bfc383 feat: Validate configured RAM (#920)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-13 11:35:08 +01:00
Kroese 092ed23085 feat: Check CPU core configuration (#919) 2025-03-13 10:47:25 +01:00
Kroese c70fa3d00a feat: Validate specified size (#918)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-12 21:17:47 +01:00
Kroese fea0ba09f6 docs: Use relative paths (#917)
Update / dockerHubDescription (push) Has been cancelled
2025-03-12 12:31:50 +01:00
Kroese 7d2af63eac docs: Kubernetes deployment (#916)
Update / dockerHubDescription (push) Has been cancelled
2025-03-07 00:42:29 +01:00
Kroese 2e73bf560e docs: Add link to download (#915) 2025-03-07 00:22:29 +01:00
Kroese bfc8d7a9c6 fix: Network shutdown (#912)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-03-05 04:59:57 +01:00
Kroese a1e9936572 fix: Set MTU value (#911)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-04 15:37:37 +01:00
Kroese 3675a50129 fix: Gateway MAC generation (#910)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-03 13:57:53 +01:00
Kroese 91229152bd feat: Set MTU size for TAP interface (#909) 2025-03-03 13:40:15 +01:00
Kroese a1993e590a feat: Automaticly match MTU size (#908) 2025-03-03 12:20:16 +01:00
Kroese 52fe712b6f docs: Readme (#907)
Update / dockerHubDescription (push) Has been cancelled
2025-03-01 14:23:51 +01:00
Kroese 7f400b6b59 feat: Improve CPU detection (#905)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-02-27 11:52:48 +01:00
Kroese 9cb88a99e6 feat: Allow bridge networks (#904) 2025-02-27 11:46:38 +01:00
Kroese b967a471b5 fix: Add e2fsprogs package (#902)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-02-26 10:03:46 +01:00
Kroese f40127df01 feat: Make app name configurable (#900)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-02-25 15:13:57 +01:00
Kroese 8c5e0ee274 fix: Generate local MAC address (#899)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-02-24 21:01:55 +01:00
Kroese 2adf0b292b fix: Preserve gateway MAC address (#898)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-02-24 03:48:42 +01:00
Kroese 1c9b793c75 fix: Move nginx config (#893)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-02-15 02:36:07 +01:00
Kroese 00c4ef7795 feat: Remove existing TAP interface (#892)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-02-14 20:19:12 +01:00
Kroese 619657adf2 docs: Add restart policy (#888)
Update / dockerHubDescription (push) Has been cancelled
2025-02-10 00:31:32 +01:00
Kroese 41db7c1035 feat: Improve CPU detection (#884)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-02-06 02:19:39 +01:00
Kroese d71834a777 build: Enable ARM64 platform (#873) 2025-01-10 18:44:37 +01:00
Kroese d078af0397 fix: TUN device error (#863)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-12-03 11:50:56 +01:00
Kroese 2827d1d375 docs: Add TUN device (#861)
Update / dockerHubDescription (push) Has been cancelled
2024-12-01 17:57:00 +01:00
Kroese 898499a4e3 feat: Make network adapter configurable (#859)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-11-26 20:01:37 +01:00
Kroese eb010cc215 feat: Improve network error handling (#856)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-11-20 16:24:07 +01:00
Kroese 84440d5159 fix: Use relative URL's (#855) 2024-11-20 13:21:20 +01:00
Kroese ff3744ead9 feat: Improve CPU detection (#854)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2024-11-20 13:13:43 +01:00
Kroese d00fe4b3eb docs: Readme (#848)
Build / Check (push) Has been cancelled
Update / dockerHubDescription (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-11-13 03:45:21 +01:00
Kroese 72a86a5d7f docs: Add Kubernetes URL (#847) 2024-11-13 03:35:50 +01:00
Kroese 811ab622df docs: Add compatibility chart (#846) 2024-11-13 03:26:15 +01:00
Kroese e76b72cddf feat: Disable HTTP keepalives (#845) 2024-11-13 02:48:27 +01:00
Kroese e9edacc9c3 feat: Support image commit (#844)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
Update / dockerHubDescription (push) Waiting to run
2024-11-13 00:39:48 +01:00
Kroese a6694a6b29 feat: Rename host to kernel (#843)
Build / Check (push) Has been cancelled
Update / dockerHubDescription (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-11-11 16:24:47 +01:00
Kroese 59323cd375 docs: KVM troubleshooting (#842) 2024-11-11 14:16:21 +01:00
Kroese 6dc714e449 feat: Display unknown filesystem (#841)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2024-11-10 15:00:38 +01:00
Kroese 5d75a9b039 feat: Improve CPU detection (#840) 2024-11-10 11:21:51 +01:00
Kroese 92b4cf5997 build: Use latest Debian image (#832)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-10-19 22:09:52 +02:00
Kroese 906e61b1b2 feat: Improve CPU detection (#831)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-10-15 10:27:51 +02:00
Kroese dab230f9d5 build: Remove ARM64 platform (#830)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2024-10-15 00:37:28 +02:00
Kroese 5e8bcda9fc feat: Improve CPU detection (#829) 2024-10-14 18:06:02 +02:00
Kroese d4bf83ae86 feat: Add NVME disk type (#828)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-10-13 03:03:32 +02:00
xrh0905 8244a48511 Correct the possible DISK_IO (io_uring) (#827)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-10-06 16:26:35 +02:00
Kroese 43ffa18a5f fix: Remove scsi parameter from virtio-blk-pci (#824)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-10-01 21:49:31 +02:00
Kroese b131a32d0c buid: Pin Debian version (#818)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-09-27 14:40:56 +02:00
D-Jy c81787b837 feat: Allow custom rendernode (#817)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-09-17 23:30:58 +02:00
Kroese f9df3c6db6 feat: Update to VirtualDSM 7.2.2 (#815)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-09-11 19:20:43 +02:00
Liang Ying-Ruei e383ec30e3 fix: Splits $USER_PORTS correctly by commas (#813)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-09-09 15:43:57 +02:00
Kroese 1197c4791e fix: Port forwarding warning (#809)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-09-05 18:58:23 +02:00
Kroese 106c684389 docs: Update package URL (#808)
Update / dockerHubDescription (push) Has been cancelled
2024-09-03 15:09:33 +02:00
Kroese a199ced77b docs: Update package URL (#803)
Update / dockerHubDescription (push) Has been cancelled
2024-08-27 16:07:09 +02:00
Kroese 77ac73666e fix: Progress calculation (#799)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-08-18 17:55:07 +02:00
Kroese 64975557c2 fix: Validate lscpu output (#798)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2024-08-18 04:40:20 +02:00
Kroese b62321806a docs: Fix badge (#796)
Update / dockerHubDescription (push) Has been cancelled
2024-08-13 20:51:55 +02:00
renovate[bot] 7c392082b1 chore(deps): update docker/build-push-action action to v6 (#775)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 12:45:23 +02:00
Kroese 392e9a6417 docs: Networking (#774)
Update / dockerHubDescription (push) Has been cancelled
2024-06-16 06:09:26 +02:00
Kroese fb5f684e7e fix: Don't set script with file descriptor (#772)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-06-14 04:35:40 +02:00
Kroese 0dbc794223 feat: Customize image filenames (#771)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2024-06-14 03:01:27 +02:00
Kroese 6295ed3b7b docs: Removed Kubevirt dependancy (#770)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
Update / dockerHubDescription (push) Has been cancelled
2024-06-13 19:31:00 +02:00
Kroese 0f2d889858 fix: Assume GB when no unit is present (#769) 2024-06-13 18:59:13 +02:00
Kroese 60e6b01982 docs: Add markdown alerts (#768) 2024-06-13 18:31:25 +02:00
Kroese 1dc69f9e22 docs: Add GHCR badge (#767)
Update / dockerHubDescription (push) Has been cancelled
2024-06-11 23:26:38 +02:00
Kroese fcca41ad93 docs: Readme (#766) 2024-06-11 21:48:18 +02:00
Kroese 9897747425 docs: Add icons (#765) 2024-06-11 21:06:38 +02:00
Kroese 4dbe9dcefd docs: KVM information (#764) 2024-06-11 19:56:14 +02:00
Kroese be8bee90f2 feat: Implement usermode networking (#762)
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2024-06-11 02:13:53 +02:00
Kroese f8879029ec fix: Do not use IO threading for SATA disks (#760)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2024-06-09 18:34:55 +02:00
Kroese 7b491b3cee feat: Verify clocksource is set to TSC (#759)
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
Update / dockerHubDescription (push) Has been cancelled
2024-06-09 17:44:15 +02:00
Kroese 2ece865417 fix: Download error messages (#756) 2024-06-05 18:18:29 +02:00
Kroese 0d8c693c65 build: Update qemu-host to v2.05 (#755) 2024-06-05 14:32:21 +02:00
Kroese 9f7d1396b6 docs: Readme (#753) 2024-06-03 02:00:04 +02:00
Kroese 5ad323486e feat: Print QEMU version on boot (#752) 2024-06-02 23:00:40 +02:00
Kroese 19b4248929 feat: Print QEMU version on boot (#751) 2024-06-02 21:04:09 +02:00
Kroese c135c4cac3 feat: Add automatic device type (#749) 2024-05-27 17:25:52 +02:00
Kroese fb1751ff26 docs: Updated issue templates (#747) 2024-05-25 14:07:30 +02:00
Kroese 34f32d4ac6 docs: Docker CLI example (#746) 2024-05-22 07:55:38 +02:00
Kroese 36f1e47c0a fix: Check for Podman IP ranges (#745) 2024-05-21 13:48:05 +02:00
Kroese c5dd5c2e46 feat: Print arguments in debug mode (#743) 2024-05-21 09:17:51 +02:00
Kroese d1d920372a feat: Support more device types (#742) 2024-05-21 09:10:30 +02:00
Kroese 12d8fd3ed0 feat: Support Kubernetes interfaces (#741) 2024-05-21 07:44:44 +02:00
Kroese 729aed536e feat: Add flag to disable RAM check (#740) 2024-05-19 23:59:14 +02:00
Kroese b588f8c90d feat: Display KVM warning on ARM64 (#739) 2024-05-19 21:19:58 +02:00
Kroese 1f1007a0f1 fix: Display reason for network failure (#738) 2024-05-17 16:09:47 +02:00
Kroese 2ec37e2802 docs: Docker CLI (#737) 2024-05-16 03:22:58 +02:00
Slavik 3126b3847b feat: Add Kubernetes manifest (#735) 2024-05-16 01:42:58 +02:00
Kroese 41e0157e9d docs: Update issue templates (#736) 2024-05-16 01:12:16 +02:00
Kroese 1d64410849 docs: Update issue template (#734) 2024-05-15 22:04:25 +02:00
Kroese 55034b0f40 feat: Additional disk device (#733) 2024-05-15 17:56:12 +02:00
Kroese acffcf3774 docs: Remove restart policy (#732) 2024-05-15 17:23:09 +02:00
Kroese fba0eb527b docs: Remove version from compose (#731) 2024-05-15 16:54:17 +02:00
Kroese d9fc2714a6 build: Declare extra variable (#730) 2024-05-13 04:02:25 +02:00
Kroese d1f1772d74 build: Optimize Dockerfile (#729) 2024-05-13 03:48:29 +02:00
Kroese bf1d47e4f3 docs: Readme (#728) 2024-05-12 20:55:50 +02:00
Kroese 3da564dfd1 feat: Support install from local PAT file (#727) 2024-05-12 20:19:30 +02:00
Kroese abd30b9d91 feat: Detect Windows and MacOS (#726) 2024-05-11 22:11:11 +02:00
Kroese c86408cbd6 fix: Additional pass-through mounts (#722) 2024-05-08 23:23:17 +02:00
Kroese 1f51974c48 fix: Set download timeout (#719) 2024-05-04 17:24:21 +02:00
Kroese 29f4cde296 feat: Show download percentage (#718) 2024-05-04 16:34:30 +02:00
Kroese c4a0035062 feat: Display RAM amount warning (#717) 2024-05-03 11:18:20 +02:00
Kroese 6724ddbd7d feat: Check the amount of RAM available (#716) 2024-05-02 20:21:21 +02:00
Kroese 8d8ed63122 docs: Disk pass-through (#715) 2024-05-01 11:57:56 +02:00
Kroese 6f4ea81907 feat: New disk pass-through method (#714) 2024-05-01 00:13:26 +02:00
Kroese 6d162744ec feat: Improved networking (#712) 2024-04-30 00:30:44 +02:00
Kroese 145b4aab5b docs: Update issue templates (#708) 2024-04-26 16:53:15 +02:00
Kroese 2e4eb56d0b fix: Curl error on Chinese mirror (#707) 2024-04-26 16:32:08 +02:00
Kroese 39c019193e fix: Curl error on Chinese mirror (#706) 2024-04-26 16:30:30 +02:00
Kroese faec563b4a feat: Display kernel version (#704) 2024-04-26 13:59:51 +02:00
Kroese 9840f8e07a feat: Support ecryptfs filesystem (#703) 2024-04-26 06:04:48 +02:00
Kroese 3a5895fa0f build: Remove armv7 support (#702) 2024-04-26 04:16:46 +02:00
Kroese 1bac5c8a7f feat: Print system info (#701) 2024-04-25 14:31:49 +02:00
Kroese dd76c60e2a fix: CPU detection (#697) 2024-04-22 16:48:41 +02:00
Kroese ac78cc7dc5 feat: Display system info on boot (#696) 2024-04-22 16:29:23 +02:00
Kroese 66ac2d2002 docs: Update issue template (#692) 2024-04-17 19:03:17 +02:00
Kroese 0bd099d704 docs: Update issue templates (#691) 2024-04-17 18:32:43 +02:00
Kroese d2dac3cfb4 docs: Add issue templates (#690) 2024-04-17 18:14:51 +02:00
Kroese e81dc0f31d fix: Verify files are not empty (#689) 2024-04-16 15:35:35 +02:00
Kroese 5015597183 fix: Ignore empty MAC address (#688) 2024-04-13 23:33:17 +02:00
Kroese 64e2af9fa2 fix: Continue if file is missing (#682) 2024-04-08 09:54:42 +02:00
Kroese debb4b69fc fix: Continue when range request fails (#680) 2024-04-08 04:53:30 +02:00
Kroese c6d3dda171 docs: Readme (#677) 2024-04-07 01:59:50 +02:00
Kroese 7c0693c2ff build: Update qemu-host to v2.04 (#670) 2024-03-31 05:24:54 +02:00
Kroese 76355d4857 fix: TUN error message (#669) 2024-03-31 04:57:56 +02:00
Kroese 404aaadefc build: Dockerfile (#663) 2024-03-25 16:49:25 +01:00
Kroese be027e10be fix: Disable IPv6 in Nginx (#662) 2024-03-25 13:53:30 +01:00
Kroese 1c8cad92f8 fix: Disable kernel networking in bridge mode (#656) 2024-03-12 01:50:43 +01:00
Kroese fabb8ea3b7 docs: Readme (#650) 2024-02-28 20:43:27 +01:00
Kroese 2ee4abca54 docs: Docker run command (#647) 2024-02-28 08:51:55 +01:00
Kroese 5896928030 feat: Persistant MAC address (#646) 2024-02-28 08:40:00 +01:00
Kroese 8652544982 docs: Readme (#638) 2024-02-19 21:32:22 +01:00
Kroese a70338ec3c feat: Print filesystem on error (#635) 2024-02-17 05:56:40 +01:00
Kroese a84878abfc fix: Detect Mac Journal filesystem (#634) 2024-02-17 03:55:30 +01:00
Kroese 8421a391b7 fix: Prevent re-entry during shutdown (#633) 2024-02-16 16:03:37 +01:00
Kroese f9340ec3d6 docs: Readme (#630) 2024-02-10 00:33:21 +01:00
Kroese 0cca9c5f83 feat: Disable CoW check on XFS (#629) 2024-02-09 23:53:18 +01:00
Kroese 13d60b7f47 build: Notify after build (#628) 2024-02-09 14:45:38 +01:00
Kroese f74771a9cc fix: Convert MAC address to uppercase (#627) 2024-02-08 17:33:11 +01:00
Kroese f24ba41930 fix: Convert dashes in custom MAC addresses (#626) 2024-02-08 17:03:30 +01:00
Kroese f412580a4a feat: Add DNS entry for container (#624) 2024-02-07 22:26:29 +01:00
Kroese 5cde1b4438 feat: Set process name (#623) 2024-02-07 13:04:29 +01:00
Kroese 7cfb57b1bc docs: Readme (#621) 2024-02-05 16:18:13 +01:00
Kroese a478b58f97 feat: Set KVM tick policy (#620) 2024-02-05 12:09:12 +01:00
Kroese 8297f4f880 fix: Support CPU's without SSE4 (#619) 2024-02-05 07:41:47 +01:00
Kroese 4c67343d33 feat: Enable L3 cache and multi-threaded TCG (#618) 2024-02-04 19:25:22 +01:00
Kroese 53cc6998f0 fix: CPU features 2024-02-02 22:44:43 +01:00
Kroese d857d71e0d fix: Merge drive function (#614) 2024-02-01 11:05:33 +01:00
Kroese 003c2766ce docs: Readme (#613) 2024-01-31 04:28:24 +01:00
Kroese 78594098cc feat: Disable CoW check on ZFS (#612) 2024-01-31 03:54:40 +01:00
Kroese 3c31bc91e4 feat: Generate unique MAC address (#611) 2024-01-30 04:46:44 +01:00
Kroese 72141bab7a build: Lint Dockerfile (#610) 2024-01-29 11:51:28 +01:00
Kroese bc52463aa4 fix: Process signal faster (#609) 2024-01-29 05:54:22 +01:00
Kroese 9fa68908a9 feat: Show download progress (#608) 2024-01-29 05:40:06 +01:00
Kroese 740dbec1b1 build: Exclude web folder (#607) 2024-01-29 02:29:05 +01:00
Kroese 440d203730 fix: Stylesheet (#606) 2024-01-29 02:27:04 +01:00
Kroese 1a83c67e2c feat: Font smoothing (#605) 2024-01-29 02:01:51 +01:00
Kroese 34a707a2a5 docs: Readme (#603) 2024-01-27 19:51:26 +01:00
Kroese cabb2cdfc9 docs: Readme (#602) 2024-01-27 19:10:43 +01:00
Kroese dc52ccf172 docs: Readme (#601) 2024-01-27 19:06:10 +01:00
Kroese bdd7fec3c3 fix: Space after URL (#600) 2024-01-27 02:01:27 +01:00
Kroese bd8b03d089 docs: Readme (#599) 2024-01-26 06:29:15 +01:00
Kroese a10588b0ce fix: Check dnsmasq (#598) 2024-01-26 02:19:31 +01:00
renovate[bot] 3503b86e12 chore(deps): update peter-evans/dockerhub-description action to v4 (#597)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-25 17:05:28 +01:00
Kroese 9e124980cd fix: Disk message (#596) 2024-01-25 17:02:50 +01:00
Kroese 675aa5e122 docs: Readme (#595) 2024-01-23 21:49:18 +01:00
Kroese 2a62d4e938 feat: Display console arguments (#594) 2024-01-23 19:32:15 +01:00
Kroese 9cbb51cc86 feat: Display QEMU version (#593) 2024-01-23 19:29:07 +01:00
Kroese 7790f81d15 fix: Trap exit code (#592) 2024-01-23 18:46:47 +01:00
Kroese fdbff4879b fix: Incorrect path (#591) 2024-01-23 03:06:29 +01:00
Kroese 739e679a66 feat: Check for SHM (#590) 2024-01-23 03:04:47 +01:00
Kroese 0dea507d85 feat: Shorter messages (#588) 2024-01-23 00:15:11 +01:00
Kroese 4f524c47d8 docs: Readme (#587) 2024-01-22 03:24:00 +01:00
Kroese 0c74201eb4 feat: CPU flags (#586) 2024-01-21 20:52:53 +01:00
Kroese 1e13258bc9 feat: Dynamic page content (#585) 2024-01-21 18:35:55 +01:00
Kroese 2c7cea042f feat: Display progress via web (#584) 2024-01-20 19:59:44 +01:00
Kroese fc92b66ff4 fix: Echo (#583) 2024-01-19 15:12:02 +01:00
Kroese 89ae24a2ac feat: Add warning macro (#582) 2024-01-19 15:10:40 +01:00
Kroese bd4a23b287 docs: Readme (#581) 2024-01-19 12:05:54 +01:00
Kroese 1b8c4d9f08 docs: Readme (#580) 2024-01-19 12:01:31 +01:00
Kroese a1187decb5 docs: Readme (#579) 2024-01-19 08:09:49 +01:00
Kroese b9d7aa182d docs: Readme (#578) 2024-01-19 07:50:07 +01:00
Kroese b908c1118d fix: Sanitize filename (#577) 2024-01-19 04:17:09 +01:00
Kroese fab776764f fix: Strip query parameters from filename (#576) 2024-01-19 03:04:26 +01:00
Kroese f3e17e399d feat: Custom VGA adaptor (#573) 2024-01-17 19:42:30 +01:00
Kroese 3706ca873b docs: Remove latest (#572) 2024-01-15 13:58:23 +01:00
Kroese 10c565f32b docs: Grammar (#571) 2024-01-15 13:31:21 +01:00
Kroese d237e5b9e6 docs: Disk passthrough (#570) 2024-01-15 11:54:57 +01:00
Kroese 3c7e1ce12f docs: DHCP mode (#568) 2024-01-15 05:00:15 +01:00
Kroese f422f64325 docs: Readme (#567) 2024-01-14 21:22:13 +01:00
Kroese df0656b345 docs: Readme (#566) 2024-01-14 20:12:51 +01:00
Kroese 1fc9c56c8f style: Quote variables (#565) 2024-01-14 16:01:15 +01:00
Kroese 893a013ae9 style: Quote variables (#563) 2024-01-14 01:11:58 +01:00
Kroese 6d3812d1d0 fix: Remove cat (#562) 2024-01-14 00:37:36 +01:00
Kroese 6422aec780 fix: Remove cat (#561) 2024-01-14 00:00:59 +01:00
Kroese fcd7b8a825 fix: Use /tmp for server (#560) 2024-01-13 20:46:05 +01:00
Kroese 575da1f574 feat: Store config in RAM (#559) 2024-01-13 20:25:57 +01:00
Kroese 3a507f5bf6 fix: Display QEMU output (#558) 2024-01-13 18:16:17 +01:00
Kroese a3d6e3740c docs: Readme (#557) 2024-01-13 14:51:57 +01:00
Kroese 53e0330e21 feat: Change qcow allocation (#555) 2024-01-12 23:50:04 +01:00
Kroese f935c1e28a docs: Readme (#554) 2024-01-12 23:19:01 +01:00
Kroese 6a0c708224 fix: Device support (#552) 2024-01-12 18:01:20 +01:00
Kroese a407d2d94d build: Install apt-utils (#551) 2024-01-10 17:58:50 +01:00
Kroese 53605bd6e8 fix: Add package (#546) 2024-01-08 01:46:21 +01:00
Kroese 944faaa927 fix: Remove slash (#545) 2024-01-07 23:56:06 +01:00
Kroese fb7cfc09de fix: Set Debian flag (#544) 2024-01-07 21:23:42 +01:00
Kroese b9ae73e322 build: Remove apt-get upgrade (#543) 2024-01-06 03:17:50 +01:00
Kroese c28dbb6b9b feat: Add FUSE warning (#542)
* feat: Add FUSE warning
2024-01-05 13:24:54 +01:00
Kroese dcc26b67a6 fix: Diskspace check (#541)
* fix: Diskspace check
2024-01-05 02:27:15 +01:00
Kroese 2627d320f3 fix: Remove VNC support (#540)
* fix: Remove VNC support
2024-01-05 00:02:49 +01:00
Kroese fd4bc28835 fix: Console mode (#538) 2024-01-04 23:24:34 +01:00
Kroese 63e4d588a2 docs: Readme (#535) 2024-01-04 05:33:30 +01:00
Kroese feb1680909 build: Update location (#534) 2024-01-04 05:31:34 +01:00
IP2Location 9d21489b8e Added api.ip2location.io (#533) 2024-01-04 04:11:20 +01:00
Kroese e70ed1900f fix: Port forwarding (#530) 2024-01-03 14:02:16 +01:00
Kroese d65b5a089a fix: KVM check (#529) 2024-01-03 13:33:38 +01:00
Kroese 84643647cc fix: Compose (#527) 2023-12-31 15:11:20 +01:00
Kroese 57f487db6d build: Remove agent
* build: Remove agent
2023-12-31 01:56:03 +01:00
44 changed files with 3258 additions and 1247 deletions

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
services:
dsm:
container_name: dsm
image: ghcr.io/vdsm/virtual-dsm
environment:
RAM_SIZE: "half"
DISK_SIZE: "max"
CPU_CORES: "max"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 5000:5000
volumes:
- ./dsm:/storage
restart: on-failure
stop_grace_period: 2m
+15
View File
@@ -0,0 +1,15 @@
{
"name": "Virtual DSM",
"service": "dsm",
"forwardPorts": [5000],
"portsAttributes": {
"5000": {
"label": "Web",
"onAutoForward": "notify"
}
},
"otherPortsAttributes": {
"onAutoForward": "ignore"
},
"dockerComposeFile": "codespaces.yml"
}
+4
View File
@@ -1,4 +1,5 @@
.dockerignore
.devcontainer
.git
.github
.gitignore
@@ -6,7 +7,10 @@
.gitmodules
Dockerfile
Dockerfile.archive
compose.yml
compose.yaml
docker-compose.yml
docker-compose.yaml
*.md
+41
View File
@@ -0,0 +1,41 @@
name: "\U0001F6A8 Technical issue"
description: When you're experiencing problems using the container
body:
- type: input
id: os
attributes:
label: Operating system
description: Your Linux distribution (can be shown by `lsb_release -a`).
placeholder: e.g. Ubuntu 24.04
validations:
required: true
- type: textarea
id: summary
attributes:
label: Description
description: A clear and concise description of your issue.
validations:
required: true
- type: textarea
id: compose
attributes:
label: Docker compose
description: The compose file (or otherwise the `docker run` command used).
render: yaml
validations:
required: true
- type: textarea
id: log
attributes:
label: Docker log
description: The logfile of the container (as shown by `docker logs dsm`).
render: shell
validations:
required: true
- type: textarea
id: screenshot
attributes:
label: Screenshots (optional)
description: Screenshots that might help to make the problem more clear.
validations:
required: false
+37
View File
@@ -0,0 +1,37 @@
name: "\U0001F680 Feature request"
description: Suggest an idea for improving the container
title: "[Feature]: "
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: Is your proposal related to a problem?
description: |
Provide a clear and concise description of what the problem is.
For example, "I'm always frustrated when..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like.
description: |
Provide a clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered.
description: |
Let us know about other solutions you've tried or researched.
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional context
description: |
Is there anything else you can add about the proposal?
You might want to link to related issues here, if you haven't already.
+43
View File
@@ -0,0 +1,43 @@
name: "\U0001F41E Bug report"
description: Create a report to help us improve the container
title: "[Bug]: "
labels: ["bug"]
body:
- type: input
id: os
attributes:
label: Operating system
description: Your Linux distribution (can be shown by `lsb_release -a`).
placeholder: e.g. Ubuntu 24.04
validations:
required: true
- type: textarea
id: summary
attributes:
label: Description
description: Describe the expected behaviour, the actual behaviour, and the steps to reproduce.
validations:
required: true
- type: textarea
id: compose
attributes:
label: Docker compose
description: The compose file (or otherwise the `docker run` command used).
render: yaml
validations:
required: true
- type: textarea
id: log
attributes:
label: Docker log
description: The logfile of the container (as shown by `docker logs dsm`).
render: shell
validations:
required: true
- type: textarea
id: screenshot
attributes:
label: Screenshots (optional)
description: Screenshots that might help to make the problem more clear.
validations:
required: false
+26
View File
@@ -0,0 +1,26 @@
name: "\U00002753 General question"
description: Questions about the container not related to an issue
title: "[Question]: "
labels: ["question"]
body:
- type: checkboxes
attributes:
label: Is your question not already answered in the FAQ?
description: Please read the [FAQ](https://github.com/vdsm/virtual-dsm/blob/master/readme.md) carefully to avoid asking duplicate questions.
options:
- label: I made sure the question is not listed in the [FAQ](https://github.com/vdsm/virtual-dsm/blob/master/readme.md).
required: true
- type: checkboxes
attributes:
label: Is this a general question and not a technical issue?
description: For questions related to issues you must use the [technical issue](https://github.com/vdsm/virtual-dsm/issues/new?assignees=&labels=&projects=&template=1-issue.yml) form instead. It contains all the right fields (system info, logfiles, etc.) we need in order to be able to help you.
options:
- label: I am sure my question is not about a technical issue.
required: true
- type: textarea
id: question
attributes:
label: Question
description: What's the question you have about the container?
validations:
required: true
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+20 -18
View File
@@ -2,16 +2,6 @@ name: Build
on:
workflow_dispatch:
push:
branches:
- master
paths-ignore:
- '**/*.md'
- '**/*.yml'
- '.gitignore'
- '.dockerignore'
- '.github/**'
- '.github/workflows/**'
concurrency:
group: build
@@ -32,13 +22,13 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
-
name: Docker metadata
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
context: git
images: |
@@ -50,31 +40,31 @@ jobs:
labels: |
org.opencontainers.image.title=${{ vars.NAME }}
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
-
name: Login into Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Login to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Build Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v7
with:
context: .
push: true
provenance: false
platforms: linux/amd64,linux/arm64,linux/arm
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
@@ -99,3 +89,15 @@ jobs:
url: ${{ secrets.GITLAB_URL }}
token: ${{ secrets.GITLAB_TOKEN }}
username: ${{ secrets.GITLAB_USERNAME }}
-
name: Send mail
uses: action-pack/send-mail@v1
with:
to: ${{secrets.MAILTO}}
from: Github Actions <${{secrets.MAILTO}}>
connection_url: ${{secrets.MAIL_CONNECTION}}
subject: Build of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} completed
body: |
The build job of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} was completed successfully!
See https://github.com/${{ github.repository }}/actions for more information.
+19 -4
View File
@@ -7,8 +7,23 @@ jobs:
name: shellcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ShellCheck
-
name: Checkout
uses: actions/checkout@v6
-
name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
env:
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2002 -e SC2223 -e SC2034 -e SC2064 -e SC2317 -e SC2028 -e SC2153 -e SC2004
env:
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
-
name: Lint Dockerfile
uses: hadolint/hadolint-action@v3.3.0
with:
dockerfile: Dockerfile
ignore: DL3008,DL3003,DL3006,DL3013
failure-threshold: warning
-
name: Validate JSON and YML files
uses: GrantBirki/json-yaml-validate@v5.0.0
with:
yaml_exclude_regex: ".*\\kubernetes\\.yml$"
+12 -10
View File
@@ -12,13 +12,15 @@ jobs:
dockerHubDescription:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
-
name: Docker Hub Description
uses: peter-evans/dockerhub-description@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: ${{ secrets.DOCKERHUB_REPO }}
short-description: ${{ github.event.repository.description }}
readme-filepath: ./readme.md
-
name: Checkout repo
uses: actions/checkout@v6
-
name: Docker Hub Description
uses: peter-evans/dockerhub-description@v5
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: ${{ secrets.DOCKERHUB_REPO }}
short-description: ${{ github.event.repository.description }}
readme-filepath: ./readme.md
+66
View File
@@ -0,0 +1,66 @@
on:
pull_request:
name: "Review"
permissions:
contents: read
pull-requests: write
checks: write
jobs:
review:
name: review
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v6
-
name: Spelling
uses: reviewdog/action-misspell@v1
with:
locale: "US"
level: warning
pattern: |
*.md
*.sh
reporter: github-pr-review
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: Hadolint
uses: reviewdog/action-hadolint@v1
with:
level: warning
reporter: github-pr-review
hadolint_ignore: DL3008 DL3003 DL3006 DL3013
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: YamlLint
uses: reviewdog/action-yamllint@v1
with:
level: warning
reporter: github-pr-review
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: ActionLint
uses: reviewdog/action-actionlint@v1
with:
level: warning
reporter: github-pr-review
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: Shellformat
uses: reviewdog/action-shfmt@v1
with:
level: warning
shfmt_flags: "-i 2 -ci -bn"
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: Shellcheck
uses: reviewdog/action-shellcheck@v1
with:
level: warning
reporter: github-pr-review
shellcheck_flags: -x -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
github_token: ${{ secrets.GITHUB_TOKEN }}
-4
View File
@@ -1,10 +1,6 @@
on:
workflow_dispatch:
pull_request:
paths:
- '**/*.sh'
- '.github/workflows/test.yml'
- '.github/workflows/check.yml'
name: "Test"
permissions: {}
+45 -23
View File
@@ -1,57 +1,79 @@
FROM qemux/qemu-host as builder
# syntax=docker/dockerfile:1
FROM qemux/qemu-host:2.05 AS builder
# FROM golang as builder
# WORKDIR /
# RUN git clone https://github.com/qemu-tools/qemu-host.git
# RUN git clone https://github.com/qemus/qemu-host.git
# WORKDIR /qemu-host/src
# RUN go mod download
# RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /qemu-host.bin .
FROM debian:trixie-slim
ARG TARGETARCH
ARG TARGETPLATFORM
ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND noninteractive
ARG VERSION_ARG="0.0"
ARG VERSION_PASST="2026_05_07"
RUN apt-get update && apt-get -y upgrade \
&& if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi \
&& apt-get --no-install-recommends -y install \
ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND="noninteractive"
ARG DEBCONF_NONINTERACTIVE_SEEN="true"
RUN set -eu && \
apt-get update && \
apt-get --no-install-recommends -y install \
jq \
tini \
curl \
cpio \
wget \
fdisk \
unzip \
socat \
nginx \
procps \
ethtool \
python3 \
python3-pip \
python3-msgpack \
python3-pysodium \
xz-utils \
iptables \
iproute2 \
dnsmasq \
fakeroot \
apt-utils \
net-tools \
e2fsprogs \
qemu-utils \
websocketd \
iputils-ping \
inotify-tools \
ca-certificates \
netcat-openbsd \
qemu-system-x86 \
"$extra" \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
qemu-system-x86 && \
wget "https://github.com/qemus/passt/releases/download/v${VERSION_PASST}/passt_${VERSION_PASST}_${TARGETARCH}.deb" -O /tmp/passt.deb -q --timeout=10 && \
dpkg -i /tmp/passt.deb && \
apt-get clean && \
pip3 install --no-cache-dir --break-system-packages --root-user-action=ignore dissect.cstruct && \
mkdir -p /etc/qemu && \
echo "allow br0" > /etc/qemu/bridge.conf && \
unlink /etc/nginx/sites-enabled/default && \
sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf && \
echo "$VERSION_ARG" > /run/version && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY ./src /run/
COPY --from=builder /qemu-host.bin /run/host.bin
RUN chmod +x /run/*.sh && chmod +x /run/*.bin
COPY --chmod=755 ./src /run/
COPY --chmod=755 ./web /var/www/
COPY --chmod=755 --from=builder /qemu-host.bin /run/host.bin
COPY --chmod=744 ./web/conf/nginx.conf /etc/nginx/default.conf
ADD --chmod=775 https://raw.githubusercontent.com/sud0woodo/patology/refs/heads/main/patology.py /run/extract.py
VOLUME /storage
EXPOSE 22 80 139 445 5000
EXPOSE 22 139 445 5000
ENV RAM_SIZE "1G"
ENV DISK_SIZE "16G"
ENV CPU_CORES "1"
ARG VERSION_ARG="0.0"
RUN echo "$VERSION_ARG" > /run/version
ENV RAM_SIZE="2G"
ENV CPU_CORES="2"
ENV DISK_SIZE="256G"
HEALTHCHECK --interval=60s --start-period=45s --retries=2 CMD /run/check.sh
-140
View File
@@ -1,140 +0,0 @@
#!/usr/bin/env bash
set -u
VERSION="9"
HEADER="VirtualDSM Agent"
# Functions
error () { echo -e "\E[1;31m❯ ERROR: $1\E[0m" ; }
info () { echo -e "\E[1;34m❯\E[1;36m $1\E[0m" ; }
finish() {
echo "❯ $HEADER: Shutting down.."
exit
}
function checkNMI {
local nmi
nmi=$(cat /proc/interrupts | grep NMI | sed 's/[^1-9]*//g')
if [ "$nmi" != "" ]; then
info "Received shutdown request through NMI.."
/usr/syno/sbin/synoshutdown -s > /dev/null
finish
fi
}
function downloadUpdate {
TMP="/tmp/agent.sh"
rm -f "${TMP}"
# Auto update the agent
URL="https://raw.githubusercontent.com/vdsm/virtual-dsm/master/agent/agent.sh"
remote_size=$(curl -sIk -m 4 "${URL}" | grep -i "content-length:" | tr -d " \t" | cut -d ':' -f 2)
remote_size=${remote_size//$'\r'}
[[ "$remote_size" == "" || "$remote_size" == "0" ]] && return
remote_size=$(($remote_size+0))
((remote_size<100)) && return
SCRIPT=$(readlink -f "${BASH_SOURCE[0]}")
local_size=$(stat -c%s "$SCRIPT")
local_size=$(($local_size+0))
[[ remote_size -eq local_size ]] && return
if ! curl -sfk -m 10 -o "${TMP}" "${URL}"; then
error "$HEADER: curl error ($?)" && return
fi
if [ ! -f "${TMP}" ]; then
error "$HEADER: update error, file not found.." && return
fi
line=$(head -1 "${TMP}")
if [[ "$line" != "#!/usr/bin/env bash" ]]; then
error "$HEADER: update error, invalid header: $line" && return
fi
if cmp --silent -- "${TMP}" "${SCRIPT}"; then
error "$HEADER: update file is already equal? (${local_size} / ${remote_size})" && return
fi
mv -f "${TMP}" "${SCRIPT}"
chmod 755 "${SCRIPT}"
info "$HEADER: succesfully installed update..."
}
function installPackages {
for filename in /usr/local/packages/*.spk; do
if [ -f "$filename" ]; then
BASE=$(basename "$filename" .spk)
BASE="${BASE%%-*}"
[[ $BASE == "ActiveInsight" ]] && continue
info "Installing package ${BASE}.."
/usr/syno/bin/synopkg install "$filename" > /dev/null
/usr/syno/bin/synopkg start "$BASE" > /dev/null &
rm "$filename"
fi
done
}
trap finish SIGINT SIGTERM
ts=$(date +%s%N)
echo ""
echo "❯ Started $HEADER v$VERSION..."
checkNMI
# Install packages
first_run=false
for filename in /usr/local/packages/*.spk; do
if [ -f "$filename" ]; then
first_run=true
fi
done
if [ "$first_run" = true ]; then
installPackages
else
downloadUpdate
fi
# Wait for NMI interrupt as a shutdown signal
while true; do
checkNMI
sleep 2 & wait $!
done
-87
View File
@@ -1,87 +0,0 @@
#!/bin/bash
PIDFILE="/var/run/agent.pid"
SCRIPT="/usr/local/bin/agent.sh"
error () { echo -e "\E[1;31m❯ ERROR: $1\E[0m" ; }
info () { echo -e "\E[1;34m❯\E[1;36m $1\E[0m" ; }
status() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")"; then
echo 'Service running'
return 1
fi
return 0
}
start() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")"; then
echo 'Service already running'
return 1
fi
echo 'Starting agent service...'
chmod 666 /dev/ttyS0
if [ ! -f "$SCRIPT" ]; then
URL="https://raw.githubusercontent.com/vdsm/virtual-dsm/master/agent/agent.sh"
if ! curl -sfk -m 10 -o "${SCRIPT}" "${URL}"; then
error 'Failed to download agent script.' > /dev/ttyS0
rm -f "${SCRIPT}"
return 1
else
info 'Agent script was missing?' > /dev/ttyS0
fi
chmod 755 "${SCRIPT}"
fi
echo "-" > /var/lock/subsys/agent.sh
"$SCRIPT" &> /dev/ttyS0 & echo $! > "$PIDFILE"
return 0
}
stop() {
if [ ! -f "$PIDFILE" ] || ! kill -0 "$(cat "$PIDFILE")"; then
echo 'Service not running'
return 1
fi
echo 'Stopping agent service...'
chmod 666 /dev/ttyS0
info 'Stopping agent service...' > /dev/ttyS0
kill -15 "$(cat "$PIDFILE")" && rm -f "$PIDFILE"
rm -f /var/lock/subsys/agent.sh
echo 'Service stopped'
return 0
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
+17
View File
@@ -0,0 +1,17 @@
services:
dsm:
container_name: dsm
image: vdsm/virtual-dsm
environment:
DISK_SIZE: "256G"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 5000:5000
volumes:
- ./dsm:/storage
restart: always
stop_grace_period: 2m
-23
View File
@@ -1,23 +0,0 @@
version: "3"
services:
dsm:
container_name: dsm
image: vdsm/virtual-dsm:latest
environment:
DISK_SIZE: "16G"
RAM_SIZE: "1G"
CPU_CORES: "1"
devices:
- /dev/kvm
- /dev/net/tun
- /dev/vhost-net
device_cgroup_rules:
- 'c *:* rwm'
cap_add:
- NET_ADMIN
ports:
- 5000:5000
volumes:
- /var/dsm:/storage
restart: on-failure
stop_grace_period: 2m
+77
View File
@@ -0,0 +1,77 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dsm-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 256Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dsm
labels:
name: dsm
spec:
replicas: 1
selector:
matchLabels:
app: dsm
template:
metadata:
labels:
app: dsm
spec:
containers:
- name: dsm
image: vdsm/virtual-dsm
env:
- name: DISK_SIZE
value: "256G"
ports:
- containerPort: 5000
name: http
protocol: TCP
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- mountPath: /storage
name: storage
- mountPath: /dev/kvm
name: dev-kvm
- mountPath: /dev/net/tun
name: dev-tun
terminationGracePeriodSeconds: 120
volumes:
- name: storage
persistentVolumeClaim:
claimName: dsm-pvc
- hostPath:
path: /dev/kvm
name: dev-kvm
- hostPath:
path: /dev/net/tun
type: CharDevice
name: dev-tun
---
apiVersion: v1
kind: Service
metadata:
name: dsm
spec:
internalTrafficPolicy: Cluster
ports:
- name: http
port: 5000
protocol: TCP
targetPort: 5000
selector:
app: dsm
type: ClusterIP
+183 -129
View File
@@ -1,223 +1,277 @@
<h1 align="center">Virtual DSM for Docker<br />
<h1 align="center">Virtual DSM<br />
<div align="center">
<img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" />
<a href="https://github.com/vdsm/virtual-dsm"><img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" /></a>
</div>
<div align="center">
[![Build]][build_url]
[![Version]][tag_url]
[![Size]][tag_url]
[![Package]][pkg_url]
[![Pulls]][hub_url]
</div></h1>
Virtual DSM in a docker container.
Virtual DSM in a Docker container.
## Features
## Features ✨
- Multiple disks
- KVM acceleration
- GPU passthrough
- Upgrades supported
## Usage
## Usage 🐳
Via `docker-compose.yml`
##### Via Docker Compose:
```yaml
version: "3"
services:
dsm:
container_name: dsm
image: vdsm/virtual-dsm:latest
image: vdsm/virtual-dsm
environment:
DISK_SIZE: "16G"
DISK_SIZE: "256G"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 5000:5000
volumes:
- /var/dsm:/storage
restart: on-failure
- ./dsm:/storage
restart: always
stop_grace_period: 2m
```
Via `docker run`
##### Via Docker CLI:
```bash
docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 60 vdsm/virtual-dsm:latest
docker run -it --rm --name dsm -e "DISK_SIZE=256G" -p 5000:5000 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v "${PWD:-.}/dsm:/storage" --stop-timeout 120 docker.io/vdsm/virtual-dsm
```
## FAQ
##### Via Kubernetes:
* ### How do I change the size of the virtual disk?
```shell
kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/master/kubernetes.yml
```
To expand the default size of 16 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity:
##### Via Github Codespaces:
```yaml
environment:
DISK_SIZE: "128G"
```
This can also be used to resize the existing disk to a larger capacity without any data loss.
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/vdsm/virtual-dsm)
* ### How do I change the location of the virtual disk?
## FAQ 💬
To change the location of the virtual disk, include the following bind mount in your compose file:
### How do I use it?
```yaml
volumes:
- /var/dsm:/storage
```
Very simple! These are the steps:
- Start the container and connect to [port 5000](http://127.0.0.1:5000/) using your web browser.
Replace the example path `/var/dsm` with the desired storage folder.
- Wait until DSM finishes its installation
- Choose an username and password, and you will be taken to the desktop.
Enjoy your brand new NAS, and don't forget to star this repo!
* ### How do I add multiple disks?
### How do I change the storage location?
To create additional disks, modify your compose file like this:
```yaml
environment:
DISK2_SIZE: "32G"
DISK3_SIZE: "64G"
volumes:
- /home/example:/storage2
- /mnt/data/example:/storage3
```
To change the storage location, include the following bind mount in your compose file:
* ### How do I create a growable disk?
```yaml
volumes:
- ./dsm:/storage
```
By default, the entire capacity of the disk is reserved in advance.
Replace the example path `./dsm` with the desired storage folder or named volume.
### How do I change the size of the disk?
To create a growable disk that only allocates space that is actually used, add the following environment variables:
To expand the default size of 256 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity:
```yaml
environment:
ALLOCATE: "N"
DISK_FMT: "qcow2"
```
```yaml
environment:
DISK_SIZE: "512G"
```
> [!TIP]
> This can also be used to resize the existing disk to a larger capacity without any data loss.
Please note that this may reduce the write performance of the disk.
### How do I add multiple disks?
* ### How do I increase the amount of CPU or RAM?
To create additional disks, modify your compose file like this:
```yaml
environment:
DISK2_SIZE: "500G"
DISK3_SIZE: "750G"
volumes:
- ./example2:/storage2
- ./example3:/storage3
```
By default, a single core and 1 GB of RAM are allocated to the container.
### How do I pass-through a disk?
To increase this, add the following environment variables:
It is possible to pass-through disk devices or partitions directly by adding them to your compose file in this way:
```yaml
environment:
RAM_SIZE: "4G"
CPU_CORES: "4"
```
```yaml
devices:
- /dev/sdb:/disk1
- /dev/sdc1:/disk2
```
* ### How do I verify if my system supports KVM?
Make sure it is totally empty (without any filesystem), otherwise DSM may not format it as a volume.
To verify if your system supports KVM, run the following commands:
### How do I change the amount of CPU or RAM?
```bash
sudo apt install cpu-checker
sudo kvm-ok
```
By default, Virtual DSM will be allowed to use 2 CPU cores and 2 GB of RAM.
If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check your BIOS settings.
If you want to adjust this, you can specify the desired amount using the following environment variables:
* ### How do I assign an individual IP address to the container?
```yaml
environment:
RAM_SIZE: "4G"
CPU_CORES: "4"
```
By default, the container uses bridge networking, which shares the IP address with the host.
### How do I verify if my system supports KVM?
If you want to assign an individual IP address to the container, you can create a macvlan network as follows:
First check if your software is compatible using this chart:
```bash
docker network create -d macvlan \
--subnet=192.168.0.0/24 \
--gateway=192.168.0.1 \
--ip-range=192.168.0.100/28 \
-o parent=eth0 vdsm
```
Be sure to modify these values to match your local subnet.
| **Product** | **Linux** | **Win11** | **Win10** | **macOS** |
|---|---|---|---|---|
| Docker CLI | ✅ | ✅ | ❌ | ❌ |
| Docker Desktop | ❌ | ✅ | ❌ | ❌ |
| Podman CLI | ✅ | ✅ | ❌ | ❌ |
| Podman Desktop | ✅ | ✅ | ❌ | ❌ |
Once you have created the network, change your compose file to look as follows:
After that you can run the following commands in Linux to check your system:
```yaml
services:
dsm:
container_name: dsm
..<snip>..
networks:
vdsm:
ipv4_address: 192.168.0.100
```bash
sudo apt install cpu-checker
sudo kvm-ok
```
networks:
vdsm:
external: true
```
An added benefit of this approach is that you won't have to perform any port mapping anymore since all ports will be exposed by default.
If you receive an error from `kvm-ok` indicating that KVM cannot be used, please check whether:
Please note that this IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
- the virtualization extensions (`Intel VT-x` or `AMD SVM`) are enabled in your BIOS.
* ### How can the container acquire an IP address from my router?
- you enabled "nested virtualization" if you are running the container inside a virtual machine.
After configuring the container for macvlan (see above), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
- you are not using a cloud provider, as most of them do not allow nested virtualization for their VPS's.
To enable this feature, add the following lines to your compose file:
If you did not receive any error from `kvm-ok` but the container still complains about a missing KVM device, it could help to add `privileged: true` to your compose file (or `sudo` to your `docker` command) to rule out any permission issue.
```yaml
environment:
DHCP: "Y"
device_cgroup_rules:
- 'c *:* rwm'
```
### How do I assign an individual IP address to the container?
Please note that even if you don't want DHCP, it's still recommended to enable this feature as it prevents NAT issues and increases performance by using a `macvtap` interface. In that case just set a static IP from the DSM control panel after you enabled this mode.
By default, the container uses bridge networking, which shares the IP address with the host.
* ### How do I passthrough the GPU?
If you want to assign an individual IP address to the container, you can create a macvlan network as follows:
To passthrough your Intel GPU, add the following lines to your compose file:
```bash
docker network create -d macvlan \
--subnet=192.168.0.0/24 \
--gateway=192.168.0.1 \
--ip-range=192.168.0.100/28 \
-o parent=eth0 vdsm
```
Be sure to modify these values to match your local subnet.
```yaml
environment:
GPU: "Y"
devices:
- /dev/dri
```
Once you have created the network, change your compose file to look as follows:
This can be used to enable the facial recognition function in Synology Photos for example.
```yaml
services:
dsm:
container_name: dsm
..<snip>..
networks:
vdsm:
ipv4_address: 192.168.0.100
* ### How do I install a specific version of vDSM?
networks:
vdsm:
external: true
```
An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default.
By default, version 7.2.1 will be installed, but if you prefer an older version, you can add its download URL to your compose file as follows:
> [!IMPORTANT]
> This IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
```yaml
environment:
URL: "https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
```
### How can DSM acquire an IP address from my router?
With this method, it is even possible to switch between different versions while keeping all your file data intact.
After configuring the container for [macvlan](#how-do-i-assign-an-individual-ip-address-to-the-container), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
* ### What are the differences compared to the standard DSM?
To enable this mode, in which the container and DSM will have separate IP addresses, add the following lines to your compose file:
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses.
* ### Is this project legal?
```yaml
environment:
DHCP: "Y"
devices:
- /dev/vhost-net
device_cgroup_rules:
- 'c *:* rwm'
```
Yes, this project contains only open-source code and does not distribute any copyrighted material. Neither does it try to circumvent any copyright protection measures. So under all applicable laws, this project would be considered legal.
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this project on an official Synology NAS, as any other use will be a violation of their terms and conditions.
### How do I pass-through the GPU?
## Disclaimer
To pass-through your Intel GPU, add the following lines to your compose file:
Only run this container on Synology hardware, any other use is not permitted by their EULA. The product names, logos, brands, and other trademarks referred to within this project are the property of their respective trademark holders. This project is not affiliated, sponsored, or endorsed by Synology, Inc.
```yaml
environment:
GPU: "Y"
devices:
- /dev/dri
```
> [!NOTE]
> This can be used to enable the facial recognition function in Synology Photos, but does not provide hardware transcoding for video.
### How do I install a specific version of vDSM?
By default, version 7.2 will be installed, but if you prefer an older version, you can add the download URL of the `.pat` file to your compose file as follows:
```yaml
environment:
URL: "https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
```
With this method, it is even possible to switch back and forth between versions while keeping your file data intact.
Alternatively, you can also skip the download and use a local file instead, by binding it in your compose file in this way:
```yaml
volumes:
- ./DSM_VirtualDSM_42218.pat:/boot.pat
```
Replace the example path `./DSM_VirtualDSM_42218.pat` with the filename of your desired `.pat` file. The value of `URL` will be ignored in this case.
### What are the differences compared to the standard DSM?
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses.
### Is this project legal?
Yes, this project contains only open-source code and does not distribute any copyrighted material. Neither does it try to circumvent any copyright protection measures. So under all applicable laws, this project will be considered legal.
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this container on an official Synology NAS, as any other use will be a violation of their terms and conditions.
## Stars 🌟
[![Stars](https://starchart.cc/vdsm/virtual-dsm.svg?variant=adaptive)](https://starchart.cc/vdsm/virtual-dsm)
## Disclaimer ⚖️
*Only run this container on Synology hardware, any other use is not permitted by their EULA. The product names, logos, brands, and other trademarks referred to within this project are the property of their respective trademark holders. This project is not affiliated, sponsored, or endorsed by Synology, Inc.*
[build_url]: https://github.com/vdsm/virtual-dsm/
[hub_url]: https://hub.docker.com/r/vdsm/virtual-dsm
[tag_url]: https://hub.docker.com/r/vdsm/virtual-dsm/tags
[pkg_url]: https://github.com/vdsm/virtual-dsm/pkgs/container/virtual-dsm
[Build]: https://github.com/vdsm/virtual-dsm/actions/workflows/build.yml/badge.svg
[Size]: https://img.shields.io/docker/image-size/vdsm/virtual-dsm/latest?color=066da5&label=size
[Pulls]: https://img.shields.io/docker/pulls/kroese/virtual-dsm.svg?style=flat&label=pulls&logo=docker
[Pulls]: https://img.shields.io/docker/pulls/vdsm/virtual-dsm.svg?style=flat&label=pulls&logo=docker
[Version]: https://img.shields.io/docker/v/vdsm/virtual-dsm/latest?arch=amd64&sort=semver&color=066da5
[Package]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fipitio.github.io%2Fbackage%2Fvdsm%2Fvirtual-dsm%2Fvirtual-dsm.json&query=%24.downloads&logo=github&style=flat&color=066da5&label=pulls
+16 -11
View File
@@ -1,25 +1,30 @@
#!/usr/bin/env bash
set -Eeuo pipefail
[ -f "/run/qemu.end" ] && echo "QEMU is shutting down.." && exit 1
[ ! -f "/run/qemu.pid" ] && echo "QEMU is not running yet.." && exit 0
: "${DHCP:="N"}"
: "${NETWORK:="Y"}"
file="/run/dsm.url"
address="/run/qemu.ip"
[ -f "/run/shm/qemu.end" ] && echo "QEMU is shutting down.." && exit 1
[ ! -s "/run/shm/qemu.pid" ] && echo "QEMU is not running yet.." && exit 0
[[ "$NETWORK" == [Nn]* ]] && echo "Networking is disabled.." && exit 0
[ ! -f "$file" ] && echo "DSM has not enabled networking yet.." && exit 1
file="/run/shm/dsm.url"
address="/run/shm/qemu.ip"
gateway="/run/shm/qemu.gw"
location=$(cat "$file")
[ ! -s "$file" ] && echo "DSM has not enabled networking yet.." && exit 1
location=$(<"$file")
if ! curl -m 20 -ILfSs "http://$location/" > /dev/null; then
if [[ "$location" == "20.20"* ]]; then
ip="20.20.20.1"
if [[ "$DHCP" == [Yy1]* ]]; then
ip=$(<"$address")
echo "Failed to reach DSM at http://$location"
else
ip=$(<"$gateway")
port="${location##*:}"
echo "Failed to reach DSM at port $port"
else
echo "Failed to reach DSM at http://$location"
ip="$(cat "$address")"
fi
echo "You might need to whitelist IP $ip in the DSM firewall." && exit 1
+5 -5
View File
@@ -2,12 +2,12 @@
set -Eeuo pipefail
DEF_OPTS="-nodefaults -boot strict=on"
RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
CPU_OPTS="-cpu $CPU_MODEL -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
MAC_OPTS="-machine type=q35,usb=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
RAM_OPTS=$(echo "-m ${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
CPU_OPTS="-cpu $CPU_FLAGS -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
MAC_OPTS="-machine type=q35,smm=off,usb=off,vmport=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
DEV_OPTS="$DEV_OPTS -object rng-random,id=objrng0,filename=/dev/urandom"
DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
DEV_OPTS+=" -object rng-random,id=objrng0,filename=/dev/urandom"
DEV_OPTS+=" -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $DEV_OPTS $ARGUMENTS"
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
+386 -194
View File
@@ -3,30 +3,30 @@ set -Eeuo pipefail
# Docker environment variables
: ${DISK_IO:='native'} # I/O Mode, can be set to 'native', 'threads' or 'io_turing'
: ${DISK_FMT:='raw'} # Disk file format, 'raw' by default for best performance
: ${DISK_FLAGS:=''} # Specifies the options for use with the qcow2 disk format
: ${DISK_CACHE:='none'} # Caching mode, can be set to 'writeback' for better performance
: ${DISK_DISCARD:='on'} # Controls whether unmap (TRIM) commands are passed to the host.
: ${DISK_ROTATION:='1'} # Rotation rate, set to 1 for SSD storage and increase for HDD
: "${DISK_IO:="native"}" # I/O Mode, can be set to 'native', 'threads' or 'io_uring'
: "${DISK_FMT:="raw"}" # Disk file format, 'raw' by default for best performance
: "${DISK_TYPE:=""}" # Device type to be used, "sata", "nvme", "blk" or "scsi"
: "${DISK_FLAGS:=""}" # Specifies the options for use with the qcow2 disk format
: "${DISK_CACHE:="none"}" # Caching mode, can be set to 'writeback' for better performance
: "${DISK_DISCARD:="on"}" # Controls whether unmap (TRIM) commands are passed to the host.
: "${DISK_ROTATION:="1"}" # Rotation rate, set to 1 for SSD storage and increase for HDD
BOOT="$STORAGE/$BASE.boot.img"
SYSTEM="$STORAGE/$BASE.system.img"
[ ! -f "$BOOT" ] && error "Virtual DSM boot-image does not exist ($BOOT)" && exit 81
[ ! -f "$SYSTEM" ] && error "Virtual DSM system-image does not exist ($SYSTEM)" && exit 82
[ ! -s "$BOOT" ] && error "Virtual DSM boot-image does not exist ($BOOT)" && exit 81
[ ! -s "$SYSTEM" ] && error "Virtual DSM system-image does not exist ($SYSTEM)" && exit 82
DISK_OPTS="\
-object iothread,id=io2 \
-device virtio-scsi-pci,id=hw-synoboot,iothread=io2,bus=pcie.0,addr=0xa \
-drive file=$BOOT,if=none,id=drive-synoboot,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
-device scsi-hd,bus=hw-synoboot.0,channel=0,scsi-id=0,lun=0,drive=drive-synoboot,id=synoboot0,rotation_rate=$DISK_ROTATION,bootindex=1 \
-device virtio-scsi-pci,id=hw-synosys,iothread=io2,bus=pcie.0,addr=0xb \
-drive file=$SYSTEM,if=none,id=drive-synosys,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
-device scsi-hd,bus=hw-synosys.0,channel=0,scsi-id=0,lun=0,drive=drive-synosys,id=synosys0,rotation_rate=$DISK_ROTATION,bootindex=2"
if ! setOwner "$BOOT"; then
error "Failed to set the owner for \"$BOOT\" !"
fi
if ! setOwner "$SYSTEM"; then
error "Failed to set the owner for \"$SYSTEM\" !"
fi
fmt2ext() {
local DISK_FMT=$1
local DISK_FMT="$1"
case "${DISK_FMT,,}" in
qcow2)
@@ -42,7 +42,7 @@ fmt2ext() {
}
ext2fmt() {
local DISK_EXT=$1
local DISK_EXT="$1"
case "${DISK_EXT,,}" in
qcow2)
@@ -58,11 +58,11 @@ ext2fmt() {
}
getSize() {
local DISK_FILE=$1
local DISK_FILE="$1"
local DISK_EXT DISK_FMT
DISK_EXT="$(echo "${DISK_FILE//*./}" | sed 's/^.*\.//')"
DISK_FMT="$(ext2fmt "$DISK_EXT")"
DISK_EXT=$(echo "${DISK_FILE//*./}" | sed 's/^.*\.//')
DISK_FMT=$(ext2fmt "$DISK_EXT")
case "${DISK_FMT,,}" in
raw)
@@ -78,27 +78,38 @@ getSize() {
}
isCow() {
local FS=$1
local FS="$1"
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
if [[ "${FS,,}" == "btrfs" ]]; then
return 0
fi
return 1
}
createDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
local DISK_FMT=$4
local FS=$5
local DATA_SIZE DIR SPACE FA
supportsDirect() {
local FS="$1"
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
return 1
fi
return 0
}
createDisk() {
local DISK_FILE="$1"
local DISK_SPACE="$2"
local DISK_DESC="$3"
local DISK_FMT="$4"
local FS="$5"
local DATA_SIZE DIR SPACE GB FA
rm -f "$DISK_FILE"
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Check free diskspace
@@ -106,14 +117,17 @@ createDisk() {
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if (( DATA_SIZE > SPACE )); then
local SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
error "Not enough free space to create a $DISK_DESC of $DISK_SPACE in $DIR, it has only $SPACE_GB GB available..."
GB=$(formatBytes "$SPACE")
error "Not enough free space to create a $DISK_DESC of ${DISK_SPACE/G/ GB} in $DIR, it has only $GB available..."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 76
fi
fi
info "Creating a $DISK_TYPE $DISK_DESC image in $DISK_FMT format with a size of $DISK_SPACE..."
local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
html "Creating a $DISK_DESC image..."
info "Creating a ${DISK_SPACE/G/ GB} $DISK_STYLE $DISK_DESC image in $DISK_FMT format..."
local FAIL="Could not create a $DISK_STYLE $DISK_FMT $DISK_DESC image of ${DISK_SPACE/G/ GB} ($DISK_FILE)"
case "${DISK_FMT,,}" in
raw)
@@ -126,7 +140,7 @@ createDisk() {
fi
if [[ "$ALLOCATE" == [Nn]* ]]; then
# Create an empty file
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
rm -f "$DISK_FILE"
@@ -136,10 +150,12 @@ createDisk() {
else
# Create an empty file
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE"; then
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
rm -f "$DISK_FILE"
error "$FAIL" && exit 77
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE" &>/dev/null; then
if ! fallocate -l -x "$DATA_SIZE" "$DISK_FILE"; then
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
rm -f "$DISK_FILE"
error "$FAIL" && exit 77
fi
fi
fi
@@ -148,8 +164,8 @@ createDisk() {
qcow2)
local DISK_PARAM="$DISK_ALLOC"
isCow "$FS" && DISK_PARAM="$DISK_PARAM,nocow=on"
[ -n "$DISK_FLAGS" ] && DISK_PARAM="$DISK_PARAM,$DISK_FLAGS"
isCow "$FS" && DISK_PARAM+=",nocow=on"
[ -n "$DISK_FLAGS" ] && DISK_PARAM+=",$DISK_FLAGS"
if ! qemu-img create -f "$DISK_FMT" -o "$DISK_PARAM" -- "$DISK_FILE" "$DATA_SIZE" ; then
rm -f "$DISK_FILE"
@@ -169,16 +185,17 @@ createDisk() {
}
resizeDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
local DISK_FMT=$4
local FS=$5
local CUR_SIZE DATA_SIZE DIR SPACE
local DISK_FILE="$1"
local DISK_SPACE="$2"
local DISK_DESC="$3"
local DISK_FMT="$4"
local FS="$5"
local CUR_SIZE DATA_SIZE DIR SPACE GB
CUR_SIZE=$(getSize "$DISK_FILE")
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
local REQ=$((DATA_SIZE-CUR_SIZE))
local REQ=$(( DATA_SIZE - CUR_SIZE ))
(( REQ < 1 )) && error "Shrinking disks is not supported yet, please increase ${DISK_DESC^^}_SIZE." && exit 71
if [[ "$ALLOCATE" != [Nn]* ]]; then
@@ -188,15 +205,18 @@ resizeDisk() {
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if (( REQ > SPACE )); then
local SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
error "Not enough free space to resize $DISK_DESC to $DISK_SPACE in $DIR, it has only $SPACE_GB GB available.."
GB=$(formatBytes "$SPACE")
error "Not enough free space to resize $DISK_DESC to ${DISK_SPACE/G/ GB} in $DIR, it has only $GB available.."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 74
fi
fi
local GB=$(( (CUR_SIZE + 1073741823)/1073741824 ))
info "Resizing $DISK_DESC from ${GB}G to $DISK_SPACE..."
local FAIL="Could not resize the $DISK_TYPE $DISK_FMT $DISK_DESC image from ${GB}G to $DISK_SPACE ($DISK_FILE)"
GB=$(formatBytes "$CUR_SIZE")
MSG="Resizing $DISK_DESC from $GB to ${DISK_SPACE/G/ GB}..."
info "$MSG" && html "$MSG"
local FAIL="Could not resize the $DISK_STYLE $DISK_FMT $DISK_DESC image from ${GB} to ${DISK_SPACE/G/ GB} ($DISK_FILE)"
case "${DISK_FMT,,}" in
raw)
@@ -211,9 +231,11 @@ resizeDisk() {
else
# Resize file by allocating more space
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE"; then
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
error "$FAIL" && exit 75
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE" &>/dev/null; then
if ! fallocate -l -x "$DATA_SIZE" "$DISK_FILE"; then
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
error "$FAIL" && exit 75
fi
fi
fi
@@ -232,13 +254,14 @@ resizeDisk() {
}
convertDisk() {
local SOURCE_FILE=$1
local SOURCE_FMT=$2
local DST_FILE=$3
local DST_FMT=$4
local DISK_BASE=$5
local DISK_DESC=$6
local FS=$7
local SOURCE_FILE="$1"
local SOURCE_FMT="$2"
local DST_FILE="$3"
local DST_FMT="$4"
local DISK_BASE="$5"
local DISK_DESC="$6"
local FS="$7"
[ -f "$DST_FILE" ] && error "Conversion failed, destination file $DST_FILE already exists?" && exit 79
[ ! -f "$SOURCE_FILE" ] && error "Conversion failed, source file $SOURCE_FILE does not exists?" && exit 79
@@ -246,49 +269,56 @@ convertDisk() {
local TMP_FILE="$DISK_BASE.tmp"
rm -f "$TMP_FILE"
local DIR
DIR=$(dirname "$TMP_FILE")
if [[ "$ALLOCATE" != [Nn]* ]]; then
local DIR CUR_SIZE SPACE
local CUR_SIZE SPACE GB
# Check free diskspace
DIR=$(dirname "$TMP_FILE")
CUR_SIZE=$(getSize "$SOURCE_FILE")
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if (( CUR_SIZE > SPACE )); then
local SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
error "Not enough free space to convert $DISK_DESC to $DST_FMT in $DIR, it has only $SPACE_GB GB available..."
GB=$(formatBytes "$SPACE")
error "Not enough free space to convert $DISK_DESC to $DST_FMT in $DIR, it has only $GB available..."
error "Please free up some disk space or disable preallocation by setting ALLOCATE=N." && exit 76
fi
fi
info "Converting $DISK_DESC to $DST_FMT, please wait until completed..."
local msg="Converting $DISK_DESC to $DST_FMT"
html "$msg..."
info "$msg, please wait until completed..."
local CONV_FLAGS="-p"
local DISK_PARAM="$DISK_ALLOC"
isCow "$FS" && DISK_PARAM="$DISK_PARAM,nocow=on"
isCow "$FS" && DISK_PARAM+=",nocow=on"
if [[ "$DST_FMT" != "raw" ]]; then
if [[ "$ALLOCATE" == [Nn]* ]]; then
CONV_FLAGS="$CONV_FLAGS -c"
fi
[ -n "$DISK_FLAGS" ] && DISK_PARAM="$DISK_PARAM,$DISK_FLAGS"
if [[ "$ALLOCATE" == [Nn]* ]]; then
CONV_FLAGS+=" -c"
fi
[ -n "$DISK_FLAGS" ] && DISK_PARAM+=",$DISK_FLAGS"
fi
# shellcheck disable=SC2086
if ! qemu-img convert -f "$SOURCE_FMT" $CONV_FLAGS -o "$DISK_PARAM" -O "$DST_FMT" -- "$SOURCE_FILE" "$TMP_FILE"; then
rm -f "$TMP_FILE"
error "Failed to convert $DISK_TYPE $DISK_DESC image to $DST_FMT format in $DIR, is there enough space available?" && exit 79
error "Failed to convert $DISK_STYLE $DISK_DESC image to $DST_FMT format in $DIR, is there enough space available?" && exit 79
fi
if [[ "$DST_FMT" == "raw" ]]; then
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Work around qemu-img bug
CUR_SIZE=$(stat -c%s "$TMP_FILE")
if ! fallocate -l "$CUR_SIZE" "$TMP_FILE"; then
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Work around qemu-img bug
CUR_SIZE=$(stat -c%s "$TMP_FILE")
if ! fallocate -l "$CUR_SIZE" "$TMP_FILE" &>/dev/null; then
if ! fallocate -l -x "$CUR_SIZE" "$TMP_FILE"; then
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
fi
fi
fi
fi
rm -f "$SOURCE_FILE"
@@ -301,29 +331,40 @@ convertDisk() {
fi
fi
info "Conversion of $DISK_DESC to $DST_FMT completed succesfully!"
msg="Conversion of $DISK_DESC"
html "$msg completed..."
info "$msg to $DST_FMT completed successfully!"
return 0
}
checkFS () {
local FS=$1
local DISK_FILE=$2
local DISK_DESC=$3
local FS="$1"
local DISK_FILE="$2"
local DISK_DESC="$3"
local DIR FA
DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0
if [[ "${FS,,}" == "overlay"* ]]; then
info "Warning: the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
if [[ "${FS,,}" == "overlay"* && "${ENGINE,,}" == "docker" ]]; then
warn "the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
fi
if [[ "${FS,,}" == "fuse"* ]]; then
warn "the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
fi
if ! supportsDirect "$FS"; then
warn "the filesystem of $DIR is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if isCow "$FS"; then
if [ -f "$DISK_FILE" ]; then
FA=$(lsattr "$DISK_FILE")
if [[ "$FA" != *"C"* ]]; then
info "Warning: COW (copy on write) is not disabled for $DISK_DESC image file $DISK_FILE, this is recommended on ${FS^^} filesystems!"
warn "COW (copy on write) is not disabled for $DISK_DESC image file $DISK_FILE, this is recommended on ${FS^^} filesystems!"
fi
fi
fi
@@ -331,161 +372,312 @@ checkFS () {
return 0
}
createDevice () {
local DISK_FILE="$1"
local DISK_TYPE="$2"
local DISK_INDEX="$3"
local DISK_ADDRESS="$4"
local DISK_FMT="$5"
local DISK_IO="$6"
local DISK_CACHE="$7"
local DISK_SERIAL="$8"
local DISK_SECTORS="$9"
local DISK_ID="data$DISK_INDEX"
local index=""
[ -n "$DISK_INDEX" ] && index=",bootindex=$DISK_INDEX"
local result=" -drive file=$DISK_FILE,id=$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on"
case "${DISK_TYPE,,}" in
"none" ) ;;
"auto" )
echo "$result"
;;
"usb" )
result+=",if=none \
-device usb-storage,drive=${DISK_ID}${index}${DISK_SERIAL}${DISK_SECTORS}"
echo "$result"
;;
"nvme" )
result+=",if=none \
-device nvme,drive=${DISK_ID}${index},serial=deadbeaf${DISK_INDEX}${DISK_SERIAL}${DISK_SECTORS}"
echo "$result"
;;
"ide" | "sata" )
result+=",if=none \
-device ich9-ahci,id=ahci${DISK_INDEX},addr=$DISK_ADDRESS \
-device ide-hd,drive=${DISK_ID},bus=ahci$DISK_INDEX.0,rotation_rate=$DISK_ROTATION${index}${DISK_SERIAL}${DISK_SECTORS}"
echo "$result"
;;
"blk" | "virtio-blk" )
result+=",if=none \
-device virtio-blk-pci,drive=${DISK_ID},bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2${index}${DISK_SERIAL}${DISK_SECTORS}"
echo "$result"
;;
"scsi" | "virtio-scsi" )
result+=",if=none \
-device virtio-scsi-pci,id=${DISK_ID}b,bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2 \
-device scsi-hd,drive=${DISK_ID},bus=${DISK_ID}b.0,channel=0,scsi-id=0,lun=0,rotation_rate=$DISK_ROTATION${index}${DISK_SERIAL}${DISK_SECTORS}"
echo "$result"
;;
esac
return 0
}
addDisk () {
local DISK_ID=$1
local DISK_BASE=$2
local DISK_EXT=$3
local DISK_DESC=$4
local DISK_SPACE=$5
local DISK_INDEX=$6
local DISK_ADDRESS=$7
local DISK_FMT=$8
local DISK_BASE="$1"
local DISK_TYPE="$2"
local DISK_DESC="$3"
local DISK_SPACE="$4"
local DISK_INDEX="$5"
local DISK_ADDRESS="$6"
local DISK_FMT="$7"
local DISK_IO="$8"
local DISK_CACHE="$9"
local DISK_EXT DIR SPACE GB DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE LEFT FREE USED
DISK_EXT=$(fmt2ext "$DISK_FMT")
local DISK_FILE="$DISK_BASE.$DISK_EXT"
local DIR DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE
DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0
[ -z "$DISK_SPACE" ] && DISK_SPACE="16G"
DISK_SPACE=$(echo "${DISK_SPACE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
if [[ "${DISK_SPACE,,}" == "max" || "${DISK_SPACE,,}" == "half" ]]; then
local SPARE=1073741824
FREE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if [[ "${DISK_SPACE,,}" == "max" ]]; then
FREE=$(( FREE - SPARE ))
else
FREE=$(( FREE / 2 ))
fi
(( FREE < SPARE )) && FREE="$SPARE"
GB=$(( FREE / 1073741825 ))
DISK_SPACE="${GB}G"
fi
SPACE="${DISK_SPACE// /}"
[ -z "$SPACE" ] && SPACE="256G"
[ -z "${SPACE//[0-9. ]}" ] && SPACE="${SPACE}G"
SPACE=$(echo "${SPACE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
if ! numfmt --from=iec "$SPACE" &>/dev/null; then
error "Invalid value for ${DISK_DESC^^}_SIZE: $DISK_SPACE" && exit 73
fi
DATA_SIZE=$(numfmt --from=iec "$SPACE")
if (( DATA_SIZE < 6442450944 )); then
if (( DATA_SIZE < 1 )); then
error "Invalid value for ${DISK_DESC^^}_SIZE: $DISK_SPACE" && exit 73
else
error "Please increase ${DISK_DESC^^}_SIZE to at least 6 GB." && exit 73
fi
error "Please increase the ${DISK_DESC^^}_SIZE variable to at least 6 GB." && exit 73
fi
FS=$(stat -f -c %T "$DIR")
checkFS "$FS" "$DISK_FILE" "$DISK_DESC" || exit $?
if ! [ -f "$DISK_FILE" ] ; then
if ! supportsDirect "$FS"; then
DISK_IO="threads"
DISK_CACHE="writeback"
fi
if [ ! -s "$DISK_FILE" ] ; then
if [[ "${DISK_FMT,,}" != "raw" ]]; then
PREV_FMT="raw"
else
PREV_FMT="qcow2"
fi
PREV_EXT="$(fmt2ext "$PREV_FMT")"
if [ -f "$DISK_BASE.$PREV_EXT" ] ; then
PREV_EXT=$(fmt2ext "$PREV_FMT")
if [ -s "$DISK_BASE.$PREV_EXT" ] ; then
convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $?
fi
fi
if [ -f "$DISK_FILE" ]; then
if [ -s "$DISK_FILE" ]; then
CUR_SIZE=$(getSize "$DISK_FILE")
if (( DATA_SIZE > CUR_SIZE )); then
resizeDisk "$DISK_FILE" "$DISK_SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
resizeDisk "$DISK_FILE" "$SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
else
if (( DATA_SIZE < CUR_SIZE )); then
if [[ "${DISK_SPACE,,}" != "max" && "${DISK_SPACE,,}" != "half" ]]; then
info "You decreased the ${DISK_DESC^^}_SIZE variable to ${DISK_SPACE/G/ GB} but shrinking disks is not supported, will be ignored..."
fi
fi
fi
else
createDisk "$DISK_FILE" "$DISK_SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
createDisk "$DISK_FILE" "$SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
fi
DISK_OPTS="$DISK_OPTS \
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
-drive file=$DISK_FILE,if=none,id=drive-$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
if [ -f "$DISK_FILE" ] && [[ "$ALLOCATE" == [Nn]* ]]; then
CUR_SIZE=$(getSize "$DISK_FILE")
USED=$(du -sB 1 "$DISK_FILE" | cut -f1)
FREE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
LEFT=$(( CUR_SIZE - USED - FREE ))
if (( LEFT > 0 )); then
GB=$(formatBytes "$FREE")
LEFT=$(formatBytes "$LEFT")
CUR_SIZE=$(formatBytes "$CUR_SIZE")
msg="The virtual size of the ${DISK_DESC,,} is $CUR_SIZE"
if [ -n "$USED" ] && [[ "$USED" != "0" ]]; then
USED=$(formatBytes "$USED")
msg+=" (of which $USED is used)"
fi
info "$msg, but there is only $GB of free space remaining in $DIR now."
info "Please consider making at least $LEFT more space available in $DIR for future expansions."
fi
fi
if [ -f "$DISK_FILE" ]; then
if ! setOwner "$DISK_FILE"; then
error "Failed to set the owner for \"$DISK_FILE\" !"
fi
fi
DISK_OPTS+=$(createDevice "$DISK_FILE" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" "" "")
return 0
}
DISK_EXT="$(fmt2ext "$DISK_FMT")" || exit $?
if [[ "$ALLOCATE" == [Nn]* ]]; then
DISK_TYPE="growable"
DISK_ALLOC="preallocation=off"
else
DISK_TYPE="preallocated"
DISK_ALLOC="preallocation=falloc"
fi
DISK1_FILE="$STORAGE/data"
if [[ ! -f "$DISK1_FILE.img" ]] && [[ -f "$STORAGE/data${DISK_SIZE}.img" ]]; then
# Fallback for legacy installs
mv "$STORAGE/data${DISK_SIZE}.img" "$DISK1_FILE.img"
fi
DISK2_FILE="/storage2/data2"
if [ ! -f "$DISK2_FILE.img" ]; then
# Fallback for legacy installs
FALLBACK="/storage2/data.img"
if [[ -f "$DISK1_FILE.img" ]] && [[ -f "$FALLBACK" ]]; then
SIZE1=$(stat -c%s "$FALLBACK")
SIZE2=$(stat -c%s "$DISK1_FILE.img")
if [[ SIZE1 -ne SIZE2 ]]; then
mv "$FALLBACK" "$DISK2_FILE.img"
fi
fi
fi
DISK3_FILE="/storage3/data3"
if [ ! -f "$DISK3_FILE.img" ]; then
# Fallback for legacy installs
FALLBACK="/storage3/data.img"
if [[ -f "$DISK1_FILE.img" ]] && [[ -f "$FALLBACK" ]]; then
SIZE1=$(stat -c%s "$FALLBACK")
SIZE2=$(stat -c%s "$DISK1_FILE.img")
if [[ SIZE1 -ne SIZE2 ]]; then
mv "$FALLBACK" "$DISK3_FILE.img"
fi
fi
fi
DISK4_FILE="/storage4/data4"
DISK5_FILE="/storage5/data5"
DISK6_FILE="/storage6/data6"
: ${DISK2_SIZE:=''}
: ${DISK3_SIZE:=''}
: ${DISK4_SIZE:=''}
: ${DISK5_SIZE:=''}
: ${DISK6_SIZE:=''}
addDisk "userdata" "$DISK1_FILE" "$DISK_EXT" "disk" "$DISK_SIZE" "3" "0xc" "$DISK_FMT" || exit $?
addDisk "userdata2" "$DISK2_FILE" "$DISK_EXT" "disk2" "$DISK2_SIZE" "4" "0xd" "$DISK_FMT" || exit $?
addDisk "userdata3" "$DISK3_FILE" "$DISK_EXT" "disk3" "$DISK3_SIZE" "5" "0xe" "$DISK_FMT" || exit $?
addDisk "userdata4" "$DISK4_FILE" "$DISK_EXT" "disk4" "$DISK4_SIZE" "9" "0x7" "$DISK_FMT" || exit $?
addDisk "userdata5" "$DISK5_FILE" "$DISK_EXT" "disk5" "$DISK5_SIZE" "10" "0x8" "$DISK_FMT" || exit $?
addDisk "userdata6" "$DISK6_FILE" "$DISK_EXT" "disk6" "$DISK6_SIZE" "11" "0x9" "$DISK_FMT" || exit $?
addDevice () {
local DISK_ID=$1
local DISK_DEV=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
local DISK_DEV="$1"
local DISK_TYPE="$2"
local DISK_INDEX="$3"
local DISK_ADDRESS="$4"
[ -z "$DISK_DEV" ] && return 0
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
DISK_OPTS="$DISK_OPTS \
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
-drive file=$DISK_DEV,if=none,id=drive-$DISK_ID,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
local sectors=""
local dev_type=""
dev_type=$(lsblk -no TYPE "$DISK_DEV" 2>/dev/null | head -n1)
# Only detect and apply sector sizes for partitions, not whole disks
# Whole disk passthrough with explicit sector sizes causes DSM not to recognize the disk
if [[ "$dev_type" == "part" ]]; then
local result logical physical
result=$(fdisk -l "$DISK_DEV" | grep -m 1 -o "(logical/physical): .*" | cut -c 21-)
logical="${result%% *}"
physical=$(echo "$result" | grep -m 1 -o "/ .*" | cut -c 3-)
physical="${physical%% *}"
if [ -n "$physical" ]; then
if [[ "$physical" != "512" ]]; then
sectors=",logical_block_size=$logical,physical_block_size=$physical"
fi
else
warn "Failed to determine the sector size for $DISK_DEV"
fi
fi
DISK_OPTS+=$(createDevice "$DISK_DEV" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "raw" "$DISK_IO" "$DISK_CACHE" "" "$sectors")
return 0
}
: ${DEVICE:=''} # Docker variable to passthrough a block device, like /dev/vdc1.
: ${DEVICE2:=''}
: ${DEVICE3:=''}
: ${DEVICE4:=''}
: ${DEVICE5:=''}
: ${DEVICE6:=''}
msg="Initializing disks..."
html "$msg"
[[ "$DEBUG" == [Yy1]* ]] && echo "$msg"
addDevice "userdata7" "$DEVICE" "6" "0xf" || exit $?
addDevice "userdata8" "$DEVICE2" "7" "0x5" || exit $?
addDevice "userdata9" "$DEVICE3" "8" "0x6" || exit $?
addDevice "userdata4" "$DEVICE4" "9" "0x7" || exit $?
addDevice "userdata5" "$DEVICE5" "10" "0x8" || exit $?
addDevice "userdata6" "$DEVICE6" "11" "0x9" || exit $?
[ -z "${DISK_OPTS:-}" ] && DISK_OPTS=""
[ -z "${DISK_TYPE:-}" ] && DISK_TYPE="scsi"
[ -z "${DISK_NAME:-}" ] && DISK_NAME="data"
case "${DISK_TYPE,,}" in
"ide" | "sata" | "nvme" | "usb" | "scsi" | "blk" | "auto" | "none" ) ;;
* ) error "Invalid DISK_TYPE specified, value \"$DISK_TYPE\" is not recognized!" && exit 80 ;;
esac
if [ -z "$ALLOCATE" ]; then
ALLOCATE="N"
fi
if [[ "$ALLOCATE" == [Nn]* ]]; then
DISK_STYLE="growable"
DISK_ALLOC="preallocation=off"
else
DISK_STYLE="preallocated"
DISK_ALLOC="preallocation=falloc"
fi
DISK_OPTS+=$(createDevice "$BOOT" "$DISK_TYPE" "1" "0xa" "raw" "$DISK_IO" "$DISK_CACHE" "" "")
DISK_OPTS+=$(createDevice "$SYSTEM" "$DISK_TYPE" "2" "0xb" "raw" "$DISK_IO" "$DISK_CACHE" "" "")
DISK1_FILE="$STORAGE/${DISK_NAME}"
DISK2_FILE="/storage2/${DISK_NAME}2"
DISK3_FILE="/storage3/${DISK_NAME}3"
DISK4_FILE="/storage4/${DISK_NAME}4"
: "${DISK2_SIZE:=""}"
: "${DISK3_SIZE:=""}"
: "${DISK4_SIZE:=""}"
: "${DEVICE:=""}" # Docker variables to passthrough a block device, like /dev/vdc1.
: "${DEVICE2:=""}"
: "${DEVICE3:=""}"
: "${DEVICE4:=""}"
[ -z "$DEVICE" ] && [ -b "/disk" ] && DEVICE="/disk"
[ -z "$DEVICE" ] && [ -b "/disk1" ] && DEVICE="/disk1"
[ -z "$DEVICE2" ] && [ -b "/disk2" ] && DEVICE2="/disk2"
[ -z "$DEVICE3" ] && [ -b "/disk3" ] && DEVICE3="/disk3"
[ -z "$DEVICE4" ] && [ -b "/disk4" ] && DEVICE4="/disk4"
[ -z "$DEVICE" ] && [ -b "/dev/disk1" ] && DEVICE="/dev/disk1"
[ -z "$DEVICE2" ] && [ -b "/dev/disk2" ] && DEVICE2="/dev/disk2"
[ -z "$DEVICE3" ] && [ -b "/dev/disk3" ] && DEVICE3="/dev/disk3"
[ -z "$DEVICE4" ] && [ -b "/dev/disk4" ] && DEVICE4="/dev/disk4"
if [ -n "$DEVICE" ]; then
addDevice "$DEVICE" "$DISK_TYPE" "3" "0xc" || exit $?
else
addDisk "$DISK1_FILE" "$DISK_TYPE" "disk" "$DISK_SIZE" "3" "0xc" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE2" ]; then
addDevice "$DEVICE2" "$DISK_TYPE" "4" "0xd" || exit $?
else
addDisk "$DISK2_FILE" "$DISK_TYPE" "disk2" "$DISK2_SIZE" "4" "0xd" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE3" ]; then
addDevice "$DEVICE3" "$DISK_TYPE" "5" "0xe" || exit $?
else
addDisk "$DISK3_FILE" "$DISK_TYPE" "disk3" "$DISK3_SIZE" "5" "0xe" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE4" ]; then
addDevice "$DEVICE4" "$DISK_TYPE" "6" "0xf" || exit $?
else
addDisk "$DISK4_FILE" "$DISK_TYPE" "disk4" "$DISK4_SIZE" "6" "0xf" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
DISK_OPTS+=" -object iothread,id=io2"
html "Initialized disks successfully..."
return 0
+26 -19
View File
@@ -3,36 +3,43 @@ set -Eeuo pipefail
# Docker environment variables
: ${GPU:='N'} # GPU passthrough
: ${DISPLAY:='none'} # Display type
: "${GPU:="N"}" # GPU passthrough
: "${VGA:="virtio"}" # VGA adaptor
: "${DISPLAY:="none"}" # Display type
: "${RENDERNODE:="/dev/dri/renderD128"}" # Render node
case "${DISPLAY,,}" in
vnc)
DISPLAY_OPTS="-display vnc=:0 -vga virtio"
;;
*)
DISPLAY_OPTS="-display $DISPLAY -vga none"
;;
esac
CPU_VENDOR=$(lscpu | awk '/Vendor ID/{print $3}')
if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
if [[ "$GPU" != [Yy1]* || "$CPU_VENDOR" != "GenuineIntel" || "$ARCH" != "amd64" ]]; then
[[ "${DISPLAY,,}" == "none" ]] && VGA="none"
DISPLAY_OPTS="-display $DISPLAY -vga $VGA"
return 0
fi
DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128 -vga virtio"
[[ "${DISPLAY,,}" == "vnc" ]] && DISPLAY_OPTS="$DISPLAY_OPTS -vnc :0"
msg="Configuring display drivers..."
html "$msg"
[[ "$DEBUG" == [Yy1]* ]] && echo "$msg"
DISPLAY_OPTS="-display egl-headless,rendernode=$RENDERNODE"
DISPLAY_OPTS+=" -vga $VGA"
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
if [ ! -c /dev/dri/card0 ]; then
if mknod /dev/dri/card0 c 226 0; then
chmod 666 /dev/dri/card0
# Extract the card number from the render node
CARD_NUMBER=$(echo "$RENDERNODE" | grep -oP '(?<=renderD)\d+')
CARD_DEVICE="/dev/dri/card$((CARD_NUMBER - 128))"
if [ ! -c "$CARD_DEVICE" ]; then
if mknod "$CARD_DEVICE" c 226 $((CARD_NUMBER - 128)); then
chmod 666 "$CARD_DEVICE"
fi
fi
if [ ! -c /dev/dri/renderD128 ]; then
if mknod /dev/dri/renderD128 c 226 128; then
chmod 666 /dev/dri/renderD128
if [ ! -c "$RENDERNODE" ]; then
if mknod "$RENDERNODE" c 226 "$CARD_NUMBER"; then
chmod 666 "$RENDERNODE"
fi
fi
+18 -8
View File
@@ -1,12 +1,16 @@
#!/usr/bin/env bash
set -Eeuo pipefail
echo "❯ Starting Virtual DSM for Docker v$(</run/version)..."
echo "❯ For support visit https://github.com/vdsm/virtual-dsm/"
: "${PLATFORM:="x64"}"
: "${APP:="Virtual DSM"}"
: "${SUPPORT:="https://github.com/vdsm/virtual-dsm"}"
cd /run
. start.sh # Startup hook
. utils.sh # Load functions
. reset.sh # Initialize system
. server.sh # Start webserver
. install.sh # Run installation
. disk.sh # Initialize disks
. display.sh # Initialize graphics
@@ -14,19 +18,25 @@ cd /run
. proc.sh # Initialize processor
. serial.sh # Initialize serialport
. power.sh # Configure shutdown
. memory.sh # Check available memory
. config.sh # Configure arguments
. finish.sh # Finish initialization
trap - ERR
version=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1 | awk '{ print $NF }')
info "Booting $APP using QEMU v$version..."
if [[ "$CONSOLE" == [Yy]* ]]; then
exec qemu-system-x86_64 ${ARGS:+ $ARGS}
fi
[[ "$DEBUG" == [Yy1]* ]] && info "$VERS" && set -x
msg=$(qemu-system-x86_64 ${ARGS:+ $ARGS})
{ qemu-system-x86_64 ${ARGS:+ $ARGS} >"$QEMU_OUT" 2>"$QEMU_LOG"; rc=$?; } || :
(( rc != 0 )) && error "$(<"$QEMU_LOG")" && exit 15
{ set +x; } 2>/dev/null && terminal "$msg"
tail -fn +0 "$QEMU_LOG" 2>/dev/null &
cat "$QEMU_TERM" 2>/dev/null & wait $! || true
terminal
tail -fn +0 "$QEMU_LOG" --pid=$$ 2>/dev/null &
cat "$QEMU_TERM" 2>/dev/null & wait $! || :
sleep 1 && finish 0
sleep 1 & wait $!
[ ! -f "$QEMU_END" ] && finish 0
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -Eeuo pipefail
if [[ "$DEBUG" == [Yy1]* ]]; then
printf "QEMU arguments:\n\n%s\n\n" "${ARGS// -/$'\n-'}"
fi
return 0
+163 -182
View File
@@ -1,23 +1,50 @@
#!/usr/bin/env bash
set -Eeuo pipefail
: ${URL:=''} # URL of the PAT file to be downloaded.
: "${URL:=""}" # URL of the PAT file to be downloaded.
if [ -f "$STORAGE"/dsm.ver ]; then
BASE=$(cat "$STORAGE/dsm.ver")
if [ -f "$STORAGE/dsm.ver" ]; then
BASE=$(<"$STORAGE/dsm.ver")
BASE="${BASE//[![:print:]]/}"
[ -z "$BASE" ] && BASE="DSM_VirtualDSM_69057"
else
# Fallback for old installs
BASE="DSM_VirtualDSM_42962"
fi
[ -n "$URL" ] && BASE=$(basename "$URL" .pat)
FN="boot.pat"
DIR=$(find / -maxdepth 1 -type d -iname "$FN" -print -quit)
[ ! -d "$DIR" ] && DIR=$(find "$STORAGE" -maxdepth 1 -type d -iname "$FN" -print -quit)
if [[ -f "$STORAGE/$BASE.boot.img" ]] && [[ -f "$STORAGE/$BASE.system.img" ]]; then
if [ -d "$DIR" ]; then
BASE="DSM_VirtualDSM" && URL="file://$DIR"
if [[ ! -s "$STORAGE/$BASE.boot.img" || ! -s "$STORAGE/$BASE.system.img" ]]; then
error "The bind $DIR maps to a file that does not exist!" && exit 65
fi
fi
FILE=$(find / -maxdepth 1 -type f -iname "$FN" -print -quit)
[ ! -s "$FILE" ] && FILE=$(find "$STORAGE" -maxdepth 1 -type f -iname "$FN" -print -quit)
[ -s "$FILE" ] && BASE="DSM_VirtualDSM" && URL="file://$FILE"
if [ -n "$URL" ] && [ ! -s "$FILE" ] && [ ! -d "$DIR" ]; then
BASE=$(basename "$URL" .pat)
if [ ! -s "$STORAGE/$BASE.system.img" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
printf -v BASE '%b' "${BASE//%/\\x}"
BASE="${BASE//[!A-Za-z0-9._-]/_}"
fi
if [[ "${URL,,}" != "http"* && "${URL,,}" != "file:"* ]] ; then
[ ! -s "$STORAGE/$BASE.pat" ] && error "Invalid URL: $URL" && exit 65
URL="file://$STORAGE/$BASE.pat"
fi
fi
if [[ -s "$STORAGE/$BASE.boot.img" && -s "$STORAGE/$BASE.system.img" ]]; then
return 0 # Previous installation found
fi
# Display wait message
/run/server.sh 5000 install &
html "Please wait while Virtual DSM is being installed..."
DL=""
DL_CHINA="https://cndl.synology.cn/download/DSM"
@@ -32,49 +59,70 @@ if [ -z "$DL" ]; then
[[ "${COUNTRY^^}" == "CN" ]] && DL="$DL_CHINA" || DL="$DL_GLOBAL"
fi
[ -z "$URL" ] && URL="$DL/release/7.2.1/69057-1/DSM_VirtualDSM_69057.pat"
if [ -z "$URL" ]; then
URL="$DL/release/7.2.2/72806/DSM_VirtualDSM_72806.pat"
fi
BASE=$(basename "$URL" .pat)
if [ ! -s "$FILE" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
printf -v BASE '%b' "${BASE//%/\\x}"
BASE="${BASE//[!A-Za-z0-9._-]/_}"
fi
if [[ "$URL" != "file://$STORAGE/$BASE.pat" ]]; then
rm -f "$STORAGE"/"$BASE".pat
rm -f "$STORAGE/$BASE.pat"
fi
rm -f "$STORAGE"/"$BASE".agent
rm -f "$STORAGE"/"$BASE".boot.img
rm -f "$STORAGE"/"$BASE".system.img
[[ "$DEBUG" == [Yy1]* ]] && set -x
rm -f "$STORAGE/$BASE.agent"
rm -f "$STORAGE/$BASE.boot.img"
rm -f "$STORAGE/$BASE.system.img"
# Check filesystem
MIN_ROOT=471859200
MIN_SPACE=6442450944
FS=$(stat -f -c %T "$STORAGE")
if [[ "${FS,,}" == "overlay"* ]]; then
info "Warning: the filesystem of $STORAGE is OverlayFS, this usually means it was binded to an invalid path!"
if [[ "${FS,,}" == "overlay"* && "${ENGINE,,}" == "docker" ]]; then
warn "the filesystem of $STORAGE is OverlayFS, this usually means it was binded to an invalid path!"
fi
if [[ "${FS,,}" != "fat"* && "${FS,,}" != "vfat"* && "${FS,,}" != "exfat"* && \
"${FS,,}" != "ntfs"* && "${FS,,}" != "fuse"* && "${FS,,}" != "msdos"* ]]; then
if [[ "${FS,,}" == "fuse"* ]]; then
warn "the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
fi
if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
warn "the filesystem of $STORAGE is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if [[ "${FS,,}" == "fat"* || "${FS,,}" == "vfat"* || "${FS,,}" == "msdos"* ]]; then
error "Unable to install on $FS filesystems, please use a different filesystem for /storage." && exit 61
fi
if [[ "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "unknown"* ]]; then
TMP="$STORAGE/tmp"
rm -rf "$TMP"
if ! makeDir "$TMP"; then
error "Failed to create directory \"$TMP\" !" && exit 93
fi
else
TMP="/tmp/dsm"
TMP_SPACE=2147483648
SPACE=$(df --output=avail -B 1 /tmp | tail -n 1)
if (( MIN_SPACE > SPACE )); then
error "The ${FS^^} filesystem of $STORAGE does not support UNIX permissions, and no space left in container!" && exit 93
SPACE_MB=$(formatBytes "$SPACE")
if (( TMP_SPACE > SPACE )); then
error "Not enough free space inside the container, have $SPACE_MB available but need at least 2 GB." && exit 93
fi
rm -rf "$TMP" && mkdir -p "$TMP"
fi
rm -rf "$TMP" && mkdir -p "$TMP"
# Check free diskspace
ROOT_SPACE=536870912
SPACE=$(df --output=avail -B 1 / | tail -n 1)
(( MIN_ROOT > SPACE )) && error "Not enough free space in container root, need at least 450 MB available." && exit 96
SPACE_MB=$(formatBytes "$SPACE" "down")
(( ROOT_SPACE > SPACE )) && error "Not enough free space inside the container, have $SPACE_MB available but need at least 500 MB." && exit 96
MIN_SPACE=15032385536
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
(( MIN_SPACE > SPACE )) && error "Not enough free space for installation in $STORAGE, have $SPACE_GB GB available but need at least 6 GB." && exit 94
SPACE_GB=$(formatBytes "$SPACE")
(( MIN_SPACE > SPACE )) && error "Not enough free space for installation in $STORAGE, have $SPACE_GB available but need at least 14 GB." && exit 94
# Check if output is to interactive TTY
if [ -t 1 ]; then
@@ -83,99 +131,50 @@ else
PROGRESS="--progress=dot:giga"
fi
# Download the required files from the Synology website
ROOT="Y"
RDC="$STORAGE/dsm.rd"
if [ ! -f "$RDC" ]; then
info "Install: Downloading installer..."
RD="$TMP/rd.gz"
POS="65627648-71021835"
VERIFY="b4215a4b213ff5154db0488f92c87864"
LOC="$DL/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
{ curl -r "$POS" -sfk -S -o "$RD" "$LOC"; rc=$?; } || :
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60
SUM=$(md5sum "$RD" | cut -f 1 -d " ")
if [ "$SUM" != "$VERIFY" ]; then
PAT="/install.pat"
rm "$RD"
rm -f "$PAT"
{ wget "$LOC" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60
tar --extract --file="$PAT" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
rm "$PAT"
fi
cp "$RD" "$RDC"
if [[ "$URL" == "file://"* ]]; then
MSG="Copying DSM"
ERR="Failed to copy ${URL:7}"
info "Install: Copying installation image..."
else
MSG="Downloading DSM"
ERR="Failed to download $URL"
info "Install: Downloading $BASE.pat..."
fi
if [ -f "$RDC" ]; then
{ xz -dc <"$RDC" >"$TMP/rd" 2>/dev/null; rc=$?; } || :
(( rc != 1 )) && error "Failed to unxz $RDC, reason $rc" && exit 91
{ (cd "$TMP" && cpio -idm <"$TMP/rd" 2>/dev/null); rc=$?; } || :
if (( rc != 0 )); then
ROOT="N"
{ (cd "$TMP" && fakeroot cpio -idmu <"$TMP/rd" 2>/dev/null); rc=$?; } || :
(( rc != 0 )) && error "Failed to extract $RDC, reason $rc" && exit 92
fi
mkdir -p /run/extract
for file in $TMP/usr/lib/libcurl.so.4 \
$TMP/usr/lib/libmbedcrypto.so.5 \
$TMP/usr/lib/libmbedtls.so.13 \
$TMP/usr/lib/libmbedx509.so.1 \
$TMP/usr/lib/libmsgpackc.so.2 \
$TMP/usr/lib/libsodium.so \
$TMP/usr/lib/libsynocodesign-ng-virtual-junior-wins.so.7 \
$TMP/usr/syno/bin/scemd; do
cp "$file" /run/extract/
done
if [ "$ARCH" != "amd64" ]; then
mkdir -p /lib64/
cp "$TMP/usr/lib/libc.so.6" /lib64/
cp "$TMP/usr/lib/libpthread.so.0" /lib64/
cp "$TMP/usr/lib/ld-linux-x86-64.so.2" /lib64/
fi
mv /run/extract/scemd /run/extract/syno_extract_system_patch
chmod +x /run/extract/syno_extract_system_patch
fi
rm -rf "$TMP" && mkdir -p "$TMP"
info "Install: Downloading $(basename "$URL")..."
html "$MSG..."
PAT="/$BASE.pat"
rm -f "$PAT"
if [[ "$URL" == "file://"* ]]; then
if [ ! -f "${URL:7}" ]; then
error "File '${URL:7}' does not exist!" && exit 65
fi
cp "${URL:7}" "$PAT"
else
{ wget "$URL" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
(( rc != 0 )) && error "Failed to download $URL, reason: $rc" && exit 69
SIZE=0
[[ "${URL,,}" == *"_72806.pat" ]] && SIZE=361010261
[[ "${URL,,}" == *"_69057.pat" ]] && SIZE=363837333
[[ "${URL,,}" == *"_42218.pat" ]] && SIZE=379637760
/run/progress.sh "$PAT" "$SIZE" "$MSG ([P])..." &
{ wget "$URL" -O "$PAT" -q --no-check-certificate --timeout=10 --no-http-keep-alive --show-progress "$PROGRESS"; rc=$?; } || :
fKill "progress.sh"
(( rc == 3 )) && error "$ERR , cannot write file (disk full?)" && exit 69
(( rc == 4 )) && error "$ERR , network failure!" && exit 69
(( rc == 8 )) && error "$ERR , server issued an error response!" && exit 69
(( rc != 0 )) && error "$ERR , reason: $rc" && exit 69
fi
[ ! -f "$PAT" ] && error "Failed to download $URL" && exit 69
[ ! -s "$PAT" ] && error "$ERR" && exit 69
SIZE=$(stat -c%s "$PAT")
@@ -183,7 +182,8 @@ if ((SIZE<250000000)); then
error "The specified PAT file is probably an update pack as it's too small." && exit 62
fi
info "Install: Extracting downloaded image..."
MSG="Extracting installation image..."
info "Install: $MSG" && html "$MSG"
if { tar tf "$PAT"; } >/dev/null 2>&1; then
@@ -191,67 +191,59 @@ if { tar tf "$PAT"; } >/dev/null 2>&1; then
else
export LD_LIBRARY_PATH="/run/extract"
{ (cd "$TMP" && python3 /run/extract.py -i "$PAT" -d 2>/run/extract.log); rc=$?; } || :
if [ "$ARCH" == "amd64" ]; then
{ /run/extract/syno_extract_system_patch "$PAT" "$TMP/."; rc=$?; } || :
else
{ qemu-x86_64 /run/extract/syno_extract_system_patch "$PAT" "$TMP/."; rc=$?; } || :
if (( rc != 0 )); then
cat /run/extract.log
error "Failed to extract PAT file, reason $rc" && exit 63
fi
export LD_LIBRARY_PATH=""
(( rc != 0 )) && error "Failed to extract PAT file, reason $rc" && exit 63
fi
info "Install: Preparing system partition..."
MSG="Preparing system partition..."
info "Install: $MSG" && html "$MSG"
BOOT=$(find "$TMP" -name "*.bin.zip")
[ ! -f "$BOOT" ] && error "The PAT file contains no boot image." && exit 67
[ ! -s "$BOOT" ] && error "The PAT file contains no boot image." && exit 67
BOOT=$(echo "$BOOT" | head -c -5)
unzip -q -o "$BOOT".zip -d "$TMP"
SYSTEM="$TMP/sys.img"
SYSTEM_SIZE=4954537983
SYSTEM="$STORAGE/$BASE.system.img"
rm -f "$SYSTEM"
# Check free diskspace
SPACE=$(df --output=avail -B 1 "$TMP" | tail -n 1)
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
(( SYSTEM_SIZE > SPACE )) && error "Not enough free space to create a 4 GB system disk, have only $SPACE_GB GB available." && exit 97
SYSTEM_SIZE=10738466816
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_MB=$(formatBytes "$SPACE")
if (( SYSTEM_SIZE > SPACE )); then
error "Not enough free space in $STORAGE to create a 10 GB system disk, have only $SPACE_MB available." && exit 97
fi
if ! touch "$SYSTEM"; then
error "Could not create file $SYSTEM for the system disk." && exit 98
fi
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
! setOwner "$SYSTEM" && error "Failed to set the owner for \"$SYSTEM\" !"
if [[ "${FS,,}" == "btrfs" ]]; then
{ chattr +C "$SYSTEM"; } || :
FA=$(lsattr "$SYSTEM")
if [[ "$FA" != *"C"* ]]; then
error "Failed to disable COW for system image $SYSTEM on ${FS^^} filesystem (returned $FA)"
error "Failed to disable COW for system image $SYSTEM on ${FS^^} filesystem."
fi
fi
if ! fallocate -l "$SYSTEM_SIZE" "$SYSTEM"; then
if ! truncate -s "$SYSTEM_SIZE" "$SYSTEM"; then
rm -f "$SYSTEM"
error "Could not allocate file $SYSTEM for the system disk." && exit 98
if ! fallocate -l "$SYSTEM_SIZE" "$SYSTEM" &>/dev/null; then
if ! fallocate -l -x "$SYSTEM_SIZE" "$SYSTEM"; then
if ! truncate -s "$SYSTEM_SIZE" "$SYSTEM"; then
rm -f "$SYSTEM"
error "Could not allocate file $SYSTEM for the system disk." && exit 98
fi
fi
fi
# Check if file exists
[ ! -f "$SYSTEM" ] && error "System disk does not exist ($SYSTEM)" && exit 99
# Check the filesize
SIZE=$(stat -c%s "$SYSTEM")
if [[ SIZE -ne SYSTEM_SIZE ]]; then
rm -f "$SYSTEM"
error "System disk has the wrong size: $SIZE vs $SYSTEM_SIZE" && exit 90
fi
PART="$TMP/partition.fdisk"
{ echo "label: dos"
@@ -260,78 +252,67 @@ PART="$TMP/partition.fdisk"
echo "unit: sectors"
echo "sector-size: 512"
echo ""
echo "${SYSTEM}1 : start= 2048, size= 4980480, type=83"
echo "${SYSTEM}2 : start= 4982528, size= 4194304, type=82"
echo "${SYSTEM}1 : start= 2048, size= 16777216, type=83"
echo "${SYSTEM}2 : start= 16779264, size= 4194304, type=82"
} > "$PART"
sfdisk -q "$SYSTEM" < "$PART"
MOUNT="$TMP/system"
rm -rf "$MOUNT" && mkdir -p "$MOUNT"
rm -rf "$MOUNT"
info "Install: Extracting system partition..."
if ! makeDir "$MOUNT"; then
error "Failed to create directory \"$MOUNT\" !" && exit 93
fi
MSG="Extracting system partition..."
info "Install: $MSG" && html "$MSG"
HDA="$TMP/hda1"
IDB="$TMP/indexdb"
PKG="$TMP/packages"
HDP="$TMP/synohdpack_img"
[ ! -f "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64
[ ! -s "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64
mv "$HDA.tgz" "$HDA.txz"
if [[ "$ROOT" != [Nn]* ]]; then
tar xpfJ "$HDA.txz" --absolute-names -C "$MOUNT/"
fi
[ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/"
rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"*
[ -f "$HDP.txz" ] && tar xpfJ "$HDP.txz" --absolute-names -C "$MOUNT/"
if [ -f "$IDB.txz" ]; then
INDEX_DB="$MOUNT/usr/syno/synoman/indexdb/"
if [ -s "$IDB.txz" ]; then
INDEX_DB="$MOUNT/usr/syno/synoman/indexdb"
mkdir -p "$INDEX_DB"
tar xpfJ "$IDB.txz" --absolute-names -C "$INDEX_DB"
fi
LABEL="1.44.1-42218"
OFFSET="1048576" # 2048 * 512
NUMBLOCKS="622560" # (4980480 * 512) / 4096
OFFSET="1048576" # 2048 * 512
NUMBLOCKS="2097152" # (16777216 * 512) / 4096
MSG="Installing system partition..."
if [[ "$ROOT" != [Nn]* ]]; then
info "Install: Installing system partition..."
mke2fs -q -t ext4 -b 4096 -d "$MOUNT/" -L "$LABEL" -F -E "offset=$OFFSET" "$SYSTEM" "$NUMBLOCKS"
else
fakeroot -- bash -c "set -Eeu;\
tar xpfJ $HDA.txz --absolute-names --skip-old-files -C $MOUNT/;\
printf '%b%s%b' '\E[1;34m❯ \E[1;36m' 'Install: Installing system partition...' '\E[0m\n';\
mke2fs -q -t ext4 -b 4096 -d $MOUNT/ -L $LABEL -F -E offset=$OFFSET $SYSTEM $NUMBLOCKS"
fi
fakeroot -- bash -c "set -Eeu;\
[ -s $HDP.txz ] && tar xpfJ $HDP.txz --absolute-names -C $MOUNT/;\
[ -s $IDB.txz ] && tar xpfJ $IDB.txz --absolute-names -C $INDEX_DB/;\
tar xpfJ $HDA.txz --absolute-names --skip-old-files -C $MOUNT/;\
printf '%b%s%b' '\E[1;34m❯ \E[1;36m' 'Install: $MSG' '\E[0m\n';\
mke2fs -q -t ext4 -b 4096 -d $MOUNT/ -L $LABEL -F -E offset=$OFFSET $SYSTEM $NUMBLOCKS"
rm -rf "$MOUNT"
echo "$BASE" > "$STORAGE"/dsm.ver
echo "$BASE" > "$STORAGE/dsm.ver"
! setOwner "$STORAGE/dsm.ver" && error "Failed to set the owner for \"$STORAGE/dsm.ver\" !"
if [[ "$URL" == "file://$STORAGE/$BASE.pat" ]]; then
rm -f "$PAT"
else
mv -f "$PAT" "$STORAGE"/"$BASE".pat
mv -f "$PAT" "$STORAGE/$BASE.pat"
fi
mv -f "$BOOT" "$STORAGE"/"$BASE".boot.img
mv -f "$SYSTEM" "$STORAGE"/"$BASE".system.img
if [ -f "$STORAGE/$BASE.pat" ]; then
! setOwner "$STORAGE/$BASE.pat" && error "Failed to set the owner for \"$STORAGE/$BASE.pat\" !"
fi
mv -f "$BOOT" "$STORAGE/$BASE.boot.img"
! setOwner "$STORAGE/$BASE.boot.img" && error "Failed to set the owner for \"$STORAGE/$BASE.boot.img\" !"
rm -rf "$TMP"
{ set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo
return 0
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env bash
set -Eeuo pipefail
msg="Checking memory..."
[[ "$DEBUG" == [Yy1]* ]] && echo "$msg"
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
AVAIL_MEM=$(formatBytes "$RAM_AVAIL")
if [[ "$RAM_CHECK" != [Nn]* && "${RAM_SIZE,,}" != "max" && "${RAM_SIZE,,}" != "half" ]]; then
wanted=$(numfmt --from=iec "$RAM_SIZE")
if (( (wanted + RAM_SPARE) > RAM_AVAIL )); then
msg="Your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is too high for the $AVAIL_MEM of free memory available,"
if [[ "${FS,,}" == "zfs" ]]; then
info "$msg but since ZFS is active this will be ignored."
else
RAM_SIZE="max"
warn "$msg it will automatically be adjusted to a lower amount."
fi
else
if (( (wanted + (RAM_SPARE * 3)) > RAM_AVAIL )); then
msg="your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is very close to the $AVAIL_MEM of free memory available,"
if [[ "${FS,,}" == "zfs" ]]; then
info "$msg but since ZFS is active this will be ignored."
else
warn "$msg please consider a lower amount."
fi
fi
fi
fi
if [[ "${RAM_SIZE,,}" == "half" ]]; then
if (( (RAM_AVAIL / 2) > RAM_SPARE )); then
wanted=$(( (RAM_AVAIL / 2) / 1048577 ))
RAM_SIZE="${wanted}M"
info "Allocated $wanted MB of RAM for the virtual machine."
else
RAM_SIZE="max"
fi
fi
if [[ "${RAM_SIZE,,}" == "max" ]]; then
if (( RAM_AVAIL < (RAM_SPARE * 2) )); then
wanted=$(( RAM_AVAIL / 2 ))
else
wanted=$(( RAM_AVAIL - (RAM_SPARE * 3) ))
if (( wanted < (RAM_SPARE * 6) )); then
wanted=$(( RAM_AVAIL - RAM_SPARE ))
fi
fi
wanted=$(( wanted / 1048577 ))
RAM_SIZE="${wanted}M"
info "Allocated $wanted MB of RAM for the virtual machine."
fi
wanted=$(numfmt --from=iec "$RAM_SIZE")
if [ "$wanted" -lt "$RAM_MINIMUM" ]; then
wanted=$(( wanted / 1048577 ))
error "Not enough memory available, there is only $wanted MB left!"
exit 16
fi
return 0
+700 -132
View File
@@ -3,18 +3,33 @@ set -Eeuo pipefail
# Docker environment variables
: ${DHCP:='N'}
: ${HOST_PORTS:=''}
: ${MAC:='02:11:32:AA:BB:CC'}
: "${MAC:=""}"
: "${MTU:=""}"
: "${DHCP:="N"}"
: "${NETWORK:="Y"}"
: "${HOST_PORTS:=""}"
: "${USER_PORTS:=""}"
: "${ADAPTER:="virtio-net-pci"}"
: ${VM_NET_DEV:=''}
: ${VM_NET_TAP:='dsm'}
: ${VM_NET_MAC:="$MAC"}
: ${VM_NET_HOST:='VirtualDSM'}
: "${VM_NET_IP:=""}"
: "${VM_NET_DEV:=""}"
: "${VM_NET_TAP:="dsm"}"
: "${VM_NET_MAC:="$MAC"}"
: "${VM_NET_BRIDGE:="docker"}"
: "${VM_NET_HOST:="VirtualDSM"}"
: "${VM_NET_MASK:="255.255.255.0"}"
: ${DNSMASQ_OPTS:=''}
: ${DNSMASQ:='/usr/sbin/dnsmasq'}
: ${DNSMASQ_CONF_DIR:='/etc/dnsmasq.d'}
: "${PASST:="/run/passt"}"
: "${PASST_MTU:=""}"
: "${PASST_OPTS:=""}"
: "${PASST_DEBUG:=""}"
: "${PASST_PID:="/var/run/passt.pid"}"
: "${DNSMASQ_OPTS:=""}"
: "${DNSMASQ_DEBUG:=""}"
: "${DNSMASQ:="/usr/sbin/dnsmasq"}"
: "${DNSMASQ_PID:="/var/run/dnsmasq.pid"}"
: "${DNSMASQ_CONF_DIR:="/etc/dnsmasq.d"}"
ADD_ERR="Please add the following setting to your container:"
@@ -24,17 +39,47 @@ ADD_ERR="Please add the following setting to your container:"
configureDHCP() {
[[ "$DEBUG" == [Yy1]* ]] && echo "Configuring MACVTAP networking..."
# Create the necessary file structure for /dev/vhost-net
if [ ! -c /dev/vhost-net ]; then
if mknod /dev/vhost-net c 10 238; then
chmod 660 /dev/vhost-net
fi
fi
# Create a macvtap network for the VM guest
{ msg=$(ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge 2>&1); rc=$?; } || :
{ ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge ; rc=$?; } || :
case "$msg" in
"RTNETLINK answers: File exists"* )
while ! ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge; do
info "Waiting for macvtap interface to become available.."
sleep 5
done ;;
"RTNETLINK answers: Invalid argument"* )
error "Cannot create macvtap interface. Please make sure that the network type of the container is 'macvlan' and not 'ipvlan'."
return 1 ;;
"RTNETLINK answers: Operation not permitted"* )
error "No permission to create macvtap interface. Please make sure that your host kernel supports it and that the NET_ADMIN capability is set."
return 1 ;;
*)
[ -n "$msg" ] && echo "$msg" >&2
if (( rc != 0 )); then
error "Cannot create macvtap interface."
return 1
fi ;;
esac
if (( rc != 0 )); then
error "Cannot create macvtap interface. Please make sure the network type is 'macvlan' and not 'ipvlan',"
error "and that the NET_ADMIN capability has been added to the container: --cap-add NET_ADMIN" && exit 16
if [[ "$MTU" != "0" && "$MTU" != "1500" ]]; then
if ! ip link set dev "$VM_NET_TAP" mtu "$MTU"; then
warn "Failed to set MTU size to $MTU."
fi
fi
while ! ip link set "$VM_NET_TAP" up; do
info "Waiting for address to become available..."
info "Waiting for MAC address $VM_NET_MAC to become available..."
info "If you cloned this machine, please delete the 'dsm.mac' file to generate a different MAC address."
sleep 2
done
@@ -44,25 +89,25 @@ configureDHCP() {
# Create dev file (there is no udev in container: need to be done manually)
IFS=: read -r MAJOR MINOR < <(cat /sys/devices/virtual/net/"$VM_NET_TAP"/tap*/dev)
(( MAJOR < 1)) && error "Cannot find: sys/devices/virtual/net/$VM_NET_TAP" && exit 18
(( MAJOR < 1)) && error "Cannot find: sys/devices/virtual/net/$VM_NET_TAP" && return 1
[[ ! -e "$TAP_PATH" ]] && [[ -e "/dev0/${TAP_PATH##*/}" ]] && ln -s "/dev0/${TAP_PATH##*/}" "$TAP_PATH"
[[ ! -e "$TAP_PATH" && -e "/dev0/${TAP_PATH##*/}" ]] && ln -s "/dev0/${TAP_PATH##*/}" "$TAP_PATH"
if [[ ! -e "$TAP_PATH" ]]; then
{ mknod "$TAP_PATH" c "$MAJOR" "$MINOR" ; rc=$?; } || :
(( rc != 0 )) && error "Cannot mknod: $TAP_PATH ($rc)" && exit 20
(( rc != 0 )) && error "Cannot mknod: $TAP_PATH ($rc)" && return 1
fi
{ exec 30>>"$TAP_PATH"; rc=$?; } 2>/dev/null || :
if (( rc != 0 )); then
error "Cannot create TAP interface ($rc). $ADD_ERR --device-cgroup-rule='c *:* rwm'" && exit 21
error "Cannot create TAP interface ($rc). $ADD_ERR --device-cgroup-rule='c *:* rwm'" && return 1
fi
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
if (( rc != 0 )); then
error "VHOST can not be found ($rc). $ADD_ERR --device=/dev/vhost-net" && exit 22
error "VHOST can not be found ($rc). $ADD_ERR --device=/dev/vhost-net" && return 1
fi
NET_OPTS="-netdev tap,id=hostnet0,vhost=on,vhostfd=40,fd=30"
@@ -72,61 +117,296 @@ configureDHCP() {
configureDNS() {
# dnsmasq configuration:
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-range=$VM_NET_IP,$VM_NET_IP --dhcp-host=$VM_NET_MAC,,$VM_NET_IP,$VM_NET_HOST,infinite --dhcp-option=option:netmask,255.255.255.0"
local fa="$1"
local ip="$2"
local mac="$3"
local host="$4"
local mask="$5"
local gateway="$6"
local arguments="$DNSMASQ_OPTS"
# Create lease file for faster resolve
echo "0 $VM_NET_MAC $VM_NET_IP $VM_NET_HOST 01:$VM_NET_MAC" > /var/lib/misc/dnsmasq.leases
chmod 644 /var/lib/misc/dnsmasq.leases
echo "$gateway" > /run/shm/qemu.gw
# Set DNS server and gateway
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1"
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
[[ "${DNSMASQ_DISABLE:-}" == [Yy1]* ]] && return 0
[[ "$DEBUG" == [Yy1]* ]] && echo "Starting dnsmasq daemon..."
[[ "$DEBUG" == [Yy1]* ]] && set -x
$DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}
{ set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo
[ -s "$DNSMASQ_PID" ] && pKill "$(<"$DNSMASQ_PID")"
rm -f "$DNSMASQ_PID"
case "${NETWORK,,}" in
"tap" | "tun" | "tuntap" | "y" )
# Create lease file for faster resolve
echo "0 $mac $ip $host 01:$mac" > /var/lib/misc/dnsmasq.leases
chmod 644 /var/lib/misc/dnsmasq.leases
# dnsmasq configuration:
arguments+=" --dhcp-authoritative"
# Set DHCP range and host
arguments+=" --dhcp-range=$ip,$ip"
arguments+=" --dhcp-host=$mac,,$ip,$host,infinite"
# Set DNS server and gateway
arguments+=" --dhcp-option=option:netmask,$mask"
arguments+=" --dhcp-option=option:router,$gateway"
arguments+=" --dhcp-option=option:dns-server,$gateway"
esac
# Set interfaces
arguments+=" --interface=$fa"
arguments+=" --bind-interfaces"
# Workaround NET_RAW capability
arguments+=" --no-ping"
# Add DNS entry for container
arguments+=" --address=/host.lan/$gateway"
# Set local dns resolver to dnsmasq when needed
[ -f /etc/resolv.dnsmasq ] && arguments+=" --resolv-file=/etc/resolv.dnsmasq"
# Enable logging to file
local log="/var/log/dnsmasq.log"
rm -f "$log"
arguments+=" --log-facility=$log"
arguments=$(echo "$arguments" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
[[ "$DEBUG" == [Yy1]* ]] && printf "Dnsmasq arguments:\n\n%s\n\n" "${arguments// -/$'\n-'}"
{ $DNSMASQ ${arguments:+ $arguments}; rc=$?; } || :
if (( rc != 0 )); then
local msg="Failed to start Dnsmasq, reason: $rc"
if [[ "${NETWORK,,}" == "slirp" || "${NETWORK,,}" == "passt" || "$ROOTLESS" != [Yy1]* || "$DEBUG" == [Yy1]* ]]; then
[ -f "$log" ] && [ -s "$log" ] && cat "$log"
error "$msg"
fi
return 1
fi
if [[ "$DNSMASQ_DEBUG" == [Yy1]* ]]; then
tail -fn +0 "$log" --pid=$$ &
fi
return 0
}
getPorts() {
getHostPorts() {
local list=$1
local list=""
list+="$MON_PORT,"
list+="${HOST_PORTS// /},"
# Remove duplicates
list=$(echo "${list//,,/,}," | awk 'BEGIN{RS=ORS=","} !seen[$0]++' | sed 's/,*$//g')
echo "$list"
return 0
}
getUserPorts() {
local ssh="22"
local dsm="5000,5001"
local list="$ssh,$dsm,"
list+="${USER_PORTS// /},"
local exclude
exclude=$(getHostPorts)
local ports=""
local userport=""
local hostport=""
for userport in ${list//,/ }; do
local num="${userport///tcp}"
num="${num///udp}"
for hostport in ${exclude//,/ }; do
local port="${hostport///tcp}"
port="${port///udp}"
if [[ "$num" == "$port" ]]; then
num=""
if [[ "$port" != "$WEB_PORT" ]]; then
warn "Could not assign port $port to \"USER_PORTS\" because it is already in \"HOST_PORTS\"!"
fi
fi
done
[ -n "$num" ] && ports+="$userport,"
done
# Remove duplicates
echo "${ports//,,/,}," | awk 'BEGIN{RS=ORS=","} !seen[$0]++' | sed 's/,*$//g'
return 0
}
getSlirp() {
local ip="$1"
local args=""
local vnc="5900"
local list=""
list="${list//,/ }"
list="${list## }"
list="${list%% }"
list=$(getUserPorts)
if [[ "${DISPLAY,,}" == "vnc" ]] && [[ "$list" != *"$vnc"* ]]; then
if [ -z "$list" ]; then
list="$vnc"
else
list="$list $vnc"
for port in ${list//,/ }; do
local proto="tcp"
local num="${port%/tcp}"
[ -z "$num" ] && continue
if [[ "$port" == *"/udp" ]]; then
proto="udp"
num="${port%/udp}"
elif [[ "$port" != *"/tcp" ]]; then
args+="hostfwd=$proto::$num-$ip:$num,"
proto="udp"
num="${port%/udp}"
fi
args+="hostfwd=$proto::$num-$ip:$num,"
done
echo "$args" | sed 's/,*$//g'
return 0
}
configureSlirp() {
NETWORK="slirp"
[[ "$DEBUG" == [Yy1]* ]] && echo "Configuring slirp networking..."
local ip="$IP"
[ -n "$VM_NET_IP" ] && ip="$VM_NET_IP"
local base="${ip%.*}."
[ "${ip/$base/}" -lt "4" ] && ip="${ip%.*}.4"
local gateway="${ip%.*}.1"
local ipv6=""
[ -n "$IP6" ] && ipv6="ipv6=on,"
NET_OPTS="-netdev user,id=hostnet0,ipv4=on,host=$gateway,net=${gateway%.*}.0/24,dhcpstart=$ip,${ipv6}hostname=$VM_NET_HOST"
local forward=""
forward=$(getSlirp "$ip")
[ -n "$forward" ] && NET_OPTS+=",$forward"
if [[ "${DNSMASQ_DISABLE:-}" == [Yy1]* ]]; then
echo "$gateway" > /run/shm/qemu.gw
else
[ ! -f /etc/resolv.dnsmasq ] && cp /etc/resolv.conf /etc/resolv.dnsmasq
configureDNS "lo" "$ip" "$VM_NET_MAC" "$VM_NET_HOST" "$VM_NET_MASK" "$gateway" || return 1
echo -e "nameserver 127.0.0.1\nsearch .\noptions ndots:0" >/etc/resolv.conf
fi
VM_NET_IP="$ip"
return 0
}
configurePasst() {
NETWORK="passt"
[[ "$DEBUG" == [Yy1]* ]] && echo "Configuring user-mode networking..."
local log="/tmp/passt.log"
rm -f "$log"
local ip="$IP"
[ -n "$VM_NET_IP" ] && ip="$VM_NET_IP"
local gateway=""
if [[ "$ip" != *".1" ]]; then
gateway="${ip%.*}.1"
else
gateway="${ip%.*}.2"
fi
# passt configuration:
[ -z "$IP6" ] && PASST_OPTS+=" -4"
PASST_OPTS+=" -a $ip"
PASST_OPTS+=" -g $gateway"
PASST_OPTS+=" -n $VM_NET_MASK"
[ -n "$PASST_MTU" ] && PASST_OPTS+=" -m $PASST_MTU"
local forward=""
forward=$(getUserPorts)
forward="${forward///tcp}"
forward="${forward///udp}"
if [ -n "$forward" ]; then
forward="%${VM_NET_DEV}/$forward"
PASST_OPTS+=" -t $forward"
PASST_OPTS+=" -u $forward"
fi
PASST_OPTS+=" -H $VM_NET_HOST"
PASST_OPTS+=" -M $GATEWAY_MAC"
PASST_OPTS+=" -P $PASST_PID"
PASST_OPTS+=" -l $log"
PASST_OPTS+=" -q"
if [[ "${DNSMASQ_DISABLE:-}" != [Yy1]* ]]; then
[ ! -f /etc/resolv.dnsmasq ] && cp /etc/resolv.conf /etc/resolv.dnsmasq
echo -e "nameserver 127.0.0.1\nsearch .\noptions ndots:0" >/etc/resolv.conf
fi
PASST_OPTS=$(echo "$PASST_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
if [[ "$DEBUG" == [Yy1]* || "$PASST_DEBUG" == [Yy1]* ]]; then
printf "Passt arguments:\n\n%s\n\n" "${PASST_OPTS// -/$'\n-'}"
fi
[ ! -f "$PASST" ] && cp /usr/bin/passt* /run
if ! $PASST ${PASST_OPTS:+ $PASST_OPTS} >/dev/null 2>&1; then
rm -f "$log"
PASST_OPTS="${PASST_OPTS/ -q/}"
{ $PASST ${PASST_OPTS:+ $PASST_OPTS}; rc=$?; } || :
if (( rc != 0 )); then
[ -f "$log" ] && [ -s "$log" ] && cat "$log"
warn "failed to start passt ($rc), falling back to slirp networking!"
configureSlirp && return 0 || return 1
fi
fi
if [[ "$PASST_DEBUG" == [Yy1]* ]]; then
tail -fn +0 "$log" --pid=$$ &
else
if [[ "$DEBUG" == [Yy1]* ]]; then
[ -f "$log" ] && [ -s "$log" ] && cat "$log" && echo ""
fi
fi
if [ -n "$list" ]; then
if [[ "$list" != *" "* ]]; then
args=" ! --dport $list"
else
args=" -m multiport ! --dports "
for port in $list; do
args="${args}${port},"
done
args="${args%?}"
fi
fi
NET_OPTS="-netdev stream,id=hostnet0,server=off,addr.type=unix,addr.path=/tmp/passt_1.socket"
echo "$args"
configureDNS "lo" "$ip" "$VM_NET_MAC" "$VM_NET_HOST" "$VM_NET_MASK" "$gateway" || return 1
VM_NET_IP="$ip"
return 0
}
configureNAT() {
local tuntap="TUN device is missing. $ADD_ERR --device /dev/net/tun"
local tables="the 'ip_tables' kernel module is not loaded. Try this command: sudo modprobe ip_tables iptable_nat"
[[ "$DEBUG" == [Yy1]* ]] && echo "Configuring NAT networking..."
# Create the necessary file structure for /dev/net/tun
if [ ! -c /dev/net/tun ]; then
[ ! -d /dev/net ] && mkdir -m 755 /dev/net
@@ -136,96 +416,225 @@ configureNAT() {
fi
if [ ! -c /dev/net/tun ]; then
error "TUN device missing. $ADD_ERR --cap-add NET_ADMIN" && exit 25
[[ "$ROOTLESS" == [Yy1]* && "$DEBUG" != [Yy1]* ]] && return 1
warn "$tuntap" && return 1
fi
# Check port forwarding flag
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
{ sysctl -w net.ipv4.ip_forward=1 ; rc=$?; } || :
if (( rc != 0 )); then
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && exit 24
{ sysctl -w net.ipv4.ip_forward=1 > /dev/null 2>&1; rc=$?; } || :
if (( rc != 0 )) || [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
[[ "$ROOTLESS" == [Yy1]* && "$DEBUG" != [Yy1]* ]] && return 1
warn "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1"
return 1
fi
fi
# Create a bridge with a static IP for the VM guest
VM_NET_IP='20.20.20.21'
[[ "$DEBUG" == [Yy1]* ]] && set -x
{ ip link add dev dockerbridge type bridge ; rc=$?; } || :
if (( rc != 0 )); then
error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && exit 23
local ip base
base=$(echo "$IP" | sed -r 's/([^.]*.){2}//')
if [[ "$IP" != "172.30."* ]]; then
ip="172.30.$base"
else
ip="172.31.$base"
fi
ip address add ${VM_NET_IP%.*}.1/24 broadcast ${VM_NET_IP%.*}.255 dev dockerbridge
[ -n "$VM_NET_IP" ] && ip="$VM_NET_IP"
while ! ip link set dockerbridge up; do
info "Waiting for address to become available..."
local gateway=""
if [[ "$ip" != *".1" ]]; then
gateway="${ip%.*}.1"
else
gateway="${ip%.*}.2"
fi
# Create a bridge with a static IP for the VM guest
{ ip link add dev "$VM_NET_BRIDGE" type bridge ; rc=$?; } || :
if (( rc != 0 )); then
[[ "$ROOTLESS" == [Yy1]* && "$DEBUG" != [Yy1]* ]] && return 1
warn "failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && return 1
fi
if ! ip address add "$gateway/24" broadcast "${ip%.*}.255" dev "$VM_NET_BRIDGE"; then
warn "failed to add IP address pool!" && return 1
fi
while ! ip link set "$VM_NET_BRIDGE" up; do
info "Waiting for IP address to become available..."
sleep 2
done
# QEMU Works with taps, set tap to the bridge created
ip tuntap add dev "$VM_NET_TAP" mode tap
if ! ip tuntap add dev "$VM_NET_TAP" mode tap; then
[[ "$ROOTLESS" == [Yy1]* && "$DEBUG" != [Yy1]* ]] && return 1
warn "$tuntap" && return 1
fi
if [[ "$MTU" != "0" && "$MTU" != "1500" ]]; then
if ! ip link set dev "$VM_NET_TAP" mtu "$MTU"; then
warn "failed to set MTU size to $MTU."
fi
fi
if ! ip link set dev "$VM_NET_TAP" address "$GATEWAY_MAC"; then
warn "failed to set gateway MAC address.."
fi
while ! ip link set "$VM_NET_TAP" up promisc on; do
info "Waiting for tap to become available..."
info "Waiting for TAP to become available..."
sleep 2
done
ip link set dev "$VM_NET_TAP" master dockerbridge
if ! ip link set dev "$VM_NET_TAP" master "$VM_NET_BRIDGE"; then
warn "failed to set master bridge!" && return 1
fi
# Add internet connection to the VM
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
if command -v iptables-nft >/dev/null 2>&1 && iptables-nft -V >/dev/null 2>&1; then
update-alternatives --set iptables /usr/sbin/iptables-nft > /dev/null
update-alternatives --set ip6tables /usr/sbin/ip6tables-nft > /dev/null
else
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
fi
exclude="$(getPorts "$HOST_PORTS")"
exclude=$(getHostPorts)
if [ -n "$exclude" ]; then
if [[ "$exclude" != *","* ]]; then
exclude=" ! --dport $exclude"
else
exclude=" -m multiport ! --dports $exclude"
fi
fi
if ! iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE > /dev/null 2>&1; then
[[ "$ROOTLESS" == [Yy1]* && "$DEBUG" != [Yy1]* ]] && return 1
if ! iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE; then
warn "$tables" && return 1
fi
fi
iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE
# shellcheck disable=SC2086
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp${exclude} -j DNAT --to "$VM_NET_IP"
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP"
if ! iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp${exclude} -j DNAT --to "$ip"; then
warn "failed to configure IP tables!" && return 1
fi
if ! iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$ip"; then
warn "failed to configure IP tables!" && return 1
fi
if (( KERNEL > 4 )); then
# Hack for guest VMs complaining about "bad udp checksums in 5 packets"
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill || true
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill > /dev/null 2>&1 || true
fi
{ set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo
NET_OPTS="-netdev tap,id=hostnet0,ifname=$VM_NET_TAP"
NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0"
if [ -c /dev/vhost-net ]; then
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
(( rc == 0 )) && NET_OPTS+=",vhost=on,vhostfd=40"
fi
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
(( rc == 0 )) && NET_OPTS="$NET_OPTS,vhost=on,vhostfd=40"
NET_OPTS+=",script=no,downscript=no"
configureDNS
configureDNS "$VM_NET_BRIDGE" "$ip" "$VM_NET_MAC" "$VM_NET_HOST" "$VM_NET_MASK" "$gateway" || return 1
VM_NET_IP="$ip"
return 0
}
closeBridge() {
[ -s "$PASST_PID" ] && pKill "$(<"$PASST_PID")"
rm -f "$PASST_PID"
[ -s "$DNSMASQ_PID" ] && pKill "$(<"$DNSMASQ_PID")"
rm -f "$DNSMASQ_PID"
case "${NETWORK,,}" in
"user"* | "passt" | "slirp" ) return 0 ;;
esac
ip link set "$VM_NET_TAP" down promisc off &> /dev/null || true
ip link delete "$VM_NET_TAP" &> /dev/null || true
ip link set "$VM_NET_BRIDGE" down &> /dev/null || true
ip link delete "$VM_NET_BRIDGE" &> /dev/null || true
return 0
}
closeWeb() {
# Shutdown nginx
nginx -s stop 2> /dev/null
fWait "nginx"
# Shutdown websocket
local pid="/var/run/websocketd.pid"
[ -s "$pid" ] && pKill "$(<"$pid")"
rm -f "$pid"
return 0
}
closeNetwork() {
if [[ "${WEB:-}" != [Nn]* && "$DHCP" == [Yy1]* ]]; then
closeWeb
fi
[[ "$NETWORK" == [Nn]* ]] && return 0
exec 30<&- || true
exec 40<&- || true
if [[ "$DHCP" != [Yy1]* ]]; then
closeBridge
return 0
fi
ip link set "$VM_NET_TAP" down || true
ip link delete "$VM_NET_TAP" || true
return 0
}
cleanUp() {
# Clean up old files
rm -f "$PASST_PID"
rm -f "$DNSMASQ_PID"
rm -f /etc/resolv.dnsmasq
if [[ -d "/sys/class/net/$VM_NET_TAP" ]]; then
info "Lingering interface will be removed..."
ip link delete "$VM_NET_TAP" || true
fi
return 0
}
checkOS() {
local os=""
local kernel=""
local iface="macvlan"
kernel=$(uname -a)
[[ "${kernel,,}" == *"darwin"* ]] && os="$ENGINE Desktop for macOS"
[[ "${kernel,,}" == *"microsoft"* ]] && os="$ENGINE Desktop for Windows"
if [[ "$DHCP" == [Yy1]* ]]; then
iface="macvtap"
[[ "${kernel,,}" == *"synology"* ]] && os="Synology Container Manager"
fi
fKill "server.sh"
ip link set "$VM_NET_TAP" down || true
ip link delete "$VM_NET_TAP" || true
else
fKill "dnsmasq"
ip link set "$VM_NET_TAP" down promisc off || true
ip link delete "$VM_NET_TAP" || true
ip link set dockerbridge down || true
ip link delete dockerbridge || true
if [ -n "$os" ]; then
warn "you are using $os which does not support $iface, please revert to bridge networking!"
fi
return 0
@@ -234,29 +643,138 @@ closeNetwork() {
getInfo() {
if [ -z "$VM_NET_DEV" ]; then
# Automaticly detect the default network interface
VM_NET_DEV=$(awk '$2 == 00000000 { print $1 }' /proc/net/route)
# Give Kubernetes priority over the default interface
[ -d "/sys/class/net/net0" ] && VM_NET_DEV="net0"
[ -d "/sys/class/net/net1" ] && VM_NET_DEV="net1"
[ -d "/sys/class/net/net2" ] && VM_NET_DEV="net2"
[ -d "/sys/class/net/net3" ] && VM_NET_DEV="net3"
# Automatically detect the default network interface
[ -z "$VM_NET_DEV" ] && VM_NET_DEV=$(awk '$2 == 00000000 { print $1 }' /proc/net/route)
[ -z "$VM_NET_DEV" ] && VM_NET_DEV="eth0"
fi
if [ ! -d "/sys/class/net/$VM_NET_DEV" ]; then
error "Network interface '$VM_NET_DEV' does not exist inside the container!"
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 26
fi
GATEWAY=$(ip route list dev "$VM_NET_DEV" | awk ' /^default/ {print $3}' | head -n 1)
{ IP=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/ | head -n 1); rc=$?; } 2>/dev/null || :
if (( rc != 0 )); then
error "Could not determine container IP address!" && exit 26
fi
IP6=""
# shellcheck disable=SC2143
if [ -f /proc/net/if_inet6 ] && [ -n "$(ifconfig -a | grep inet6)" ]; then
{ IP6=$(ip -6 addr show dev "$VM_NET_DEV" scope global up); rc=$?; } 2>/dev/null || :
(( rc != 0 )) && IP6=""
[ -n "$IP6" ] && IP6=$(echo "$IP6" | sed -e's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d' | head -n 1)
fi
local result nic bus
result=$(ethtool -i "$VM_NET_DEV")
nic=$(grep -m 1 -i 'driver:' <<< "$result" | awk '{print $(2)}')
bus=$(grep -m 1 -i 'bus-info:' <<< "$result" | awk '{print $(2)}')
if [[ "${bus,,}" != "" && "${bus,,}" != "n/a" && "${bus,,}" != "tap" ]]; then
[[ "$DEBUG" == [Yy1]* ]] && info "Detected BUS: $bus"
error "This container does not support host mode networking!"
exit 29
fi
if [[ "$DHCP" == [Yy1]* ]]; then
checkOS
if [[ "${nic,,}" == "ipvlan" ]]; then
error "This container does not support IPVLAN networking when DHCP=Y."
exit 29
fi
if [[ "${nic,,}" != "macvlan" ]]; then
[[ "$DEBUG" == [Yy1]* ]] && info "Detected NIC: $nic"
error "The container needs to be in a MACVLAN network when DHCP=Y."
exit 29
fi
if uname -a | grep -Eqi 'unraid|truenas'; then
# Check if host exposes the bridge-nf sysctl
# (only visible if br_netfilter is loaded and /proc/sys is accessible)
BNF="/proc/sys/net/bridge/bridge-nf-call-iptables"
if [[ -r "$BNF" ]] && [[ "$(cat "$BNF")" != "0" ]]; then
warn "external LAN clients may not be able to reach this container, because net.bridge.bridge-nf-call-iptables=1."
warn "you can fix this issue by running 'sysctl -w net.bridge.bridge-nf-call-iptables=0' on the host system."
fi
fi
else
if [[ "$IP" != "172."* && "$IP" != "10.8"* && "$IP" != "10.9"* ]]; then
checkOS
fi
fi
local mtu=""
if [ -f "/sys/class/net/$VM_NET_DEV/mtu" ]; then
mtu=$(< "/sys/class/net/$VM_NET_DEV/mtu")
fi
[ -z "$MTU" ] && MTU="$mtu"
[ -z "$MTU" ] && MTU="0"
if [[ "${ADAPTER,,}" != "virtio-net-pci" ]]; then
if [[ "$MTU" != "0" ]] && [ "$MTU" -lt "1500" ]; then
warn "MTU size is $MTU, but cannot be set for $ADAPTER adapters!" && MTU="0"
fi
fi
if [ -z "$VM_NET_MAC" ]; then
local file="$STORAGE/dsm.mac"
[ -s "$file" ] && VM_NET_MAC=$(<"$file")
VM_NET_MAC="${VM_NET_MAC//[![:print:]]/}"
if [ -z "$VM_NET_MAC" ]; then
# Generate MAC address based on Docker container ID in hostname
VM_NET_MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:11:32:\3:\4:\5/')
echo "${VM_NET_MAC^^}" > "$file"
! setOwner "$file" && error "Failed to set the owner for \"$file\" !"
fi
fi
VM_NET_MAC="${VM_NET_MAC^^}"
VM_NET_MAC="${VM_NET_MAC//-/:}"
if [[ ${#VM_NET_MAC} == 12 ]]; then
m="$VM_NET_MAC"
VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
fi
if [[ ${#VM_NET_MAC} != 17 ]]; then
error "Invalid mac address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
error "Invalid MAC address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
fi
GATEWAY=$(ip r | grep default | awk '{print $3}')
IP=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/)
echo "$IP" > /run/qemu.ip
GATEWAY_MAC=$(echo "$VM_NET_MAC" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
if [[ "$DEBUG" == [Yy1]* ]]; then
line="Host: $HOST IP: $IP Gateway: $GATEWAY Interface: $VM_NET_DEV MAC: $VM_NET_MAC MTU: $mtu"
[[ "$MTU" != "0" && "$MTU" != "$mtu" ]] && line+=" ($MTU)"
info "$line"
if [ -f /etc/resolv.conf ]; then
nameservers=$(grep '^nameserver*' /etc/resolv.conf | head -c -1 | sed 's/nameserver //g;' | sed -z 's/\n/, /g')
[ -n "$nameservers" ] && info "Nameservers: $nameservers"
fi
echo
fi
echo "$IP" > /run/shm/qemu.ip
echo "$nic" > /run/shm/qemu.nic
return 0
}
@@ -265,41 +783,91 @@ getInfo() {
# Configure Network
# ######################################
fKill "server.sh"
if [ ! -c /dev/vhost-net ]; then
if mknod /dev/vhost-net c 10 238; then
chmod 660 /dev/vhost-net
fi
if [[ "$NETWORK" == [Nn]* ]]; then
NET_OPTS=""
return 0
fi
msg="Initializing network..."
html "$msg"
[[ "$DEBUG" == [Yy1]* ]] && echo "$msg"
getInfo
cleanUp
if [[ "$DEBUG" == [Yy1]* ]]; then
info "Container IP is $IP with gateway $GATEWAY on interface $VM_NET_DEV" && echo
if [[ "$IP" == "172.17."* ]]; then
warn "your container IP starts with 172.17.* which will cause conflicts when you install the Container Manager package inside DSM!"
fi
MSG="Booting DSM instance..."
html "$MSG"
if [[ "$DHCP" == [Yy1]* ]]; then
if [[ "$GATEWAY" == "172."* ]]; then
if [[ "$DEBUG" != [Yy1]* ]]; then
error "You can only enable DHCP while the container is on a macvlan network!" && exit 26
fi
fi
# Configuration for DHCP IP
configureDHCP
# Display IP on port 80 and 5000
/run/server.sh 5000 /run/ip.sh &
# Configure for macvtap interface
configureDHCP || exit 20
else
# Configuration for static IP
configureNAT
if [[ "${WEB:-}" != [Nn]* ]]; then
sleep 1.2
closeWeb
fi
case "${NETWORK,,}" in
"passt" | "slirp" | "user"* ) ;;
"tap" | "tun" | "tuntap" | "y" | "" )
# Configure tap interface
if ! configureNAT; then
closeBridge
NETWORK="user"
if [[ "$ROOTLESS" != [Yy1]* || "$DEBUG" == [Yy1]* ]]; then
msg="falling back to user-mode networking!"
msg="failed to setup NAT networking, $msg"
warn "$msg"
fi
fi ;;
esac
case "${NETWORK,,}" in
"tap" | "tun" | "tuntap" | "y" | "" ) ;;
"passt" | "user"* )
# Configure for user-mode networking (passt)
if ! configurePasst; then
error "Failed to configure user-mode networking!"
exit 24
fi ;;
"slirp" )
# Configure for user-mode networking (slirp)
if ! configureSlirp; then
error "Failed to configure user-mode networking!"
exit 24
fi ;;
*)
error "Unrecognized NETWORK value: \"$NETWORK\"" && exit 24 ;;
esac
case "${NETWORK,,}" in
"passt" | "slirp" )
if [ -z "$USER_PORTS" ]; then
info "Notice: because user-mode networking is active, when you need to forward custom ports to DSM, add them to the \"USER_PORTS\" variable."
fi ;;
esac
fi
NET_OPTS="$NET_OPTS -device virtio-net-pci,romfile=,netdev=hostnet0,mac=$VM_NET_MAC,id=net0"
NET_OPTS+=" -device $ADAPTER,id=net0,netdev=hostnet0,romfile=,mac=$VM_NET_MAC"
[[ "$MTU" != "0" && "$MTU" != "1500" ]] && NET_OPTS+=",host_mtu=$MTU"
return 0
+50 -28
View File
@@ -1,27 +1,24 @@
#!/usr/bin/env bash
set -Eeuo pipefail
: "${API_TIMEOUT:="50"}" # API Call timeout
: "${QEMU_TIMEOUT:="50"}" # QEMU Termination timeout
# Configure QEMU for graceful shutdown
API_CMD=6
API_TIMEOUT=50
API_HOST="127.0.0.1:2210"
API_HOST="127.0.0.1:$COM_PORT"
QEMU_TERM=""
QEMU_PORT=7100
QEMU_TIMEOUT=50
QEMU_PID="/run/qemu.pid"
QEMU_LOG="/run/qemu.log"
QEMU_END="/run/qemu.end"
QEMU_LOG="$QEMU_DIR/qemu.log"
QEMU_OUT="$QEMU_DIR/qemu.out"
QEMU_END="$QEMU_DIR/qemu.end"
if [[ "$KVM" == [Nn]* ]]; then
API_TIMEOUT=$(( API_TIMEOUT*2 ))
QEMU_TIMEOUT=$(( QEMU_TIMEOUT*2 ))
fi
rm -f "$QEMU_PID"
rm -f "$QEMU_LOG"
rm -f "$QEMU_END"
touch "$QEMU_LOG"
_trap() {
@@ -34,19 +31,32 @@ _trap() {
finish() {
local pid
local cnt=0
local reason=$1
if [ -f "$QEMU_PID" ]; then
touch "$QEMU_END"
pid="$(cat "$QEMU_PID")"
echo && error "Forcefully terminating QEMU process, reason: $reason..."
if [ -s "$QEMU_PID" ]; then
pid=$(<"$QEMU_PID")
echo && error "Forcefully terminating Virtual DSM, reason: $reason..."
{ kill -15 "$pid" || true; } 2>/dev/null
while isAlive "$pid"; do
sleep 1
cnt=$((cnt+1))
# Workaround for zombie pid
[ ! -f "$QEMU_PID" ] && break
[ ! -s "$QEMU_PID" ] && break
if [ "$cnt" -eq 5 ]; then
echo && error "QEMU did not terminate itself, forcefully killing process..."
{ kill -9 "$pid" || true; } 2>/dev/null
fi
done
fi
fKill "print.sh"
@@ -62,17 +72,27 @@ finish() {
terminal() {
local msg=$1
local dev=""
if [[ "${msg,,}" != "char"* || "$msg" != *"serial0)" ]]; then
echo "$msg"
if [ -s "$QEMU_OUT" ]; then
local msg
msg=$(<"$QEMU_OUT")
if [ -n "$msg" ]; then
if [[ "${msg,,}" != "char"* || "$msg" != *"serial0)" ]]; then
echo "$msg"
fi
dev="${msg#*/dev/p}"
dev="/dev/p${dev%% *}"
fi
fi
local dev="${msg#*/dev/p}"
dev="/dev/p${dev%% *}"
if [ ! -c "$dev" ]; then
dev=$(echo 'info chardev' | nc -q 1 -w 1 localhost "$QEMU_PORT" | tr -d '\000')
dev=$(echo 'info chardev' | nc -q 1 -w 1 localhost "$MON_PORT" | tr -d '\000')
dev="${dev#*serial0}"
dev="${dev#*pty:}"
dev="${dev%%$'\n'*}"
@@ -90,7 +110,6 @@ terminal() {
_graceful_shutdown() {
local cnt=0
local code=$?
local pid url response
@@ -104,12 +123,12 @@ _graceful_shutdown() {
touch "$QEMU_END"
echo && info "Received $1 signal, sending shutdown command..."
if [ ! -f "$QEMU_PID" ]; then
if [ ! -s "$QEMU_PID" ]; then
echo && error "QEMU PID file does not exist?"
finish "$code" && return "$code"
fi
pid="$(cat "$QEMU_PID")"
pid=$(<"$QEMU_PID")
if ! isAlive "$pid"; then
echo && error "QEMU process does not exist?"
@@ -117,7 +136,7 @@ _graceful_shutdown() {
fi
# Don't send the powerdown signal because vDSM ignores ACPI signals
# echo 'system_powerdown' | nc -q 1 -w 1 localhost "${QEMU_PORT}" > /dev/null
# echo 'system_powerdown' | nc -q 1 -w 1 localhost "$MON_PORT" > /dev/null
# Send shutdown command to guest agent via serial port
url="http://$API_HOST/read?command=$API_CMD&timeout=$API_TIMEOUT"
@@ -136,6 +155,8 @@ _graceful_shutdown() {
fi
local cnt=0
while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do
! isAlive "$pid" && break
@@ -146,7 +167,7 @@ _graceful_shutdown() {
[[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt/$QEMU_TIMEOUT)"
# Workaround for zombie pid
[ ! -f "$QEMU_PID" ] && break
[ ! -s "$QEMU_PID" ] && break
done
@@ -159,11 +180,12 @@ _graceful_shutdown() {
MON_OPTS="\
-pidfile $QEMU_PID \
-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay"
-name $PROCESS,process=$PROCESS,debug-threads=on \
-monitor telnet:localhost:$MON_PORT,server,nowait,nodelay"
if [[ "$CONSOLE" != [Yy]* ]]; then
MON_OPTS="$MON_OPTS -daemonize -D $QEMU_LOG"
MON_OPTS+=" -daemonize -D $QEMU_LOG"
_trap _graceful_shutdown SIGTERM SIGHUP SIGINT SIGABRT SIGQUIT
+34 -15
View File
@@ -1,21 +1,28 @@
#!/usr/bin/env bash
set -Eeuo pipefail
: ${DHCP:='N'}
: "${DHCP:="N"}"
: "${NETWORK:="Y"}"
[[ "$NETWORK" == [Nn]* ]] && exit 0
info () { printf "%b%s%b" "\E[1;34m❯ \E[1;36m" "$1" "\E[0m\n" >&2; }
error () { printf "%b%s%b" "\E[1;31m❯ " "ERROR: $1" "\E[0m\n" >&2; }
file="/run/dsm.url"
address="/run/qemu.ip"
shutdown="/run/qemu.end"
file="/run/shm/dsm.url"
info="/run/shm/msg.html"
driver="/run/shm/qemu.nic"
page="/run/shm/index.html"
address="/run/shm/qemu.ip"
shutdown="/run/shm/qemu.end"
template="/var/www/index.html"
url="http://127.0.0.1:2210/read?command=10"
resp_err="Guest returned an invalid response:"
curl_err="Failed to connect to guest: curl error"
jq_err="Failed to parse response from guest: jq error"
while [ ! -f "$file" ]
while [ ! -s "$file" ]
do
# Check if not shutting down
@@ -24,7 +31,7 @@ do
sleep 3
[ -f "$shutdown" ] && exit 1
[ -f "$file" ] && break
[ -s "$file" ] && break
# Retrieve network info from guest VM
{ json=$(curl -m 20 -sk "$url"); rc=$?; } || :
@@ -50,29 +57,39 @@ do
(( rc != 0 )) && error "$jq_err $rc ( $json )" && continue
[[ "$ip" == "null" ]] && error "$resp_err $json" && continue
if [ -z "$ip" ]; then
[[ "$DHCP" == [Yy1]* ]] && continue
ip="20.20.20.21"
fi
[ -z "$ip" ] && continue
echo "$ip:$port" > $file
done
[ -f "$shutdown" ] && exit 1
location=$(cat "$file")
location=$(<"$file")
if [[ "$location" != "20.20"* ]]; then
if [[ "$DHCP" == [Yy1]* ]]; then
msg="http://$location"
title="<title>Virtual DSM</title>"
body="The location of DSM is <a href='http://$location'>http://$location</a>"
script="<script>setTimeout(function(){ window.location.assign('http://$location'); }, 3000);</script>"
HTML=$(<"$template")
HTML="${HTML/\[1\]/$title}"
HTML="${HTML/\[2\]/$script}"
HTML="${HTML/\[3\]/$body}"
HTML="${HTML/\[4\]/}"
HTML="${HTML/\[5\]/}"
echo "$HTML" > "$page"
echo "$body" > "$info"
else
ip="$(cat "$address")"
nic=$(<"$driver")
ip=$(<"$address")
port="${location##*:}"
if [[ "$ip" == "172."* ]]; then
if [[ "${nic,,}" != "macvlan" ]]; then
msg="port $port"
else
msg="http://$ip:$port"
@@ -85,3 +102,5 @@ info "-----------------------------------------------------------"
info " You can now login to DSM at $msg"
info "-----------------------------------------------------------"
echo "" >&2
exit 0
+98 -31
View File
@@ -3,60 +3,127 @@ set -Eeuo pipefail
# Docker environment variables
: ${KVM:='Y'}
: ${HOST_CPU:=''}
: ${CPU_MODEL:='host'}
: ${CPU_FEATURES:='+ssse3,+sse4.1,+sse4.2'}
: "${HOST_CPU:=""}"
: "${CPU_FLAGS:=""}"
: "${CPU_MODEL:=""}"
[ "$ARCH" != "amd64" ] && KVM="N"
CLOCKSOURCE="tsc"
[[ "${ARCH,,}" == "arm64" ]] && CLOCKSOURCE="arch_sys_counter"
CLOCK="/sys/devices/system/clocksource/clocksource0/current_clocksource"
if [ ! -f "$CLOCK" ]; then
warn "file \"$CLOCK\" cannot be found?"
else
result=$(<"$CLOCK")
result="${result//[![:print:]]/}"
case "${result,,}" in
"${CLOCKSOURCE,,}" ) ;;
"kvm-clock" ) info "Nested KVM virtualization detected.." ;;
"hyperv_clocksource_tsc_page" ) info "Nested Hyper-V virtualization detected.." ;;
"hpet" ) warn "unsupported clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
*) warn "unexpected clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
esac
fi
flags=$(sed -ne '/^flags/s/^.*: //p' /proc/cpuinfo)
if [[ "$KVM" != [Nn]* ]]; then
KVM_ERR=""
CPU_FEATURES="kvm=on,l3-cache=on,+hypervisor"
KVM_OPTS=",accel=kvm -enable-kvm -global kvm-pit.lost_tick_policy=discard"
if [ -e /dev/kvm ] && sh -c 'echo -n > /dev/kvm' &> /dev/null; then
if ! grep -q -e vmx -e svm /proc/cpuinfo; then
KVM_ERR="(vmx/svm disabled)"
fi
else
[ -e /dev/kvm ] && KVM_ERR="(no write access)" || KVM_ERR="(device file missing)"
fi
if [ -n "$KVM_ERR" ]; then
KVM="N"
error "KVM acceleration not detected $KVM_ERR, this will cause a major loss of performance."
error "See the FAQ on how to enable it, or continue without KVM by setting KVM=N (not recommended)."
if ! grep -qw "sse4_2" <<< "$flags"; then
error "Your CPU does not have the SSE4 instruction set that Virtual DSM requires!"
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi
fi
if [ -z "$CPU_MODEL" ]; then
CPU_MODEL="host"
CPU_FEATURES+=",migratable=no"
fi
if [[ "$KVM" != [Nn]* ]]; then
if grep -qw "svm" <<< "$flags"; then
KVM_OPTS=",accel=kvm -enable-kvm"
# AMD processor
if grep -qw "tsc_scale" <<< "$flags"; then
CPU_FEATURES+=",+invtsc"
fi
else
# Intel processor
vmx=$(sed -ne '/^vmx flags/s/^.*: //p' /proc/cpuinfo)
if grep -qw "tsc_scaling" <<< "$vmx"; then
CPU_FEATURES+=",+invtsc"
fi
if ! grep -qE '^flags.* (sse4_2)' /proc/cpuinfo; then
error "Your host CPU does not have the SSE4.2 instruction set that Virtual DSM requires to boot."
error "Disable KVM by setting KVM=N to emulate a compatible CPU, at the cost of performance."
[[ "$DEBUG" != [Yy1]* ]] && exit 89
fi
else
KVM_OPTS=""
CPU_FEATURES="l3-cache=on,+hypervisor"
if [[ "$CPU_MODEL" == "host"* ]]; then
if [[ "$ARCH" == "amd64" ]]; then
KVM_OPTS=" -accel tcg,thread=multi"
fi
if [ -z "$CPU_MODEL" ]; then
if [[ "$ARCH" == "amd64" ]]; then
CPU_MODEL="max,$CPU_FEATURES"
CPU_MODEL="max"
CPU_FEATURES+=",migratable=no"
else
CPU_MODEL="qemu64,$CPU_FEATURES"
CPU_MODEL="qemu64"
fi
fi
CPU_FEATURES+=",+ssse3,+sse4.1,+sse4.2"
fi
if [[ "$ARGUMENTS" == *"-cpu host,"* ]]; then
args="${ARGUMENTS} "
prefix="${args/-cpu host,*/}"
suffix="${args/*-cpu host,/}"
param="${suffix%% *}"
suffix="${suffix#* }"
args="${prefix}${suffix}"
ARGUMENTS="${args::-1}"
if [ -z "$CPU_FLAGS" ]; then
CPU_FLAGS="$param"
else
CPU_FLAGS+=",$param"
fi
else
if [[ "$ARGUMENTS" == *"-cpu host"* ]]; then
ARGUMENTS="${ARGUMENTS//-cpu host/}"
fi
fi
if [ -z "$CPU_FLAGS" ]; then
if [ -z "$CPU_FEATURES" ]; then
CPU_FLAGS="$CPU_MODEL"
else
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES"
fi
else
if [ -z "$CPU_FEATURES" ]; then
CPU_FLAGS="$CPU_MODEL,$CPU_FLAGS"
else
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES,$CPU_FLAGS"
fi
fi
if [ -z "$HOST_CPU" ]; then
HOST_CPU=$(lscpu | grep 'Model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
[[ "${CPU,,}" != "unknown" ]] && HOST_CPU="$CPU"
fi
if [ -n "$HOST_CPU" ]; then
@@ -64,9 +131,9 @@ if [ -n "$HOST_CPU" ]; then
else
HOST_CPU="QEMU, Virtual CPU,"
if [ "$ARCH" == "amd64" ]; then
HOST_CPU="$HOST_CPU X86_64"
HOST_CPU+=" X86_64"
else
HOST_CPU="$HOST_CPU $ARCH"
HOST_CPU+=" $ARCH"
fi
fi
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -Eeuo pipefail
info="/run/shm/msg.html"
escape () {
local s
s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
printf -- %s "$s"
return 0
}
path="$1"
total="$2"
body=$(escape "$3")
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body::-3}</p>"
fi
while true
do
if [ ! -s "$path" ] && [ ! -d "$path" ]; then
bytes="0"
else
bytes=$(du -sb "$path" | cut -f1)
fi
if (( bytes > 4096 )); then
if [ -z "$total" ] || [[ "$total" == "0" ]] || [ "$bytes" -gt "$total" ]; then
size=$(numfmt --to=iec --suffix=B "$bytes" | sed -r 's/([A-Z])/ \1/')
else
size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')"
size="$size%"
fi
[[ "$size" != "0.0%" ]] && echo "${body//(\[P\])/($size)}"> "$info"
fi
sleep 1 & wait $!
done
+211 -123
View File
@@ -1,147 +1,235 @@
#!/usr/bin/env bash
set -Eeuo pipefail
info () { printf "%b%s%b" "\E[1;34m❯ \E[1;36m" "$1" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m❯ " "ERROR: $1" "\E[0m\n" >&2; }
trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
[[ "${TRACE:-}" == [Yy1]* ]] && set -o functrace && trap 'echo "# $BASH_COMMAND" >&2' DEBUG
[ ! -f "/run/entry.sh" ] && error "Script must run inside Docker container!" && exit 11
[ ! -f "/run/entry.sh" ] && error "Script must be run inside the container!" && exit 11
[ "$(id -u)" -ne "0" ] && error "Script must be executed with root privileges." && exit 12
# Docker environment variables
: ${TZ:=''} # System local timezone
: ${DEBUG:='N'} # Disable debugging mode
: ${COUNTRY:=''} # Country code for mirror
: ${CONSOLE:='N'} # Disable console mode
: ${ALLOCATE:='Y'} # Preallocate diskspace
: ${ARGUMENTS:=''} # Extra QEMU parameters
: ${CPU_CORES:='1'} # Amount of CPU cores
: ${RAM_SIZE:='1G'} # Maximum RAM amount
: ${DISK_SIZE:='16G'} # Initial data disk size
: "${TZ:=""}" # System timezone
: "${KVM:="Y"}" # KVM acceleration
: "${DEBUG:="N"}" # Disable debugging mode
: "${COUNTRY:=""}" # Country code for mirror
: "${CONSOLE:="N"}" # Disable console mode
: "${ALLOCATE:=""}" # Preallocate diskspace
: "${ARGUMENTS:=""}" # Extra QEMU parameters
: "${CPU_CORES:="2"}" # Amount of CPU cores
: "${RAM_SIZE:="2G"}" # Maximum RAM amount
: "${RAM_CHECK:="Y"}" # Check available RAM
: "${DISK_SIZE:="16G"}" # Initial data disk size
: "${STORAGE:="/storage"}" # Storage folder location
# Helper variables
KERNEL=$(uname -r | cut -b 1)
MINOR=$(uname -r | cut -d '.' -f2)
ROOTLESS="N"
PRIVILEGED="N"
ENGINE="Docker"
PROCESS="${APP,,}"
PROCESS="${PROCESS// /-}"
if [ -f "/run/.containerenv" ]; then
ENGINE="${container:-}"
if [[ "${ENGINE,,}" == *"podman"* ]]; then
ROOTLESS="Y"
ENGINE="Podman"
else
[ -z "$ENGINE" ] && ENGINE="Kubernetes"
fi
fi
echo "❯ Starting $APP for $ENGINE v$(</run/version)..."
echo "❯ For support visit $SUPPORT"
# Get the capability bounding set
CAP_BND=$(grep '^CapBnd:' /proc/$$/status | awk '{print $2}')
CAP_BND=$(printf "%d" "0x${CAP_BND}")
# Get the last capability number
LAST_CAP=$(cat /proc/sys/kernel/cap_last_cap)
# Calculate the maximum capability value
MAX_CAP=$(((1 << (LAST_CAP + 1)) - 1))
if [ "${CAP_BND}" -eq "${MAX_CAP}" ]; then
ROOTLESS="N"
PRIVILEGED="Y"
fi
INFO="/run/shm/msg.html"
PAGE="/run/shm/index.html"
TEMPLATE="/var/www/index.html"
FOOTER1="$APP for $ENGINE v$(</run/version)"
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
SOCKETS=1
CPU=$(cpu)
SYS=$(uname -r)
HOST=$(hostname -s)
KERNEL=$(echo "$SYS" | cut -b 1)
MINOR=$(echo "$SYS" | cut -d '.' -f2)
ARCH=$(dpkg --print-architecture)
VERS=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1)
CORES=$(grep -c '^processor' /proc/cpuinfo)
if grep -qi "socket(s)" <<< "$(lscpu)"; then
SOCKETS=$(lscpu | grep -m 1 -i 'socket(s)' | awk '{print $2}')
[ -z "${SOCKETS##*[!0-9]*}" ] && SOCKETS=1
[ "$SOCKETS" -lt "1" ] && SOCKETS=1
fi
CPU_CORES="${CPU_CORES// /}"
[ -z "$CPU_CORES" ] && CPU_CORES=2
[[ "${CPU_CORES,,}" == "max" ]] && CPU_CORES="$CORES"
[[ "${CPU_CORES,,}" == "half" ]] && CPU_CORES=$(( CORES / 2 ))
[ -z "${CPU_CORES##*[!0-9]*}" ] && error "Invalid amount of CPU_CORES: $CPU_CORES" && exit 15
[ "$CPU_CORES" -lt "1" ] && CPU_CORES=1
if [ "$CPU_CORES" -gt "$CORES" ]; then
warn "The amount for CPU_CORES (${CPU_CORES}) exceeds the amount of logical cores available (${CORES}) and will be limited."
CPU_CORES="$CORES"
fi
# Check system
QEMU_DIR="/run/shm"
if [ ! -d "/dev/shm" ]; then
error "Directory /dev/shm not found!" && exit 14
else
[ ! -d "$QEMU_DIR" ] && ln -s /dev/shm "$QEMU_DIR"
fi
QEMU_PID="$QEMU_DIR/qemu.pid"
rm -f "$QEMU_PID"
# Check folder
STORAGE="/storage"
[ ! -d "$STORAGE" ] && error "Storage folder ($STORAGE) not found!" && exit 13
if [[ "${STORAGE,,}" != "/storage" ]]; then
mkdir -p "$STORAGE"
fi
if [ ! -d "$STORAGE" ]; then
error "Storage folder ($STORAGE) not found!" && exit 13
fi
if [ ! -w "$STORAGE" ]; then
msg="Storage folder ($STORAGE) is not writeable!"
msg+=" If SELinux is active, you need to add the \":Z\" flag to the bind mount."
error "$msg" && exit 13
fi
# Check filesystem
FS=$(stat -f -c %T "$STORAGE")
if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
DISK_IO="threads"
DISK_CACHE="writeback"
fi
# Read memory
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
RAM_TOTAL=$(free -b | grep -m 1 Mem: | awk '{print $2}')
RAM_SPARE=500000000
RAM_MINIMUM=136314880
RAM_SIZE="${RAM_SIZE// /}"
[ -z "$RAM_SIZE" ] && RAM_SIZE="2G"
if [[ "${RAM_SIZE,,}" != "max" && "${RAM_SIZE,,}" != "half" ]]; then
if [ -z "${RAM_SIZE//[0-9. ]}" ]; then
[ "${RAM_SIZE%%.*}" -lt "130" ] && RAM_SIZE="${RAM_SIZE}G" || RAM_SIZE="${RAM_SIZE}M"
fi
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
! numfmt --from=iec "$RAM_SIZE" &>/dev/null && error "Invalid RAM_SIZE: $RAM_SIZE" && exit 16
wanted=$(numfmt --from=iec "$RAM_SIZE")
[ "$wanted" -lt "$RAM_MINIMUM" ] && error "RAM_SIZE is too low: $RAM_SIZE" && exit 16
fi
# Print system info
SYS="${SYS/-generic/}"
FS="${FS/UNKNOWN //}"
FS="${FS/ext2\/ext3/ext4}"
FS=$(echo "$FS" | sed 's/[)(]//g')
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_GB=$(formatBytes "$SPACE" "down")
AVAIL_MEM=$(formatBytes "$RAM_AVAIL" "down")
TOTAL_MEM=$(formatBytes "$RAM_TOTAL" "up")
echo "❯ CPU: ${CPU} | RAM: ${AVAIL_MEM/ GB/}/$TOTAL_MEM | DISK: $SPACE_GB (${FS}) | KERNEL: ${SYS}..."
echo
# Check KVM support
if [[ "${PLATFORM,,}" == "x64" ]]; then
TARGET="amd64"
else
TARGET="arm64"
fi
if [[ "$KVM" == [Nn]* ]]; then
warn "KVM acceleration is disabled, this will cause the machine to run about 10 times slower!"
else
if [[ "${ARCH,,}" != "$TARGET" ]]; then
KVM="N"
warn "your CPU architecture is ${ARCH^^} and cannot provide KVM acceleration for ${PLATFORM^^} instructions, so the machine will run about 10 times slower."
fi
fi
if [[ "$KVM" != [Nn]* ]]; then
KVM_ERR=""
if [ ! -e /dev/kvm ]; then
KVM_ERR="(/dev/kvm is missing)"
else
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
KVM_ERR="(/dev/kvm is unwriteable)"
else
if [[ "${PLATFORM,,}" == "x64" ]]; then
flags=$(sed -ne '/^flags/s/^.*: //p' /proc/cpuinfo)
if ! grep -qw "vmx\|svm" <<< "$flags"; then
KVM_ERR="(not enabled in BIOS)"
fi
if ! grep -qw "sse4_2" <<< "$flags"; then
error "Your CPU does not have the SSE4 instruction set that Virtual DSM requires!"
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi
fi
fi
fi
if [ -n "$KVM_ERR" ]; then
KVM="N"
if [[ "$OSTYPE" =~ ^darwin ]]; then
warn "you are using macOS which has no KVM support, so the machine will run about 10 times slower."
else
kernel=$(uname -a)
case "${kernel,,}" in
*"microsoft"* )
error "Please bind '/dev/kvm' as a volume in the optional container settings when using Docker Desktop." ;;
*"synology"* )
error "Please make sure that Synology VMM (Virtual Machine Manager) is installed and that '/dev/kvm' is binded to this container." ;;
*)
error "KVM acceleration is not available $KVM_ERR, this will cause the machine to run about 10 times slower."
error "See the FAQ for possible causes, or disable acceleration by adding the \"KVM=N\" variable (not recommended)." ;;
esac
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi
fi
fi
# Cleanup files
rm -f /run/dsm.url
rm -f /run/qemu.ip
rm -f /run/qemu.log
rm -f /run/qemu.pid
rm -f /run/qemu.end
rm -f /run/shm/qemu.*
rm -f /run/shm/dsm.url
# Cleanup dirs
rm -rf /tmp/dsm
rm -f /tmp/server.*
rm -rf "$STORAGE/tmp"
# Helper functions
isAlive() {
local pid=$1
if kill -0 "$pid" 2>/dev/null; then
return 0
fi
return 1
}
pKill() {
local pid=$1
{ kill -15 "$pid" || true; } 2>/dev/null
while isAlive "$pid"; do
sleep 0.1
done
return 0
}
fKill() {
local name=$1
{ pkill -f "$name" || true; } 2>/dev/null
while pgrep -f -l "$name" >/dev/null; do
sleep 0.1
done
return 0
}
getCountry() {
local url=$1
local query=$2
local rc json result
{ json=$(curl -m 5 -H "Accept: application/json" -sfk "$url"); rc=$?; } || :
(( rc != 0 )) && return 0
{ result=$(echo "$json" | jq -r "$query" 2> /dev/null); rc=$?; } || :
(( rc != 0 )) && return 0
[[ ${#result} -ne 2 ]] && return 0
[[ "${result^^}" == "XX" ]] && return 0
COUNTRY="${result^^}"
return 0
}
setCountry() {
[[ "${TZ,,}" == "asia/harbin" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/beijing" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/urumqi" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/kashgar" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/shanghai" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/chongqing" ]] && COUNTRY="CN"
[ -z "$COUNTRY" ] && getCountry "https://api.ipapi.is" ".location.country_code"
[ -z "$COUNTRY" ] && getCountry "https://ifconfig.co/json" ".country_iso"
[ -z "$COUNTRY" ] && getCountry "https://ipinfo.io/json" ".country"
[ -z "$COUNTRY" ] && getCountry "https://api.myip.com" ".cc"
return 0
}
addPackage() {
local pkg=$1
local desc=$2
if apt-mark showinstall | grep -qx "$pkg"; then
return 0
fi
info "Installing $desc..."
export DEBCONF_NOWARNINGS="yes"
export DEBIAN_FRONTEND="noninteractive"
[ -z "$COUNTRY" ] && setCountry
if [[ "${COUNTRY^^}" == "CN" ]]; then
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
fi
apt-get -qq update
apt-get -qq --no-install-recommends -y install "$pkg" > /dev/null
return 0
}
return 0
+30 -10
View File
@@ -3,11 +3,26 @@ set -Eeuo pipefail
# Docker environment variables
: ${HOST_MAC:=''}
: ${HOST_DEBUG:=''}
: ${HOST_SERIAL:=''}
: ${HOST_MODEL:=''}
: ${GUEST_SERIAL:=''}
: "${HOST_MAC:=""}"
: "${HOST_DEBUG:=""}"
: "${HOST_SERIAL:=""}"
: "${HOST_MODEL:=""}"
: "${GUEST_SERIAL:=""}"
if [ -n "$HOST_MAC" ]; then
HOST_MAC="${HOST_MAC//-/:}"
if [[ ${#HOST_MAC} == 12 ]]; then
m="$HOST_MAC"
HOST_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
fi
if [[ ${#HOST_MAC} != 17 ]]; then
error "Invalid HOST_MAC address: '$HOST_MAC', should be 12 or 17 digits long!" && exit 28
fi
fi
HOST_ARGS=()
HOST_ARGS+=("-cpu=$CPU_CORES")
@@ -30,7 +45,7 @@ fi
cnt=0
sleep 0.2
while ! nc -z -w2 127.0.0.1 2210 > /dev/null 2>&1; do
while ! nc -z -w2 127.0.0.1 "$COM_PORT" > /dev/null 2>&1; do
sleep 0.1
cnt=$((cnt + 1))
(( cnt > 50 )) && error "Failed to connect to qemu-host.." && exit 58
@@ -38,7 +53,7 @@ done
cnt=0
while ! nc -z -w2 127.0.0.1 12345 > /dev/null 2>&1; do
while ! nc -z -w2 127.0.0.1 "$CHR_PORT" > /dev/null 2>&1; do
sleep 0.1
cnt=$((cnt + 1))
(( cnt > 50 )) && error "Failed to connect to qemu-host.." && exit 59
@@ -46,10 +61,15 @@ done
# Configure serial ports
SERIAL_OPTS="\
-serial pty \
if [[ "$CONSOLE" != [Yy]* ]]; then
SERIAL_OPTS="-serial pty"
else
SERIAL_OPTS="-serial mon:stdio"
fi
SERIAL_OPTS+=" \
-device virtio-serial-pci,id=virtio-serial0,bus=pcie.0,addr=0x3 \
-chardev socket,id=charchannel0,host=127.0.0.1,port=12345,reconnect=10 \
-chardev socket,id=charchannel0,host=127.0.0.1,port=$CHR_PORT,reconnect=10 \
-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=vchannel"
return 0
+24 -51
View File
@@ -1,66 +1,39 @@
#!/usr/bin/env bash
set -eu
set -Eeuo pipefail
TMP_FILE=$(mktemp -q /tmp/server.XXXXXX)
: "${COM_PORT:="2210"}" # Comm port
: "${MON_PORT:="7100"}" # Monitor port
: "${WEB_PORT:="5000"}" # Webserver port
: "${CHR_PORT:="12345"}" # Character port
: "${WSD_PORT:="8004"}" # Websockets port
stop() {
trap - SIGINT EXIT
{ pkill -f socat || true; } 2>/dev/null
[ -f "$TMP_FILE" ] && rm -f "$TMP_FILE"
}
cp -r /var/www/* /run/shm
rm -f /var/run/websocketd.pid
trap 'stop' EXIT SIGINT SIGTERM SIGHUP
html "Starting $APP for $ENGINE..."
html()
{
local h="<!DOCTYPE html><HTML><HEAD><TITLE>VirtualDSM</TITLE>"
h="$h<STYLE>body { color: white; background-color: #125bdb; font-family: Verdana,"
h="$h Arial,sans-serif; } a, a:hover, a:active, a:visited { color: white; }</STYLE></HEAD>"
h="$h<BODY><BR><BR><H1><CENTER>$1</CENTER></H1></BODY></HTML>"
if [[ "${WEB:-}" != [Nn]* ]]; then
echo "$h"
}
mkdir -p /etc/nginx/sites-enabled
cp /etc/nginx/default.conf /etc/nginx/sites-enabled/web.conf
if [[ "$2" != "/"* ]]; then
sed -i "s/listen 5000 default_server;/listen $WEB_PORT default_server;/g" /etc/nginx/sites-enabled/web.conf
sed -i "s/proxy_pass http:\/\/127.0.0.1:8004\/;/proxy_pass http:\/\/127.0.0.1:$WSD_PORT\/;/g" /etc/nginx/sites-enabled/web.conf
BODY="$2"
# shellcheck disable=SC2143
if [ -f /proc/net/if_inet6 ] && [ -n "$(ifconfig -a | grep inet6)" ]; then
sed -i "s/listen $WEB_PORT default_server;/listen [::]:$WEB_PORT default_server ipv6only=off;/g" /etc/nginx/sites-enabled/web.conf
if [[ "$BODY" == "install" ]]; then
BODY="Please wait while Virtual DSM is being installed..."
BODY="$BODY<script>setTimeout(() => { document.location.reload(); }, 9999);</script>"
fi
HTML=$(html "$BODY")
printf '%b' "HTTP/1.1 200 OK\nContent-Length: ${#HTML}\nConnection: close\n\n$HTML" > "$TMP_FILE"
# Start webserver
nginx -e stderr
socat TCP4-LISTEN:80,reuseaddr,fork,crlf SYSTEM:"cat $TMP_FILE" 2> /dev/null &
socat TCP4-LISTEN:"${1:-5000}",reuseaddr,fork,crlf SYSTEM:"cat $TMP_FILE" 2> /dev/null & wait $!
exit
fi
if [[ "$2" != "/run/ip.sh" ]]; then
cp "$2" "$TMP_FILE"
else
BODY="The location of DSM is <a href='http://\$LOCATION'>http://\$LOCATION</a><script>"
BODY="$BODY setTimeout(function(){ window.location.assign('http://\$LOCATION'); }, 3000);</script>"
WAIT="Please wait while discovering IP...<script>setTimeout(() => { document.location.reload(); }, 4999);</script>"
HTML=$(html "xxx")
{ echo "#!/bin/bash"
echo "[ -f \"/run/dsm.url\" ] && LOCATION=\$(cat \"/run/dsm.url\")"
echo "HTML=\"$HTML\"; [ -z \"\$LOCATION\" ] && BODY=\"$WAIT\" || BODY=\"$BODY\"; HTML=\${HTML/xxx/\$BODY}"
echo "printf '%b' \"HTTP/1.1 200 OK\\nContent-Length: \${#HTML}\\nConnection: close\\n\\n\$HTML\""
} > "$TMP_FILE"
# Start websocket server
websocketd --address 127.0.0.1 --port="$WSD_PORT" /run/socket.sh >/var/log/websocketd.log &
echo "$!" > /var/run/websocketd.pid
fi
chmod +x "$TMP_FILE"
socat TCP4-LISTEN:80,reuseaddr,fork,crlf SYSTEM:"$TMP_FILE" 2> /dev/null &
socat TCP4-LISTEN:"${1:-5000}",reuseaddr,fork,crlf SYSTEM:"$TMP_FILE" 2> /dev/null & wait $!
return 0
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -Eeuo pipefail
lastmsg=""
path="/run/shm/msg.html"
refresh() {
[ ! -f "$path" ] && return 0
[ ! -s "$path" ] && return 0
msg=$(< "$path")
msg="${msg%$'\n'}"
[ -z "$msg" ] && return 0
[[ "$msg" == "$lastmsg" ]] && return 0
lastmsg="$msg"
echo "s: $msg"
return 0
}
refresh
inotifywait -m "$path" |
while read -r fp event fn; do
case "${event,,}" in
"modify"* ) refresh ;;
"delete_self" ) echo "c: vnc" ;;
esac
done
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# You can override this hook to execute a script before startup!
return 0
+254
View File
@@ -0,0 +1,254 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Helper functions
info () { printf "%b%s%b" "\E[1;34m❯ \E[1;36m" "${1:-}" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m❯ " "ERROR: ${1:-}" "\E[0m\n" >&2; }
warn () { printf "%b%s%b" "\E[1;31m❯ " "Warning: ${1:-}" "\E[0m\n" >&2; }
formatBytes() {
local result
result=$(numfmt --to=iec --suffix=B "$1" | sed -r 's/([A-Z])/ \1/' | sed 's/ B/ bytes/g;')
local unit="${result//[0-9. ]}"
result="${result//[a-zA-Z ]/}"
if [[ "${2:-}" == "up" ]]; then
if [[ "$result" == *"."* ]]; then
result="${result%%.*}"
result=$((result+1))
fi
else
if [[ "${2:-}" == "down" ]]; then
result="${result%%.*}"
fi
fi
echo "$result $unit"
return 0
}
isAlive() {
local pid="$1"
if kill -0 "$pid" 2>/dev/null; then
return 0
fi
return 1
}
pKill() {
local pid="$1"
{ kill -15 "$pid" || true; } 2>/dev/null
while isAlive "$pid"; do
sleep 0.2
done
return 0
}
fWait() {
local name="$1"
while pgrep -f -l "$name" >/dev/null; do
sleep 0.2
done
return 0
}
fKill() {
local name="$1"
{ pkill -f "$name" || true; } 2>/dev/null
fWait "$name"
return 0
}
setOwner() {
local file="$1"
local dir uid gid
[ ! -f "$file" ] && return 1
dir=$(dirname -- "$file")
uid=$(stat -c '%u' "$dir")
gid=$(stat -c '%g' "$dir")
! chown "$uid:$gid" "$file" && return 1
return 0
}
makeDir() {
local path="$1"
local dir uid gid
[ -d "$path" ] && return 0
! mkdir -p "$path" && return 1
dir=$(dirname -- "$path")
uid=$(stat -c '%u' "$dir")
gid=$(stat -c '%g' "$dir")
! chown "$uid:$gid" "$path" && return 1
return 0
}
escape () {
local s
s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
printf -- %s "$s"
return 0
}
html() {
local title
local body
local script
local footer
title=$(escape "$APP")
title="<title>$title</title>"
footer=$(escape "$FOOTER1")
body=$(escape "$1")
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body/.../}</p>"
fi
[ -n "${2:-}" ] && script="$2" || script=""
local HTML
HTML=$(<"$TEMPLATE")
HTML="${HTML/\[1\]/$title}"
HTML="${HTML/\[2\]/$script}"
HTML="${HTML/\[3\]/$body}"
HTML="${HTML/\[4\]/$footer}"
HTML="${HTML/\[5\]/$FOOTER2}"
echo "$HTML" > "$PAGE"
echo "$body" > "$INFO"
return 0
}
cpu() {
local ret
local cpu=""
ret=$(lscpu)
if grep -qi "model name" <<< "$ret"; then
cpu=$(echo "$ret" | grep -m 1 -i 'model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
fi
if [ -z "${cpu// /}" ] && grep -qi "model:" <<< "$ret"; then
cpu=$(echo "$ret" | grep -m 1 -i 'model:' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
fi
cpu="${cpu// CPU/}"
cpu="${cpu// [0-9][0-9][0-9] Core}"
cpu="${cpu// [0-9][0-9] Core}"
cpu="${cpu// [0-9] Core}"
cpu="${cpu//[0-9][0-9]th Gen }"
cpu="${cpu//[0-9]th Gen }"
cpu="${cpu// Processor/}"
cpu="${cpu// Quad core/}"
cpu="${cpu// Dual core/}"
cpu="${cpu// Octa core/}"
cpu="${cpu// Hexa core/}"
cpu="${cpu// Core TM/ Core}"
cpu="${cpu// with Radeon Graphics/}"
cpu="${cpu// with Radeon Vega Graphics/}"
cpu="${cpu// with Radeon Vega Mobile Gfx/}"
cpu="${cpu// w Radeon [0-9][0-9][0-9]M Graphics/}"
[ -z "${cpu// /}" ] && cpu="Unknown"
echo "$cpu"
return 0
}
hasDisk() {
[ -b "/disk" ] && return 0
[ -b "/disk1" ] && return 0
[ -b "/dev/disk1" ] && return 0
[ -b "${DEVICE:-}" ] && return 0
[ -z "${DISK_NAME:-}" ] && DISK_NAME="data"
[ -s "$STORAGE/$DISK_NAME.img" ] && return 0
[ -s "$STORAGE/$DISK_NAME.qcow2" ] && return 0
return 1
}
getCountry() {
local url=$1
local query=$2
local rc json result
{ json=$(curl -m 5 -H "Accept: application/json" -sfk "$url"); rc=$?; } || :
(( rc != 0 )) && return 0
{ result=$(echo "$json" | jq -r "$query" 2> /dev/null); rc=$?; } || :
(( rc != 0 )) && return 0
[[ ${#result} -ne 2 ]] && return 0
[[ "${result^^}" == "XX" ]] && return 0
COUNTRY="${result^^}"
return 0
}
setCountry() {
[[ "${TZ,,}" == "asia/harbin" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/beijing" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/urumqi" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/kashgar" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/shanghai" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/chongqing" ]] && COUNTRY="CN"
[ -z "$COUNTRY" ] && getCountry "https://api.ipapi.is" ".location.country_code"
[ -z "$COUNTRY" ] && getCountry "https://ifconfig.co/json" ".country_iso"
[ -z "$COUNTRY" ] && getCountry "https://api.ip2location.io" ".country_code"
[ -z "$COUNTRY" ] && getCountry "https://ipinfo.io/json" ".country"
[ -z "$COUNTRY" ] && getCountry "https://api.ipquery.io/?format=json" ".location.country_code"
[ -z "$COUNTRY" ] && getCountry "https://api.myip.com" ".cc"
return 0
}
addPackage() {
local pkg=$1
local desc=$2
if apt-mark showinstall | grep -qx "$pkg"; then
return 0
fi
MSG="Installing $desc..."
info "$MSG" && html "$MSG"
[ -z "$COUNTRY" ] && setCountry
if [[ "${COUNTRY^^}" == "CN" ]]; then
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
fi
DEBIAN_FRONTEND=noninteractive apt-get -qq update
DEBIAN_FRONTEND=noninteractive apt-get -qq --no-install-recommends -y install "$pkg" > /dev/null
return 0
}
return 0
+44
View File
@@ -0,0 +1,44 @@
server {
listen 5000 default_server;
autoindex on;
tcp_nodelay on;
server_tokens off;
absolute_redirect off;
error_log /dev/null;
access_log /dev/null;
include /etc/nginx/mime.types;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 500;
gzip_disable "msie6";
gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/json application/xml application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
add_header Cache-Control "no-cache";
location / {
root /run/shm;
index index.html;
}
location /status {
proxy_http_version 1.1;
proxy_set_header Connection 'upgrade';
proxy_set_header Upgrade $http_upgrade;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_pass http://127.0.0.1:8004/;
}
}
+167
View File
@@ -0,0 +1,167 @@
body {
color: white;
background-color: #125bdb;
font-smoothing: antialiased;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: Verdana, Geneva, sans-serif;
}
#info {
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.25);
}
#content {
text-align: center;
padding: 20px;
margin-top: 50px;
}
footer {
width: 98%;
position: fixed;
bottom: 0px;
height: 40px;
text-align: center;
color: #0c8aeb;
text-shadow: 0 0 1px #0c8aeb;
}
#empty {
height: 40px;
/* Same height as footer */
}
a,
a:hover,
a:active,
a:visited {
color: white;
}
footer a:link,
footer a:visited,
footer a:active {
color: #0c8aeb;
}
footer a:hover {
color: #73e6ff;
}
.loading:after {
content: " .";
animation: dots 1s steps(5, end) infinite;
}
@keyframes dots {
0%,
20% {
color: rgba(0, 0, 0, 0);
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
}
40% {
color: white;
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
}
60% {
text-shadow: 0.25em 0 0 white, 0.5em 0 0 rgba(0, 0, 0, 0);
}
80%,
100% {
text-shadow: 0.25em 0 0 white, 0.5em 0 0 white;
}
}
.spinner_LWk7 {
animation: spinner_GWy6 1.2s linear infinite, spinner_BNNO 1.2s linear infinite
}
.spinner_yOMU {
animation: spinner_GWy6 1.2s linear infinite, spinner_pVqn 1.2s linear infinite;
animation-delay: .15s
}
.spinner_KS4S {
animation: spinner_GWy6 1.2s linear infinite, spinner_6uKB 1.2s linear infinite;
animation-delay: .3s
}
.spinner_zVee {
animation: spinner_GWy6 1.2s linear infinite, spinner_Qw4x 1.2s linear infinite;
animation-delay: .45s
}
@keyframes spinner_GWy6 {
0%,
50% {
width: 9px;
height: 9px
}
10% {
width: 11px;
height: 11px
}
}
@keyframes spinner_BNNO {
0%,
50% {
x: 1.5px;
y: 1.5px
}
10% {
x: .5px;
y: .5px
}
}
@keyframes spinner_pVqn {
0%,
50% {
x: 13.5px;
y: 1.5px
}
10% {
x: 12.5px;
y: .5px
}
}
@keyframes spinner_6uKB {
0%,
50% {
x: 13.5px;
y: 13.5px
}
10% {
x: 12.5px;
y: 12.5px
}
}
@keyframes spinner_Qw4x {
0%,
50% {
x: 1.5px;
y: 13.5px
}
10% {
x: .5px;
y: 12.5px
}
}
+1
View File
@@ -0,0 +1 @@
<svg id="Capa_1" enable-background="new 0 0 511.962 511.962" height="512" viewBox="0 0 511.962 511.962" width="512" xmlns="http://www.w3.org/2000/svg"><g><path d="m489.965 120.063c0-5.77-3.31-11.028-8.512-13.524l-218.984-105.063c-4.102-1.967-8.875-1.967-12.977 0l-218.985 105.063c-5.202 2.496-8.511 7.755-8.511 13.524l-.003 271.834c0 5.77 3.31 11.028 8.512 13.524l218.989 105.064c2.051.983 4.27 1.476 6.488 1.476 2.219 0 4.438-.492 6.488-1.476l218.989-105.064c5.202-2.496 8.512-7.755 8.512-13.524z" fill="#4e6ba6"/><path d="m489.965 120.063c0-5.77-3.31-11.028-8.512-13.524l-218.984-105.063c-2.051-.984-4.269-1.476-6.488-1.476v511.962c2.219 0 4.438-.492 6.488-1.476l218.989-105.064c5.202-2.496 8.512-7.755 8.512-13.524z" fill="#28487a"/><path d="m425.812 160.441c0-2.27-.519-4.457-1.457-6.432l-336.701-.095c-.967 1.999-1.504 4.22-1.504 6.526l-.002 191.081c0 5.769 3.31 11.028 8.512 13.524l154.833 74.285c2.051.983 4.27 1.476 6.488 1.476 2.219 0 4.438-.492 6.488-1.476l154.834-74.285c5.202-2.496 8.512-7.755 8.512-13.524z" fill="#8dc2eb"/><path d="m424.354 154.009h-168.373v286.798c2.219 0 4.438-.492 6.488-1.476l154.834-74.285c5.202-2.496 8.512-7.755 8.512-13.524l-.003-191.081c0-2.27-.52-4.458-1.458-6.432z" fill="#5e9ff6"/><path d="m417.3 146.916-154.831-74.284c-4.102-1.967-8.875-1.967-12.977 0l-154.831 74.284c-3.122 1.498-5.555 3.996-7.007 6.998l168.328 80.812 168.374-80.717c-1.448-3.044-3.9-5.579-7.056-7.093z" fill="#ecf9fd"/><path d="m417.3 146.916-154.831-74.284c-2.051-.983-4.27-1.476-6.488-1.476v163.569l168.374-80.717c-1.447-3.043-3.899-5.578-7.055-7.092z" fill="#d9f3fc"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+34
View File
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
[1]
<meta http-equiv="Cache-Control" content="no-cache" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="css/style.css" />
<link rel="icon" href="img/favicon.svg" type="image/x-icon">
[2]
</head>
<body>
<div id="page">
<div id="content">
<svg id="spinner" width="64" height="64" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<rect class="spinner_LWk7" fill="#0c8aeb" x="1.5" y="1.5" rx="1" width="9" height="9"/>
<rect class="spinner_yOMU" fill="#0c8aeb" x="13.5" y="1.5" rx="1" width="9" height="9"/>
<rect class="spinner_KS4S" fill="#0c8aeb" x="13.5" y="13.5" rx="1" width="9" height="9"/>
<rect class="spinner_zVee" fill="#0c8aeb" x="1.5" y="13.5" rx="1" width="9" height="9"/>
</svg>
<h1 id="info">[3]</h1>
</div>
<div id="empty">
</div>
<footer id="footer">
[4]<br />
[5]
</footer>
</div>
<script type="text/javascript" src="js/script.js"></script>
</body>
</html>
+204
View File
@@ -0,0 +1,204 @@
var request;
var booting = false;
var interval = 1000;
function getInfo() {
var url = "msg.html";
try {
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else {
throw "XMLHttpRequest not available!";
}
request.onreadystatechange = processInfo;
request.open("GET", url, true);
request.send();
} catch (e) {
setError("Error: " + e.message);
}
}
function getURL() {
var protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
var path = window.location.pathname.replace(/[^/]*$/, '').replace(/\/$/, '');
return protocol + "//" + window.location.host + path;
}
function processMsg(msg) {
if (msg.toLowerCase().indexOf("href=") !== -1) {
var div = document.createElement("div");
div.innerHTML = msg;
var url = div.querySelector("a").href;
setTimeout(() => {
window.location.assign(url);
}, 3000);
}
setInfo(msg);
return true;
}
function processInfo() {
try {
if (request.readyState != 4) {
return true;
}
var msg = request.responseText;
if (msg == null || msg.length == 0) {
if (booting) {
schedule();
return true;
}
window.location.reload();
return false;
}
var notFound = (request.status == 404);
if (request.status == 200) {
if (msg.toLowerCase().indexOf("<html>") !== -1) {
notFound = true;
} else {
processMsg(msg);
if (msg.toLowerCase().indexOf("href=") == -1) {
schedule();
}
return true;
}
}
if (notFound) {
setInfo("Connecting to web portal", true);
reload();
return true;
}
setError("Error: Received statuscode " + request.status);
return false;
} catch (e) {
setError("Error: " + e.message);
return false;
}
}
function extractContent(s) {
var span = document.createElement('span');
span.innerHTML = s;
return span.textContent || span.innerText;
};
function setInfo(msg, loading, error) {
try {
if (msg == null || msg.length == 0) {
return false;
}
if (msg.includes("Booting ")) {
booting = true;
}
var el = document.getElementById("info");
if (el.innerText == msg || el.innerHTML == msg) {
return true;
}
var spin = document.getElementById("spinner");
error = !!error;
if (!error) {
spin.style.visibility = 'visible';
} else {
spin.style.visibility = 'hidden';
}
var p = "<p class=\"loading\">";
loading = !!loading;
if (loading) {
msg = p + msg + "</p>";
}
if (msg.includes(p)) {
if (el.innerHTML.includes(p)) {
el.getElementsByClassName('loading')[0].textContent = extractContent(msg);
return true;
}
}
el.innerHTML = msg;
return true;
} catch (e) {
console.log("Error: " + e.message);
return false;
}
}
function setError(text) {
console.warn(text);
return setInfo(text, false, true);
}
function schedule() {
setTimeout(getInfo, interval);
}
function reload() {
setTimeout(() => {
window.location.reload();
}, 3000);
}
function connect() {
var wsUrl = getURL() + "/status";
var ws = new WebSocket(wsUrl);
ws.onmessage = function(e) {
var pos = e.data.indexOf(":");
var cmd = e.data.substring(0, pos);
var msg = e.data.substring(pos + 2);
switch (cmd) {
case "s":
processMsg(msg);
break;
case "e":
setError(msg);
break;
default:
console.warn("Unknown event: " + cmd);
break;
}
};
ws.onclose = function(e) {
setTimeout(function() {
connect();
}, interval);
};
ws.onerror = function(e) {
ws.close();
if (!booting) {
window.location.reload();
}
};
}
schedule();
connect();