├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug.md └── workflows │ ├── data.yml │ └── issues.yml ├── .gitignore ├── LICENSE ├── README.md ├── TODO ├── VERSION ├── docs ├── addons.json ├── addons.xlsx ├── changelogs.html ├── index.html ├── issues.html ├── models.json ├── models.xlsx ├── modules.json ├── modules.xlsx ├── pats.json └── pats.xlsx ├── files ├── initrd │ └── opt │ │ └── rr │ │ ├── boot.sh │ │ ├── bzImage-template-v4.gz │ │ ├── bzImage-template-v5.gz │ │ ├── bzImage-to-vmlinux.sh │ │ ├── extract-vmlinux │ │ ├── grub.img.gz │ │ ├── i915ids │ │ ├── include │ │ ├── addons.sh │ │ ├── configFile.sh │ │ ├── consts.sh │ │ ├── functions.py │ │ ├── functions.sh │ │ ├── i18n.sh │ │ ├── logo.png │ │ ├── modules.sh │ │ └── qhxg.png │ │ ├── init.sh │ │ ├── kpatch │ │ ├── lang │ │ ├── ar_SA │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── de_DE │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── en_US │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── es_ES │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── fr_FR │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── ja_JP │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── ko_KR │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── rr.pot │ │ ├── ru_RU │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── th_TH │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── tr_TR │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── uk_UA │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── vi_VN │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── zh_CN │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ ├── zh_HK │ │ │ └── LC_MESSAGES │ │ │ │ └── rr.po │ │ └── zh_TW │ │ │ └── LC_MESSAGES │ │ │ └── rr.po │ │ ├── menu.sh │ │ ├── patch │ │ ├── iosched-trampoline.sh │ │ ├── modulelist │ │ ├── ramdisk-etc-rc-25556.patch │ │ ├── ramdisk-init-script-25556.patch │ │ ├── ramdisk-init-script-42218.patch │ │ ├── ramdisk-init-script-64216.patch │ │ ├── ramdisk-init-script-69057.patch │ │ ├── ramdisk-post-init-script-25556.patch │ │ ├── ramdisk-post-init-script-42218.patch │ │ ├── ramdisk-post-init-script-42661.patch │ │ ├── ramdisk-post-init-script-42951.patch │ │ └── ramdisk-post-init-script-69057.patch │ │ ├── platforms.yml │ │ ├── ramdisk-patch.sh │ │ ├── serialnumber.yml │ │ ├── vmlinux-to-bzImage.sh │ │ └── zimage-patch.sh └── mnt │ └── p1 │ ├── EFI │ └── BOOT │ │ ├── SynoBootLoader.conf │ │ └── SynoBootLoader.efi │ ├── RR_VERSION │ └── boot │ └── grub │ ├── gfxblacklist.txt │ ├── grub.cfg │ ├── logo.png │ └── memtest ├── guide.md ├── kpatch ├── Makefile └── main.c ├── localbuild.sh ├── scripts ├── func.py ├── func.sh └── requirements.txt ├── sourcebuild.sh ├── update-check.sh └── update-list.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | charset = utf-8 9 | indent_size = 2 10 | 11 | # Tab indentation (no size specified) 12 | [Makefile] 13 | indent_style = tab 14 | 15 | # YAML 16 | [*.yml] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | # PYTHON 21 | [*.py] 22 | indent_style = space 23 | indent_size = 4 24 | 25 | [*.{c,h}] 26 | indent_style = space 27 | indent_size = 4 28 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.png binary 3 | *.jpg binary 4 | *.gif binary 5 | *.ico binary 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: wjz304 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: BUG 3 | about: Describe this issue template's purpose here. 4 | title: 'BUG' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 请填写以下信息. 11 | Please fill in the following information. 12 | 13 | Install ENV: (You can find it in the boot interface.) 14 | * DMI: 15 | * CPU: 16 | * NIC: (pid & vid) 17 | 18 | RR version: (You can find it in the update menu.) 19 | * RR: 20 | * addons: 21 | * modules: 22 | * lkms: 23 | 24 | DSM: 25 | * model: 26 | * version: 27 | 28 | Issue: 29 | 30 | logs: 31 | 32 | (## 因为 log中存在 SN/MAC 等一些敏感信息, 当提供完整文件时请自行抹除他们, 当然你也可以发送到我的邮箱. ##) 33 | (## Because the log contains some sensitive information such as SN/MAC, please delete them when providing the complete file. Of course, you can also send it to my email. ##) 34 | ... 35 | 36 | (请先看一下#173、#175、#226 的内容) 37 | (Plz review the content of #173, #175, #226 first) 38 | ... 39 | 40 | (如果你只是说 XXX 不能用, 什么详细信息也不提供, 我也只能说感谢你的反馈.) 41 | (If you just say XXX doesn't work without providing any details, I can only say thank you for your feedback.) 42 | ... 43 | -------------------------------------------------------------------------------- /.github/workflows/data.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2022 Ing 3 | # 4 | # This is free software, licensed under the MIT License. 5 | # See /LICENSE for more information. 6 | # 7 | 8 | name: Data 9 | on: 10 | release: 11 | types: 12 | - created 13 | 14 | workflow_dispatch: 15 | inputs: 16 | push: 17 | description: "push" 18 | default: false 19 | type: boolean 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@main 27 | with: 28 | ref: main 29 | 30 | - name: Init Env 31 | run: | 32 | git config --global user.email "github-actions[bot]@users.noreply.github.com" 33 | git config --global user.name "github-actions[bot]" 34 | sudo timedatectl set-timezone "Asia/Shanghai" 35 | 36 | - name: Delay 37 | run: | 38 | echo "Delaying for 1 minutes..." 39 | sleep 60 40 | 41 | - name: Get Release RR 42 | run: | 43 | REPO="${{ github.server_url }}/${{ github.repository }}" 44 | PRERELEASE="true" 45 | 46 | TAG="" 47 | if [ "${PRERELEASE}" = "true" ]; then 48 | TAG="$(curl -skL --connect-timeout 10 "${REPO}/tags" | grep "/refs/tags/.*\.zip" | sed -E 's/.*\/refs\/tags\/(.*)\.zip.*$/\1/' | sort -rV | head -1)" 49 | else 50 | TAG="$(curl -skL --connect-timeout 10 -w "%{url_effective}" -o /dev/null "${REPO}/releases/latest" | awk -F'/' '{print $NF}')" 51 | fi 52 | [ "${TAG:0:1}" = "v" ] && TAG="${TAG:1}" 53 | rm -f rr-${TAG}.img.zip 54 | STATUS=$(curl -kL --connect-timeout 10 -w "%{http_code}" "${REPO}/releases/download/${TAG}/rr-${TAG}.img.zip" -o "rr-${TAG}.img.zip") 55 | if [ $? -ne 0 ] || [ ${STATUS:-0} -ne 200 ]; then 56 | echo "Download failed" 57 | exit 1 58 | fi 59 | 60 | unzip rr-${TAG}.img.zip -d "rr" 61 | 62 | export TERM=xterm 63 | 64 | sudo ./localbuild.sh create rr/ws rr/rr.img 65 | if [ $? -ne 0 ]; then 66 | echo "create failed" 67 | exit 1 68 | fi 69 | 70 | - name: Get data 71 | run: | 72 | sudo apt update 73 | sudo apt install -y locales busybox dialog gettext sed gawk jq curl 74 | sudo apt install -y python-is-python3 python3-pip libelf-dev qemu-utils cpio xz-utils lz4 lzma bzip2 gzip zstd 75 | sudo apt install -y build-essential libtool pkgconf libzstd-dev liblzma-dev libssl-dev # kmodule dependencies 76 | 77 | # Backup the original python3 executable. 78 | sudo mv -f "$(realpath $(which python3))/EXTERNALLY-MANAGED" "$(realpath $(which python3))/EXTERNALLY-MANAGED.bak" 2>/dev/null || true 79 | sudo pip3 install -U -r scripts/requirements.txt 80 | 81 | python3 scripts/func.py getmodels -w "rr/ws/initrd" -j "docs/models.json" -x "docs/models.xlsx" 82 | python3 scripts/func.py getpats -w "rr/ws/initrd" -j "docs/pats.json" -x "docs/pats.xlsx" 83 | python3 scripts/func.py getaddons -w "rr/ws" -j "docs/addons.json" -x "docs/addons.xlsx" 84 | python3 scripts/func.py getmodules -w "rr/ws" -j "docs/modules.json" -x "docs/modules.xlsx" 85 | 86 | - name: Upload to Artifacts 87 | if: success() 88 | uses: actions/upload-artifact@v4 89 | with: 90 | name: docs 91 | path: | 92 | docs/*.json 93 | docs/*.xlsx 94 | retention-days: 5 95 | 96 | - name: Check and Push 97 | if: success() && (inputs.push == true || github.event.action == 'created') 98 | run: | 99 | echo "Git push ..." 100 | # git checkout main 101 | git pull 102 | status=$(git status -s | grep -E "docs" | awk '{printf " %s", $2}') 103 | if [ -n "${status}" ]; then 104 | git add ${status} 105 | git commit -m "update $(date +%Y-%m-%d" "%H:%M:%S)" 106 | git push -f 107 | fi 108 | -------------------------------------------------------------------------------- /.github/workflows/issues.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2022 Ing 3 | # 4 | # This is free software, licensed under the MIT License. 5 | # See /LICENSE for more information. 6 | # 7 | 8 | name: Issues 9 | on: 10 | issues: 11 | types: [opened, reopened] 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@main 19 | 20 | - name: Init Env 21 | run: | 22 | git config --global user.email "github-actions[bot]@users.noreply.github.com" 23 | git config --global user.name "github-actions[bot]" 24 | sudo timedatectl set-timezone "Asia/Shanghai" 25 | 26 | - name: Check Issues 27 | shell: python 28 | run: | 29 | # -*- coding: utf-8 -*- 30 | import json, subprocess 31 | def set_output(name, value): 32 | subprocess.call(["echo '{}={}' >> $GITHUB_ENV".format(name, value)], shell=True) 33 | 34 | issuetitle = ${{ toJSON(github.event.issue.title) }} 35 | issuebody = ${{ toJSON(github.event.issue.body) }} 36 | 37 | iscustom = 'false' 38 | warinfo = 'false' 39 | 40 | format = '' 41 | size = '' 42 | template = '' 43 | language= '' 44 | sn = '' 45 | macs = '' 46 | model = '' 47 | version = '' 48 | kernel = '' 49 | addons = '' 50 | modules = '' 51 | try: 52 | if issuetitle.lower().startswith('custom'): 53 | jsonbody = json.loads(issuebody) 54 | iscustom = 'true' 55 | format = jsonbody.get('format', '') 56 | size = jsonbody.get('size', '') 57 | template = jsonbody.get('template', '') 58 | language = jsonbody.get('language', '') 59 | sn = jsonbody.get('sn', '') 60 | macs = jsonbody.get('macs', '') 61 | model = jsonbody.get('model', '') 62 | version = jsonbody.get('version', '') 63 | kernel = jsonbody.get('kernel', '') 64 | addons = jsonbody.get('addons', '') 65 | modules = jsonbody.get('modules', '') 66 | except ValueError as e: 67 | pass 68 | 69 | if iscustom == 'false': 70 | if issuebody.find('DMI') < 0 and issuebody.find('CPU') < 0 and issuebody.find('NIC') < 0: 71 | warinfo = 'true' 72 | 73 | set_output("iscustom", iscustom) 74 | set_output("warinfo", warinfo) 75 | 76 | set_output("format", format) 77 | set_output("size", size) 78 | set_output("template", template) 79 | set_output("language", language) 80 | set_output("sn", sn) 81 | set_output("macs", macs) 82 | set_output("model", model) 83 | set_output("version", version) 84 | set_output("kernel", kernel) 85 | set_output("addons", addons) 86 | set_output("modules", modules) 87 | 88 | - name: Update Comment Warinfo 89 | if: env.warinfo == 'true' 90 | uses: actions-cool/issues-helper@v3 91 | with: 92 | actions: "create-comment" 93 | token: ${{ secrets.GITHUB_TOKEN }} 94 | issue-number: ${{ github.event.issue.number }} 95 | body: | 96 | 97 | 98 | 请填写以下信息. 99 | Please fill in the following information. 100 | 101 | Install ENV: (You can find it in the boot interface.) 102 | * DMI: 103 | * CPU: 104 | * NIC: (pid & vid) 105 | 106 | RR version: (You can find it in the update menu.) 107 | * RR: 108 | * addons: 109 | * modules: 110 | * lkms: 111 | 112 | DSM: 113 | * model: 114 | * version: 115 | 116 | Issue: 117 | 118 | logs: 119 | 120 | (## 因为 log中存在 SN/MAC 等一些敏感信息, 当提供完整文件时请自行抹除他们, 当然你也可以发送到我的邮箱. ##) 121 | (## Because the log contains some sensitive information such as SN/MAC, please delete them when providing the complete file. Of course, you can also send it to my email. ##) 122 | ... 123 | 124 | (请先看一下#173、#175、#226 的内容) 125 | (Plz review the content of #173, #175, #226 first) 126 | ... 127 | 128 | (如果你只是说 XXX 不能用, 什么详细信息也不提供, 我也只能说感谢你的反馈.) 129 | (If you just say XXX doesn't work without providing any details, I can only say thank you for your feedback.) 130 | ... 131 | 132 | emoji: heart 133 | 134 | - name: Update Comment Labels 135 | if: env.iscustom == 'true' 136 | uses: actions-cool/issues-helper@v3 137 | with: 138 | actions: 'add-labels' 139 | token: ${{ secrets.GITHUB_TOKEN }} 140 | issue-number: ${{ github.event.issue.number }} 141 | labels: 'custom,${{ env.model }}' 142 | 143 | - name: Update Comment Building 144 | if: env.iscustom == 'true' 145 | id: comment 146 | uses: actions-cool/issues-helper@v3 147 | with: 148 | actions: 'create-comment' 149 | token: ${{ secrets.GITHUB_TOKEN }} 150 | issue-number: ${{ github.event.issue.number }} 151 | body: | 152 | Hi @${{ github.event.issue.user.login }}. 153 | RR-${{ env.model }} building (Usually about 5 minutes) ... 154 | > ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} 155 | ---- 156 | emoji: heart 157 | 158 | - name: Run Build 159 | if: env.iscustom == 'true' 160 | run: | 161 | # 累了, 毁灭吧! 162 | 163 | # yq need sudo !!! 164 | function deleteConfigKey() { 165 | sudo yq eval "del(.${1})" --inplace "${2}" 2>/dev/null 166 | } 167 | 168 | function writeConfigKey() { 169 | local value="${2}" 170 | [ "${value}" = "{}" ] && sudo yq eval ".${1} = {}" --inplace "${3}" 2>/dev/null || sudo yq eval ".${1} = \"${value}\"" --inplace "${3}" 2>/dev/null 171 | } 172 | 173 | function readConfigKey() { 174 | local result 175 | result=$(sudo yq eval ".${1} | explode(.)" "${2}" 2>/dev/null) 176 | [ "${result}" = "null" ] && echo "" || echo "${result}" 177 | } 178 | 179 | function mergeConfigModules() { 180 | # Error: bad file '-': cannot index array with '8139cp' (strconv.ParseInt: parsing "8139cp": invalid syntax) 181 | # When the first key is a pure number, yq will not process it as a string by default. The current solution is to insert a placeholder key. 182 | local MS ML XF 183 | MS="RRORG\n${1// /\\n}" 184 | ML="$(echo -en "${MS}" | awk '{print "modules."$1":"}')" 185 | XF=$(mktemp 2>/dev/null) 186 | XF=${XF:-/tmp/tmp.XXXXXXXXXX} 187 | echo -en "${ML}" | sudo yq -p p -o y >"${XF}" 188 | deleteConfigKey "modules.\"RRORG\"" "${XF}" 189 | sudo yq eval-all --inplace '. as $item ireduce ({}; . * $item)' --inplace "${2}" "${XF}" 2>/dev/null 190 | rm -f "${XF}" 191 | } 192 | 193 | REPO="${{ github.server_url }}/${{ github.repository }}" 194 | MODEL="${{ env.model }}" 195 | VERSION="${{ env.version }}" 196 | PRERELEASE="true" 197 | 198 | TAG="" 199 | if [ "${PRERELEASE}" = "true" ]; then 200 | TAG="$(curl -skL --connect-timeout 10 "${REPO}/tags" | grep "/refs/tags/.*\.zip" | sed -E 's/.*\/refs\/tags\/(.*)\.zip.*$/\1/' | sort -rV | head -1)" 201 | else 202 | TAG="$(curl -skL --connect-timeout 10 -w "%{url_effective}" -o /dev/null "${REPO}/releases/latest" | awk -F'/' '{print $NF}')" 203 | fi 204 | [ "${TAG:0:1}" = "v" ] && TAG="${TAG:1}" 205 | rm -f rr-${TAG}.img.zip 206 | STATUS=$(curl -kL --connect-timeout 10 -w "%{http_code}" "${REPO}/releases/download/${TAG}/rr-${TAG}.img.zip" -o "rr-${TAG}.img.zip") 207 | if [ $? -ne 0 ] || [ ${STATUS:-0} -ne 200 ]; then 208 | echo "Download failed" 209 | exit 1 210 | fi 211 | 212 | unzip rr-${TAG}.img.zip -d "rr" 213 | 214 | export TERM=xterm 215 | 216 | sudo ./localbuild.sh create rr/ws rr/rr.img 217 | if [ $? -ne 0 ]; then 218 | echo "create failed" 219 | exit 1 220 | fi 221 | 222 | # sudo cp -rf files/initrd/opt/rr/* rr/ws/initrd/opt/rr/ 223 | # sudo sed -i "s/set -e/set -ex/" rr/ws/initrd/opt/rr/init.sh 224 | # sudo sed -i '/^alias/i\set -x' rr/ws/initrd/opt/rr/menu.sh 225 | 226 | [ -n "${{ env.language }}" ] && echo "${{ env.language }}.UTF-8" | sudo tee rr/ws/mnt/p1/.locale 227 | 228 | sudo ./localbuild.sh init 229 | if [ $? -ne 0 ]; then 230 | echo "init failed" 231 | exit 1 232 | fi 233 | 234 | if [ -n "${{ env.kernel }}" ]; then 235 | echo "set kernel" 236 | USER_CONFIG_FILE="rr/ws/mnt/p1/user-config.yml" 237 | writeConfigKey "kernel" "${{ env.kernel }}" "${USER_CONFIG_FILE}" 238 | fi 239 | 240 | sudo ./localbuild.sh config "${MODEL}" "${VERSION}" 241 | if [ $? -ne 0 ]; then 242 | echo "config failed" 243 | exit 1 244 | fi 245 | 246 | if [ -n "${{ env.sn }}" ]; then 247 | echo "set sn: ${{ env.sn }}" 248 | USER_CONFIG_FILE="rr/ws/mnt/p1/user-config.yml" 249 | writeConfigKey "sn" "${{ env.sn }}" "${USER_CONFIG_FILE}" 250 | fi 251 | 252 | if [ -n "${{ env.macs }}" ]; then 253 | echo "set macs: ${{ env.macs }}" 254 | USER_CONFIG_FILE="rr/ws/mnt/p1/user-config.yml" 255 | MACS=($(echo "${{ env.macs }}" | sed 's/[:-]//g' | sed 's/.*/\U&/' | sed 's/[;,]/ /g')) 256 | writeConfigKey "mac1" "${MACS[0]}" "${USER_CONFIG_FILE}" 257 | writeConfigKey "mac2" "${MACS[1]}" "${USER_CONFIG_FILE}" 258 | fi 259 | 260 | if [ -n "${{ env.addons }}" ]; then 261 | echo "set addons: ${{ env.addons }}" 262 | USER_CONFIG_FILE="rr/ws/mnt/p1/user-config.yml" 263 | writeConfigKey "addons" "{}" "${USER_CONFIG_FILE}" 264 | IFS=',' read -ra ADDON_ARR <<< "${{ env.addons }}" 265 | for A in "${ADDON_ARR[@]}"; do 266 | if echo "${A}" | grep -qE '^[^:]+:[^:]+$'; then 267 | KEY="$(echo "${A}" | cut -d':' -f1 | xargs)" 268 | VAL="$(echo "${A}" | cut -d':' -f2 | xargs)" 269 | else 270 | KEY="${A}" 271 | VAL="" 272 | fi 273 | writeConfigKey "addons.\"${KEY}\"" "${VAL}" "${USER_CONFIG_FILE}" 274 | done 275 | fi 276 | 277 | if [ ! "custom" = "${{ env.kernel }}" ] && [ -n "${{ env.modules }}" ]; then 278 | echo "set modules: ${{ env.modules }}" 279 | USER_CONFIG_FILE="rr/ws/mnt/p1/user-config.yml" 280 | writeConfigKey "modules" "{}" "${USER_CONFIG_FILE}" 281 | mergeConfigModules "$(echo "${{ env.modules }}" | sed 's/,/\n/g')" "${USER_CONFIG_FILE}" 282 | # for M in $(echo "${{ env.modules }}" | sed 's/,/ /g'); do 283 | # writeConfigKey "modules.\"${M}\"" "" "${USER_CONFIG_FILE}" 284 | # done 285 | fi 286 | 287 | sudo ./localbuild.sh build 288 | if [ $? -ne 0 ]; then 289 | echo "build failed" 290 | exit 1 291 | fi 292 | 293 | if [ "true" = "${{ env.template }}" ]; then 294 | echo "set template: ${{ env.template }}" 295 | USER_CONFIG_FILE="rr/ws/mnt/p1/user-config.yml" 296 | writeConfigKey "sn" "" "${USER_CONFIG_FILE}" 297 | writeConfigKey "mac1" "" "${USER_CONFIG_FILE}" 298 | writeConfigKey "mac2" "" "${USER_CONFIG_FILE}" 299 | fi 300 | 301 | sudo ./localbuild.sh pack rr/rr.img 302 | if [ $? -ne 0 ]; then 303 | echo "pack failed" 304 | exit 1 305 | fi 306 | 307 | case "${{ env.size }}" in 308 | 2GB) 309 | echo "2GB" 310 | ;; 311 | 4GB) 312 | echo "4GB" 313 | sudo ./localbuild.sh resize rr/rr.img +2048M 314 | ;; 315 | 8GB) 316 | echo "8GB" 317 | sudo ./localbuild.sh resize rr/rr.img +6144M 318 | ;; 319 | *) 320 | echo "unknown size" 321 | ;; 322 | esac 323 | 324 | ls rr -al 325 | 326 | RR_VERSION_FILE="rr/ws/mnt/p1/RR_VERSION" 327 | USER_CONFIG_FILE="rr/ws/mnt/p1/user-config.yml" 328 | { 329 | echo "RR: " 330 | echo " VERSION: $(cat "${RR_VERSION_FILE}" 2>/dev/null | head -1)" 331 | echo " CUSTOM: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" 332 | echo 333 | echo "DSM:" 334 | echo " MODEL: $(readConfigKey "model" "${USER_CONFIG_FILE}")" 335 | echo " VERSION: $(readConfigKey "productver" "${USER_CONFIG_FILE}")" 336 | echo " KERNEL: $(readConfigKey "kernel" "${USER_CONFIG_FILE}")" 337 | echo " PATURL: $(readConfigKey "paturl" "${USER_CONFIG_FILE}")" 338 | echo " PATSUM: $(readConfigKey "patsum" "${USER_CONFIG_FILE}")" 339 | echo 340 | echo 341 | echo "After the image is written to the disk, it will boot directly into DSM without the need to compile again." 342 | echo "Of course, you can also modify the settings yourself." 343 | } >README.txt 344 | 345 | case "${{ env.format }}" in 346 | ova) 347 | echo "OVA" 348 | . scripts/func.sh "${{ secrets.RRORG }}" 349 | convertova "rr/rr.img" "rr/rr.ova" 350 | (cd rr && sha256sum rr.ova >../sha256sum) 351 | zip -9 "rr-${MODEL}-${TAG}-${{ github.run_id }}.ova.zip" -j rr/rr.ova ${USER_CONFIG_FILE} sha256sum README.txt 352 | ;; 353 | vmx) 354 | echo "VMX" 355 | . scripts/func.sh "${{ secrets.RRORG }}" 356 | convertvmx "rr/rr.img" "rr.vmx" # rr.vmx is a directory 357 | (cd rr.vmx && sha256sum * >../sha256sum) 358 | zip -9 "rr-${MODEL}-${TAG}-${{ github.run_id }}.vmx.zip" -r rr.vmx ${USER_CONFIG_FILE} sha256sum README.txt 359 | ;; 360 | vmdk) 361 | echo "VMDK" 362 | qemu-img convert rr/rr.img -O vmdk -o 'adapter_type=lsilogic,subformat=streamOptimized,compat6' rr/rr.vmdk 363 | (cd rr && sha256sum rr.vmdk >../sha256sum) 364 | zip -9 "rr-${MODEL}-${TAG}-${{ github.run_id }}.vmdk.zip" -j rr/rr.vmdk ${USER_CONFIG_FILE} sha256sum README.txt 365 | ;; 366 | flat) 367 | echo "FLAT" 368 | qemu-img convert rr/rr.img -O vmdk -o 'adapter_type=lsilogic,subformat=monolithicFlat,compat6' rr/rr.vmdk 369 | (cd rr && sha256sum rr*.vmdk >../sha256sum) 370 | zip -9 "rr-${MODEL}-${TAG}-${{ github.run_id }}.flat.zip" -j rr/rr*.vmdk ${USER_CONFIG_FILE} sha256sum README.txt 371 | ;; 372 | vhd) 373 | echo "VHD" 374 | . scripts/func.sh "${{ secrets.RRORG }}" 375 | qemu-img convert rr/rr.img -O vpc rr/rr.vhd 376 | createvmc "rr/rr.vhd" "rr/rr.vmc" 377 | (cd rr && sha256sum rr.vhd >../sha256sum) 378 | zip -9 "rr-${MODEL}-${TAG}-${{ github.run_id }}.vhd.zip" -j rr/rr.vmc rr/rr.vhd ${USER_CONFIG_FILE} sha256sum README.txt 379 | ;; 380 | vhdx) 381 | echo "VHDX" 382 | qemu-img convert rr/rr.img -O vhdx -o subformat=dynamic rr/rr.vhdx 383 | (cd rr && sha256sum rr.vhdx >../sha256sum) 384 | zip -9 "rr-${MODEL}-${TAG}-${{ github.run_id }}.vhdx.zip" -j rr/rr.vhdx ${USER_CONFIG_FILE} sha256sum README.txt 385 | ;; 386 | *) 387 | echo "IMG" 388 | (cd rr && sha256sum rr.img >../sha256sum) 389 | zip -9 "rr-${MODEL}-${TAG}-${{ github.run_id }}.img.zip" -j rr/rr.img ${USER_CONFIG_FILE} sha256sum README.txt 390 | esac 391 | 392 | echo "TAG=${TAG}" >> $GITHUB_ENV 393 | 394 | - name: Upload to Artifacts 395 | if: env.iscustom == 'true' && success() 396 | uses: actions/upload-artifact@v4 397 | with: 398 | name: rr-${{ env.model }}-${{ env.TAG }} 399 | path: | 400 | rr-${{ env.model }}-${{ env.TAG }}*.zip 401 | retention-days: 5 402 | 403 | - name: Update Comment Success 404 | if: env.iscustom == 'true' && success() 405 | uses: actions-cool/issues-helper@v3 406 | with: 407 | actions: 'update-comment' 408 | token: ${{ secrets.GITHUB_TOKEN }} 409 | comment-id: ${{ steps.comment.outputs.comment-id }} 410 | update-mode: replace 411 | body: | 412 | Hi @${{ github.event.issue.user.login }}. 413 | RR-${{ env.model }}-${{ env.TAG }} build success, please download the attachment from the below link (Attachments are only kept for 5 days). 414 | > ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} 415 | ---- 416 | emoji: hooray 417 | 418 | - name: Close Issues 419 | if: env.iscustom == 'true' && success() 420 | uses: actions-cool/issues-helper@v3 421 | with: 422 | actions: 'close-issue' 423 | token: ${{ secrets.GITHUB_TOKEN }} 424 | issue-number: ${{ github.event.issue.number }} 425 | 426 | - name: Update Comment Fail 427 | if: env.iscustom == 'true' && failure() 428 | uses: actions-cool/issues-helper@v3 429 | with: 430 | actions: 'update-comment' 431 | token: ${{ secrets.GITHUB_TOKEN }} 432 | comment-id: ${{ steps.comment.outputs.comment-id }} 433 | update-mode: replace 434 | body: | 435 | Hi @${{ github.event.issue.user.login }}. 436 | RR-${{ env.model }}-${{ env.TAG }} build failed, please try again. 437 | > ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} 438 | ---- 439 | emoji: confused 440 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !.gitkeep 2 | .vscode 3 | /rr 4 | /rr.env 5 | rr*.img 6 | rr*.vmdk 7 | *.zip 8 | *.bak 9 | *.o 10 | **.po~ 11 | **.mo 12 | 13 | downloads.md 14 | tests 15 | Changelog* 16 | sha256sum 17 | 18 | ovftool* 19 | OVA* 20 | **.ova 21 | 22 | files/mnt/p1/.locale 23 | files/mnt/p1/grub_cksum.syno 24 | files/mnt/p1/GRUB_VER 25 | files/mnt/p1/user-config.yml 26 | files/mnt/p2 27 | files/mnt/p3 28 | files/tmp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | logo 2 | 3 |

RR: redpill’s preinstallation and recovery environment

4 | 5 | [![GitHub Release](https://img.shields.io/github/v/release/rrorg/rr?logo=github&style=flat-square)](https://github.com/rrorg/rr/releases/latest) 6 | [![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/rrorg/rr/total?logo=github&style=flat-square)](https://github.com/rrorg/rr/releases) 7 | [![GitHub Issues or Pull Requests by label](https://img.shields.io/github/issues-closed-raw/rrorg/rr/custom?logo=github&style=flat-square&label=custom)](https://rrorg.github.io/rr/) 8 | 9 | > The ultimate solution to self-centralized Synology DSM OS on any local machine with any x86/x64 CPU architecture via a single flash of bootload pre-installation process in addition within recovery environment. 10 | 11 | ### 1: Disclaimer 12 | 13 | * 硬盘有价,数据无价,任何对引导的修改都是有风险的,本人/组织不承担数据丢失的责任。本工具仅用作学习交流,严禁用于商业用途。 14 | ---- 15 | * Hardware/hard-drives are priced whilst data are priceless, any user-specific custom modification of the tested & prebuilt bootloader images could potentially cause irreversible data destruction towards your local machine. Us, as (RROrg) are not responsibly liable for damage nor personal loss of any types. The project with its affiliation is released for educational and learning purpose only, commercial application of the software is strictly prohibited. 16 | 17 | 18 | ### 2: Documentation & FAQ 19 | 20 | - [RRManager](https://github.com/T-REX-XP/RRManager) 21 | - [rr-tools](https://github.com/RROrg/rr-tools) 22 | - [blog](https://rrorg.cn) 23 | - [docs](https://rrorg.github.io/rr-docs) 24 | - [📣](https://github.com/orgs/RROrg/discussions) 25 | 26 | ### 3: Components 27 | 28 | - During the compilation process, you need to connect to the Internet to obtain model and version information and download the corresponding ROM. 29 | If you cannot connect to the Internet, please build a pre-compiled bootloader through [RR-CUSTOM](https://rrorg.github.io/rr/). 30 | - Models: [models](https://github.com/RROrg/rr/raw/main/docs/models.xlsx) 31 | - PATs: [pats](https://github.com/RROrg/rr/raw/main/docs/pats.xlsx) 32 | - Addons: [addons](https://github.com/RROrg/rr/raw/main/docs/addons.xlsx) 33 | - Modules: [modules](https://github.com/RROrg/rr/raw/main/docs/modules.xlsx) 34 | 35 | 36 | ### 4: GPU: 37 | 38 | - vGPU: 39 | - [蔚然小站](https://blog.kkk.rs/) 40 | - [syno_nvidia_gpu_driver](https://github.com/pdbear/syno_nvidia_gpu_driver/) 41 | - iGPU: 42 | - [Jim's Blog](https://jim.plus/) 43 | - iGPU: 44 | - [intel-gpu-i915-backports](https://github.com/MoetaYuko/intel-gpu-i915-backports) 45 | 46 | ## 5: Contributing 47 | 48 | * The following is a roughly truncated guide to involve in project localization for internationalization. 49 | 50 | ```shell 51 | # If deletion nor addition proces of code hunk is not required, comply with the following process 52 | sudo apt install gettext 53 | git clone https://github.com/rrorg/rr.git 54 | cd files/initrd/opt/rr 55 | xgettext -L Shell --keyword=TEXT *.sh -o lang/rr.pot 56 | sed -i 's/charset=CHARSET/charset=UTF-8/' lang/rr.pot 57 | # If you have to replace certain language string of the project, please suggest and modify translation changes within each correlated PO file 58 | mkdir -p lang/zh_CN/LC_MESSAGES 59 | msginit -i lang/rr.pot -l zh_CN.UTF-8 -o lang/zh_CN/LC_MESSAGES/rr.po 60 | # Update translation files 61 | for I in $(find lang -path *rr.po); do msgmerge --width=256 -U ${I} lang/rr.pot; done 62 | # This formatting process will be automatically conducted during packaging. 63 | for I in $(find lang -path *rr.po); do msgfmt ${I} -o ${I/.po/.mo}; done 64 | ``` 65 | 66 | - PRs of new language translations towards the project is welcomed with appreciation. 67 | 68 | - Community maintainers of each supporting list of languages are accredited below. 69 | 70 | - `de_DE`: `@Tim Krämer`: [Tim Krämer](https://tim-kraemer.de) 71 | - `en_US`: `@rrorg` 72 | - `ja_JP`: `@andatoshiki` & `@toshikidev` 73 | - `ko_KR`: `@EXP` : jeong1986 74 | - `ru_RU`: `@Alex`: TG 75 | - `tr_TR`: `@miraç bahadır öztürk`: miracozturk 76 | - `vi_VN`: `@Ngọc Anh Trần`: mr.ngocanhtran 77 | - `zh_CN`: `@rrorg` 78 | - `zh_HK`: `@rrorg` 79 | - `zh_TW`: `@March Fun`: [豪客幫]() 80 | 81 | ### 6: Acknowledgment & Credits 82 | 83 | - [ARPL](https://github.com/fbelavenuto/arpl): `@fbelavenuto` 84 | - Redpill: `@RedPill-TTG` `@pocopico` `@jim3ma` `@fbelavenuto` `@MoetaYuko` 85 | - [RedPill-TTG](https://github.com/RedPill-TTG) 86 | - [redpill-lkm5](https://github.com/XPEnology-Community/redpill-lkm5) 87 | - [linux_dsm_epyc7002](https://github.com/MoetaYuko/linux_dsm_epyc7002) 88 | - Framework: 89 | - [Buildroot](https://github.com/buildroot/buildroot) 90 | - [Eudev](https://github.com/eudev-project/eudev) 91 | - [Grub](https://git.savannah.gnu.org/git/grub) 92 | - Addons: `@xbl3&@wirgen` `@007revad` `@PeterSuh-Q3` `@jim3ma` `@jinlife` 93 | - [synocodectool-patch](https://github.com/xbl3/synocodectool-patch) 94 | - [Synology_HDD_db](https://github.com/007revad/Synology_HDD_db) 95 | - [nvme-cache](https://github.com/PeterSuh-Q3/tcrp-addons/tree/main/nvme-cache) 96 | - [Synology_enable_M2_volume](https://github.com/007revad/Synology_enable_M2_volume) 97 | - [synology-installation-with-nvme-disks-only](https://jim.plus/blog/post/jim/synology-installation-with-nvme-disks-only) 98 | - [Synology_Photos_Face_Patch](https://github.com/jinlife/Synology_Photos_Face_Patch) 99 | - Modules:`@jim3ma` `@MoetaYuko` 100 | - [synology-igc](https://github.com/jim3ma/synology-igc) 101 | - [intel-gpu-i915-backports](https://github.com/MoetaYuko/intel-gpu-i915-backports) 102 | 103 | ### 7: Links & Community 104 | 105 | #### 7.1: Group 106 | 107 | - `QQ群1: 21609194` [`点击加入QQ群`](https://qm.qq.com/q/YTPvSXfeU0) 108 | - `QQ群2: 73119176` [`点击加入QQ群`](https://qm.qq.com/q/YV1B0NFvWK) 109 | - `QQ群3: 51929774` [`点击加入QQ群`](https://qm.qq.com/q/aVjM3Wb6KY) 110 | - `QQ群4: 49756829` [`点击加入QQ群`](https://qm.qq.com/q/9PHzmZDkqI) 111 | - `QQ群5: 30267817` [`点击加入QQ群`](https://qm.qq.com/q/6RgVDfOSXe) 112 | - `QQ群6: 68640297` [`点击加入QQ群`](https://qm.qq.com/q/PU71eSXAic) 113 | - `QQ Channel: RROrg` [`点击加入QQ频道`](https://pd.qq.com/s/aklqb0uij) 114 | - `Telegram Channel: RROrg` [`Click to join`](https://t.me/RR_Org) 115 | 116 | ### 7: Sponsoring 117 | 118 | - 119 | 120 | ### 8: License 121 | 122 | - [GPL-V3](https://github.com/RROrg/rr/blob/main/LICENSE) 123 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/TODO -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 25.6.2 2 | -------------------------------------------------------------------------------- /docs/addons.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/docs/addons.xlsx -------------------------------------------------------------------------------- /docs/changelogs.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 18 | 19 | 21 | 23 | 37 | 38 | 70 | 71 | 72 | 73 |
74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/models.json: -------------------------------------------------------------------------------- 1 | { 2 | "apollolake": { 3 | "productvers": { 4 | "7.0": "4.4.180", 5 | "7.1": "4.4.180", 6 | "7.2": "4.4.302" 7 | }, 8 | "models": [ 9 | "DS1019+", 10 | "DS620slim", 11 | "DS218+", 12 | "DS418play", 13 | "DS718+", 14 | "DS918+" 15 | ] 16 | }, 17 | "broadwell": { 18 | "productvers": { 19 | "7.0": "4.4.180", 20 | "7.1": "4.4.180", 21 | "7.2": "4.4.302" 22 | }, 23 | "models": [ 24 | "FS3400", 25 | "RS3618xs", 26 | "DS3617xs", 27 | "DS3617xsII", 28 | "FS2017", 29 | "RS18017xs+", 30 | "RS3617RPxs", 31 | "RS3617xs+", 32 | "RS4017xs+" 33 | ] 34 | }, 35 | "broadwellnk": { 36 | "productvers": { 37 | "7.0": "4.4.180", 38 | "7.1": "4.4.180", 39 | "7.2": "4.4.302" 40 | }, 41 | "models": [ 42 | "DS1621xs+", 43 | "DS3622xs+", 44 | "FS3600", 45 | "RS1619xs+", 46 | "RS3621RPxs", 47 | "RS3621xs+", 48 | "RS4021xs+", 49 | "SA3400", 50 | "SA3600", 51 | "DS3018xs", 52 | "FS1018" 53 | ] 54 | }, 55 | "broadwellnkv2": { 56 | "productvers": { 57 | "7.0": "4.4.180", 58 | "7.1": "4.4.180", 59 | "7.2": "4.4.302" 60 | }, 61 | "models": [ 62 | "FS3410", 63 | "SA3410", 64 | "SA3610" 65 | ] 66 | }, 67 | "broadwellntbap": { 68 | "productvers": { 69 | "7.0": "4.4.180", 70 | "7.1": "4.4.180", 71 | "7.2": "4.4.302" 72 | }, 73 | "models": [ 74 | "SA3200D", 75 | "SA3400D" 76 | ] 77 | }, 78 | "denverton": { 79 | "productvers": { 80 | "7.0": "4.4.180", 81 | "7.1": "4.4.180", 82 | "7.2": "4.4.302" 83 | }, 84 | "models": [ 85 | "DS1819+", 86 | "DS2419+", 87 | "DS2419+II", 88 | "DVA3219", 89 | "DVA3221", 90 | "RS820+", 91 | "RS820RP+", 92 | "DS1618+", 93 | "RS2418+", 94 | "RS2418RP+", 95 | "RS2818RP+" 96 | ] 97 | }, 98 | "geminilake": { 99 | "productvers": { 100 | "7.0": "4.4.180", 101 | "7.1": "4.4.180", 102 | "7.2": "4.4.302" 103 | }, 104 | "models": [ 105 | "DS1520+", 106 | "DS220+", 107 | "DS224+", 108 | "DS420+", 109 | "DS423+", 110 | "DS720+", 111 | "DS920+", 112 | "DVA1622" 113 | ] 114 | }, 115 | "purley": { 116 | "productvers": { 117 | "7.0": "4.4.180", 118 | "7.1": "4.4.180", 119 | "7.2": "4.4.302" 120 | }, 121 | "models": [ 122 | "HD6500", 123 | "FS6400" 124 | ] 125 | }, 126 | "r1000": { 127 | "productvers": { 128 | "7.0": "4.4.180", 129 | "7.1": "4.4.180", 130 | "7.2": "4.4.302" 131 | }, 132 | "models": [ 133 | "DS1522+", 134 | "DS723+", 135 | "DS923+", 136 | "RS422+" 137 | ] 138 | }, 139 | "v1000": { 140 | "productvers": { 141 | "7.0": "4.4.180", 142 | "7.1": "4.4.180", 143 | "7.2": "4.4.302" 144 | }, 145 | "models": [ 146 | "DS1621+", 147 | "DS1821+", 148 | "DS1823xs+", 149 | "DS2422+", 150 | "FS2500", 151 | "RS1221+", 152 | "RS1221RP+", 153 | "RS2421+", 154 | "RS2421RP+", 155 | "RS2423+", 156 | "RS2423RP+", 157 | "RS2821RP+", 158 | "RS822+", 159 | "RS822RP+" 160 | ] 161 | }, 162 | "epyc7002": { 163 | "productvers": { 164 | "7.1": "7.1-5.10.55", 165 | "7.2": "7.2-5.10.55" 166 | }, 167 | "models": [ 168 | "SA6400" 169 | ] 170 | }, 171 | "geminilakenk": { 172 | "productvers": { 173 | "7.1": "7.1-5.10.55", 174 | "7.2": "7.2-5.10.55" 175 | }, 176 | "models": [ 177 | "DS425+" 178 | ] 179 | }, 180 | "r1000nk": { 181 | "productvers": { 182 | "7.1": "7.1-5.10.55", 183 | "7.2": "7.2-5.10.55" 184 | }, 185 | "models": [ 186 | "DS725+" 187 | ] 188 | }, 189 | "v1000nk": { 190 | "productvers": { 191 | "7.1": "7.1-5.10.55", 192 | "7.2": "7.2-5.10.55" 193 | }, 194 | "models": [ 195 | "DS1525+", 196 | "DS1825+", 197 | "DS925+", 198 | "RS2825RP+" 199 | ] 200 | } 201 | } -------------------------------------------------------------------------------- /docs/models.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/docs/models.xlsx -------------------------------------------------------------------------------- /docs/modules.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/docs/modules.xlsx -------------------------------------------------------------------------------- /docs/pats.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/docs/pats.xlsx -------------------------------------------------------------------------------- /files/initrd/opt/rr/bzImage-template-v4.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/files/initrd/opt/rr/bzImage-template-v4.gz -------------------------------------------------------------------------------- /files/initrd/opt/rr/bzImage-template-v5.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/files/initrd/opt/rr/bzImage-template-v5.gz -------------------------------------------------------------------------------- /files/initrd/opt/rr/bzImage-to-vmlinux.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | read_u8() { 10 | dd if="${1}" bs=1 skip="$((${2}))" count=1 2>/dev/null | od -An -tu1 | grep -Eo '[0-9]+' 11 | } 12 | read_u32() { 13 | dd if="${1}" bs=1 skip="$((${2}))" count=4 2>/dev/null | od -An -tu4 | grep -Eo '[0-9]+' 14 | } 15 | 16 | set -x 17 | setup_size=$(read_u8 "${1}" 0x1f1) 18 | payload_offset=$(read_u32 "${1}" 0x248) 19 | payload_length=$(read_u32 "${1}" 0x24c) 20 | inner_pos=$(((setup_size + 1) * 512)) 21 | 22 | tail -c+$((inner_pos + 1)) "${1}" | tail -c+$((payload_offset + 1)) | head -c "${payload_length}" | head -c $((payload_length - 4)) | unlzma >"${2}" 23 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/extract-vmlinux: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | # ---------------------------------------------------------------------- 4 | # extract-vmlinux - Extract uncompressed vmlinux from a kernel image 5 | # 6 | # Inspired from extract-ikconfig 7 | # (c) 2009,2010 Dick Streefland 8 | # 9 | # (c) 2011 Corentin Chary 10 | # 11 | # ---------------------------------------------------------------------- 12 | 13 | check_vmlinux() { 14 | # Use readelf to check if it's a valid ELF 15 | # TODO: find a better to way to check that it's really vmlinux 16 | # and not just an elf 17 | readelf -h $1 >/dev/null 2>&1 || return 1 18 | 19 | cat $1 20 | exit 0 21 | } 22 | 23 | try_decompress() { 24 | # The obscure use of the "tr" filter is to work around older versions of 25 | # "grep" that report the byte offset of the line instead of the pattern. 26 | 27 | # Try to find the header ($1) and decompress from here 28 | for pos in $(tr "$1\n$2" "\n$2=" <"$img" | grep -abo "^$2"); do 29 | pos=${pos%%:*} 30 | tail -c+$pos "$img" | $3 >$tmp 2>/dev/null 31 | check_vmlinux $tmp 32 | done 33 | } 34 | 35 | # Check invocation: 36 | me=${0##*/} 37 | img=$1 38 | if [ $# -ne 1 ] || [ ! -s "$img" ]; then 39 | echo "Usage: $me " >&2 40 | exit 2 41 | fi 42 | 43 | # Prepare temp files: 44 | tmp=$(mktemp /tmp/vmlinux-XXX) 45 | trap "rm -f $tmp" 0 46 | 47 | # That didn't work, so retry after decompression. 48 | try_decompress '\037\213\010' xy gunzip 49 | try_decompress '\3757zXZ\000' abcde unxz 50 | try_decompress 'BZh' xy bunzip2 51 | try_decompress '\135\0\0\0' xxx unlzma 52 | try_decompress '\211\114\132' xy 'lzop -d' 53 | try_decompress '\002!L\030' xxx 'lz4 -d' 54 | try_decompress '(\265/\375' xxx unzstd 55 | 56 | # Finally check for uncompressed images or objects: 57 | check_vmlinux $img 58 | 59 | # Bail out: 60 | echo "$me: Cannot find vmlinux." >&2 61 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/grub.img.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/files/initrd/opt/rr/grub.img.gz -------------------------------------------------------------------------------- /files/initrd/opt/rr/i915ids: -------------------------------------------------------------------------------- 1 | # INTEL_I810_IDS 2 | 80867121 3 | 80867123 4 | 80867125 5 | # INTEL_I815_IDS 6 | 80861132 7 | # INTEL_I830_IDS 8 | 80863577 9 | # INTEL_I845G_IDS 10 | 80862562 11 | # INTEL_I85X_IDS 12 | 80863582 13 | 8086358e 14 | # INTEL_I865G_IDS 15 | 80862572 16 | # INTEL_I915G_IDS 17 | 80862582 18 | 8086258a 19 | # INTEL_I915GM_IDS 20 | 80862592 21 | # INTEL_I945G_IDS 22 | 80862772 23 | # INTEL_I945GM_IDS 24 | 808627a2 25 | 808627ae 26 | # INTEL_I965G_IDS 27 | 80862972 28 | 80862982 29 | 80862992 30 | 808629a2 31 | # INTEL_G33_IDS 32 | 808629b2 33 | 808629c2 34 | 808629d2 35 | # INTEL_I965GM_IDS 36 | 80862a02 37 | 80862a12 38 | # INTEL_GM45_IDS 39 | 80862a42 40 | # INTEL_G45_IDS 41 | 80862e02 42 | 80862e12 43 | 80862e22 44 | 80862e32 45 | 80862e42 46 | 80862e92 47 | # INTEL_PINEVIEW_G_IDS 48 | 8086a001 49 | # INTEL_PINEVIEW_M_IDS 50 | 8086a011 51 | # INTEL_IRONLAKE_D_IDS 52 | 80860042 53 | # INTEL_IRONLAKE_M_IDS 54 | 80860046 55 | # INTEL_SNB_D_GT1_IDS 56 | 80860102 57 | 8086010A 58 | # INTEL_SNB_D_GT2_IDS 59 | 80860112 60 | 80860122 61 | # INTEL_SNB_M_GT1_IDS 62 | 80860106 63 | # INTEL_SNB_M_GT2_IDS 64 | 80860116 65 | 80860126 66 | # INTEL_IVB_M_GT1_IDS 67 | 80860156 68 | # INTEL_IVB_M_GT2_IDS 69 | 80860166 70 | # INTEL_IVB_D_GT1_IDS 71 | 80860152 72 | 8086015a 73 | # INTEL_IVB_D_GT2_IDS 74 | 80860162 75 | 8086016a 76 | # INTEL_HSW_ULT_GT1_IDS 77 | 80860A02 78 | 80860A06 79 | 80860A0A 80 | 80860A0B 81 | # INTEL_HSW_ULX_GT1_IDS 82 | 80860A0E 83 | # INTEL_HSW_GT1_IDS 84 | 80860402 85 | 80860406 86 | 8086040A 87 | 8086040B 88 | 8086040E 89 | 80860C02 90 | 80860C06 91 | 80860C0A 92 | 80860C0B 93 | 80860C0E 94 | 80860D02 95 | 80860D06 96 | 80860D0A 97 | 80860D0B 98 | 80860D0E 99 | # INTEL_HSW_ULT_GT2_IDS 100 | 80860A12 101 | 80860A16 102 | 80860A1A 103 | 80860A1B 104 | # INTEL_HSW_ULX_GT2_IDS 105 | 80860A1E 106 | # INTEL_HSW_GT2_IDS 107 | 80860412 108 | 80860416 109 | 8086041A 110 | 8086041B 111 | 8086041E 112 | 80860C12 113 | 80860C16 114 | 80860C1A 115 | 80860C1B 116 | 80860C1E 117 | 80860D12 118 | 80860D16 119 | 80860D1A 120 | 80860D1B 121 | 80860D1E 122 | # INTEL_HSW_ULT_GT3_IDS 123 | 80860A22 124 | 80860A26 125 | 80860A2A 126 | 80860A2B 127 | 80860A2E 128 | # INTEL_HSW_GT3_IDS 129 | 80860422 130 | 80860426 131 | 8086042A 132 | 8086042B 133 | 8086042E 134 | 80860C22 135 | 80860C26 136 | 80860C2A 137 | 80860C2B 138 | 80860C2E 139 | 80860D22 140 | 80860D26 141 | 80860D2A 142 | 80860D2B 143 | 80860D2E 144 | # INTEL_VLV_IDS 145 | 80860f30 146 | 80860f31 147 | 80860f32 148 | 80860f33 149 | # INTEL_BDW_ULT_GT1_IDS 150 | 80861606 151 | 8086160B 152 | # INTEL_BDW_ULX_GT1_IDS 153 | 8086160E 154 | # INTEL_BDW_GT1_IDS 155 | 80861602 156 | 8086160A 157 | 8086160D 158 | # INTEL_BDW_ULT_GT2_IDS 159 | 80861616 160 | 8086161B 161 | # INTEL_BDW_ULX_GT2_IDS 162 | 8086161E 163 | # INTEL_BDW_GT2_IDS 164 | 80861612 165 | 8086161A 166 | 8086161D 167 | # INTEL_BDW_ULT_GT3_IDS 168 | 80861626 169 | 8086162B 170 | # INTEL_BDW_ULX_GT3_IDS 171 | 8086162E 172 | # INTEL_BDW_GT3_IDS 173 | 80861622 174 | 8086162A 175 | 8086162D 176 | # INTEL_BDW_ULT_RSVD_IDS 177 | 80861636 178 | 8086163B 179 | # INTEL_BDW_ULX_RSVD_IDS 180 | 8086163E 181 | # INTEL_BDW_RSVD_IDS 182 | 80861632 183 | 8086163A 184 | 8086163D 185 | # INTEL_CHV_IDS 186 | 808622b0 187 | 808622b1 188 | 808622b2 189 | 808622b3 190 | # INTEL_SKL_ULT_GT1_IDS 191 | 80861906 192 | 80861913~ 193 | # INTEL_SKL_ULX_GT1_IDS 194 | 8086190E 195 | 80861915~ 196 | # INTEL_SKL_GT1_IDS 197 | 80861902 198 | 8086190A 199 | 8086190B 200 | 80861917~ 201 | # INTEL_SKL_ULT_GT2_IDS 202 | 80861916 203 | 80861921 204 | # INTEL_SKL_ULX_GT2_IDS 205 | 8086191E 206 | # INTEL_SKL_GT2_IDS 207 | 80861912 208 | 8086191A 209 | 8086191B 210 | 8086191D 211 | # INTEL_SKL_ULT_GT3_IDS 212 | 80861923 213 | 80861926 214 | 80861927 215 | # INTEL_SKL_GT3_IDS 216 | 8086192A 217 | 8086192B 218 | 8086192D 219 | # INTEL_SKL_GT4_IDS 220 | 80861932 221 | 8086193A 222 | 8086193B 223 | 8086193D 224 | # INTEL_BXT_IDS 225 | 80860A84 226 | 80861A84 227 | 80861A85 228 | 80865A84 229 | 80865A85 230 | # INTEL_GLK_IDS 231 | 80863184 232 | 80863185 233 | # INTEL_KBL_ULT_GT1_IDS 234 | 80865906 235 | 80865913 236 | # INTEL_KBL_ULX_GT1_IDS 237 | 8086590E 238 | 80865915 239 | # INTEL_KBL_GT1_IDS 240 | 80865902 241 | 80865908 242 | 8086590A 243 | 8086590B 244 | # INTEL_KBL_ULT_GT2_IDS 245 | 80865916 246 | 80865921 247 | # INTEL_KBL_ULX_GT2_IDS 248 | 8086591E 249 | # INTEL_KBL_GT2_IDS 250 | 80865912 251 | 80865917 252 | 8086591A 253 | 8086591B 254 | 8086591D 255 | # INTEL_KBL_ULT_GT3_IDS 256 | 80865926 257 | # INTEL_KBL_GT3_IDS 258 | 80865923 259 | 80865927 260 | # INTEL_KBL_GT4_IDS 261 | 8086593B 262 | # INTEL_AML_KBL_GT2_IDS 263 | 8086591C 264 | 808687C0 265 | # INTEL_AML_CFL_GT2_IDS 266 | 808687CA 267 | # INTEL_CML_GT1_IDS 268 | 80869BA2 269 | 80869BA4 270 | 80869BA5 271 | 80869BA8 272 | # INTEL_CML_U_GT1_IDS 273 | 80869B21 274 | 80869BAA 275 | 80869BAC 276 | # INTEL_CML_GT2_IDS 277 | 80869BC2 278 | 80869BC4 279 | 80869BC5 280 | 80869BC6 281 | 80869BC8 282 | 80869BE6 283 | 80869BF6 284 | # INTEL_CML_U_GT2_IDS 285 | 80869B41 286 | 80869BCA 287 | 80869BCC 288 | # INTEL_CFL_S_GT1_IDS 289 | 80863E90 290 | 80863E93 291 | 80863E99 292 | # INTEL_CFL_S_GT2_IDS 293 | 80863E91 294 | 80863E92 295 | 80863E96 296 | 80863E98 297 | 80863E9A 298 | # INTEL_CFL_H_GT1_IDS 299 | 80863E9C 300 | # INTEL_CFL_H_GT2_IDS 301 | 80863E94 302 | 80863E9B 303 | # INTEL_CFL_U_GT2_IDS 304 | 80863EA9 305 | # INTEL_CFL_U_GT3_IDS 306 | 80863EA5 307 | 80863EA6 308 | 80863EA7 309 | 80863EA8 310 | # INTEL_WHL_U_GT1_IDS 311 | 80863EA1 312 | 80863EA4 313 | # INTEL_WHL_U_GT2_IDS 314 | 80863EA0 315 | 80863EA3 316 | # INTEL_WHL_U_GT3_IDS 317 | 80863EA2 318 | # INTEL_CNL_PORT_F_IDS 319 | 80865A44 320 | 80865A4C 321 | 80865A54 322 | 80865A5C 323 | # INTEL_CNL_IDS 324 | 80865A40 325 | 80865A41 326 | 80865A42 327 | 80865A49 328 | 80865A4A 329 | 80865A50 330 | 80865A51 331 | 80865A52 332 | 80865A59 333 | 80865A5A 334 | # INTEL_ICL_PORT_F_IDS 335 | 80868A50 336 | 80868A52 337 | 80868A53 338 | 80868A54 339 | 80868A56 340 | 80868A57 341 | 80868A58 342 | 80868A59 343 | 80868A5A 344 | 80868A5B 345 | 80868A5C 346 | 80868A70 347 | 80868A71 348 | # INTEL_ICL_11_IDS 349 | 80868A51 350 | 80868A5D 351 | # INTEL_EHL_IDS 352 | 80864500~ 353 | 80864541 354 | 80864551 355 | 80864555 356 | 80864557 357 | 80864570~ 358 | 80864571 359 | # INTEL_JSL_IDS 360 | 80864E51 361 | 80864E55 362 | 80864E57 363 | 80864E61 364 | 80864E71 365 | # INTEL_TGL_12_GT1_IDS 366 | 80869A60 367 | 80869A68 368 | 80869A70 369 | # INTEL_TGL_12_GT2_IDS 370 | 80869A40 371 | 80869A49 372 | 80869A59 373 | 80869A78 374 | 80869AC0 375 | 80869AC9 376 | 80869AD9 377 | 80869AF8 378 | # INTEL_RKL_IDS 379 | 80864C80 380 | 80864C8A 381 | 80864C8B 382 | 80864C8C 383 | 80864C90 384 | 80864C9A 385 | # INTEL_DG1_IDS 386 | 80864905 387 | 80864906~ 388 | 80864907~ 389 | 80864908~ 390 | 80864909~ 391 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/include/addons.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | # shellcheck disable=SC2115,SC2155 10 | 11 | ############################################################################### 12 | # Return list of available addons 13 | # 1 - Platform 14 | # 2 - Kernel Version 15 | function availableAddons() { 16 | if [ -z "${1}" ] || [ -z "${2}" ]; then 17 | echo "" 18 | return 1 19 | fi 20 | while read -r D; do 21 | [ ! -f "${D}/manifest.yml" ] && continue 22 | local ADDON=$(basename "${D}") 23 | checkAddonExist "${ADDON}" "${1}" "${2}" || continue 24 | local SYSTEM=$(readConfigKey "system" "${D}/manifest.yml") 25 | [ "${SYSTEM}" = "true" ] && continue 26 | local LOCALE="${LC_ALL%%.*}" 27 | local DESC="" 28 | [ -z "${DESC}" ] && DESC="$(readConfigKey "description.${LOCALE:-"en_US"}" "${D}/manifest.yml")" 29 | [ -z "${DESC}" ] && DESC="$(readConfigKey "description.en_US" "${D}/manifest.yml")" 30 | [ -z "${DESC}" ] && DESC="$(readConfigKey "description" "${D}/manifest.yml")" 31 | 32 | DESC="$(echo "${DESC}" | tr -d '\n\r\t\\' | sed "s/\"/'/g")" 33 | echo "${ADDON} \"${DESC:-"unknown"}\"" 34 | done <<<"$(find "${ADDONS_PATH}" -maxdepth 1 -type d 2>/dev/null | sort)" 35 | } 36 | 37 | ############################################################################### 38 | # Read Addon Key 39 | # 1 - Addon 40 | # 2 - key 41 | function readAddonKey() { 42 | if [ -z "${1}" ] || [ -z "${2}" ]; then 43 | echo "" 44 | return 1 45 | fi 46 | if [ ! -f "${ADDONS_PATH}/${1}/manifest.yml" ]; then 47 | echo "" 48 | return 1 49 | fi 50 | readConfigKey "${2}" "${ADDONS_PATH}/${1}/manifest.yml" 51 | } 52 | 53 | ############################################################################### 54 | # Check if addon exist 55 | # 1 - Addon id 56 | # 2 - Platform 57 | # 3 - Kernel Version 58 | # Return ERROR if not exists 59 | function checkAddonExist() { 60 | if [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ]; then 61 | return 1 # ERROR 62 | fi 63 | # First check generic files 64 | if [ -f "${ADDONS_PATH}/${1}/all.tgz" ]; then 65 | return 0 # OK 66 | fi 67 | # Now check specific platform file 68 | if [ -f "${ADDONS_PATH}/${1}/${2}-${3}.tgz" ]; then 69 | return 0 # OK 70 | fi 71 | return 1 # ERROR 72 | } 73 | 74 | ############################################################################### 75 | # Install Addon into ramdisk image 76 | # 1 - Addon id 77 | # 2 - Platform 78 | # 3 - Kernel Version 79 | # Return ERROR if not installed 80 | function installAddon() { 81 | if [ -z "${1}" ]; then 82 | echo "ERROR: installAddon: Addon not defined" 83 | return 1 84 | fi 85 | local ADDON="${1}" 86 | mkdir -p "${TMP_PATH}/${ADDON}" 87 | local HAS_FILES=0 88 | # First check generic files 89 | if [ -f "${ADDONS_PATH}/${ADDON}/all.tgz" ]; then 90 | tar -zxf "${ADDONS_PATH}/${ADDON}/all.tgz" -C "${TMP_PATH}/${ADDON}" 2>"${LOG_FILE}" 91 | if [ $? -ne 0 ]; then 92 | return 1 93 | fi 94 | HAS_FILES=1 95 | fi 96 | # Now check specific platform files 97 | if [ -f "${ADDONS_PATH}/${ADDON}/${2}-${3}.tgz" ]; then 98 | tar -zxf "${ADDONS_PATH}/${ADDON}/${2}-${3}.tgz" -C "${TMP_PATH}/${ADDON}" 2>"${LOG_FILE}" 99 | if [ $? -ne 0 ]; then 100 | return 1 101 | fi 102 | HAS_FILES=1 103 | fi 104 | # If has files to copy, copy it, else return error 105 | if [ ${HAS_FILES} -ne 1 ]; then 106 | echo "ERROR: installAddon: ${ADDON} addon not found" >"${LOG_FILE}" 107 | return 1 108 | fi 109 | cp -f "${TMP_PATH}/${ADDON}/install.sh" "${RAMDISK_PATH}/addons/${ADDON}.sh" 2>"${LOG_FILE}" 110 | chmod +x "${RAMDISK_PATH}/addons/${ADDON}.sh" 111 | [ -d "${TMP_PATH}/${ADDON}/root" ] && cp -rnf "${TMP_PATH}/${ADDON}/root/"* "${RAMDISK_PATH}/" 2>"${LOG_FILE}" 112 | rm -rf "${TMP_PATH}/${ADDON}" 113 | return 0 114 | } 115 | 116 | ############################################################################### 117 | # Untar an addon to correct path 118 | # 1 - Addon file path 119 | # Return name of addon on success or empty on error 120 | function untarAddon() { 121 | if [ -z "${1}" ]; then 122 | echo "" 123 | return 1 124 | fi 125 | rm -rf "${TMP_PATH}/addon" 126 | mkdir -p "${TMP_PATH}/addon" 127 | tar -xaf "${1}" -C "${TMP_PATH}/addon" || return 1 128 | local ADDON=$(readConfigKey "name" "${TMP_PATH}/addon/manifest.yml") 129 | [ -z "${ADDON}" ] && return 1 130 | rm -rf "${ADDONS_PATH}/${ADDON}" 131 | mv -f "${TMP_PATH}/addon" "${ADDONS_PATH}/${ADDON}" 132 | echo "${ADDON}" 133 | return 0 134 | } 135 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/include/configFile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | ############################################################################### 10 | # Delete a key in config file 11 | # 1 - Path of Key 12 | # 2 - Path of yaml config file 13 | function deleteConfigKey() { 14 | yq eval "del(.${1})" --inplace "${2}" 2>/dev/null 15 | } 16 | 17 | ############################################################################### 18 | # Write to yaml config file 19 | # 1 - Path of Key 20 | # 2 - Value 21 | # 3 - Path of yaml config file 22 | function writeConfigKey() { 23 | local value="${2}" 24 | [ "${value}" = "{}" ] && yq eval ".${1} = {}" --inplace "${3}" 2>/dev/null || yq eval ".${1} = \"${value}\"" --inplace "${3}" 2>/dev/null 25 | } 26 | 27 | ############################################################################### 28 | # Read key value from yaml config file 29 | # 1 - Path of key 30 | # 2 - Path of yaml config file 31 | # Return Value 32 | function readConfigKey() { 33 | local result 34 | result=$(yq eval ".${1} | explode(.)" "${2}" 2>/dev/null) 35 | [ "${result}" = "null" ] && echo "" || echo "${result}" 36 | } 37 | 38 | ############################################################################### 39 | # Write to yaml config file 40 | # 1 - Modules 41 | # 2 - Path of yaml config file 42 | function mergeConfigModules() { 43 | # Error: bad file '-': cannot index array with '8139cp' (strconv.ParseInt: parsing "8139cp": invalid syntax) 44 | # When the first key is a pure number, yq will not process it as a string by default. The current solution is to insert a placeholder key. 45 | local MS ML XF 46 | MS="RRORG\n${1// /\\n}" 47 | ML="$(echo -en "${MS}" | awk '{print "modules."$1":"}')" 48 | XF=$(mktemp 2>/dev/null) 49 | XF=${XF:-/tmp/tmp.XXXXXXXXXX} 50 | echo -en "${ML}" | yq -p p -o y >"${XF}" 51 | deleteConfigKey "modules.\"RRORG\"" "${XF}" 52 | yq eval-all --inplace '. as $item ireduce ({}; . * $item)' --inplace "${2}" "${XF}" 2>/dev/null 53 | rm -f "${XF}" 54 | } 55 | 56 | ############################################################################### 57 | # Write to yaml config file if key not exists 58 | # 1 - Path of Key 59 | # 2 - Value 60 | # 3 - Path of yaml config file 61 | function initConfigKey() { 62 | [ -z "$(readConfigKey "${1}" "${3}")" ] && writeConfigKey "${1}" "${2}" "${3}" || true 63 | } 64 | 65 | ############################################################################### 66 | # Read Entries as map(key=value) from yaml config file 67 | # 1 - Path of key 68 | # 2 - Path of yaml config file 69 | # Returns map of values 70 | function readConfigMap() { 71 | yq eval ".${1} | explode(.) | to_entries | map([.key, .value] | join(\": \")) | .[]" "${2}" 2>/dev/null 72 | } 73 | 74 | ############################################################################### 75 | # Read an array from yaml config file 76 | # 1 - Path of key 77 | # 2 - Path of yaml config file 78 | # Returns array/map of values 79 | function readConfigArray() { 80 | yq eval ".${1}[]" "${2}" 2>/dev/null 81 | } 82 | 83 | ############################################################################### 84 | # Read Entries as array from yaml config file 85 | # 1 - Path of key 86 | # 2 - Path of yaml config file 87 | # Returns array of values 88 | function readConfigEntriesArray() { 89 | yq eval ".${1} | explode(.) | to_entries | map([.key])[] | .[]" "${2}" 2>/dev/null 90 | } 91 | 92 | ############################################################################### 93 | # Check yaml config file 94 | # 1 - Path of yaml config file 95 | # Returns error information 96 | function checkConfigFile() { 97 | yq eval "${1}" 2>&1 98 | } 99 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/include/consts.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | # shellcheck disable=SC2034 10 | 11 | RR_VERSION="25.6.2" 12 | RR_RELEASE="" 13 | RR_TITLE="RR v${RR_VERSION}" 14 | 15 | # Define paths 16 | # CHROOT_PATH: Defined during PC debugging. 17 | PART1_PATH="${CHROOT_PATH}/mnt/p1" 18 | PART2_PATH="${CHROOT_PATH}/mnt/p2" 19 | PART3_PATH="${CHROOT_PATH}/mnt/p3" 20 | TMP_PATH="${CHROOT_PATH}/tmp" 21 | 22 | UNTAR_PAT_PATH="${TMP_PATH}/pat" 23 | RAMDISK_PATH="${TMP_PATH}/ramdisk" 24 | LOG_FILE="${TMP_PATH}/log.txt" 25 | 26 | USER_GRUB_CONFIG="${PART1_PATH}/boot/grub/grub.cfg" 27 | USER_GRUBENVFILE="${PART1_PATH}/boot/grub/grubenv" 28 | USER_RSYSENVFILE="${PART1_PATH}/boot/grub/rsysenv" 29 | USER_CONFIG_FILE="${PART1_PATH}/user-config.yml" 30 | USER_LOCALE_FILE="${PART1_PATH}/.locale" 31 | 32 | ORI_ZIMAGE_FILE="${PART2_PATH}/zImage" 33 | ORI_RDGZ_FILE="${PART2_PATH}/rd.gz" 34 | 35 | RR_BZIMAGE_FILE="${PART3_PATH}/bzImage-rr" 36 | RR_RAMDISK_FILE="${PART3_PATH}/initrd-rr" 37 | RR_RAMUSER_FILE="${PART3_PATH}/initrd-rru" 38 | MC_RAMDISK_FILE="${PART3_PATH}/microcode.img" 39 | MOD_ZIMAGE_FILE="${PART3_PATH}/zImage-dsm" 40 | MOD_RDGZ_FILE="${PART3_PATH}/initrd-dsm" 41 | 42 | CKS_PATH="${PART3_PATH}/cks" 43 | LKMS_PATH="${PART3_PATH}/lkms" 44 | ADDONS_PATH="${PART3_PATH}/addons" 45 | MODULES_PATH="${PART3_PATH}/modules" 46 | USER_UP_PATH="${PART3_PATH}/users" 47 | SCRIPTS_PATH="${PART3_PATH}/scripts" 48 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/include/functions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | # This script is a CLI to RR. 9 | # 10 | # # Backup the original python3 executable. 11 | # sudo mv -f "$(realpath $(which python3))/EXTERNALLY-MANAGED" "$(realpath $(which python3))/EXTERNALLY-MANAGED.bak" 2>/dev/null || true 12 | # sudo pip3 install -U click requests requests-toolbelt qrcode[pil] beautifulsoup4 13 | 14 | import os, click 15 | 16 | WORK_PATH = os.path.abspath(os.path.dirname(__file__)) 17 | 18 | 19 | @click.group() 20 | def cli(): 21 | """ 22 | The CLI is a commands to RR. 23 | """ 24 | pass 25 | 26 | 27 | def mutually_exclusive_options(ctx, param, value): 28 | other_option = "file" if param.name == "data" else "data" 29 | if value is not None and ctx.params.get(other_option) is not None: 30 | raise click.UsageError(f"Illegal usage: `{param.name}` is mutually exclusive with `{other_option}`.") 31 | return value 32 | 33 | 34 | def validate_required_param(ctx, param, value): 35 | if not value and "file" not in ctx.params and "data" not in ctx.params: 36 | raise click.MissingParameter(param_decls=[param.name]) 37 | return value 38 | 39 | 40 | def __fullversion(ver): 41 | arr = ver.split('-') 42 | a, b, c = (arr[0].split('.') + ['0', '0', '0'])[:3] 43 | d = arr[1] if len(arr) > 1 else '00000' 44 | e = arr[2] if len(arr) > 2 else '0' 45 | return f'{a}.{b}.{c}-{d}-{e}' 46 | 47 | 48 | @cli.command() 49 | @click.option("-d", "--data", type=str, callback=mutually_exclusive_options, is_eager=True, help="The data of QRCode.") 50 | @click.option("-f", "--file", type=str, callback=mutually_exclusive_options, is_eager=True, help="The file of QRCode.") 51 | @click.option("--validate", is_flag=True, callback=validate_required_param, expose_value=False, is_eager=True) 52 | @click.option("-l", "--location", type=click.IntRange(0, 7), required=True, help="The location of QRCode. (range 0<=x<=7)") 53 | @click.option("-o", "--output", type=str, required=True, help="The output file of QRCode.") 54 | def makeqr(data, file, location, output): 55 | """ 56 | Generate a QRCode. 57 | """ 58 | try: 59 | import fcntl, struct 60 | import qrcode 61 | from PIL import Image 62 | 63 | FBIOGET_VSCREENINFO = 0x4600 64 | FBIOPUT_VSCREENINFO = 0x4601 65 | FBIOGET_FSCREENINFO = 0x4602 66 | FBDEV = "/dev/fb0" 67 | 68 | if data: 69 | qr = qrcode.QRCode(version=1, box_size=10, error_correction=qrcode.constants.ERROR_CORRECT_H, border=4) 70 | qr.add_data(data) 71 | qr.make(fit=True) 72 | img = qr.make_image(fill_color="purple", back_color="white").convert("RGBA") 73 | pixels = img.load() 74 | for i in range(img.size[0]): 75 | for j in range(img.size[1]): 76 | if pixels[i, j] == (255, 255, 255, 255): 77 | pixels[i, j] = (255, 255, 255, 0) 78 | 79 | logo_path = os.path.join(WORK_PATH, "logo.png") 80 | if os.path.exists(logo_path): 81 | icon = Image.open(logo_path).convert("RGBA") 82 | img.paste(icon.resize((img.size[0] // 5, img.size[1] // 5)), ((img.size[0] - img.size[0] // 5) // 2, (img.size[1] - img.size[1] // 5) // 2)) 83 | 84 | elif file: 85 | img = Image.open(file) 86 | # img = img.convert("RGBA") 87 | # pixels = img.load() 88 | # for i in range(img.size[0]): 89 | # for j in range(img.size[1]): 90 | # if pixels[i, j] == (255, 255, 255, 255): 91 | # pixels[i, j] = (255, 255, 255, 0) 92 | else: 93 | raise click.UsageError("Either data or file must be provided.") 94 | 95 | with open(FBDEV, "rb") as fb: 96 | vi = fcntl.ioctl(fb, FBIOGET_VSCREENINFO, bytes(160)) 97 | res = struct.unpack("I" * 40, vi) 98 | xres, yres = res[0], res[1] if res[0] and res[1] else (1920, 1080) 99 | 100 | img = img.resize((xres // 8, xres // 8)) 101 | alpha = Image.new("RGBA", (xres, yres), (0, 0, 0, 0)) 102 | loc = (img.size[0] * location, alpha.size[1] - img.size[1]) 103 | alpha.paste(img, loc) 104 | alpha.save(output) 105 | 106 | except Exception as e: 107 | click.echo(f"Error: {e}") 108 | 109 | 110 | @cli.command() 111 | @click.option("-p", "--platforms", type=str, help="The platforms of Syno.") 112 | def getmodels(platforms=None): 113 | """ 114 | Get Syno Models. 115 | """ 116 | import re, json, requests, urllib3 117 | from requests.adapters import HTTPAdapter 118 | from requests.packages.urllib3.util.retry import Retry # type: ignore 119 | 120 | adapter = HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504])) 121 | session = requests.Session() 122 | session.mount("http://", adapter) 123 | session.mount("https://", adapter) 124 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 125 | 126 | PS = platforms.lower().replace(",", " ").split() if platforms else [] 127 | 128 | models = [] 129 | try: 130 | url = "http://update7.synology.com/autoupdate/genRSS.php?include_beta=1" 131 | #url = "https://update7.synology.com/autoupdate/genRSS.php?include_beta=1" 132 | 133 | req = session.get(url, timeout=10, verify=False) 134 | req.encoding = "utf-8" 135 | p = re.compile(r"(.*?).*?(.*?)", re.MULTILINE | re.DOTALL) 136 | data = p.findall(req.text) 137 | for item in data: 138 | if not "DSM" in item[1]: 139 | continue 140 | arch = item[0].split("_")[1] 141 | name = item[1].split("/")[-1].split("_")[1].replace("%2B", "+") 142 | if PS and arch.lower() not in PS: 143 | continue 144 | if not any(m["name"] == name for m in models): 145 | models.append({"name": name, "arch": arch}) 146 | 147 | models.sort(key=lambda k: (k["arch"], k["name"])) 148 | 149 | except Exception as e: 150 | # click.echo(f"Error: {e}") 151 | pass 152 | 153 | print(json.dumps(models, indent=4)) 154 | 155 | 156 | @cli.command() 157 | @click.option("-p", "--platforms", type=str, help="The platforms of Syno.") 158 | def getmodelsbykb(platforms=None): 159 | """ 160 | Get Syno Models. 161 | """ 162 | import re, json, requests, urllib3 163 | from bs4 import BeautifulSoup 164 | from requests.adapters import HTTPAdapter 165 | from requests.packages.urllib3.util.retry import Retry # type: ignore 166 | 167 | adapter = HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504])) 168 | session = requests.Session() 169 | session.mount("http://", adapter) 170 | session.mount("https://", adapter) 171 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 172 | 173 | PS = platforms.lower().replace(",", " ").split() if platforms else [] 174 | 175 | models = [] 176 | try: 177 | url = "https://kb.synology.com/en-us/DSM/tutorial/What_kind_of_CPU_does_my_NAS_have" 178 | #url = "https://kb.synology.cn/zh-cn/DSM/tutorial/What_kind_of_CPU_does_my_NAS_have" 179 | 180 | req = session.get(url, timeout=10, verify=False) 181 | req.encoding = "utf-8" 182 | bs = BeautifulSoup(req.text, "html.parser") 183 | p = re.compile(r"data: (.*?),$", re.MULTILINE | re.DOTALL) 184 | data = json.loads(p.search(bs.find("script", string=p).prettify()).group(1)) 185 | model = "(.*?)" # (.*?): all, FS6400: one 186 | p = re.compile(r"{}<\/td>(.*?)<\/td>(.*?)<\/td>(.*?)<\/td>(.*?)<\/td>(.*?)<\/td>(.*?)<\/td>".format(model), re.MULTILINE | re.DOTALL) 187 | it = p.finditer(data["preload"]["content"].replace("\n", "").replace("\t", "")) 188 | for i in it: 189 | d = i.groups() 190 | if len(d) == 6: 191 | d = model + d 192 | if PS and d[5].lower() not in PS: 193 | continue 194 | models.append({"name": d[0].split(" 0 else "" 225 | minor = f"&minor={version.split('.')[1]}" if len(version.split('.')) > 1 else "" 226 | req = session.get(f"{urlInfo}&product={model.replace('+', '%2B')}{major}{minor}", timeout=10, verify=False) 227 | req.encoding = "utf-8" 228 | data = json.loads(req.text) 229 | 230 | build_ver = data['info']['system']['detail'][0]['items'][0]['build_ver'] 231 | build_num = data['info']['system']['detail'][0]['items'][0]['build_num'] 232 | buildnano = data['info']['system']['detail'][0]['items'][0]['nano'] 233 | V = __fullversion(f"{build_ver}-{build_num}-{buildnano}") 234 | if V not in pats: 235 | pats[V] = { 236 | 'url': data['info']['system']['detail'][0]['items'][0]['files'][0]['url'].split('?')[0], 237 | 'sum': data['info']['system']['detail'][0]['items'][0]['files'][0].get('checksum', '0' * 32) 238 | } 239 | 240 | from_ver = min(I['build'] for I in data['info']['pubVers']) 241 | 242 | for I in data['info']['productVers']: 243 | if not I['version'].startswith(version): 244 | continue 245 | if not major or not minor: 246 | majorTmp = f"&major={I['version'].split('.')[0]}" if len(I['version'].split('.')) > 0 else "" 247 | minorTmp = f"&minor={I['version'].split('.')[1]}" if len(I['version'].split('.')) > 1 else "" 248 | reqTmp = session.get(f"{urlInfo}&product={model.replace('+', '%2B')}{majorTmp}{minorTmp}", timeout=10, verify=False) 249 | reqTmp.encoding = "utf-8" 250 | dataTmp = json.loads(reqTmp.text) 251 | 252 | build_ver = dataTmp['info']['system']['detail'][0]['items'][0]['build_ver'] 253 | build_num = dataTmp['info']['system']['detail'][0]['items'][0]['build_num'] 254 | buildnano = dataTmp['info']['system']['detail'][0]['items'][0]['nano'] 255 | V = __fullversion(f"{build_ver}-{build_num}-{buildnano}") 256 | if V not in pats: 257 | pats[V] = { 258 | 'url': dataTmp['info']['system']['detail'][0]['items'][0]['files'][0]['url'].split('?')[0], 259 | 'sum': dataTmp['info']['system']['detail'][0]['items'][0]['files'][0].get('checksum', '0' * 32) 260 | } 261 | 262 | for J in I['versions']: 263 | to_ver = J['build'] 264 | reqSteps = session.get(f"{urlSteps}&product={model.replace('+', '%2B')}&from_ver={from_ver}&to_ver={to_ver}", timeout=10, verify=False) 265 | if reqSteps.status_code != 200: 266 | continue 267 | reqSteps.encoding = "utf-8" 268 | dataSteps = json.loads(reqSteps.text) 269 | for S in dataSteps['upgrade_steps']: 270 | if not S.get('full_patch') or not S['build_ver'].startswith(version): 271 | continue 272 | V = __fullversion(f"{S['build_ver']}-{S['build_num']}-{S['nano']}") 273 | if V not in pats: 274 | reqPat = session.head(S['files'][0]['url'].split('?')[0], timeout=10, verify=False) 275 | if reqPat.status_code == 403: 276 | continue 277 | pats[V] = { 278 | 'url': S['files'][0]['url'].split('?')[0], 279 | 'sum': S['files'][0].get('checksum', '0' * 32) 280 | } 281 | except Exception as e: 282 | # click.echo(f"Error: {e}") 283 | pass 284 | 285 | pats = {k: pats[k] for k in sorted(pats.keys(), reverse=True)} 286 | print(json.dumps(pats, indent=4)) 287 | 288 | 289 | @cli.command() 290 | @click.option("-p", "--models", type=str, help="The models of Syno.") 291 | def getpats(models=None): 292 | import re, json, requests, urllib3 293 | from bs4 import BeautifulSoup 294 | from requests.adapters import HTTPAdapter 295 | from requests.packages.urllib3.util.retry import Retry # type: ignore 296 | 297 | adapter = HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504])) 298 | session = requests.Session() 299 | session.mount("http://", adapter) 300 | session.mount("https://", adapter) 301 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 302 | 303 | MS = models.lower().replace(",", " ").split() if models else [] 304 | 305 | pats = {} 306 | try: 307 | req = session.get('https://archive.synology.com/download/Os/DSM', timeout=10, verify=False) 308 | req.encoding = 'utf-8' 309 | bs = BeautifulSoup(req.text, 'html.parser') 310 | p = re.compile(r"(.*?)-(.*?)", re.MULTILINE | re.DOTALL) 311 | l = bs.find_all('a', string=p) 312 | for i in l: 313 | ver = i.attrs['href'].split('/')[-1] 314 | if not ver.startswith('7'): 315 | continue 316 | req = session.get(f'https://archive.synology.com{i.attrs["href"]}', timeout=10, verify=False) 317 | req.encoding = 'utf-8' 318 | bs = BeautifulSoup(req.text, 'html.parser') 319 | p = re.compile(r"DSM_(.*?)_(.*?).pat", re.MULTILINE | re.DOTALL) 320 | data = bs.find_all('a', string=p) 321 | for item in data: 322 | rels = p.search(item.attrs['href']) 323 | if rels: 324 | model, _ = rels.groups() 325 | model = model.replace('%2B', '+') 326 | if MS and model.lower() not in MS: 327 | continue 328 | if model not in pats: 329 | pats[model] = {} 330 | pats[model][__fullversion(ver)] = item.attrs['href'] 331 | except Exception as e: 332 | # click.echo(f"Error: {e}") 333 | pass 334 | 335 | print(json.dumps(pats, indent=4)) 336 | 337 | 338 | if __name__ == "__main__": 339 | cli() 340 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/include/i18n.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | [ -z "${WORK_PATH}" ] || [ ! -d "${WORK_PATH}/include" ] && WORK_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/../" >/dev/null 2>&1 && pwd)" 10 | 11 | type gettext >/dev/null 2>&1 && alias TEXT='gettext "rr"' || alias TEXT='echo' 12 | shopt -s expand_aliases 13 | 14 | [ -d "${WORK_PATH}/lang" ] && export TEXTDOMAINDIR="${WORK_PATH}/lang" 15 | [ -f "${PART1_PATH}/.locale" ] && LC_ALL="$(cat "${PART1_PATH}/.locale")" && export LC_ALL="${LC_ALL}" 16 | 17 | if [ -f "${PART1_PATH}/.timezone" ]; then 18 | TIMEZONE="$(cat "${PART1_PATH}/.timezone")" 19 | if [ -f "/usr/share/zoneinfo/right/${TIMEZONE}" ]; then 20 | ln -sf "/usr/share/zoneinfo/right/${TIMEZONE}" /etc/localtime 21 | fi 22 | fi 23 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/include/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/files/initrd/opt/rr/include/logo.png -------------------------------------------------------------------------------- /files/initrd/opt/rr/include/modules.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | ############################################################################### 10 | # Unpack modules from a tgz file 11 | # 1 - Platform 12 | # 2 - Kernel Version 13 | function unpackModules() { 14 | local PLATFORM=${1} 15 | local PKVER=${2} 16 | local KERNEL 17 | KERNEL="$(readConfigKey "kernel" "${USER_CONFIG_FILE}")" 18 | 19 | rm -rf "${TMP_PATH}/modules" 20 | mkdir -p "${TMP_PATH}/modules" 21 | if [ "${KERNEL}" = "custom" ]; then 22 | tar -zxf "${CKS_PATH}/modules-${PLATFORM}-${PKVER}.tgz" -C "${TMP_PATH}/modules" 23 | else 24 | tar -zxf "${MODULES_PATH}/${PLATFORM}-${PKVER}.tgz" -C "${TMP_PATH}/modules" 25 | fi 26 | } 27 | 28 | ############################################################################### 29 | # Packag modules to a tgz file 30 | # 1 - Platform 31 | # 2 - Kernel Version 32 | function packagModules() { 33 | local PLATFORM=${1} 34 | local PKVER=${2} 35 | local KERNEL 36 | KERNEL="$(readConfigKey "kernel" "${USER_CONFIG_FILE}")" 37 | 38 | if [ "${KERNEL}" = "custom" ]; then 39 | tar -zcf "${CKS_PATH}/modules-${PLATFORM}-${PKVER}.tgz" -C "${TMP_PATH}/modules" . 40 | else 41 | tar -zcf "${MODULES_PATH}/${PLATFORM}-${PKVER}.tgz" -C "${TMP_PATH}/modules" . 42 | fi 43 | } 44 | 45 | ############################################################################### 46 | # Return list of all modules available 47 | # 1 - Platform 48 | # 2 - Kernel Version 49 | function getAllModules() { 50 | local PLATFORM=${1} 51 | local PKVER=${2} 52 | 53 | if [ -z "${PLATFORM}" ] || [ -z "${PKVER}" ]; then 54 | return 1 55 | fi 56 | 57 | unpackModules "${PLATFORM}" "${PKVER}" 58 | 59 | for F in ${TMP_PATH}/modules/*.ko; do 60 | [ ! -e "${F}" ] && continue 61 | local N DESC 62 | N="$(basename "${F}" .ko)" 63 | DESC="$(modinfo -F description "${F}" 2>/dev/null)" 64 | DESC="$(echo "${DESC}" | tr -d '\n\r\t\\' | sed "s/\"/'/g")" 65 | echo "${N} \"${DESC:-${N}}\"" 66 | done 67 | 68 | rm -rf "${TMP_PATH}/modules" 69 | } 70 | 71 | ############################################################################### 72 | # Return list of all modules available 73 | # 1 - Platform 74 | # 2 - Kernel Version 75 | # 3 - Module list 76 | function installModules() { 77 | local PLATFORM=${1} 78 | local PKVER=${2} 79 | 80 | if [ -z "${PLATFORM}" ] || [ -z "${PKVER}" ]; then 81 | echo "ERROR: installModules: Platform or Kernel Version not defined" >"${LOG_FILE}" 82 | return 1 83 | fi 84 | local MLIST ODP KERNEL 85 | shift 2 86 | MLIST="${*}" 87 | 88 | unpackModules "${PLATFORM}" "${PKVER}" 89 | 90 | ODP="$(readConfigKey "odp" "${USER_CONFIG_FILE}")" 91 | for F in ${TMP_PATH}/modules/*.ko; do 92 | [ ! -e "${F}" ] && continue 93 | M=$(basename "${F}") 94 | [ "${ODP}" = "true" ] && [ -f "${RAMDISK_PATH}/usr/lib/modules/${M}" ] && continue 95 | if echo "${MLIST}" | grep -wq "$(basename "${M}" .ko)"; then 96 | cp -f "${F}" "${RAMDISK_PATH}/usr/lib/modules/${M}" 2>"${LOG_FILE}" 97 | else 98 | rm -f "${RAMDISK_PATH}/usr/lib/modules/${M}" 2>"${LOG_FILE}" 99 | fi 100 | done 101 | 102 | mkdir -p "${RAMDISK_PATH}/usr/lib/firmware" 103 | KERNEL=$(readConfigKey "kernel" "${USER_CONFIG_FILE}") 104 | if [ "${KERNEL}" = "custom" ]; then 105 | tar -zxf "${CKS_PATH}/firmware.tgz" -C "${RAMDISK_PATH}/usr/lib/firmware" 2>"${LOG_FILE}" 106 | else 107 | tar -zxf "${MODULES_PATH}/firmware.tgz" -C "${RAMDISK_PATH}/usr/lib/firmware" 2>"${LOG_FILE}" 108 | fi 109 | if [ $? -ne 0 ]; then 110 | return 1 111 | fi 112 | 113 | rm -rf "${TMP_PATH}/modules" 114 | return 0 115 | } 116 | 117 | ############################################################################### 118 | # add a ko of modules.tgz 119 | # 1 - Platform 120 | # 2 - Kernel Version 121 | # 3 - ko file 122 | function addToModules() { 123 | local PLATFORM=${1} 124 | local PKVER=${2} 125 | local KOFILE=${3} 126 | 127 | if [ -z "${PLATFORM}" ] || [ -z "${PKVER}" ] || [ -z "${KOFILE}" ]; then 128 | echo "" 129 | return 1 130 | fi 131 | 132 | unpackModules "${PLATFORM}" "${PKVER}" 133 | 134 | cp -f "${KOFILE}" "${TMP_PATH}/modules" 135 | 136 | packagModules "${PLATFORM}" "${PKVER}" 137 | } 138 | 139 | ############################################################################### 140 | # del a ko of modules.tgz 141 | # 1 - Platform 142 | # 2 - Kernel Version 143 | # 3 - ko name 144 | function delToModules() { 145 | local PLATFORM=${1} 146 | local PKVER=${2} 147 | local KONAME=${3} 148 | 149 | if [ -z "${PLATFORM}" ] || [ -z "${PKVER}" ] || [ -z "${KONAME}" ]; then 150 | echo "" 151 | return 1 152 | fi 153 | 154 | unpackModules "${PLATFORM}" "${PKVER}" 155 | 156 | rm -f "${TMP_PATH}/modules/${KONAME}" 157 | 158 | packagModules "${PLATFORM}" "${PKVER}" 159 | } 160 | 161 | ############################################################################### 162 | # get depends of ko 163 | # 1 - Platform 164 | # 2 - Kernel Version 165 | # 3 - ko name 166 | function getdepends() { 167 | function _getdepends() { 168 | if [ -f "${TMP_PATH}/modules/${1}.ko" ]; then 169 | local depends 170 | depends="$(modinfo -F depends "${TMP_PATH}/modules/${1}.ko" 2>/dev/null | sed 's/,/\n/g')" 171 | if [ "$(echo "${depends}" | wc -w)" -gt 0 ]; then 172 | for k in ${depends}; do 173 | echo "${k}" 174 | _getdepends "${k}" 175 | done 176 | fi 177 | fi 178 | } 179 | 180 | local PLATFORM=${1} 181 | local PKVER=${2} 182 | local KONAME=${3} 183 | 184 | if [ -z "${PLATFORM}" ] || [ -z "${PKVER}" ] || [ -z "${KONAME}" ]; then 185 | echo "" 186 | return 1 187 | fi 188 | 189 | unpackModules "${PLATFORM}" "${PKVER}" 190 | 191 | _getdepends "${KONAME}" | sort -u 192 | echo "${KONAME}" 193 | rm -rf "${TMP_PATH}/modules" 194 | } 195 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/include/qhxg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/files/initrd/opt/rr/include/qhxg.png -------------------------------------------------------------------------------- /files/initrd/opt/rr/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | set -e 10 | [ -z "${WORK_PATH}" ] || [ ! -d "${WORK_PATH}/include" ] && WORK_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" 11 | 12 | . "${WORK_PATH}/include/functions.sh" 13 | . "${WORK_PATH}/include/addons.sh" 14 | 15 | if type vmware-toolbox-cmd >/dev/null 2>&1; then 16 | if [ "Disable" = "$(vmware-toolbox-cmd timesync status 2>/dev/null)" ]; then 17 | vmware-toolbox-cmd timesync enable >/dev/null 2>&1 || true 18 | fi 19 | if [ "Enabled" = "$(vmware-toolbox-cmd timesync status 2>/dev/null)" ]; then 20 | vmware-toolbox-cmd timesync disable >/dev/null 2>&1 || true 21 | fi 22 | fi 23 | 24 | [ -z "${LOADER_DISK}" ] && die "$(TEXT "Loader is not init!")" 25 | checkBootLoader || die "$(TEXT "The loader is corrupted, please rewrite it!")" 26 | 27 | # Shows title 28 | clear 29 | COLUMNS=$(ttysize 2>/dev/null | awk '{print $1}') 30 | COLUMNS=${COLUMNS:-80} 31 | TITLE="$(printf "$(TEXT "Welcome to %s")" "${RR_TITLE}${RR_RELEASE:+(${RR_RELEASE})}")" 32 | DATE="$(date)" 33 | printf "\033[1;44m%*s\n" "${COLUMNS}" "" 34 | printf "\033[1;44m%*s\033[A\n" "${COLUMNS}" "" 35 | printf "\033[1;31m%*s\033[0m\n" "$(((${#TITLE} + ${COLUMNS}) / 2))" "${TITLE}" 36 | printf "\033[1;44m%*s\033[A\n" "${COLUMNS}" "" 37 | printf "\033[1;32m%*s\033[0m\n" "${COLUMNS}" "${DATE}" 38 | 39 | # Get first MAC address 40 | ETHX="$(find /sys/class/net/ -mindepth 1 -maxdepth 1 ! -name lo -exec basename {} \; | sort)" 41 | # No network devices 42 | [ "$(echo "${ETHX}" | wc -w)" -le 0 ] && die "$(TEXT "Network devices not found! Please re execute init.sh after connecting to the network!")" 43 | 44 | # If user config file not exists, initialize it 45 | if [ ! -f "${USER_CONFIG_FILE}" ]; then 46 | touch "${USER_CONFIG_FILE}" 47 | fi 48 | 49 | initConfigKey "kernel" "official" "${USER_CONFIG_FILE}" 50 | initConfigKey "rd-compressed" "false" "${USER_CONFIG_FILE}" 51 | initConfigKey "satadom" "2" "${USER_CONFIG_FILE}" 52 | initConfigKey "lkm" "prod" "${USER_CONFIG_FILE}" 53 | initConfigKey "dsmlogo" "true" "${USER_CONFIG_FILE}" 54 | initConfigKey "directboot" "false" "${USER_CONFIG_FILE}" 55 | initConfigKey "prerelease" "false" "${USER_CONFIG_FILE}" 56 | initConfigKey "bootwait" "10" "${USER_CONFIG_FILE}" 57 | initConfigKey "bootipwait" "10" "${USER_CONFIG_FILE}" 58 | initConfigKey "kernelway" "power" "${USER_CONFIG_FILE}" 59 | initConfigKey "kernelpanic" "5" "${USER_CONFIG_FILE}" 60 | initConfigKey "odp" "false" "${USER_CONFIG_FILE}" 61 | initConfigKey "hddsort" "false" "${USER_CONFIG_FILE}" 62 | initConfigKey "usbasinternal" "false" "${USER_CONFIG_FILE}" 63 | initConfigKey "emmcboot" "false" "${USER_CONFIG_FILE}" 64 | initConfigKey "platform" "" "${USER_CONFIG_FILE}" 65 | initConfigKey "model" "" "${USER_CONFIG_FILE}" 66 | initConfigKey "modelid" "" "${USER_CONFIG_FILE}" 67 | initConfigKey "productver" "" "${USER_CONFIG_FILE}" 68 | initConfigKey "buildnum" "" "${USER_CONFIG_FILE}" 69 | initConfigKey "smallnum" "" "${USER_CONFIG_FILE}" 70 | initConfigKey "dt" "" "${USER_CONFIG_FILE}" 71 | initConfigKey "kver" "" "${USER_CONFIG_FILE}" 72 | initConfigKey "kpre" "" "${USER_CONFIG_FILE}" 73 | initConfigKey "paturl" "" "${USER_CONFIG_FILE}" 74 | initConfigKey "patsum" "" "${USER_CONFIG_FILE}" 75 | initConfigKey "sn" "" "${USER_CONFIG_FILE}" 76 | initConfigKey "mac1" "" "${USER_CONFIG_FILE}" 77 | initConfigKey "mac2" "" "${USER_CONFIG_FILE}" 78 | initConfigKey "layout" "qwerty" "${USER_CONFIG_FILE}" 79 | initConfigKey "keymap" "" "${USER_CONFIG_FILE}" 80 | initConfigKey "zimage-hash" "" "${USER_CONFIG_FILE}" 81 | initConfigKey "ramdisk-hash" "" "${USER_CONFIG_FILE}" 82 | initConfigKey "cmdline" "{}" "${USER_CONFIG_FILE}" 83 | initConfigKey "synoinfo" "{}" "${USER_CONFIG_FILE}" 84 | initConfigKey "addons" "{}" "${USER_CONFIG_FILE}" 85 | if [ -z "$(readConfigMap "addons" "${USER_CONFIG_FILE}")" ]; then 86 | initConfigKey "addons.acpid" "" "${USER_CONFIG_FILE}" 87 | initConfigKey "addons.trivial" "" "${USER_CONFIG_FILE}" 88 | initConfigKey "addons.vmtools" "" "${USER_CONFIG_FILE}" 89 | initConfigKey "addons.mountloader" "" "${USER_CONFIG_FILE}" 90 | initConfigKey "addons.powersched" "" "${USER_CONFIG_FILE}" 91 | initConfigKey "addons.reboottoloader" "" "${USER_CONFIG_FILE}" 92 | fi 93 | initConfigKey "modules" "{}" "${USER_CONFIG_FILE}" 94 | initConfigKey "modblacklist" "evbug,cdc_ether" "${USER_CONFIG_FILE}" 95 | 96 | if [ ! "LOCALBUILD" = "${LOADER_DISK}" ]; then 97 | if arrayExistItem "sortnetif:" "$(readConfigMap "addons" "${USER_CONFIG_FILE}")"; then 98 | _sort_netif "$(readConfigKey "addons.sortnetif" "${USER_CONFIG_FILE}")" 99 | fi 100 | for N in ${ETHX}; do 101 | MACR="$(cat "/sys/class/net/${N}/address" 2>/dev/null | sed 's/://g')" 102 | IPR="$(readConfigKey "network.${MACR}" "${USER_CONFIG_FILE}")" 103 | if [ -n "${IPR}" ]; then 104 | if [ ! "1" = "$(cat "/sys/class/net/${N}/carrier" 2>/dev/null)" ]; then 105 | ip link set "${N}" up 2>/dev/null || true 106 | fi 107 | IFS='/' read -r -a IPRA <<<"${IPR}" 108 | ip addr flush dev "${N}" 2>/dev/null || true 109 | ip addr add "${IPRA[0]}/${IPRA[1]:-"255.255.255.0"}" dev "${N}" 2>/dev/null || true 110 | if [ -n "${IPRA[2]}" ]; then 111 | ip route add default via "${IPRA[2]}" dev "${N}" 2>/dev/null || true 112 | fi 113 | if [ -n "${IPRA[3]:-${IPRA[2]}}" ]; then 114 | sed -i "/nameserver ${IPRA[3]:-${IPRA[2]}}/d" /etc/resolv.conf 115 | echo "nameserver ${IPRA[3]:-${IPRA[2]}}" >>/etc/resolv.conf 116 | fi 117 | sleep 1 118 | fi 119 | [ "${N::4}" = "wlan" ] && connectwlanif "${N}" 1 && sleep 1 120 | [ "${N::3}" = "eth" ] && ethtool -s "${N}" wol g 2>/dev/null || true 121 | # [ "${N::3}" = "eth" ] && ethtool -K ${N} rxhash off 2>/dev/null || true 122 | done 123 | fi 124 | 125 | # Get the VID/PID if we are in USB 126 | VID="0x46f4" 127 | PID="0x0001" 128 | TYPE="DoM" 129 | BUS=$(getBus "${LOADER_DISK}") 130 | 131 | BUSLIST="usb sata sas scsi nvme mmc ide virtio vmbus xen" 132 | if [ "${BUS}" = "usb" ]; then 133 | VID="0x$(udevadm info --query property --name "${LOADER_DISK}" 2>/dev/null | grep "ID_VENDOR_ID" | cut -d= -f2)" 134 | PID="0x$(udevadm info --query property --name "${LOADER_DISK}" 2>/dev/null | grep "ID_MODEL_ID" | cut -d= -f2)" 135 | TYPE="flashdisk" 136 | elif ! echo "${BUSLIST}" | grep -wq "${BUS}"; then 137 | if [ "LOCALBUILD" = "${LOADER_DISK}" ]; then 138 | echo "LOCALBUILD MODE" 139 | TYPE="PC" 140 | else 141 | die "$(printf "$(TEXT "The boot disk does not support the current %s, only %s DoM is supported.")" "${BUS}" "${BUSLIST// /\/}")" 142 | fi 143 | fi 144 | 145 | # Save variables to user config file 146 | writeConfigKey "vid" "${VID}" "${USER_CONFIG_FILE}" 147 | writeConfigKey "pid" "${PID}" "${USER_CONFIG_FILE}" 148 | 149 | # Inform user 150 | printf "%s \033[1;32m%s (%s %s)\033[0m\n" "$(TEXT "Loader disk:")" "${LOADER_DISK}" "${BUS^^}" "${TYPE}" 151 | 152 | # Load keymap name 153 | LAYOUT="$(readConfigKey "layout" "${USER_CONFIG_FILE}")" 154 | KEYMAP="$(readConfigKey "keymap" "${USER_CONFIG_FILE}")" 155 | 156 | # Loads a keymap if is valid 157 | if [ -f "/usr/share/keymaps/i386/${LAYOUT}/${KEYMAP}.map.gz" ]; then 158 | printf "%s \033[1;32m%s/%s\033[0m\n" "$(TEXT "Loading keymap:")" "${LAYOUT}" "${KEYMAP}" 159 | zcat "/usr/share/keymaps/i386/${LAYOUT}/${KEYMAP}.map.gz" | loadkeys 160 | fi 161 | 162 | # Decide if boot automatically 163 | BOOT=1 164 | if ! loaderIsConfigured; then 165 | printf "\033[1;33m%s\033[0m\n" "$(TEXT "Loader is not configured!")" 166 | BOOT=0 167 | elif grep -q "IWANTTOCHANGETHECONFIG" /proc/cmdline; then 168 | printf "\033[1;33m%s\033[0m\n" "$(TEXT "User requested edit settings.")" 169 | BOOT=0 170 | fi 171 | 172 | # If is to boot automatically, do it 173 | if [ ${BOOT} -eq 1 ]; then 174 | "${WORK_PATH}/boot.sh" && exit 0 175 | fi 176 | 177 | HTTP=$(grep -i '^HTTP_PORT=' /etc/rrorg.conf 2>/dev/null | cut -d'=' -f2) 178 | DUFS=$(grep -i '^DUFS_PORT=' /etc/rrorg.conf 2>/dev/null | cut -d'=' -f2) 179 | TTYD=$(grep -i '^TTYD_PORT=' /etc/rrorg.conf 2>/dev/null | cut -d'=' -f2) 180 | 181 | # Wait for an IP 182 | printf "$(TEXT "Detected %s network cards.\n")" "$(echo "${ETHX}" | wc -w)" 183 | printf "$(TEXT "Checking Connect.")" 184 | COUNT=0 185 | while [ ${COUNT} -lt 30 ]; do 186 | MSG="" 187 | for N in ${ETHX}; do 188 | if [ "1" = "$(cat "/sys/class/net/${N}/carrier" 2>/dev/null)" ]; then 189 | MSG+="${N} " 190 | fi 191 | done 192 | if [ -n "${MSG}" ]; then 193 | printf "\r%s%s \n" "${MSG}" "$(TEXT "connected.")" 194 | break 195 | fi 196 | COUNT=$((COUNT + 1)) 197 | printf "." 198 | sleep 1 199 | done 200 | 201 | [ ! -f /var/run/dhcpcd/pid ] && /etc/init.d/S41dhcpcd restart >/dev/null 2>&1 || true 202 | 203 | printf "$(TEXT "Waiting IP.\n")" 204 | for N in ${ETHX}; do 205 | COUNT=0 206 | DRIVER="$(basename "$(realpath "/sys/class/net/${N}/device/driver" 2>/dev/null)" 2>/dev/null)" 207 | MAC="$(cat "/sys/class/net/${N}/address" 2>/dev/null)" 208 | printf "%s(%s): " "${N}" "${MAC}@${DRIVER}" 209 | while true; do 210 | if [ -z "$(cat "/sys/class/net/${N}/carrier" 2>/dev/null)" ]; then 211 | printf "\r%s(%s): %s\n" "${N}" "${MAC}@${DRIVER}" "$(TEXT "DOWN")" 212 | break 213 | fi 214 | if [ "0" = "$(cat "/sys/class/net/${N}/carrier" 2>/dev/null)" ]; then 215 | printf "\r%s(%s): %s\n" "${N}" "${MAC}@${DRIVER}" "$(TEXT "NOT CONNECTED")" 216 | break 217 | fi 218 | if [ ${COUNT} -eq 15 ]; then # Under normal circumstances, no errors should occur here. 219 | printf "\r%s(%s): %s\n" "${N}" "${MAC}@${DRIVER}" "$(TEXT "TIMEOUT (Please check the IP on the router.)")" 220 | break 221 | fi 222 | COUNT=$((COUNT + 1)) 223 | IP="$(getIP "${N}")" 224 | if [ -n "${IP}" ]; then 225 | if echo "${IP}" | grep -q "^169\.254\."; then 226 | printf "\r%s(%s): %s\n" "${N}" "${MAC}@${DRIVER}" "$(TEXT "LINK LOCAL (No DHCP server detected.)")" 227 | else 228 | printf "\r%s(%s): %s\n" "${N}" "${MAC}@${DRIVER}" "$(printf "$(TEXT "Access \033[1;34mhttp://%s:%d\033[0m to configure the loader via web terminal.")" "${IP}" "${TTYD:-7681}")" 229 | fi 230 | break 231 | fi 232 | printf "." 233 | sleep 1 234 | done 235 | done 236 | 237 | # Inform user 238 | printf "\n" 239 | printf "$(TEXT "Call \033[1;32minit.sh\033[0m to re get init info\n")" 240 | printf "$(TEXT "Call \033[1;32mmenu.sh\033[0m to configure loader\n")" 241 | printf "\n" 242 | printf "$(TEXT "User config is on \033[1;32m%s\033[0m\n")" "${USER_CONFIG_FILE}" 243 | printf "$(TEXT "HTTP: \033[1;34mhttp://%s:%d\033[0m\n")" "rr" "${HTTP:-7080}" 244 | printf "$(TEXT "DUFS: \033[1;34mhttp://%s:%d\033[0m\n")" "rr" "${DUFS:-7304}" 245 | printf "$(TEXT "TTYD: \033[1;34mhttp://%s:%d\033[0m\n")" "rr" "${TTYD:-7681}" 246 | printf "\n" 247 | if [ -f "/etc/shadow-" ]; then 248 | printf "$(TEXT "SSH port is \033[1;31m%d\033[0m, The \033[1;31mroot\033[0m password has been changed\n")" "22" 249 | else 250 | printf "$(TEXT "SSH port is \033[1;31m%d\033[0m, The \033[1;31mroot\033[0m password is \033[1;31m%s\033[0m\n")" "22" "rr" 251 | fi 252 | printf "\n" 253 | 254 | DSMLOGO="$(readConfigKey "dsmlogo" "${USER_CONFIG_FILE}")" 255 | if [ "${DSMLOGO}" = "true" ] && [ -c "/dev/fb0" ] && [ ! "LOCALBUILD" = "${LOADER_DISK}" ]; then 256 | IP="$(getIP)" 257 | echo "${IP}" | grep -q "^169\.254\." && IP="" 258 | [ -n "${IP}" ] && URL="http://${IP}:${TTYD:-7681}" || URL="http://rr:${TTYD:-7681}" 259 | python3 "${WORK_PATH}/include/functions.py" makeqr -d "${URL}" -l "0" -o "${TMP_PATH}/qrcode_init.png" 260 | [ -f "${TMP_PATH}/qrcode_init.png" ] && echo | fbv -acufi "${TMP_PATH}/qrcode_init.png" >/dev/null 2>&1 || true 261 | 262 | python3 "${WORK_PATH}/include/functions.py" makeqr -f "${WORK_PATH}/include/qhxg.png" -l "7" -o "${TMP_PATH}/qrcode_qhxg.png" 263 | [ -f "${TMP_PATH}/qrcode_qhxg.png" ] && echo | fbv -acufi "${TMP_PATH}/qrcode_qhxg.png" >/dev/null 2>&1 || true 264 | fi 265 | WEBHOOKURL="$(readConfigKey "webhookurl" "${USER_CONFIG_FILE}")" 266 | if [ -n "${WEBHOOKURL}" ] && [ ! -f "${TMP_PATH}/WebhookSent" ]; then 267 | DMI="$(dmesg 2>/dev/null | grep -i "DMI:" | head -1 | sed 's/\[.*\] DMI: //i')" 268 | IP="$(getIP)" 269 | echo "${IP}" | grep -q "^169\.254\." && IP="" 270 | [ -n "${IP}" ] && URL="http://${IP}:${TTYD:-7681}" || URL="http://rr:${TTYD:-7681}" 271 | sendWebhook "${WEBHOOKURL}" "{\"RR\":\"${RR_TITLE}${RR_RELEASE:+(${RR_RELEASE})}\", \"DATE\":\"$(date +'%Y-%m-%d %H:%M:%S')\", \"DMI\":\"${DMI}\", \"URL\":\"${URL}\"}" 272 | touch "${TMP_PATH}/WebhookSent" 273 | fi 274 | 275 | # Check memory 276 | RAM="$(awk '/MemTotal:/ {printf "%.0f", $2 / 1024}' /proc/meminfo 2>/dev/null)" 277 | if [ "${RAM:-0}" -le 3500 ]; then 278 | printf "\033[1;33m%s\033[0m\n" "$(TEXT "You have less than 4GB of RAM, if errors occur in loader creation, please increase the amount of memory.")" 279 | fi 280 | 281 | mkdir -p "${CKS_PATH}" 282 | mkdir -p "${LKMS_PATH}" 283 | mkdir -p "${ADDONS_PATH}" 284 | mkdir -p "${MODULES_PATH}" 285 | 286 | exit 0 287 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/kpatch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/files/initrd/opt/rr/kpatch -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/iosched-trampoline.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # This script is saved to /sbin/modprobe which is a so called UMH (user-mode-helper) for kmod (kernel/kmod.c) 4 | # The kmod subsystem in the kernel is used to load modules from kernel. We exploit it a bit to load RP as soon as 5 | # possible (which turns out to be via init/main.c => load_default_modules => load_default_elevator_module 6 | # When the kernel is booted with "elevator=elevator" it will attempt to load a module "elevator-iosched"... and the rest 7 | # should be obvious from the code below. DO NOT print anything here (kernel doesn't attach STDOUT) 8 | 9 | for arg in "$@"; do 10 | if [ "${arg}" = "elevator-iosched" ]; then 11 | insmod /usr/lib/modules/rp.ko 12 | rm /usr/lib/modules/rp.ko 13 | rm /usr/sbin/modprobe 14 | ln -s /usr/bin/kmod /usr/sbin/modprobe 15 | exit 0 16 | fi 17 | done 18 | exit 1 19 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/modulelist: -------------------------------------------------------------------------------- 1 | # `#: comment 2 | # $1: operation 3 | # N: copy module to ramdisk, do not overwrite an existing file 4 | # F: copy module to ramdisk, overwrite an existing file 5 | # $2: module file name (not module name) 6 | # 7 | # eg: N i915.ko 8 | 9 | # kvm 10 | F irqbypass.ko 11 | F kvm-intel.ko 12 | F kvm-amd.ko 13 | F kvm.ko 14 | 15 | # acpi 16 | N acpi_call.ko 17 | 18 | # misc 19 | N check_signature.ko 20 | N rfkill.ko 21 | N rfkill-gpio.ko 22 | 23 | # sensors 24 | N coretemp.ko 25 | N k10temp.ko 26 | N hwmon-vid.ko 27 | N it87.ko 28 | N adt7470.ko 29 | N adt7475.ko 30 | N nct6683.ko 31 | N nct6775.ko 32 | 33 | # rndis 34 | F mii.ko 35 | F cdc_ether.ko 36 | F rndis_host.ko 37 | F r8152.ko 38 | F aqc111.ko 39 | F ax88179_178a.ko 40 | F aic_load_fw.ko 41 | F aic8800_fdrv.ko 42 | 43 | # iwlwifi 44 | N libarc4.ko 45 | N cfg80211.ko 46 | N mac80211.ko 47 | N iwlwifi.ko 48 | N iwlmvm.ko 49 | N iwldvm.ko 50 | 51 | ## i915 52 | #N dmabuf.ko 53 | #N drm.ko 54 | #N drm_buddy.ko 55 | #N drm_display_helper.ko 56 | #N drm_kms_helper.ko 57 | #N drm_mipi_dsi.ko 58 | #N drm_panel_orientation_quirks.ko 59 | #N i2c-algo-bit.ko 60 | #N i915-compat.ko 61 | #N intel-gtt.ko 62 | #N ttm.ko 63 | #N i915.ko -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-etc-rc-25556.patch: -------------------------------------------------------------------------------- 1 | --- a/etc/rc 2 | +++ b/etc/rc 3 | @@ -469,5 +469,5 @@ 4 | echo "============ Date ============" 5 | date 6 | echo "==============================" 7 | - 8 | +/addons/addons.sh rcExit 9 | exit 0 10 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-init-script-25556.patch: -------------------------------------------------------------------------------- 1 | --- a/linuxrc.syno 2 | +++ b/linuxrc.syno 3 | @@ -51,6 +51,8 @@ 4 | UnknownSynoPartitionMigrationFlag="/.unknown_syno_partition_migrate" 5 | IncompatibleRootDevice="/.incompatible_root_device" 6 | 7 | +/addons/addons.sh early 8 | + 9 | UmountRoot() 10 | { 11 | grep "^${RootDevice}" /proc/mounts && /bin/umount -f ${Mnt} 12 | @@ -73,6 +75,9 @@ 13 | if [ "$SupportDualhead" = "yes" ]; then 14 | /etc.defaults/AHAtasks stage_change_end 15 | fi 16 | + 17 | + /addons/addons.sh jrExit 18 | + 19 | UmountRoot 20 | exit $1 21 | } 22 | @@ -154,6 +159,8 @@ 23 | echo "Insert basic USB modules..." 24 | SYNOLoadModules $USB_MODULES 25 | 26 | +/addons/addons.sh modules 27 | + 28 | # insert Etron USB3.0 drivers 29 | 30 | if [ $KERNEL_VCODE -ge $(KernelVersionCode "3.10") ]; then 31 | @@ -206,6 +213,8 @@ 32 | fi 33 | fi 34 | 35 | +/addons/addons.sh patches 36 | + 37 | if [ "$SupportDualhead" = "yes" ]; then 38 | # Run HA script 39 | /etc.defaults/AHAtasks check_stage 40 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-init-script-42218.patch: -------------------------------------------------------------------------------- 1 | --- a/linuxrc.syno.impl 2 | +++ b/linuxrc.syno.impl 3 | @@ -38,6 +38,8 @@ 4 | UnknownSynoPartitionMigrationFlag="/.unknown_syno_partition_migrate" 5 | IncompatibleRootDevice="/.incompatible_root_device" 6 | 7 | +/addons/addons.sh early 8 | + 9 | UmountRoot() 10 | { 11 | grep "^${RootDevice}" /proc/mounts && /bin/umount -f ${Mnt} 12 | @@ -59,5 +61,6 @@ 13 | fi 14 | 15 | + /addons/addons.sh jrExit 16 | UmountRoot 17 | 18 | exit $1 19 | } 20 | @@ -155,6 +158,8 @@ 21 | # insert basic USB modules for detect f401/FDT 22 | echo "Insert basic USB modules..." 23 | SYNOLoadModules $USB_MODULES 24 | + 25 | +/addons/addons.sh modules 26 | 27 | # insert Etron USB3.0 drivers 28 | 29 | @@ -209,6 +214,8 @@ 30 | fi 31 | fi 32 | 33 | +/addons/addons.sh patches 34 | + 35 | if [ "$SupportDualhead" = "yes" ]; then 36 | # Run HA script 37 | /etc.defaults/AHAtasks check_stage 38 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-init-script-64216.patch: -------------------------------------------------------------------------------- 1 | --- a/linuxrc.syno.impl 2 | +++ b/linuxrc.syno.impl 3 | @@ -51,6 +51,8 @@ 4 | UnknownSynoPartitionMigrationFlag="/.unknown_syno_partition_migrate" 5 | IncompatibleRootDevice="/.incompatible_root_device" 6 | 7 | +/addons/addons.sh early 8 | + 9 | UmountRoot() 10 | { 11 | grep "^${RootDevice}" /proc/mounts && /bin/umount -f ${Mnt} 12 | @@ -67,6 +69,7 @@ 13 | # show date for login info 14 | date 15 | 16 | + /addons/addons.sh jrExit 17 | UmountRoot 18 | 19 | exit $1 20 | @@ -176,6 +179,8 @@ 21 | echo "Insert basic USB modules..." 22 | SYNOLoadModules $USB_MODULES 23 | + 24 | +/addons/addons.sh modules 25 | 26 | # insert Etron USB3.0 drivers 27 | 28 | if [ $KERNEL_VCODE -ge "$(KernelVersionCode "3.10")" ]; then 29 | @@ -224,6 +229,7 @@ 30 | fi 31 | fi 32 | 33 | +/addons/addons.sh patches 34 | LoadBrmModules 35 | 36 | #################################################### 37 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-init-script-69057.patch: -------------------------------------------------------------------------------- 1 | --- a/linuxrc.syno.impl 2 | +++ b/linuxrc.syno.impl 3 | @@ -51,6 +51,8 @@ 4 | UnknownSynoPartitionMigrationFlag="/.unknown_syno_partition_migrate" 5 | IncompatibleRootDevice="/.incompatible_root_device" 6 | 7 | +/addons/addons.sh early 8 | + 9 | UmountRoot() 10 | { 11 | grep "^${RootDevice}" /proc/mounts && /bin/umount -f ${Mnt} 12 | @@ -67,6 +69,7 @@ 13 | # show date for login info 14 | date 15 | 16 | + /addons/addons.sh jrExit 17 | if [ "$1" -eq 0 ]; then 18 | TryRestoringDeviceBackToSwapRaid 19 | fi 20 | @@ -176,6 +179,8 @@ 21 | echo "Insert basic USB modules..." 22 | SYNOLoadModules $USB_MODULES 23 | + 24 | +/addons/addons.sh modules 25 | 26 | # insert Etron USB3.0 drivers 27 | 28 | if [ $KERNEL_VCODE -ge "$(KernelVersionCode "3.10")" ]; then 29 | @@ -224,6 +229,7 @@ 30 | fi 31 | fi 32 | 33 | +/addons/addons.sh patches 34 | LoadBrmModules 35 | 36 | if [ "$KERNEL_VCODE" -ge "$(KernelVersionCode "5.10")" ]; then 37 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-post-init-script-25556.patch: -------------------------------------------------------------------------------- 1 | --- a/usr/sbin/init.post 2 | +++ b/usr/sbin/init.post 3 | @@ -18,6 +18,8 @@ 4 | fi 5 | mount $RootDevice /tmpRoot -o barrier=1 6 | 7 | +/addons/addons.sh late 8 | + 9 | mkdir -p /tmpRoot/initrd 10 | 11 | umount /proc &> /dev/null 12 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-post-init-script-42218.patch: -------------------------------------------------------------------------------- 1 | --- a/usr/sbin/init.post 2 | +++ b/usr/sbin/init.post 3 | @@ -18,6 +18,8 @@ 4 | fi 5 | Mount "$RootDevice" /tmpRoot -o barrier=1 6 | 7 | +/addons/addons.sh late 8 | + 9 | Mkdir -p /tmpRoot/initrd 10 | 11 | Umount /proc >/dev/null 2>&1 12 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-post-init-script-42661.patch: -------------------------------------------------------------------------------- 1 | --- a/usr/sbin/init.post 2 | +++ b/usr/sbin/init.post 3 | @@ -32,6 +32,8 @@ 4 | # shellcheck disable=SC2046 5 | Mount "${RootMountPath}" /tmpRoot -o barrier=1 ${OptPrjQuota} 6 | 7 | +/addons/addons.sh late 8 | + 9 | Mkdir -p /tmpRoot/initrd 10 | 11 | Umount /proc >/dev/null 2>&1 12 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-post-init-script-42951.patch: -------------------------------------------------------------------------------- 1 | --- a/usr/sbin/init.post 2 | +++ b/usr/sbin/init.post 3 | @@ -32,6 +32,8 @@ 4 | # shellcheck disable=SC2046 5 | Mount "${RootMountPath}" /tmpRoot -o barrier=1,noatime ${OptPrjQuota} 6 | 7 | +/addons/addons.sh late 8 | + 9 | Mkdir -p /tmpRoot/initrd 10 | 11 | Umount /proc >/dev/null 2>&1 12 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/patch/ramdisk-post-init-script-69057.patch: -------------------------------------------------------------------------------- 1 | --- a/usr/sbin/init.post 2 | +++ b/usr/sbin/init.post 3 | @@ -23,6 +23,8 @@ 4 | 5 | Mount "$(GetRootMountOpt)" "$(GetRootMountPath)" /tmpRoot 6 | 7 | +/addons/addons.sh late 8 | + 9 | Mkdir -p /tmpRoot/initrd 10 | 11 | Umount /proc >/dev/null 2>&1 12 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/platforms.yml: -------------------------------------------------------------------------------- 1 | synoinfo: &synoinfo 2 | supportext4: "yes" 3 | support_uasp: "yes" 4 | support_printer: "yes" 5 | support_usb_printer: "yes" 6 | support_disk_compatibility: "no" 7 | support_synodrive_ability: "no" # DS925+ 8 | support_memory_compatibility: "no" 9 | support_memory_limitation: "no" # DVA3219 10 | support_led_brightness_adjustment: "no" 11 | support_leds_atmega1608: "no" 12 | support_leds_lp3943: "no" 13 | support_oob_ctl: "no" 14 | support_syno_hybrid_raid: "no" 15 | supportraidgroup: "no" 16 | enableRCPower: "yes" 17 | # mem_max_mb: "" # Impact Creating an SSD Cache 18 | # mem_min_mb: "" # Impact Creating an SSD Cache 19 | support_fan: "no" 20 | support_fan_adjust_dual_mode: "no" 21 | supportadt7490: "no" 22 | maxlanport: "8" 23 | netif_seq: "" 24 | buzzeroffen: "0xffff" 25 | 26 | productvers4: &productvers4 27 | "7.0": 28 | kver: "4.4.180" 29 | "7.1": 30 | kver: "4.4.180" 31 | "7.2": 32 | kver: "4.4.302" 33 | 34 | productvers5: &productvers5 35 | "7.1": 36 | kpre: "7.1" 37 | kver: "5.10.55" 38 | "7.2": 39 | kpre: "7.2" 40 | kver: "5.10.55" 41 | 42 | platforms: 43 | apollolake: 44 | dt: false 45 | flags: ["movbe"] 46 | noflags: ["x2apic"] 47 | synoinfo: 48 | <<: *synoinfo 49 | HddEnableDynamicPower: "no" 50 | productvers: *productvers4 51 | broadwell: 52 | dt: false 53 | synoinfo: *synoinfo 54 | productvers: *productvers4 55 | broadwellnk: 56 | dt: false 57 | synoinfo: 58 | <<: *synoinfo 59 | support_bde_internal_10g: "no" 60 | supportsas: "no" 61 | productvers: *productvers4 62 | broadwellnkv2: 63 | dt: true 64 | synoinfo: 65 | <<: *synoinfo 66 | support_bde_internal_10g: "no" 67 | supportsas: "no" 68 | supportsas_v2_r1: "no" 69 | support_multipath: "yes" 70 | productvers: *productvers4 71 | broadwellntbap: 72 | dt: false 73 | synoinfo: 74 | <<: *synoinfo 75 | support_bde_internal_10g: "no" 76 | supportsas: "no" 77 | supportbootinst: "no" 78 | no_disk_system: "no" 79 | support_auto_install: "no" 80 | support_install_only_dev: "no" 81 | required_system_disk_number: "0" 82 | productvers: *productvers4 83 | denverton: 84 | dt: false 85 | flags: ["movbe"] 86 | synoinfo: *synoinfo 87 | productvers: *productvers4 88 | geminilake: 89 | dt: true 90 | noflags: ["x2apic"] 91 | synoinfo: *synoinfo 92 | productvers: *productvers4 93 | purley: 94 | dt: true 95 | noflags: ["x2apic"] 96 | synoinfo: 97 | <<: *synoinfo 98 | supportsas: "no" 99 | supportsas_v2_r1: "no" 100 | support_multipath: "yes" 101 | support_install_only_dev: "no" 102 | isolated_disk_system: "no" 103 | required_system_disk_number: "0" 104 | internal_disk_without_led_mask: "no" 105 | productvers: *productvers4 106 | r1000: 107 | dt: true 108 | synoinfo: *synoinfo 109 | productvers: *productvers4 110 | v1000: 111 | dt: true 112 | synoinfo: *synoinfo 113 | productvers: *productvers4 114 | epyc7002: 115 | dt: true 116 | synoinfo: 117 | <<: *synoinfo 118 | netif_seq_by_dts: "no" 119 | productvers: *productvers5 120 | geminilakenk: 121 | dt: true 122 | noflags: ["x2apic"] 123 | synoinfo: 124 | <<: *synoinfo 125 | netif_seq_by_dts: "no" 126 | show_autoupdatetype_notify: "yes" 127 | productvers: *productvers5 128 | r1000nk: 129 | dt: true 130 | synoinfo: 131 | <<: *synoinfo 132 | netif_seq_by_dts: "no" 133 | show_autoupdatetype_notify: "yes" 134 | productvers: *productvers5 135 | v1000nk: 136 | dt: true 137 | synoinfo: 138 | <<: *synoinfo 139 | netif_seq_by_dts: "no" 140 | show_autoupdatetype_notify: "yes" 141 | productvers: *productvers5 142 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/ramdisk-patch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | # shellcheck disable=SC2034 10 | 11 | [ -z "${WORK_PATH}" ] || [ ! -d "${WORK_PATH}/include" ] && WORK_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" 12 | 13 | . "${WORK_PATH}/include/functions.sh" 14 | . "${WORK_PATH}/include/addons.sh" 15 | . "${WORK_PATH}/include/modules.sh" 16 | 17 | set -o pipefail # Get exit code from process piped 18 | 19 | # get user data 20 | PLATFORM="$(readConfigKey "platform" "${USER_CONFIG_FILE}")" 21 | MODEL="$(readConfigKey "model" "${USER_CONFIG_FILE}")" 22 | PRODUCTVER="$(readConfigKey "productver" "${USER_CONFIG_FILE}")" 23 | BUILDNUM="$(readConfigKey "buildnum" "${USER_CONFIG_FILE}")" 24 | SMALLNUM="$(readConfigKey "smallnum" "${USER_CONFIG_FILE}")" 25 | KERNEL="$(readConfigKey "kernel" "${USER_CONFIG_FILE}")" 26 | RD_COMPRESSED="$(readConfigKey "rd-compressed" "${USER_CONFIG_FILE}")" 27 | LKM="$(readConfigKey "lkm" "${USER_CONFIG_FILE}")" 28 | SN="$(readConfigKey "sn" "${USER_CONFIG_FILE}")" 29 | LAYOUT="$(readConfigKey "layout" "${USER_CONFIG_FILE}")" 30 | KEYMAP="$(readConfigKey "keymap" "${USER_CONFIG_FILE}")" 31 | PATURL="$(readConfigKey "paturl" "${USER_CONFIG_FILE}")" 32 | PATSUM="$(readConfigKey "patsum" "${USER_CONFIG_FILE}")" 33 | ODP="$(readConfigKey "odp" "${USER_CONFIG_FILE}")" # official drivers priorities 34 | 35 | DT="$(readConfigKey "dt" "${USER_CONFIG_FILE}")" 36 | KVER="$(readConfigKey "kver" "${USER_CONFIG_FILE}")" 37 | KPRE="$(readConfigKey "kpre" "${USER_CONFIG_FILE}")" 38 | 39 | # Sanity check 40 | if [ -z "${PLATFORM}" ] || [ -z "${KVER}" ]; then 41 | echo "ERROR: Configuration for model ${MODEL} and productversion ${PRODUCTVER} not found." >"${LOG_FILE}" 42 | exit 1 43 | fi 44 | 45 | [ "${PATURL:0:1}" = "#" ] && PATURL="" 46 | [ "${PATSUM:0:1}" = "#" ] && PATSUM="" 47 | 48 | # Sanity check 49 | if [ ! -f "${ORI_RDGZ_FILE}" ]; then 50 | echo "ERROR: ${ORI_RDGZ_FILE} not found!" >"${LOG_FILE}" 51 | exit 1 52 | fi 53 | 54 | # Unzipping ramdisk 55 | rm -rf "${RAMDISK_PATH}" # Force clean 56 | mkdir -p "${RAMDISK_PATH}" 57 | (cd "${RAMDISK_PATH}" && xz -dc <"${ORI_RDGZ_FILE}" | cpio -idm) >/dev/null 2>&1 58 | 59 | # Check if DSM buildnumber changed 60 | . "${RAMDISK_PATH}/etc/VERSION" 61 | 62 | if [ -n "${PRODUCTVER}" ] && [ -n "${BUILDNUM}" ] && [ -n "${SMALLNUM}" ] && 63 | ([ ! "${PRODUCTVER}" = "${majorversion:-0}.${minorversion:-0}" ] || [ ! "${BUILDNUM}" = "${buildnumber:-0}" ] || [ ! "${SMALLNUM}" = "${smallfixnumber:-0}" ]); then 64 | OLDVER="${PRODUCTVER}(${BUILDNUM}$([ ${SMALLNUM:-0} -ne 0 ] && echo "u${SMALLNUM}"))" 65 | NEWVER="${majorversion}.${minorversion}(${buildnumber}$([ ${smallfixnumber:-0} -ne 0 ] && echo "u${smallfixnumber}"))" 66 | echo -e "\033[A\n\033[1;32mBuild number changed from \033[1;31m${OLDVER}\033[1;32m to \033[1;31m${NEWVER}\033[0m" 67 | PATURL="" 68 | PATSUM="" 69 | # Clean old pat file 70 | rm -f "${PART3_PATH}/dl/${MODEL}-${PRODUCTVER}.pat" 2>/dev/null || true 71 | fi 72 | 73 | echo -n "Patching Ramdisk" 74 | 75 | # Update new buildnumber 76 | PRODUCTVER=${majorversion}.${minorversion} 77 | BUILDNUM=${buildnumber} 78 | SMALLNUM=${smallfixnumber} 79 | writeConfigKey "productver" "${PRODUCTVER}" "${USER_CONFIG_FILE}" 80 | writeConfigKey "buildnum" "${BUILDNUM}" "${USER_CONFIG_FILE}" 81 | writeConfigKey "smallnum" "${SMALLNUM}" "${USER_CONFIG_FILE}" 82 | 83 | declare -A ADDONS 84 | declare -A MODULES 85 | declare -A SYNOINFO 86 | 87 | # Read addons, modules and synoinfo from user config 88 | while IFS=': ' read -r KEY VALUE; do 89 | [ -n "${KEY}" ] && ADDONS["${KEY}"]="${VALUE}" 90 | done <<<"$(readConfigMap "addons" "${USER_CONFIG_FILE}")" 91 | 92 | # Read modules from user config 93 | while IFS=': ' read -r KEY VALUE; do 94 | [ -n "${KEY}" ] && MODULES["${KEY}"]="${VALUE}" 95 | done <<<"$(readConfigMap "modules" "${USER_CONFIG_FILE}")" 96 | 97 | # SYNOINFO["SN"]="${SN}" 98 | while IFS=': ' read -r KEY VALUE; do 99 | [ -n "${KEY}" ] && SYNOINFO["${KEY}"]="${VALUE}" 100 | done <<<"$(readConfigMap "synoinfo" "${USER_CONFIG_FILE}")" 101 | 102 | # Patches (diff -Naru OLDFILE NEWFILE > xxx.patch) 103 | PATCHS=( 104 | "ramdisk-etc-rc-*.patch" 105 | "ramdisk-init-script-*.patch" 106 | "ramdisk-post-init-script-*.patch" 107 | ) 108 | for PE in "${PATCHS[@]}"; do 109 | RET=1 110 | echo "Patching with ${PE}" >"${LOG_FILE}" 111 | # ${PE} contains *, so double quotes cannot be added 112 | for PF in ${WORK_PATH}/patch/${PE}; do 113 | [ ! -e "${PF}" ] && continue 114 | echo "Patching with ${PF}" >>"${LOG_FILE}" 115 | # busybox patch and gun patch have different processing methods and parameters. 116 | (cd "${RAMDISK_PATH}" && busybox patch -p1 -i "${PF}") >>"${LOG_FILE}" 2>&1 117 | RET=$? 118 | [ ${RET} -eq 0 ] && break 119 | done 120 | [ ${RET} -ne 0 ] && exit 1 121 | done 122 | 123 | mkdir -p "${RAMDISK_PATH}/addons" 124 | 125 | # Addons 126 | echo -n "." 127 | echo "Create addons.sh" >"${LOG_FILE}" 128 | { 129 | echo "#!/bin/sh" 130 | echo 'echo "addons.sh called with params ${@}"' 131 | echo "export LOADERLABEL=\"RR\"" 132 | echo "export LOADERRELEASE=\"${RR_RELEASE}\"" 133 | echo "export LOADERVERSION=\"${RR_VERSION}\"" 134 | echo "export PLATFORM=\"${PLATFORM}\"" 135 | echo "export MODEL=\"${MODEL}\"" 136 | echo "export PRODUCTVERL=\"${PRODUCTVERL}\"" 137 | echo "export MLINK=\"${PATURL}\"" 138 | echo "export MCHECKSUM=\"${PATSUM}\"" 139 | echo "export LAYOUT=\"${LAYOUT}\"" 140 | echo "export KEYMAP=\"${KEYMAP}\"" 141 | } >"${RAMDISK_PATH}/addons/addons.sh" 142 | chmod +x "${RAMDISK_PATH}/addons/addons.sh" 143 | 144 | # This order cannot be changed. 145 | for ADDON in "redpill" "revert" "misc" "eudev" "disks" "localrss" "notify" "wol"; do 146 | PARAMS="" 147 | if [ "${ADDON}" = "disks" ]; then 148 | [ -f "${USER_UP_PATH}/model.dts" ] && cp -f "${USER_UP_PATH}/model.dts" "${RAMDISK_PATH}/addons/model.dts" 149 | [ -f "${USER_UP_PATH}/${MODEL}.dts" ] && cp -f "${USER_UP_PATH}/${MODEL}.dts" "${RAMDISK_PATH}/addons/model.dts" 150 | fi 151 | installAddon "${ADDON}" "${PLATFORM}" "${KPRE:+${KPRE}-}${KVER}" || exit 1 152 | echo "/addons/${ADDON}.sh \${1} ${PARAMS}" >>"${RAMDISK_PATH}/addons/addons.sh" 2>>"${LOG_FILE}" || exit 1 153 | done 154 | 155 | # User addons 156 | for ADDON in "${!ADDONS[@]}"; do 157 | PARAMS=${ADDONS[${ADDON}]} 158 | installAddon "${ADDON}" "${PLATFORM}" "${KPRE:+${KPRE}-}${KVER}" || exit 1 159 | echo "/addons/${ADDON}.sh \${1} ${PARAMS}" >>"${RAMDISK_PATH}/addons/addons.sh" 2>>"${LOG_FILE}" || exit 1 160 | done 161 | 162 | # Extract ck modules to ramdisk 163 | echo -n "." 164 | installModules "${PLATFORM}" "${KPRE:+${KPRE}-}${KVER}" "${!MODULES[@]}" || exit 1 165 | 166 | # Copying fake modprobe 167 | [ "$(echo "${KVER:-4}" | cut -d'.' -f1)" -lt 5 ] && cp -f "${WORK_PATH}/patch/iosched-trampoline.sh" "${RAMDISK_PATH}/usr/sbin/modprobe" 168 | # Copying LKM to /usr/lib/modules 169 | gzip -dc "${LKMS_PATH}/rp-${PLATFORM}-${KPRE:+${KPRE}-}${KVER}-${LKM}.ko.gz" >"${RAMDISK_PATH}/usr/lib/modules/rp.ko" 2>"${LOG_FILE}" || exit 1 170 | 171 | # Patch synoinfo.conf 172 | echo -n "." 173 | echo -n "" >"${RAMDISK_PATH}/addons/synoinfo.conf" 174 | for KEY in "${!SYNOINFO[@]}"; do 175 | echo "Set synoinfo ${KEY}" >>"${LOG_FILE}" 176 | echo "${KEY}=\"${SYNOINFO[${KEY}]}\"" >>"${RAMDISK_PATH}/addons/synoinfo.conf" 177 | _set_conf_kv "${RAMDISK_PATH}/etc/synoinfo.conf" "${KEY}" "${SYNOINFO[${KEY}]}" || exit 1 178 | _set_conf_kv "${RAMDISK_PATH}/etc.defaults/synoinfo.conf" "${KEY}" "${SYNOINFO[${KEY}]}" || exit 1 179 | done 180 | if [ ! -x "${RAMDISK_PATH}/usr/bin/get_key_value" ]; then 181 | printf '#!/bin/sh\n%s\n_get_conf_kv "$@"' "$(declare -f _get_conf_kv)" >"${RAMDISK_PATH}/usr/bin/get_key_value" 182 | chmod a+x "${RAMDISK_PATH}/usr/bin/get_key_value" 183 | fi 184 | if [ ! -x "${RAMDISK_PATH}/usr/bin/set_key_value" ]; then 185 | printf '#!/bin/sh\n%s\n_set_conf_kv "$@"' "$(declare -f _set_conf_kv)" >"${RAMDISK_PATH}/usr/bin/set_key_value" 186 | chmod a+x "${RAMDISK_PATH}/usr/bin/set_key_value" 187 | fi 188 | 189 | echo -n "." 190 | echo "Modify files" >"${LOG_FILE}" 191 | # Remove function from scripts 192 | [ "2" = "${BUILDNUM:0:1}" ] && find "${RAMDISK_PATH}/addons/" -type f -name "*.sh" -exec sed -i 's/function //g' {} \; 193 | 194 | # Build modules dependencies 195 | # ${WORK_PATH}/depmod -a -b ${RAMDISK_PATH} 2>/dev/null # addon eudev will do this 196 | 197 | # Copying modulelist 198 | if [ -f "${USER_UP_PATH}/modulelist" ]; then 199 | cp -f "${USER_UP_PATH}/modulelist" "${RAMDISK_PATH}/addons/modulelist" 200 | else 201 | cp -f "${WORK_PATH}/patch/modulelist" "${RAMDISK_PATH}/addons/modulelist" 202 | fi 203 | 204 | # backup current loader configs 205 | mkdir -p "${RAMDISK_PATH}/usr/rr" 206 | { 207 | echo "LOADERLABEL=\"RR\"" 208 | echo "LOADERRELEASE=\"${RR_RELEASE}\"" 209 | echo "LOADERVERSION=\"${RR_VERSION}\"" 210 | } >"${RAMDISK_PATH}/usr/rr/VERSION" 211 | BACKUP_PATH="${RAMDISK_PATH}/usr/rr/backup" 212 | rm -rf "${BACKUP_PATH}" 213 | for F in "${USER_GRUB_CONFIG}" "${USER_CONFIG_FILE}" "${USER_LOCALE_FILE}" "${USER_UP_PATH}" "${SCRIPTS_PATH}"; do 214 | if [ -f "${F}" ]; then 215 | FD="$(dirname "${F}")" 216 | mkdir -p "${FD/\/mnt/${BACKUP_PATH}}" 217 | cp -f "${F}" "${FD/\/mnt/${BACKUP_PATH}}" 218 | elif [ -d "${F}" ]; then 219 | SIZE="$(du -sm "${F}" 2>/dev/null | awk '{print $1}')" 220 | if [ ${SIZE:-0} -gt 4 ]; then 221 | echo "Backup of ${F} skipped, size is ${SIZE}MB" >>"${LOG_FILE}" 222 | continue 223 | fi 224 | FD="$(dirname "${F}")" 225 | mkdir -p "${FD/\/mnt/${BACKUP_PATH}}" 226 | cp -rf "${F}" "${FD/\/mnt/${BACKUP_PATH}}" 227 | fi 228 | done 229 | 230 | # Network card configuration file 231 | for N in $(seq 0 7); do 232 | echo -e "DEVICE=eth${N}\nBOOTPROTO=dhcp\nONBOOT=yes\nIPV6INIT=dhcp\nIPV6_ACCEPT_RA=1" >"${RAMDISK_PATH}/etc/sysconfig/network-scripts/ifcfg-eth${N}" 233 | done 234 | 235 | # issues/313 236 | if [ "$(echo "${KVER:-4}" | cut -d'.' -f1)" -lt 5 ]; then 237 | : 238 | else 239 | sed -i 's#/dev/console#/var/log/lrc#g' "${RAMDISK_PATH}/usr/bin/busybox" 240 | sed -i '/^echo "START/a \\nmknod -m 0666 /dev/console c 1 3' "${RAMDISK_PATH}/linuxrc.syno" 241 | fi 242 | 243 | if [ "${PLATFORM}" = "broadwellntbap" ]; then 244 | sed -i 's/IsUCOrXA="yes"/XIsUCOrXA="yes"/g; s/IsUCOrXA=yes/XIsUCOrXA=yes/g' "${RAMDISK_PATH}/usr/syno/share/environments.sh" 245 | fi 246 | 247 | # Call user patch scripts 248 | echo -n "." 249 | for F in ${SCRIPTS_PATH}/*.sh; do 250 | [ ! -e "${F}" ] && continue 251 | echo "Calling ${F}" >"${LOG_FILE}" 252 | # shellcheck source=/dev/null 253 | . "${F}" >>"${LOG_FILE}" 2>&1 || exit 1 254 | done 255 | 256 | # Reassembly ramdisk 257 | rm -f "${MOD_RDGZ_FILE}" 258 | if [ "${RD_COMPRESSED}" = "true" ]; then 259 | (cd "${RAMDISK_PATH}" && find . 2>/dev/null | cpio -o -H newc -R root:root | xz -9 --format=lzma >"${MOD_RDGZ_FILE}") >"${LOG_FILE}" 2>&1 || exit 1 260 | else 261 | (cd "${RAMDISK_PATH}" && find . 2>/dev/null | cpio -o -H newc -R root:root >"${MOD_RDGZ_FILE}") >"${LOG_FILE}" 2>&1 || exit 1 262 | fi 263 | 264 | sync 265 | 266 | # Clean 267 | rm -rf "${RAMDISK_PATH}" 268 | 269 | # Update SHA256 hash 270 | RAMDISK_HASH_CUR="$(sha256sum "${ORI_RDGZ_FILE}" | awk '{print $1}')" 271 | writeConfigKey "ramdisk-hash" "${RAMDISK_HASH_CUR}" "${USER_CONFIG_FILE}" 272 | 273 | echo -n "." 274 | echo 275 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/serialnumber.yml: -------------------------------------------------------------------------------- 1 | "DS224+": 2 | prefix: 3 | - "2350" 4 | middle: 5 | - "WBR" 6 | suffix: "alpha" 7 | "DS423+": 8 | prefix: 9 | - "22A0" 10 | middle: 11 | - "VKR" 12 | suffix: "alpha" 13 | "DS718+": 14 | prefix: 15 | - "1930" 16 | middle: 17 | - "PEN" 18 | suffix: "numeric" 19 | "DS720+": 20 | prefix: 21 | - "2010" 22 | - "2110" 23 | middle: 24 | - "QWR" 25 | suffix: "alpha" 26 | "DS918+": 27 | prefix: 28 | - "1910" 29 | middle: 30 | - "PDN" 31 | suffix: "numeric" 32 | "DS920+": 33 | prefix: 34 | - "2030" 35 | - "2040" 36 | - "20C0" 37 | - "2150" 38 | middle: 39 | - "SBR" 40 | suffix: "alpha" 41 | "DS923+": 42 | prefix: 43 | - "2270" 44 | middle: 45 | - "TQR" 46 | suffix: "alpha" 47 | macpre: 9009d0 48 | "DS925+": 49 | prefix: 50 | - "2520" 51 | middle: 52 | - "YHR" 53 | suffix: "alpha" 54 | macpre: 9009d0 55 | "DS1019+": 56 | prefix: 57 | - "1850" 58 | - "1880" 59 | middle: 60 | - "QXR" 61 | suffix: "numeric" 62 | "DS1520+": 63 | prefix: 64 | - "2060" 65 | middle: 66 | - "RYR" 67 | suffix: "alpha" 68 | "DS1522+": 69 | prefix: 70 | - "2270" 71 | middle: 72 | - "TRR" 73 | suffix: "alpha" 74 | macpre: 9009d0 75 | "DS1621+": 76 | prefix: 77 | - "2080" 78 | middle: 79 | - "S7R" 80 | suffix: "alpha" 81 | "DS1621xs+": 82 | prefix: 83 | - "2070" 84 | middle: 85 | - "RVR" 86 | suffix: "alpha" 87 | "DS1819+": 88 | prefix: 89 | - "1890" 90 | middle: 91 | - "R5R" 92 | suffix: "alpha" 93 | "DS1821+": 94 | prefix: 95 | - "2110" 96 | middle: 97 | - "SKR" 98 | suffix: "alpha" 99 | "DS1823xs+": 100 | prefix: 101 | - "2280" 102 | middle: 103 | - "V5R" 104 | suffix: "alpha" 105 | "DS2419+": 106 | prefix: 107 | - "1880" 108 | middle: 109 | - "QZA" 110 | suffix: "alpha" 111 | "DS2422+": 112 | prefix: 113 | - "2140" 114 | - "2180" 115 | middle: 116 | - "SLR" 117 | suffix: "alpha" 118 | "DS3617xs": 119 | prefix: 120 | - "1130" 121 | - "1230" 122 | - "1330" 123 | - "1430" 124 | middle: 125 | - "ODN" 126 | suffix: "numeric" 127 | "DS3622xs+": 128 | prefix: 129 | - "2150" 130 | middle: 131 | - "SQR" 132 | suffix: "alpha" 133 | "DVA1622": 134 | prefix: 135 | - "2030" 136 | - "2040" 137 | - "20C0" 138 | - "2150" 139 | middle: 140 | - "UBR" 141 | suffix: "alpha" 142 | "DVA3219": 143 | prefix: 144 | - "1930" 145 | - "1940" 146 | middle: 147 | - "RFR" 148 | suffix: "alpha" 149 | "DVA3221": 150 | prefix: 151 | - "2030" 152 | - "2040" 153 | - "20C0" 154 | - "2150" 155 | middle: 156 | - "SJR" 157 | suffix: "alpha" 158 | "FS2500": 159 | prefix: 160 | - "1960" 161 | middle: 162 | - "PSN" 163 | suffix: "numeric" 164 | "FS6400": 165 | prefix: 166 | - "0000" 167 | middle: 168 | - "XXX" 169 | suffix: "alpha" 170 | "HD6500": 171 | prefix: 172 | - "20A0" 173 | - "21C0" 174 | middle: 175 | - "RUR" 176 | suffix: "alpha" 177 | macpre: 9009d0 178 | "RS1221+": 179 | prefix: 180 | - "20B0" 181 | middle: 182 | - "RWR" 183 | suffix: "alpha" 184 | "RS1619xs+": 185 | prefix: 186 | - "1920" 187 | middle: 188 | - "QPR" 189 | suffix: "alpha" 190 | "RS2423RP+": 191 | prefix: 192 | - "22B0" 193 | middle: 194 | - "V3R" 195 | suffix: "alpha" 196 | macpre: 9009d0 197 | "RS3621xs+": 198 | prefix: 199 | - "20A0" 200 | middle: 201 | - "SZR" 202 | suffix: "alpha" 203 | "RS4021xs+": 204 | prefix: 205 | - "2160" 206 | middle: 207 | - "T2R" 208 | suffix: "alpha" 209 | macpre: 9009d0 210 | "SA3200D": 211 | prefix: 212 | - "19A0" 213 | middle: 214 | - "S4R" 215 | suffix: "alpha" 216 | "SA3400": 217 | prefix: 218 | - "1970" 219 | middle: 220 | - "RJR" 221 | suffix: "alpha" 222 | "SA6400": 223 | prefix: 224 | - "2350" 225 | middle: 226 | - "W8R" 227 | suffix: "alpha" 228 | "SA3410": 229 | prefix: 230 | - "2270" 231 | middle: 232 | - "UMR" 233 | suffix: "alpha" 234 | macpre: 9009d0 235 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/vmlinux-to-bzImage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | # Based on code and ideas from @jumkey 9 | 10 | [ -z "${WORK_PATH}" ] || [ ! -d "${WORK_PATH}/include" ] && WORK_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" 11 | 12 | calc_run_size() { 13 | NUM='\([0-9a-fA-F]*[ \t]*\)' 14 | OUT=$(sed -n 's/^[ \t0-9]*.b[sr][sk][ \t]*'"${NUM}${NUM}${NUM}${NUM}"'.*/0x\1 0x\4/p') 15 | 16 | if [ -z "${OUT}" ]; then 17 | echo "Never found .bss or .brk file offset" >&2 18 | return 1 19 | fi 20 | 21 | read -r sizeA offsetA sizeB offsetB <<<"$(echo "${OUT}" | awk '{printf "%d %d %d %d", strtonum($1), strtonum($2), strtonum($3), strtonum($4)}')" 22 | 23 | runSize=$((offsetA + sizeA + sizeB)) 24 | 25 | # BFD linker shows the same file offset in ELF. 26 | if [ "${offsetA}" -ne "${offsetB}" ]; then 27 | # Gold linker shows them as consecutive. 28 | endSize=$((offsetB + sizeB)) 29 | if [ "${endSize}" -ne "${runSize}" ]; then 30 | printf "sizeA: 0x%x\n" "${sizeA}" >&2 31 | printf "offsetA: 0x%x\n" "${offsetA}" >&2 32 | printf "sizeB: 0x%x\n" "${sizeB}" >&2 33 | printf "offsetB: 0x%x\n" "${offsetB}" >&2 34 | echo ".bss and .brk are non-contiguous" >&2 35 | return 1 36 | fi 37 | fi 38 | 39 | printf "%d\n" ${runSize} 40 | return 0 41 | } 42 | 43 | # Adapted from: scripts/Makefile.lib 44 | # Usage: size_append FILE [FILE2] [FILEn]... 45 | # Output: LE HEX with size of file in bytes (to STDOUT) 46 | file_size_le() { 47 | printf "$( 48 | local dec_size=0 49 | for F in "$@"; do dec_size=$((dec_size + $(stat -c "%s" "${F}"))); done 50 | printf "%08x\n" "${dec_size}" | sed 's/\(..\)/\1 /g' | { 51 | read -r ch0 ch1 ch2 ch3 52 | for ch in "${ch3}" "${ch2}" "${ch1}" "${ch0}"; do printf '%s%03o' '\' "$((0x${ch}))"; done 53 | } 54 | )" 55 | } 56 | 57 | size_le() { 58 | printf "$( 59 | printf "%08x\n" "${@}" | sed 's/\(..\)/\1 /g' | { 60 | read -r ch0 ch1 ch2 ch3 61 | for ch in "${ch3}" "${ch2}" "${ch1}" "${ch0}"; do printf '%s%03o' '\' "$((0x${ch}))"; done 62 | } 63 | )" 64 | } 65 | 66 | VMLINUX_MOD=${1} 67 | ZIMAGE_MOD=${2} 68 | 69 | KVER=$(strings "${VMLINUX_MOD}" | grep -Eo "Linux version [0-9]+\.[0-9]+\.[0-9]+" | head -1 | awk '{print $3}') 70 | if [ "$(echo "${KVER:-4}" | cut -d'.' -f1)" -lt 5 ]; then 71 | # Kernel version 4.x or 3.x (bromolow) 72 | # zImage_head 16494 73 | # payload( 74 | # vmlinux.bin x 75 | # padding 0xf00000-x 76 | # vmlinux.bin size 4 77 | # ) 0xf00004 78 | # zImage_tail( 79 | # unknown 72 80 | # run_size 4 81 | # unknown 30 82 | # vmlinux.bin size 4 83 | # unknown 114460 84 | # ) 114570 85 | # crc32 4 86 | gzip -dc "${WORK_PATH}/bzImage-template-v4.gz" >"${ZIMAGE_MOD}" || exit 1 87 | 88 | dd if="${VMLINUX_MOD}" of="${ZIMAGE_MOD}" bs=16494 seek=1 conv=notrunc || exit 1 89 | file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=15745134 seek=1 conv=notrunc || exit 1 90 | file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=15745244 seek=1 conv=notrunc || exit 1 91 | 92 | RUN_SIZE=$(objdump -h "${VMLINUX_MOD}" | calc_run_size) 93 | size_le "${RUN_SIZE}" | dd of="${ZIMAGE_MOD}" bs=15745210 seek=1 conv=notrunc || exit 1 94 | size_le "$((16#$(crc32 "${ZIMAGE_MOD}" | awk '{print $1}') ^ 0xFFFFFFFF))" | dd of="${ZIMAGE_MOD}" conv=notrunc oflag=append || exit 1 95 | else 96 | # Kernel version 5.x 97 | gzip -dc "${WORK_PATH}/bzImage-template-v5.gz" >"${ZIMAGE_MOD}" || exit 1 98 | 99 | dd if="${VMLINUX_MOD}" of="${ZIMAGE_MOD}" bs=14561 seek=1 conv=notrunc || exit 1 100 | file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=34463421 seek=1 conv=notrunc || exit 1 101 | file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=34479132 seek=1 conv=notrunc || exit 1 102 | # RUN_SIZE=$(objdump -h "${VMLINUX_MOD}" | calc_run_size) 103 | # size_le "${RUN_SIZE}" | dd of="${ZIMAGE_MOD}" bs=34626904 seek=1 conv=notrunc || exit 1 104 | size_le "$((16#$(crc32 "${ZIMAGE_MOD}" | awk '{print $1}') ^ 0xFFFFFFFF))" | dd of="${ZIMAGE_MOD}" conv=notrunc oflag=append || exit 1 105 | fi 106 | -------------------------------------------------------------------------------- /files/initrd/opt/rr/zimage-patch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | [ -z "${WORK_PATH}" ] || [ ! -d "${WORK_PATH}/include" ] && WORK_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" 10 | 11 | . "${WORK_PATH}/include/functions.sh" 12 | 13 | set -o pipefail # Get exit code from process piped 14 | 15 | # Sanity check 16 | if [ ! -f "${ORI_ZIMAGE_FILE}" ]; then 17 | echo "ERROR: ${ORI_ZIMAGE_FILE} not found!" >"${LOG_FILE}" 18 | exit 1 19 | fi 20 | 21 | echo -n "Patching zImage" 22 | rm -f "${MOD_ZIMAGE_FILE}" 23 | 24 | KERNEL="$(readConfigKey "kernel" "${USER_CONFIG_FILE}")" 25 | 26 | if [ "${KERNEL}" = "custom" ]; then 27 | echo -n "." 28 | PLATFORM="$(readConfigKey "platform" "${USER_CONFIG_FILE}")" 29 | KVER="$(readConfigKey "kver" "${USER_CONFIG_FILE}")" 30 | KPRE="$(readConfigKey "kpre" "${USER_CONFIG_FILE}")" 31 | # Extract bzImage 32 | gzip -dc "${CKS_PATH}/bzImage-${PLATFORM}-${KPRE:+${KPRE}-}${KVER}.gz" >"${MOD_ZIMAGE_FILE}" 33 | echo -n "..." 34 | else 35 | echo -n "." 36 | # Extract vmlinux 37 | "${WORK_PATH}/bzImage-to-vmlinux.sh" "${ORI_ZIMAGE_FILE}" "${TMP_PATH}/vmlinux" >"${LOG_FILE}" 2>&1 || exit 1 38 | echo -n "." 39 | # Patch boot params and ramdisk check 40 | "${WORK_PATH}/kpatch" "${TMP_PATH}/vmlinux" "${TMP_PATH}/vmlinux-mod" >"${LOG_FILE}" 2>&1 || exit 1 41 | echo -n "." 42 | # Rebuild zImage 43 | "${WORK_PATH}/vmlinux-to-bzImage.sh" "${TMP_PATH}/vmlinux-mod" "${MOD_ZIMAGE_FILE}" >"${LOG_FILE}" 2>&1 || exit 1 44 | echo -n "." 45 | fi 46 | 47 | sync 48 | 49 | echo -n "." 50 | # Update HASH of new DSM zImage 51 | HASH="$(sha256sum "${ORI_ZIMAGE_FILE}" | awk '{print $1}')" 52 | writeConfigKey "zimage-hash" "${HASH}" "${USER_CONFIG_FILE}" 53 | 54 | echo -n "." 55 | echo 56 | -------------------------------------------------------------------------------- /files/mnt/p1/EFI/BOOT/SynoBootLoader.conf: -------------------------------------------------------------------------------- 1 | serial --unit=1 --speed=115200 2 | terminal serial 3 | default 1 4 | timeout 3 5 | verbose 6 | hiddenmenu 7 | fallback 0 8 | 9 | title SYNOLOGY_1 10 | root (hd0,0) 11 | kernel /zImage root=/dev/md0 12 | initrd /rd.gz 13 | 14 | title SYNOLOGY_2 15 | root (hd0,1) 16 | cksum /grub_cksum.syno 17 | vender /vender show 18 | kernel /zImage root=/dev/md0 19 | initrd /rd.gz 20 | -------------------------------------------------------------------------------- /files/mnt/p1/EFI/BOOT/SynoBootLoader.efi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/files/mnt/p1/EFI/BOOT/SynoBootLoader.efi -------------------------------------------------------------------------------- /files/mnt/p1/RR_VERSION: -------------------------------------------------------------------------------- 1 | 25.6.2 2 | -------------------------------------------------------------------------------- /files/mnt/p1/boot/grub/gfxblacklist.txt: -------------------------------------------------------------------------------- 1 | # GRUB gfxpayload blacklist. The format is a sequence of lines of the 2 | # following form, using lower-case hexadecimal for all ID components: 3 | # 4 | # vVENDORdDEVICEsvSUBVENDORsdSUBDEVICEbcBASECLASSscSUBCLASS 5 | # 6 | # Blacklist lines are regex-matched (currently using Lua's string.find with 7 | # the line surrounded by ^ and $) against a corresponding PCI ID string. In 8 | # practice this means that you can replace any part of the ID string with .* 9 | # to match anything. 10 | # 11 | # There is no need to customise this file locally. If you need to disable 12 | # gfxpayload=keep on your system, just add this line (uncommented) to 13 | # /etc/default/grub: 14 | # 15 | # GRUB_GFXPAYLOAD_LINUX=text 16 | 17 | v15add0710.* 18 | v15add0405.* 19 | v80eedbeef.* 20 | v1002d6738.* 21 | -------------------------------------------------------------------------------- /files/mnt/p1/boot/grub/grub.cfg: -------------------------------------------------------------------------------- 1 | 2 | set timeout="5" 3 | set timeout_style="menu" 4 | 5 | if [ -s ${prefix}/grubenv ]; then 6 | load_env --skip-sig --file=${prefix}/grubenv 7 | fi 8 | 9 | if [ "${next_entry}" ]; then 10 | set default="${next_entry}" 11 | unset next_entry 12 | save_env next_entry 13 | else 14 | set default="boot" 15 | fi 16 | 17 | if [ "${linux_gfx_mode}" ]; then 18 | save_env linux_gfx_mode 19 | else 20 | set linux_gfx_mode=keep 21 | save_env linux_gfx_mode 22 | fi 23 | 24 | if [ x"${feature_menuentry_id}" = xy ]; then 25 | menuentry_id_option="--id" 26 | else 27 | menuentry_id_option="" 28 | fi 29 | 30 | export menuentry_id_option 31 | 32 | function load_video { 33 | if [ x"${feature_all_video_module}" = xy ]; then 34 | insmod all_video 35 | else 36 | insmod efi_gop 37 | insmod efi_uga 38 | insmod ieee1275_fb 39 | insmod vbe 40 | insmod vga 41 | insmod video_bochs 42 | insmod video_cirrus 43 | fi 44 | } 45 | 46 | if [ x"${feature_default_font_path}" = xy ]; then 47 | font=unicode 48 | else 49 | font=${prefix}/fonts/unicode.pf2 50 | fi 51 | 52 | if loadfont ${font}; then 53 | set gfxmode=auto 54 | load_video 55 | insmod gfxterm 56 | set locale_dir=$prefix/locale 57 | set lang=en_US 58 | insmod gettext 59 | fi 60 | 61 | terminal_output gfxterm 62 | 63 | if serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1; then 64 | terminal_input --append serial 65 | terminal_output --append serial 66 | fi 67 | 68 | set color_normal=white/black 69 | set menu_color_normal=light-cyan/black 70 | set menu_color_highlight=black/cyan 71 | 72 | insmod png 73 | background_image ${prefix}/logo.png 74 | 75 | function gfxmode { 76 | set gfxpayload="${linux_gfx_mode}" 77 | } 78 | 79 | set RR_CMDLINE="earlyprintk earlycon=uart8250,io,0x3f8,115200n8 console=ttyS0,115200n8 root=/dev/ram rootwait intremap=off amd_iommu_intr=legacy net.ifnames=0 panic=5 split_lock_detect=off pcie_aspm=off intel_pstate=disable amd_pstate=disable nox2apic nomodeset nowatchdog" 80 | 81 | search --set=root --label "RR3" 82 | if [ -e /initrd-rru ]; then set RRU=/initrd-rru; fi 83 | if [ -e /microcode.img ]; then set MCI=/microcode.img; fi 84 | 85 | if [ -s /zImage-dsm -a -s /initrd-dsm ]; then 86 | if [ "${default}" = "direct" ]; then 87 | set timeout="1" 88 | if [ -s ${prefix}/rsysenv ]; then 89 | load_env --skip-sig --file=${prefix}/rsysenv 90 | fi 91 | menuentry 'Boot DSM kernel directly' ${menuentry_id_option} direct { 92 | gfxmode 93 | echo "RRVersion: ${rr_version}" 94 | echo "${rr_booting}" 95 | echo -n "Boot Time: "; date 96 | echo "" 97 | echo "Model: ${dsm_model}" 98 | echo "version: ${dsm_version}" 99 | echo "kernel: ${dsm_kernel}" 100 | echo "LKM: ${dsm_lkm}" 101 | echo "MEV: ${sys_mev}" 102 | echo "DMI: ${sys_dmi}" 103 | echo "CPU: ${sys_cpu}" 104 | echo "MEM: ${sys_mem}" 105 | echo "Cmdline:" 106 | echo "${dsm_cmdline}" 107 | echo "" 108 | echo "Loading DSM kernel..." 109 | linux /zImage-dsm ${dsm_cmdline} 110 | echo "Loading DSM initramfs..." 111 | initrd ${MCI} /initrd-dsm 112 | echo "Booting..." 113 | echo "Access http://find.synology.com/ to connect the DSM via web." 114 | } 115 | fi 116 | menuentry 'Boot DSM' ${menuentry_id_option} boot { 117 | gfxmode 118 | echo "Loading kernel..." 119 | linux /bzImage-rr ${RR_CMDLINE} ${rr_cmdline} 120 | echo "Loading initramfs..." 121 | initrd ${MCI} /initrd-rr ${RRU} 122 | echo "Booting..." 123 | } 124 | menuentry 'Boot Recovery' ${menuentry_id_option} recovery { 125 | gfxmode 126 | echo "Loading kernel..." 127 | linux /bzImage-rr ${RR_CMDLINE} ${rr_cmdline} recovery 128 | echo "Loading initramfs..." 129 | initrd ${MCI} /initrd-rr ${RRU} 130 | echo "Booting..." 131 | } 132 | menuentry 'Force re-install DSM' ${menuentry_id_option} junior { 133 | gfxmode 134 | echo "Loading kernel..." 135 | linux /bzImage-rr ${RR_CMDLINE} ${rr_cmdline} force_junior 136 | echo "Loading initramfs..." 137 | initrd ${MCI} /initrd-rr ${RRU} 138 | echo "Booting..." 139 | } 140 | fi 141 | 142 | menuentry 'Configure loader' ${menuentry_id_option} config { 143 | gfxmode 144 | echo "Loading kernel..." 145 | linux /bzImage-rr earlycon=uart8250,io,0x3f8,115200n8 console=ttyS0,115200n8 ${RR_CMDLINE} ${rr_cmdline} IWANTTOCHANGETHECONFIG 146 | echo "Loading initramfs..." 147 | initrd ${MCI} /initrd-rr ${RRU} 148 | echo "Booting..." 149 | } 150 | 151 | menuentry 'Configure loader (verbose)' ${menuentry_id_option} verbose { 152 | gfxmode 153 | echo "Loading kernel..." 154 | linux /bzImage-rr ${RR_CMDLINE} ${rr_cmdline} earlycon=tty2 console=tty2 IWANTTOCHANGETHECONFIG 155 | echo "Loading initramfs..." 156 | initrd ${MCI} /initrd-rr ${RRU} 157 | echo "Booting..." 158 | } 159 | 160 | if [ "${grub_platform}" = "efi" ]; then 161 | insmod bli 162 | menuentry 'UEFI Firmware Settings' ${menuentry_id_option} uefi { 163 | fwsetup 164 | } 165 | fi 166 | 167 | if [ -e ${prefix}/memtest ]; then 168 | menuentry 'Start Memtest86+' ${menuentry_id_option} memtest { 169 | echo "Loading memtest86+..." 170 | linux ${prefix}/memtest 171 | } 172 | fi 173 | 174 | if [ "${linux_gfx_mode}" = "keep" ]; then 175 | menuentry 'Change vesa to text video mode' ${menuentry_id_option} videomode { 176 | set linux_gfx_mode=text 177 | save_env linux_gfx_mode 178 | configfile ${prefix}/grub.cfg 179 | } 180 | else 181 | menuentry 'Change text to vesa video mode' ${menuentry_id_option} videomode { 182 | set linux_gfx_mode=keep 183 | save_env linux_gfx_mode 184 | configfile ${prefix}/grub.cfg 185 | } 186 | fi 187 | -------------------------------------------------------------------------------- /files/mnt/p1/boot/grub/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/files/mnt/p1/boot/grub/logo.png -------------------------------------------------------------------------------- /files/mnt/p1/boot/grub/memtest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RROrg/rr/f9d09c2bf5b7cec4039298fff3413437b1890b7d/files/mnt/p1/boot/grub/memtest -------------------------------------------------------------------------------- /guide.md: -------------------------------------------------------------------------------- 1 | 2 | # ENV: 3 | * ### 常用工具: 4 | * telnet 工具 putty (下载: https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html) 5 | * ssh 工具 WindTerm (下载: https://github.com/kingToolbox/WindTerm) 6 | * sftp 工具 WinSCP (下载: https://winscp.net/eng/index.php) 7 | * 文本编辑工具 Notepad3 (下载: https://github.com/rizonesoft/Notepad3/releases) 8 | * 镜像写盘工具 Rufus (下载: https://rufus.ie/zh/) 9 | * 镜像转换工具 qemu-img (下载: https://cloudbase.it/qemu-img-windows/) 10 | * 镜像转换工具 StarWind V2V Image Converter (下载: https://www.starwindsoftware.com/starwind-v2v-converter) 11 | * 磁盘管理工具 Diskgenius (下载: https://www.diskgenius.com/) 12 | 13 | # LINK: 14 | * 查找: 15 | * http://find.synology.cn/ 16 | * http://find.synology.com/ 17 | * 下载: 18 | * https://archive.synology.cn/download/Os/DSM 19 | * https://archive.synology.com/download/Os/DSM 20 | * 介绍: 21 | * https://www.synology.cn/zh-cn/products#specs 22 | * https://www.synology.com/en-us/products#specs 23 | * 型号列表: 24 | * https://kb.synology.cn/zh-cn/DSM/tutorial/What_kind_of_CPU_does_my_NAS_have 25 | * https://kb.synology.com/en-us/DSM/tutorial/What_kind_of_CPU_does_my_NAS_have 26 | * RAID计算: 27 | * https://www.synology.cn/zh-cn/support/RAID_calculator 28 | * https://www.synology.com/en-us/support/RAID_calculator 29 | * 恢复数据: 30 | * https://kb.synology.cn/zh-cn/DSM/tutorial/How_can_I_recover_data_from_my_DiskStation_using_a_PC 31 | * https://kb.synology.com/en-us/DSM/tutorial/How_can_I_recover_data_from_my_DiskStation_using_a_PC 32 | * SDK: 33 | * https://dataupdate7.synology.com/toolchain/v1/get_download_list?identify=toolkit&version=7.2&platform=base 34 | * https://dataupdate7.synology.com/toolchain/v1/get_download_list?identify=toolkit&version=7.2&platform=purley 35 | 36 | # 安装条件 37 | 1. 引导盘:当前支持 SATA/SCSI/NVME/MMC/IDE or USB 设备, 且要大于 2GB. (SCSI 比较复杂, 并不是全部可用) 38 | 2. 安装盘: 至少需要 1 个 SATA 接口硬盘(DT 型号支持 NVME 安装) 或者 1 个 MMC 作为存储设备. 且要大于 32GB 才可创建存储池. 39 | 3. 内存: 需要大于 4GB. 40 | 4. DT 的型号目前不支持 HBA 扩展卡(较新版本的RR引导 SA6400 支持). 41 | 5. NVME 的 PCIPATH 有两种格式, 单层深度路径的仅兼容 DT 的型号, 多层深度路径的兼容 DT 和非 DT 等型号. 42 | 43 | # 镜像格式 44 | ```shell 45 | # 安装 qemu-img 46 | # https://cloudbase.it/qemu-img-windows/ # Windows 47 | # apt install qemu-img # Debian/Ubuntu 48 | # yum install qemu-img # CentOS 49 | # brew install qemu-img # MacOS 50 | 51 | # img to vmdk (VMWare / ESXi6 / ESXi7) 52 | qemu-img convert -O vmdk -o adapter_type=lsilogic,subformat=streamOptimized,compat6 rr.img rr.vmdk 53 | 54 | # img to vmdk (ESXi8) 55 | qemu-img convert -O vmdk -o adapter_type=lsilogic,subformat=monolithicFlat,compat6 rr.img rr.vmdk 56 | 57 | # img to vhdx (Hyper-V) 58 | qemu-img convert -O vhdx -o subformat=dynamic rr.img rr.vhdx 59 | 60 | # img to vhd (Parallels Desktop) 61 | qemu-img convert -O vpc rr.img rr.vhd 62 | ``` 63 | 64 | 65 | # GPU 66 | * vGPU: https://blog.kkk.rs/ 67 | * iGPU: https://jim.plus/ 68 | * iGPU: https://github.com/MoetaYuko/intel-gpu-i915-backports 69 | 70 | # RR: 71 | * RR 各版本间切换(手动方式, 全量): 72 | ```shell 73 | # 在 shell 中下载需要的版本或者手动上传到 ~/ 下 74 | # Download the required version in the shell or manually upload it to ~/ 75 | curl -kL -o ~/rr.zip https://github.com/wjz304/rr/releases/download/23.4.5/rr-23.11.1.img.zip 76 | # 卸载挂载的引导盘 77 | # Uninstalling the mounted boot disk 78 | umount /mnt/p1 /mnt/p2 /mnt/p3 79 | # 解压 并写入到引导盘 80 | # Decompress and write to the boot disk 81 | # 获取当前的引导盘 82 | LOADER_DISK="$(blkid -L RR3 2>/dev/null | cut -d3 -f1)" 83 | unzip -p rr.zip | dd of=${LOADER_DISK} bs=1M conv=fsync 84 | # 重启 reboot 85 | reboot 86 | ``` 87 | * RR 备份 (Any version): 88 | ```shell 89 | # 备份为 disk.img.gz, 自行导出. 90 | dd if="$(blkid -L RR3 2>/dev/null | cut -d3 -f1)" | gzip > disk.img.gz 91 | # 结合 transfer.sh 直接导出链接 92 | curl -skL --insecure -w '\n' --upload-file disk.img.gz https://transfer.sh 93 | ``` 94 | 95 | * RR 开机强行进入到 RR shell: 96 | ```shell 97 | # 在 wait IP 的时候, 快速的连上, 杀死 boot.sh 进程. 98 | kill $(ps | grep -v grep | grep boot.sh | awk '{print $1}') 99 | ``` 100 | 101 | # SYNO: 102 | * ssh 开启 root 权限: 103 | ```shell 104 | sudo -i 105 | sed -i 's/^.*PermitRootLogin.*$/PermitRootLogin yes/' /etc/ssh/sshd_config 106 | synouser --setpw root xxxxxx # xxxxxx 为你要设置的密码 107 | systemctl restart sshd 108 | ``` 109 | * dsm下挂载引导盘: 110 | ```shell 111 | sudo -i 112 | echo 1 > /proc/sys/kernel/syno_install_flag 113 | ls /dev/synoboot* # 正常会有 /dev/synoboot /dev/synoboot1 /dev/synoboot2 /dev/synoboot3 114 | # 挂载第1个分区 115 | mkdir -p /tmp/synoboot1 116 | mount /dev/synoboot1 /tmp/synoboot1 117 | ls /tmp/synoboot1/ 118 | # 挂载第2个分区 119 | mkdir -p /tmp/synoboot2 120 | mount /dev/synoboot2 /tmp/synoboot2 121 | ls /tmp/synoboot2/ 122 | ``` 123 | * dsm下重启到RR(免键盘) (Any version): 124 | ```shell 125 | sudo -i # 输入密码 126 | /usr/bin/loader-reboot.sh "config" 127 | ``` 128 | * dsm下修改sn (Any version): 129 | ```shell 130 | sudo -i # 输入密码 131 | SN=xxxxxxxxxx # 输入你要设置的SN 132 | echo 1 > /proc/sys/kernel/syno_install_flag 133 | [ -b "/dev/synoboot1" ] && (mkdir -p /tmp/synoboot1; mount /dev/synoboot1 /tmp/synoboot1) 134 | [ -f "/tmp/synoboot1/user-config.yml" ] && OLD_SN=$(sed -E 's/^sn:(.*)/\1/; s/[\" ]//g' /tmp/synoboot1/user-config.yml) 135 | [ -n "${OLD_SN}" ] && sed -i "s/${OLD_SN}/${SN}/g" /tmp/synoboot1/user-config.yml 136 | reboot 137 | ``` 138 | * 群晖 opkg 包管理: 139 | ```shell 140 | curl -#kL http://bin.entware.net/x64-k3.2/installer/generic.sh | /bin/sh 141 | /opt/bin/opkg update 142 | /opt/bin/opkg install rename 143 | ``` 144 | * 群晖 ipkg 包管理: 145 | ```shell 146 | curl -#kL http://ipkg.nslu2-linux.org/feeds/optware/syno-i686/cross/unstable/syno-i686-bootstrap_1.2-7_i686.xsh | /bin/sh 147 | ipkg update 148 | ipkg install lm-sensors 149 | ``` 150 | * 群晖 python pip 包管理: 151 | ```shell 152 | curl -#kL https://bootstrap.pypa.io/get-pip.py | python3 153 | ``` 154 | * virt-what (MEV): 155 | ```shell 156 | kvm ---- Proxmox VE / Unraid ... 157 | qemu ---- QEMU (windows) 158 | vmware ---- VMware / VMware ESXi 159 | parallels ---- Parallels Desktop 160 | virtualbox ---- VirtualBox 161 | ``` 162 | 163 | ## DEBUG 164 | * log: 165 | ``` 166 | # 内核相关 167 | sysctl -n kernel.syno_serial # 查看当前鉴权的 SN 168 | cat /proc/sys/kernel/syno_serial # 查看当前鉴权的 SN 169 | sysctl -n kernel.syno_mac_address1 # 查看当前鉴权的 mac1 (kernel.syno_mac_addresses) 170 | cat /proc/sys/kernel/syno_mac_address1 # 查看当前鉴权的 mac1 (/proc/sys/kernel/syno_mac_addresses) 171 | sysctl -n kernel.syno_internal_netif_num # 查看当前鉴权的网卡数量 172 | cat /proc/sys/kernel/syno_internal_netif_num # 查看当前鉴权的网卡数量 173 | sysctl -w kernel.syno_CPU_info_core=32 # 设置线程数 (无效) 174 | 175 | ls -d /sys/devices/system/node/node* | wc -l # 查看当前 CPU 物理路数 176 | cat /proc/cpuinfo | grep "physical id" | sort -u | wc -l # 查看当前 CPU 物理路数 177 | cat /proc/cpuinfo | grep "core id" | sort -u | wc -l # 查看当前 CPU 核心数 178 | cat /proc/cpuinfo | grep "processor" | wc -l # 查看当前 CPU 核心数 179 | cat /proc/sys/kernel/syno_CPU_info_core # 查看当前线程数 (only syno) 180 | nproc # 查看当前 CPU 核心数 181 | lscpu | grep 'NUMA node(s):' # 查看当前 NUMA 数量 182 | 183 | # 设备相关 184 | lsmod # 查看已加载驱动 185 | lsusb # 查看 USB 设备 186 | lsblk # 查看磁盘设备 187 | lspci -Qnnk # 查看 PCI 设备 188 | 189 | # 驱动相关 190 | ls -ld /sys/class/net/*/device/driver # 查看已加载网卡和对应驱动 191 | cat /sys/class/net/*/address # 查看已加载网卡的 MAC 地址 192 | 193 | # 串口 194 | cat /proc/tty/drivers # 查看串口属性 195 | cat /proc/tty/driver/serial # 查看串口属性 196 | stty -F /dev/ttyS0 -a # 查看串口参数 197 | stty -F /dev/ttyS0 ispeed 115200 ospeed 115200 cs8 -parenb -cstopb -echo # 设置串口参数 198 | stty size # 打印终端的行数和列数 199 | echo helloworld >/dev/ttyS0 # 向串口发送数据 200 | cat /dev/ttyS0 # 读取串口数据 201 | getty -L /dev/ttyS0 115200 # 启动串口终端 202 | agetty -L /dev/ttyS0 115200 # 启动串口终端 203 | 204 | # 磁盘相关 205 | fdisk -l # 查看硬盘信息 206 | lspci -d ::100 # 查看 SCSI 存储控制器 https://admin.pci-ids.ucw.cz/read/PD/ 207 | lspci -d ::101 # 查看 IDE 接口 208 | lspci -d ::102 # 查看 软盘 磁盘控制器 209 | lspci -d ::103 # 查看 IPI 总线控制器 210 | lspci -d ::104 # 查看 RAID 总线控制器 211 | lspci -d ::105 # 查看 ATA 总线控制器 212 | lspci -d ::106 # 查看 SATA 总线控制器 213 | lspci -d ::107 # 查看 SAS 总线控制器 214 | lspci -d ::108 # 查看 NVM 控制器 215 | 216 | ls -l /sys/class/scsi_host # 查看 ATA 硬盘 host 信息 217 | ls -l /sys/class/mmc_host # 查看 MMC 硬盘 host 信息 218 | ls -l /sys/class/nvme # 查看 NVME 硬盘 host 信息 219 | ls /sys/block/ # 查看块设备 220 | ls /sys/block/sd* # 查看识别的 sata 硬盘 (非设备树(dtb)的型号) 221 | ls /sys/block/sata* # 查看识别的 sata 硬盘 (设备树(dtb)的型号) 222 | ls /sys/block/nvme* # 查看识别的 nvme 硬盘 223 | ls /sys/block/mmc* # 查看识别的 mmc 硬盘 224 | ls /sys/block/usb* # 查看识别的 usb 硬盘 225 | cat /sys/block/sd*/device/syno_block_info # 查看识别的 sata 硬盘挂载点 (非设备树(dtb)的型号) 226 | cat /sys/block/sata*/device/syno_block_info # 查看识别的 sata 硬盘挂载点 (设备树(dtb)的型号) 227 | cat /sys/block/nvme*/device/syno_block_info # 查看识别的 nvme 硬盘挂载点 228 | 229 | # 判断是否支持热插拔 (返回 min_power, medium_power 则可能支持热插拔; 返回 max_performance 则可能不支持热插拔.) 230 | cat /sys/class/scsi_host/host*/link_power_management_policy 231 | 232 | # Raid 相关 233 | lsblk -f # 查看 磁盘 信息 234 | cat /proc/mdstat # 查看 Raid 状态 235 | mdadm --detail --scan # 查看 Raid 信息 (-D, --detail; -s, --scan) 236 | mdadm --assemble --scan # 扫描所有的磁盘,尝试组装所有可以找到的 RAID 设备 (-A, --assemble; -s, --scan) 237 | mdadm -AsfR # 扫描所有的磁盘,尝试组装所有可以找到的 RAID 设备并强制启动 (-f, --force; -R, --run) 238 | vgchange -ay # 激活所有的逻辑卷组 239 | 240 | mdadm -D /dev/md0 # 查看 Raid 0 的详细信息 (-D, --detail) 241 | mdadm -C /dev/md0 -e 1.2 -amd -R -l1 -f -n2 /dev/sda1 /dev/sdb1 # 创建 Raid 0 (-C, --create; -R, --run; -l, --level; -n, --raid-devices) 242 | mdadm -S /dev/md0 # 停止 Raid 0 (-S, --stop) 243 | mdadm --add /dev/md0 /dev/sda1 # 添加一个磁盘到 Raid 0 中 244 | mdadm --remove /dev/md0 /dev/sda1 # 移除 Raid 0 中的一个磁盘 245 | mdadm --monitor /dev/md0 # 监控 Raid 0 状态 246 | mdadm --grow /dev/md0 --level=5 # 将 Raid 0 设备的级别改变为 RAID 5 247 | mdadm --zero-superblock /dev/sda1 # 清除 sda1 磁盘分区的 RAID 超级块 (使这个磁盘分区不再被识别为 RAID 设备的一部分) 248 | 249 | # eudev 250 | udevadm control --reload-rules # 重新加载 udev 规则 251 | udevadm trigger # 触发 udev 事件 252 | udevadm info --query all --name /dev/sata1 # 查看 udev 属性 253 | udevadm info --query all --path /sys/class/net/eth0 # 查看 udev 属性 254 | udevadm info --attribute-walk --name=/dev/sata1 # 列出 udev 属性 255 | udevadm monitor --property --udev # 监控 udev 事件 256 | udevadm test /dev/sata1 # 测试 udev 规则 257 | 258 | # 服务相关 259 | journalctl -xe # 查看服务日志 260 | systemctl # 查看服务 261 | systemctl | grep failed # 查看失败的服务 262 | systemctl list-unit-files # 查看服务配置文件 263 | systemctl list-units # 查看服务状态 264 | systemctl daemon-reload # 重新加载配置文件 265 | systemctl status cpufreq.service # 查看 CPU 频率调节器状态 266 | systemctl start cpufreq.service # 启动 CPU 频率调节器 267 | systemctl stop cpufreq.service # 停止 CPU 频率调节器 268 | systemctl enable cpufreq.service # 开机启动 CPU 频率调节器 269 | systemctl disable cpufreq.service # 永久停止 CPU 频率调节器 270 | netstat -tunlp # 查看端口 271 | lsof -i :7681 # 查看 7681 端口占用情况 272 | 273 | # CPU 274 | cat /sys/devices/system/cpu/cpufreq/boost # 查看 CPU 睿频状态 275 | echo 1 > /sys/devices/system/cpu/cpufreq/boost # 开启 CPU 睿频 276 | echo 0 > /sys/devices/system/cpu/cpufreq/boost # 关闭 CPU 睿频 277 | cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_available_governors # 查看可用的 CPU 频率调节器状态 278 | cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor # 查看 CPU 频率调节器状态 279 | echo userspace | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor # 设置 CPU 频率调节器状态为 userspace 280 | cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq # 查看 CPU 当前频率 281 | cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq # 查看 CPU 最大频率 282 | echo 2000000 | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq # 设置 CPU 最大频率 283 | cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_min_freq # 查看 CPU 最小频率 284 | echo 1000000 | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_min_freq # 设置 CPU 最小频率 285 | cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_setspeed # 查看 CPU 设置频率 286 | echo 1000000 | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_setspeed # 设置 CPU 设置频率 287 | 288 | 289 | # 日志相关 290 | dmesg # 内核日志 291 | cat /proc/cmdline # 内核启动参数 292 | cat /var/log/messages # 系统消息日志 293 | cat /var/log/linuxrc.syno.log # 系统 linuxrc 日志 (junior mode) 294 | cat /tmp/installer_sh.log # 系统安装日志 (junior mode) 295 | systemctl enable syslog-ng.service # 开机启动所有日志 296 | systemctl disable syslog-ng.service # 永久停止所有日志 297 | 298 | # 显卡相关 299 | lspci -d ::300 # 查看 VGA 兼容控制器 300 | lspci -d ::301 # 查看 XGA 控制器 301 | lspci -d ::302 # 查看 3D 控制器 (不是 VGA 兼容) 302 | 303 | # Intel GPU 304 | lspci -nd ::300 | cut -d' ' -f3 # PIDVID 305 | ls /dev/dri # 查看显卡设备 306 | cat /sys/kernel/debug/dri/0/i915_frequency_info # 显卡驱动详细信息 307 | 308 | # Nvidia GPU 309 | ls /dev/nvid* # 查看显卡设备 310 | nvidia-smi # 显卡驱动详细信息 311 | 312 | # 管理软件包 313 | synopkg list # 列出所有已安装软件包 314 | synopkg show # 查看软件包信息 315 | synopkg install # 安装软件包 316 | synopkg install "$(synopkg show CodecPack 2>/dev/null | jq -r '.link')" # 安装软件包, url 方式 317 | synopkg install_from_server CodecPac # 安装软件包, 自动从服务器下载 318 | synopkg uninstall # 卸载软件包 319 | synopkg start # 启动软件包 320 | synopkg stop # 停止软件包 321 | synopkg restart # 重启软件包 322 | 323 | # 初始化 324 | synodsdefault --reinstall # 重装系统 325 | synodsdefault --factory-default # 重置系统 (清空全部数据) 326 | 327 | # 虚拟机 328 | virsh -h # 列出所有虚拟机命令 329 | virsh list --all # 列出所有虚拟机 330 | virsh console # 进入虚拟机控制台 331 | 332 | etcdctl -h # 列出所有 etcd 命令 333 | etcdctl ls /syno/live_cluster/guests/ # 列出所有虚拟机 (etcd) 334 | 335 | # API 336 | # 获取系统信息 337 | synowebapi --exec api=SYNO.Core.System method=info version=3 338 | synowebapi --exec api=SYNO.Core.System method=info version=3 type="firmware" 339 | # 获取设备信息 340 | synowebapi --exec api=SYNO.Core.System.Utilization method=get version=1 341 | # 关机 342 | synowebapi --exec api=SYNO.Core.System method=shutdown version=2 local=true force=false 343 | # 重启 344 | synowebapi --exec api=SYNO.Core.System method=reboot version=2 local=true force=false 345 | 346 | # 关闭 自动 https 重定向 347 | synowebapi --exec api=SYNO.Core.Web.DSM method=set version=2 enable_https_redirect=false 348 | # 开启 telnet/ssh 349 | synowebapi --exec api=SYNO.Core.Terminal method=set version=3 enable_telnet=true enable_ssh=true ssh_port=22 forbid_console=false 350 | 351 | # Get MD5 352 | certutil -hashfile xxx.pat MD5 # windows 353 | md5sum xxx.pat # linux/mac 354 | ``` 355 | -------------------------------------------------------------------------------- /kpatch/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS = -Wall -pedantic 3 | LDFLAGS = 4 | LIBS = /lib/x86_64-linux-gnu/libelf.a /lib/x86_64-linux-gnu/libz.a 5 | 6 | all: kpatch 7 | 8 | kpatch: main.o 9 | cc $(LDFLAGS) -o $@ $^ $(LIBS) 10 | 11 | clean: 12 | rm -f kpatch *.o 13 | -------------------------------------------------------------------------------- /kpatch/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Fabio Belavenuto 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | * 18 | */ 19 | /** 20 | * Converted from php code by Fabio Belavenuto 21 | * 22 | * A quick tool for patching the boot_params check in the DSM kernel image 23 | * This lets you tinker with the initial ramdisk contents without disabling mount() features and modules loading 24 | * 25 | * The overall pattern we need to find is: 26 | * - an CDECL function 27 | * - does "LOCK OR [const-ptr],n" 4x 28 | * - values of ORs are 1/2/4/8 respectively 29 | * - [const-ptr] is always the same 30 | * 31 | * Added patch for CMOS_WRITE by Fabio Belavenuto 32 | * 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | const int DIR_FWD = 1; 48 | const int DIR_RWD = -1; 49 | 50 | /* Variables */ 51 | int fd, verbose = 1, read_only = 0; 52 | Elf *elfHandle; 53 | GElf_Ehdr elfExecHeader; 54 | uint64_t orPos[4], fileSize, rodataAddr, rodataOffs, initTextOffs; 55 | unsigned char *fileData; 56 | 57 | /*****************************************************************************/ 58 | void errorMsg(char *fmt, ...) 59 | { 60 | va_list args; 61 | va_start(args, fmt); 62 | vfprintf(stderr, fmt, args); 63 | va_end(args); 64 | fprintf(stderr, "\n"); 65 | exit(1); 66 | } 67 | 68 | /*****************************************************************************/ 69 | void errorNum() 70 | { 71 | char str[100] = {0}; 72 | perror(str); 73 | exit(2); 74 | } 75 | 76 | /*****************************************************************************/ 77 | void elfErrno() 78 | { 79 | int err; 80 | 81 | if ((err = elf_errno()) != 0) 82 | { 83 | fprintf(stderr, "%s\n", elf_errmsg(err)); 84 | exit(3); 85 | } 86 | } 87 | 88 | /*****************************************************************************/ 89 | // Finding a function boundary is non-trivial really as patters can vary, we can have multiple exit points, and in CISC 90 | // there are many things which may match e.g. "PUSH EBP". Implementing even a rough disassembler is pointless. 91 | // However, we can certainly cheat here as we know with CDECL a non-empty function will always contain one or more 92 | // PUSH (0x41) R12-R15 (0x54-57) sequences. Then we can search like a 1K forward for these characteristic LOCK OR. 93 | uint64_t findPUSH_R12_R15_SEQ(uint64_t start) 94 | { 95 | uint64_t i; 96 | 97 | for (i = start; i < fileSize; i++) 98 | { 99 | if (fileData[i] == 0x41 && (fileData[i + 1] >= 0x54 && fileData[i + 1] <= 0x57)) 100 | { 101 | return i; 102 | } 103 | } 104 | return -1; 105 | } 106 | 107 | /*****************************************************************************/ 108 | //[0xF0, 0x80, null, null, null, null, null, 0xXX], 109 | uint64_t findORs(uint64_t start, uint32_t maxCheck) 110 | { 111 | uint64_t i; 112 | int c = 0; 113 | uint8_t lb = 0x01; 114 | 115 | for (i = start; i < fileSize; i++) 116 | { 117 | if (fileData[i] == 0xF0 && fileData[i + 1] == 0x80 && fileData[i + 7] == lb) 118 | { 119 | orPos[c++] = i; 120 | i += 7; 121 | lb <<= 1; 122 | } 123 | if (c == 4) 124 | { 125 | break; 126 | } 127 | if (--maxCheck == 0) 128 | { 129 | break; 130 | } 131 | } 132 | return c; 133 | } 134 | 135 | /*****************************************************************************/ 136 | void patchBootParams() 137 | { 138 | uint64_t addr, pos; 139 | uint64_t newPtrOffset, ptrOffset; 140 | int n; 141 | 142 | printf("Patching boot params.\n"); 143 | // The function will reside in init code part. We don't care we may potentially search beyond as we expect it to be found 144 | while (initTextOffs < fileSize) 145 | { 146 | addr = findPUSH_R12_R15_SEQ(initTextOffs); 147 | if (addr == -1) 148 | break; // no more "functions" left 149 | printf("\rAnalyzing f() candidate @ %lX, PUSH @ %lX", initTextOffs, addr); 150 | // we found something looking like PUSH R12-R15, now find the ORs 151 | n = findORs(initTextOffs, 1024); 152 | if (n != 4) 153 | { 154 | // We can always move forward by the function token length (obvious) but if we couldn't find any LOCK-OR tokens 155 | // we can skip the whole look ahead distance. We CANNOT do that if we found even a single token because the next one 156 | // might have been just after the look ahead distance 157 | initTextOffs += 2; 158 | if (n == 0) 159 | { 160 | initTextOffs += 1024; 161 | } 162 | continue; // Continue the main search loop to find next function candidate 163 | } 164 | // We found LOCK(); OR ptr sequences so we can print some logs and collect ptrs (as this is quite expensive) 165 | printf("\n[?] Found possible f() @ %lX\n", initTextOffs); 166 | ptrOffset = 0; 167 | int ec = 0; 168 | for (n = 0; n < 4; n++) 169 | { 170 | // data will have the following bytes: 171 | // [0-LOCK()] [1-OR()] [2-BYTE-PTR] [3-OFFS-b3] [4-OFFS-b2] [5-OFFS-b1] [6-OFFS-b1] [7-NUMBER] 172 | pos = orPos[n]; 173 | // how far it "jumps" 174 | newPtrOffset = pos + (fileData[pos + 6] << 24 | fileData[pos + 5] << 16 | fileData[pos + 4] << 8 | fileData[pos + 3]); 175 | if (ptrOffset == 0) 176 | { 177 | ptrOffset = newPtrOffset; 178 | ++ec; 179 | } 180 | else if (ptrOffset == newPtrOffset) 181 | { 182 | ++ec; 183 | } 184 | printf("\t[+] Found LOCK-OR#%d sequence @ %lX => %02X %02X %02X %02X %02X %02X %02X %02X [RIP+%lX]\n", 185 | n, pos, fileData[pos], fileData[pos + 1], fileData[pos + 2], fileData[pos + 3], fileData[pos + 4], 186 | fileData[pos + 5], fileData[pos + 6], fileData[pos + 7], newPtrOffset); 187 | } 188 | if (ec != 4) 189 | { 190 | printf("\t[-] LOCK-OR PTR offset mismatch - %d/4 matched\n", ec); 191 | // If the pointer checking failed we can at least move beyond the last LOCK-OR found as we know there's no valid 192 | // sequence of LOCK-ORs there 193 | initTextOffs = orPos[3]; 194 | continue; 195 | } 196 | printf("\t[+] All %d LOCK-OR PTR offsets equal - match found!\n", ec); 197 | break; 198 | } 199 | if (addr == -1) 200 | { 201 | errorMsg("\nFailed to find matching sequences\n"); 202 | } 203 | else 204 | { 205 | // Patch offsets 206 | for (n = 0; n < 4; n++) 207 | { 208 | // The offset will point at LOCK(), we need to change the OR (0x80 0x0d) to AND (0x80 0x25) so the two bytes after 209 | pos = orPos[n] + 2; 210 | printf("Patching OR to AND @ %lX\n", pos); 211 | fileData[pos] = 0x25; 212 | } 213 | } 214 | } 215 | 216 | /*****************************************************************************/ 217 | uint32_t changeEndian(uint32_t num) 218 | { 219 | return ((num >> 24) & 0xff) | // move byte 3 to byte 0 220 | ((num << 8) & 0xff0000) | // move byte 1 to byte 2 221 | ((num >> 8) & 0xff00) | // move byte 2 to byte 1 222 | ((num << 24) & 0xff000000); // move byte 0 to byte 3 223 | } 224 | 225 | /*****************************************************************************/ 226 | uint64_t findSeq(const char *seq, int len, uint32_t pos, int dir, uint64_t max) 227 | { 228 | uint64_t i = pos; 229 | 230 | do 231 | { 232 | if (memcmp((const char *)fileData + i, seq, len) == 0) 233 | { 234 | return i; 235 | } 236 | i += dir; 237 | --max; 238 | } while (i > 0 && i < fileSize && max > 0); 239 | return -1; 240 | } 241 | 242 | /*****************************************************************************/ 243 | void patchRamdiskCheck() 244 | { 245 | uint64_t pos, errPrintAddr; 246 | uint64_t printkPos, testPos, jzPos; 247 | const char str[] = "3ramdisk corrupt"; 248 | 249 | printf("Patching ramdisk check.\n"); 250 | for (pos = rodataOffs; pos < fileSize; pos++) 251 | { 252 | if (memcmp(str, (const char *)(fileData + pos), 16) == 0) 253 | { 254 | pos -= rodataOffs; 255 | break; 256 | } 257 | } 258 | errPrintAddr = rodataAddr + pos - 1; 259 | printf("LE arg addr: %08lX\n", errPrintAddr); 260 | printkPos = findSeq((const char *)&errPrintAddr, 4, 0, DIR_FWD, -1); 261 | if (printkPos == -1) 262 | { 263 | errorMsg("printk pos not found!\n"); 264 | } 265 | // double check if it's a MOV reg,VAL (where reg is EAX/ECX/EDX/EBX/ESP/EBP/ESI/EDI) 266 | printkPos -= 3; 267 | if (memcmp((const char *)fileData + printkPos, "\x48\xc7", 2) != 0) 268 | { 269 | errorMsg("Expected MOV=>reg before printk error, got %02X %02X\n", fileData[printkPos], fileData[printkPos + 1]); 270 | } 271 | if (fileData[printkPos + 2] < 0xC0 || fileData[printkPos + 2] > 0xC7) 272 | { 273 | errorMsg("Expected MOV w/reg operand [C0-C7], got %02X\n", fileData[printkPos + 2]); 274 | } 275 | printf("Found printk MOV @ %08lX\n", printkPos); 276 | 277 | // now we should seek a reasonable amount (say, up to 32 bytes) for a sequence of CALL x => TEST EAX,EAX => JZ 278 | testPos = findSeq("\x85\xc0", 2, printkPos, DIR_RWD, 32); 279 | if (testPos == -1) 280 | { 281 | errorMsg("Failed to find TEST eax,eax\n"); 282 | } 283 | printf("Found TEST eax,eax @ %08lX\n", testPos); 284 | jzPos = testPos + 2; 285 | if (fileData[jzPos] != 0x74) 286 | { 287 | errorMsg("Failed to find JZ\n"); 288 | } 289 | printf("OK - patching %02X%02X (JZ) to %02X%02X (JMP) @ %08lX\n", 290 | fileData[jzPos], fileData[jzPos + 1], 0xEB, fileData[jzPos + 1], jzPos); 291 | fileData[jzPos] = 0xEB; 292 | } 293 | 294 | /*****************************************************************************/ 295 | void patchCmosWrite() 296 | { 297 | uint64_t pos, errPrintAddr; 298 | uint64_t pr_errPos, testPos, callPos; 299 | const char str[] = "3smpboot: %s: this boot have memory training"; 300 | 301 | printf("Patching call to rtc_cmos_write.\n"); 302 | for (pos = rodataOffs; pos < fileSize; pos++) 303 | { 304 | if (memcmp(str, (const char *)(fileData + pos), 16) == 0) 305 | { 306 | pos -= rodataOffs; 307 | break; 308 | } 309 | } 310 | errPrintAddr = rodataAddr + pos - 1; 311 | printf("LE arg addr: %08lX\n", errPrintAddr); 312 | pr_errPos = findSeq((const char *)&errPrintAddr, 4, 0, DIR_FWD, -1); 313 | if (pr_errPos == -1) 314 | { 315 | printf("pr_err pos not found - ignoring.\n"); // Some kernels do not have the call, exit without error 316 | return; 317 | } 318 | // double check if it's a MOV reg,VAL (where reg is EAX/ECX/EDX/EBX/ESP/EBP/ESI/EDI) 319 | pr_errPos -= 3; 320 | if (memcmp((const char *)fileData + pr_errPos, "\x48\xc7", 2) != 0) 321 | { 322 | errorMsg("Expected MOV=>reg before pr_err error, got %02X %02X\n", fileData[pr_errPos], fileData[pr_errPos + 1]); 323 | } 324 | if (fileData[pr_errPos + 2] < 0xC0 || fileData[pr_errPos + 2] > 0xC7) 325 | { 326 | errorMsg("Expected MOV w/reg operand [C0-C7], got %02X\n", fileData[pr_errPos + 2]); 327 | } 328 | printf("Found pr_err MOV @ %08lX\n", pr_errPos); 329 | 330 | // now we should seek a reasonable amount (say, up to 64 bytes) for a sequence of 331 | // MOV ESI, 0x48 => MOV EDI, 0xFF => MOV EBX, EAX 332 | testPos = findSeq("\xBE\x48\x00\x00\x00\xBF\xFF\x00\x00\x00\x89\xC3", 12, pr_errPos, DIR_RWD, 64); 333 | if (testPos == -1) 334 | { 335 | printf("Failed to find MOV ESI, 0x48 => MOV EDI, 0xFF => MOV EBX, EAX\n"); 336 | return; 337 | } 338 | printf("Found MOV ESI, 0x48 => MOV EDI, 0xFF => MOV EBX, EAX @ %08lX\n", testPos); 339 | callPos = testPos + 12; 340 | if (fileData[callPos] != 0xE8) 341 | { 342 | errorMsg("Failed to find CALL\n"); 343 | } 344 | printf("OK - patching %02X (CALL) to 0x90.. (NOPs) @ %08lX\n", 345 | fileData[callPos], callPos); 346 | for (uint64_t i = 0; i < 5; i++) 347 | fileData[callPos + i] = 0x90; 348 | } 349 | 350 | /*****************************************************************************/ 351 | int main(int argc, char *argv[]) 352 | { 353 | struct stat fileInf; 354 | Elf_Scn *section; 355 | GElf_Shdr sectionHeader; 356 | char *sectionName; 357 | char *fileIn = NULL, *fileOut = NULL; 358 | int onlyBoot = 0, onlyRD = 0, onlyCMOS = 0, c; 359 | 360 | if (argc < 3) 361 | { 362 | errorMsg("Use: kpatch (option) \nOptions:\n -b Only bootparams\n -r Only ramdisk\n -c Only CMOS"); 363 | } 364 | c = 1; 365 | while (c < argc) 366 | { 367 | if (strcmp(argv[c], "-b") == 0) 368 | { 369 | onlyBoot = 1; 370 | } 371 | else if (strcmp(argv[c], "-r") == 0) 372 | { 373 | onlyRD = 1; 374 | } 375 | else if (strcmp(argv[c], "-c") == 0) 376 | { 377 | onlyCMOS = 1; 378 | } 379 | else if (fileIn == NULL) 380 | { 381 | fileIn = argv[c]; 382 | } 383 | else 384 | { 385 | fileOut = argv[c]; 386 | break; 387 | } 388 | ++c; 389 | } 390 | if (NULL == fileIn) 391 | { 392 | errorMsg("Please give a input filename"); 393 | } 394 | if (NULL == fileOut) 395 | { 396 | errorMsg("Please give a output filename"); 397 | } 398 | 399 | if (elf_version(EV_CURRENT) == EV_NONE) 400 | elfErrno(); 401 | 402 | if ((fd = open(fileIn, O_RDONLY)) == -1) 403 | errorNum(); 404 | 405 | if ((elfHandle = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 406 | elfErrno(); 407 | if (gelf_getehdr(elfHandle, &elfExecHeader) == NULL) 408 | elfErrno(); 409 | 410 | switch (elf_kind(elfHandle)) 411 | { 412 | case ELF_K_NUM: 413 | case ELF_K_NONE: 414 | errorMsg("file type unknown\n"); 415 | break; 416 | case ELF_K_COFF: 417 | errorMsg("COFF binaries not supported\n"); 418 | break; 419 | case ELF_K_AR: 420 | errorMsg("AR archives not supported\n"); 421 | break; 422 | case ELF_K_ELF: 423 | break; 424 | } 425 | 426 | section = NULL; 427 | while ((section = elf_nextscn(elfHandle, section)) != NULL) 428 | { 429 | if (gelf_getshdr(section, §ionHeader) != §ionHeader) 430 | elfErrno(); 431 | if ((sectionName = elf_strptr(elfHandle, elfExecHeader.e_shstrndx, sectionHeader.sh_name)) == NULL) 432 | elfErrno(); 433 | if (strcmp(sectionName, ".init.text") == 0) 434 | { 435 | initTextOffs = sectionHeader.sh_offset; 436 | } 437 | else if (strcmp(sectionName, ".rodata") == 0) 438 | { 439 | rodataAddr = sectionHeader.sh_addr & 0xFFFFFFFF; 440 | rodataOffs = sectionHeader.sh_offset; 441 | } 442 | } 443 | elfErrno(); /* If there isn't elf_errno set, nothing will happend. */ 444 | elf_end(elfHandle); 445 | 446 | if (fstat(fd, &fileInf) == -1) 447 | errorNum(); 448 | 449 | fileSize = fileInf.st_size; 450 | fileData = malloc(fileSize); 451 | if (fileSize != read(fd, fileData, fileSize)) 452 | { 453 | errorNum(); 454 | } 455 | close(fd); 456 | 457 | printf("Found .init.text offset @ %lX\n", initTextOffs); 458 | printf("Found .rodata address @ %lX\n", rodataAddr); 459 | printf("Found .rodata offset @ %lX\n", rodataOffs); 460 | if (onlyBoot == 0 && onlyCMOS == 0 && onlyRD == 0) 461 | { 462 | patchBootParams(); 463 | patchRamdiskCheck(); 464 | patchCmosWrite(); 465 | } 466 | else 467 | { 468 | if (onlyBoot == 1) 469 | { 470 | patchBootParams(); 471 | } 472 | if (onlyRD == 1) 473 | { 474 | patchRamdiskCheck(); 475 | } 476 | if (onlyCMOS == 1) 477 | { 478 | patchCmosWrite(); 479 | } 480 | } 481 | if ((fd = open(fileOut, O_WRONLY | O_CREAT, 0644)) == -1) 482 | { 483 | errorNum(); 484 | } 485 | if (fileSize != write(fd, fileData, fileSize)) 486 | { 487 | errorNum(); 488 | } 489 | close(fd); 490 | printf("Finish!\n"); 491 | return 0; 492 | } 493 | -------------------------------------------------------------------------------- /localbuild.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | if [ "$(id -u)" -ne 0 ]; then 10 | echo "This script must be run as root" 11 | exit 1 12 | fi 13 | 14 | function help() { 15 | cat < [args] 17 | Commands: 18 | create [workspace] [rr.img] - Create the workspace 19 | init - Initialize the environment 20 | config [model] [version] - Config the DSM system 21 | build - Build the DSM system 22 | pack [rr.img] - Pack to rr.img 23 | help - Show this help 24 | EOF 25 | exit 1 26 | } 27 | 28 | function create() { 29 | local WORKSPACE RRIMGPATH LOOPX INITRD_FILE INITRD_FORMAT 30 | WORKSPACE="$(realpath "${1:-workspace}")" 31 | RRIMGPATH="$(realpath "${2:-rr.img}")" 32 | 33 | if [ ! -f "${RRIMGPATH}" ]; then 34 | echo "File not found: ${RRIMGPATH}" 35 | exit 1 36 | fi 37 | 38 | sudo apt update 39 | sudo apt install -y locales busybox dialog gettext sed gawk jq curl 40 | sudo apt install -y python-is-python3 python3-pip libelf-dev qemu-utils dosfstools cpio xz-utils lz4 lzma bzip2 gzip zstd 41 | # sudo snap install yq 42 | if ! type yq >/dev/null 2>&1 || ! yq --version 2>/dev/null | grep -q "v4."; then 43 | sudo curl -kL https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -o /usr/bin/yq && sudo chmod a+x /usr/bin/yq 44 | fi 45 | 46 | # Backup the original python3 executable. 47 | sudo mv -f "$(realpath "$(which python3)")/EXTERNALLY-MANAGED" "$(realpath "$(which python3)")/EXTERNALLY-MANAGED.bak" 2>/dev/null || true 48 | sudo pip3 install -U click requests requests-toolbelt qrcode[pil] beautifulsoup4 49 | 50 | sudo locale-gen ar_SA.UTF-8 de_DE.UTF-8 en_US.UTF-8 es_ES.UTF-8 fr_FR.UTF-8 ja_JP.UTF-8 ko_KR.UTF-8 ru_RU.UTF-8 th_TH.UTF-8 tr_TR.UTF-8 uk_UA.UTF-8 vi_VN.UTF-8 zh_CN.UTF-8 zh_HK.UTF-8 zh_TW.UTF-8 51 | 52 | LOOPX=$(sudo losetup -f) 53 | sudo losetup -P "${LOOPX}" "${RRIMGPATH}" 54 | 55 | # Check partitions and ignore errors 56 | fsck.vfat -aw "${LOOPX}p1" >/dev/null 2>&1 || true 57 | fsck.ext2 -p "${LOOPX}p2" >/dev/null 2>&1 || true 58 | fsck.ext4 -p "${LOOPX}p3" >/dev/null 2>&1 || true 59 | 60 | echo "Mounting image file" 61 | for i in {1..3}; do 62 | rm -rf "/tmp/mnt/p${i}" 63 | mkdir -p "/tmp/mnt/p${i}" 64 | sudo mount "${LOOPX}p${i}" "/tmp/mnt/p${i}" || { 65 | echo "Can't mount ${LOOPX}p${i}." 66 | exit 1 67 | } 68 | done 69 | 70 | echo "Create WORKSPACE" 71 | rm -rf "${WORKSPACE}" 72 | mkdir -p "${WORKSPACE}/mnt" "${WORKSPACE}/tmp" "${WORKSPACE}/initrd" 73 | cp -rpf /tmp/mnt/p{1,2,3} "${WORKSPACE}/mnt/" 74 | 75 | INITRD_FILE="${WORKSPACE}/mnt/p3/initrd-rr" 76 | INITRD_FORMAT=$(file -b --mime-type "${INITRD_FILE}") 77 | 78 | case "${INITRD_FORMAT}" in 79 | *'x-cpio'*) (cd "${WORKSPACE}/initrd" && sudo cpio -idm <"${INITRD_FILE}") >/dev/null 2>&1 ;; 80 | *'x-xz'*) (cd "${WORKSPACE}/initrd" && xz -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 81 | *'x-lz4'*) (cd "${WORKSPACE}/initrd" && lz4 -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 82 | *'x-lzma'*) (cd "${WORKSPACE}/initrd" && lzma -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 83 | *'x-bzip2'*) (cd "${WORKSPACE}/initrd" && bzip2 -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 84 | *'gzip'*) (cd "${WORKSPACE}/initrd" && gzip -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 85 | *'zstd'*) (cd "${WORKSPACE}/initrd" && zstd -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 86 | *) ;; 87 | esac 88 | 89 | sudo sync 90 | for i in {1..3}; do 91 | sudo umount "/tmp/mnt/p${i}" 92 | rm -rf "/tmp/mnt/p${i}" 93 | done 94 | sudo losetup --detach "${LOOPX}" 95 | 96 | if [ ! -f "${WORKSPACE}/initrd/opt/rr/init.sh" ] || [ ! -f "${WORKSPACE}/initrd/opt/rr/menu.sh" ]; then 97 | echo "initrd decompression failed." 98 | exit 1 99 | fi 100 | 101 | rm -f "$(dirname "${BASH_SOURCE[0]}")/rr.env" 102 | cat <"$(dirname "${BASH_SOURCE[0]}")/rr.env" 103 | export LOADER_DISK="LOCALBUILD" 104 | export CHROOT_PATH="${WORKSPACE}" 105 | EOF 106 | echo "OK." 107 | } 108 | 109 | function init() { 110 | if [ ! -f "$(dirname "${BASH_SOURCE[0]}")/rr.env" ]; then 111 | echo "Please run init first" 112 | exit 1 113 | fi 114 | . "$(dirname "${BASH_SOURCE[0]}")/rr.env" 115 | pushd "${CHROOT_PATH}/initrd/opt/rr" || exit 1 116 | echo "init" 117 | ./init.sh 118 | local RET=$? 119 | popd || exit 1 120 | [ ${RET} -ne 0 ] && echo "Failed." || echo "Success." 121 | exit ${RET} 122 | } 123 | 124 | function config() { 125 | if [ ! -f "$(dirname "${BASH_SOURCE[0]}")/rr.env" ]; then 126 | echo "Please run init first" 127 | exit 1 128 | fi 129 | . "$(dirname "${BASH_SOURCE[0]}")/rr.env" 130 | local RET=1 131 | pushd "${CHROOT_PATH}/initrd/opt/rr" || exit 1 132 | while true; do 133 | if [ -z "${1}" ]; then 134 | echo "menu" 135 | ./menu.sh || break 136 | RET=0 137 | else 138 | echo "model" 139 | ./menu.sh modelMenu "${1:-SA6400}" || break 140 | echo "version" 141 | ./menu.sh productversMenu "${2:-7.2}" || break 142 | RET=0 143 | fi 144 | break 145 | done 146 | popd || exit 1 147 | [ ${RET} -ne 0 ] && echo "Failed." || echo "Success." 148 | exit ${RET} 149 | } 150 | 151 | function build() { 152 | if [ ! -f "$(dirname "${BASH_SOURCE[0]}")/rr.env" ]; then 153 | echo "Please run init first" 154 | exit 1 155 | fi 156 | . "$(dirname "${BASH_SOURCE[0]}")/rr.env" 157 | local RET=1 158 | pushd "${CHROOT_PATH}/initrd/opt/rr" || exit 1 159 | while true; do 160 | echo "build" 161 | ./menu.sh make -1 || break 162 | echo "clean" 163 | ./menu.sh cleanCache -1 || break 164 | RET=0 165 | break 166 | done 167 | popd || exit 1 168 | [ ${RET} -ne 0 ] && echo "Failed." || echo "Success." 169 | exit ${RET} 170 | } 171 | 172 | function pack() { 173 | if [ ! -f "$(dirname "${BASH_SOURCE[0]}")/rr.env" ]; then 174 | echo "Please run init first" 175 | exit 1 176 | fi 177 | . "$(dirname "${BASH_SOURCE[0]}")/rr.env" 178 | 179 | local RRIMGPATH LOOPX 180 | RRIMGPATH="$(realpath "${1:-rr.img}")" 181 | rm -f "${RRIMGPATH}" 182 | gzip -dc "${CHROOT_PATH}/initrd/opt/rr/grub.img.gz" >"${RRIMGPATH}" 183 | fdisk -l "${RRIMGPATH}" 184 | 185 | LOOPX=$(sudo losetup -f) 186 | sudo losetup -P "${LOOPX}" "${RRIMGPATH}" 187 | 188 | # Check partitions and ignore errors 189 | fsck.vfat -aw "${LOOPX}p1" >/dev/null 2>&1 || true 190 | fsck.ext2 -p "${LOOPX}p2" >/dev/null 2>&1 || true 191 | fsck.ext4 -p "${LOOPX}p3" >/dev/null 2>&1 || true 192 | 193 | echo "Mounting image file" 194 | for i in {1..3}; do 195 | rm -rf "/tmp/mnt/p${i}" 196 | mkdir -p "/tmp/mnt/p${i}" 197 | sudo mount "${LOOPX}p${i}" "/tmp/mnt/p${i}" || { 198 | echo "Can't mount ${LOOPX}p${i}." 199 | exit 1 200 | } 201 | done 202 | 203 | echo "Pack image file" 204 | for i in {1..3}; do 205 | [ ${i} -eq 1 ] && sudo cp -af "${CHROOT_PATH}/mnt/p${i}/"{.locale,.timezone} "/tmp/mnt/p${i}/" 2>/dev/null 206 | sudo cp -rf "${CHROOT_PATH}/mnt/p${i}/"* "/tmp/mnt/p${i}" || { 207 | echo "Can't cp ${LOOPX}p${i}." 208 | exit 1 209 | } 210 | done 211 | 212 | sudo sync 213 | for i in {1..3}; do 214 | sudo umount "/tmp/mnt/p${i}" 215 | rm -rf "/tmp/mnt/p${i}" 216 | done 217 | sudo losetup --detach "${LOOPX}" 218 | echo "OK." 219 | exit 0 220 | } 221 | 222 | function resize() { 223 | local INPUT_FILE="${1}" 224 | local CHANGE_SIZE="${2}" 225 | local OUTPUT_FILE="${3:-${INPUT_FILE}}" 226 | 227 | [ -z "${INPUT_FILE}" ] || [ ! -f "${INPUT_FILE}" ] && exit 1 228 | [ -z "${CHANGE_SIZE}" ] && exit 1 229 | 230 | INPUT_FILE="$(realpath "${INPUT_FILE}")" 231 | OUTPUT_FILE="$(realpath "${OUTPUT_FILE}")" 232 | 233 | local SIZE=$(($(du -sm "${INPUT_FILE}" 2>/dev/null | awk '{print $1}')$(echo "${CHANGE_SIZE}" | sed 's/M//g; s/b//g'))) 234 | [ "${SIZE:-0}" -lt 0 ] && exit 1 235 | 236 | if [ ! "${INPUT_FILE}" = "${OUTPUT_FILE}" ]; then 237 | sudo cp -f "${INPUT_FILE}" "${OUTPUT_FILE}" 238 | fi 239 | 240 | sudo truncate -s ${SIZE}M "${OUTPUT_FILE}" 241 | echo -e "d\n\nn\n\n\n\n\nn\nw" | sudo fdisk "${OUTPUT_FILE}" >/dev/null 2>&1 242 | local LOOPX LOOPXPY 243 | LOOPX=$(sudo losetup -f) 244 | sudo losetup -P "${LOOPX}" "${OUTPUT_FILE}" 245 | LOOPXPY="$(find "${LOOPX}p"* -maxdepth 0 2>/dev/null | sort -n | tail -1)" 246 | sudo e2fsck -fp "${LOOPXPY:-${LOOPX}p3}" 247 | sudo resize2fs "${LOOPXPY:-${LOOPX}p3}" 248 | sudo losetup -d "${LOOPX}" 249 | } 250 | 251 | "$@" 252 | -------------------------------------------------------------------------------- /scripts/func.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | 9 | import os, re, sys, glob, json, yaml, click, shutil, tarfile, kmodule, requests, urllib3 10 | from requests.adapters import HTTPAdapter 11 | from requests.packages.urllib3.util.retry import Retry # type: ignore 12 | from openpyxl import Workbook 13 | 14 | @click.group() 15 | def cli(): 16 | """ 17 | The CLI is a commands to RR. 18 | """ 19 | pass 20 | 21 | 22 | @cli.command() 23 | @click.option("-w", "--workpath", type=str, required=True, help="The workpath of RR.") 24 | @click.option("-j", "--jsonpath", type=str, required=True, help="The output path of jsonfile.") 25 | @click.option("-x", "--xlsxpath", type=str, required=False, help="The output path of xlsxfile.") 26 | def getmodels(workpath, jsonpath, xlsxpath): 27 | models = {} 28 | platforms_yml = os.path.join(workpath, "opt", "rr", "platforms.yml") 29 | with open(platforms_yml, "r") as f: 30 | P_data = yaml.safe_load(f) 31 | P_platforms = P_data.get("platforms", []) 32 | for P in P_platforms: 33 | productvers = {} 34 | for V in P_platforms[P]["productvers"]: 35 | kpre = P_platforms[P]["productvers"][V].get("kpre", "") 36 | kver = P_platforms[P]["productvers"][V].get("kver", "") 37 | productvers[V] = f"{kpre}-{kver}" if kpre else kver 38 | models[P] = {"productvers": productvers, "models": []} 39 | 40 | adapter = HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504])) 41 | session = requests.Session() 42 | session.mount("http://", adapter) 43 | session.mount("https://", adapter) 44 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 45 | 46 | try: 47 | url = "http://update7.synology.com/autoupdate/genRSS.php?include_beta=1" 48 | #url = "https://update7.synology.com/autoupdate/genRSS.php?include_beta=1" 49 | 50 | req = session.get(url, timeout=10, verify=False) 51 | req.encoding = "utf-8" 52 | p = re.compile(r"(.*?).*?(.*?)", re.MULTILINE | re.DOTALL) 53 | data = p.findall(req.text) 54 | except Exception as e: 55 | click.echo(f"Error: {e}") 56 | return 57 | 58 | for item in data: 59 | if not "DSM" in item[1]: 60 | continue 61 | arch = item[0].split("_")[1] 62 | name = item[1].split("/")[-1].split("_")[1].replace("%2B", "+") 63 | if arch not in models: 64 | continue 65 | if name in (A for B in models for A in models[B]["models"]): 66 | continue 67 | models[arch]["models"].append(name) 68 | 69 | if jsonpath: 70 | with open(jsonpath, "w") as f: 71 | json.dump(models, f, indent=4, ensure_ascii=False) 72 | if xlsxpath: 73 | wb = Workbook() 74 | ws = wb.active 75 | ws.append(["platform", "productvers", "Model"]) 76 | for k, v in models.items(): 77 | ws.append([k, str(v["productvers"]), str(v["models"])]) 78 | wb.save(xlsxpath) 79 | 80 | 81 | @cli.command() 82 | @click.option("-w", "--workpath", type=str, required=True, help="The workpath of RR.") 83 | @click.option("-j", "--jsonpath", type=str, required=True, help="The output path of jsonfile.") 84 | @click.option("-x", "--xlsxpath", type=str, required=False, help="The output path of xlsxfile.") 85 | def getpats(workpath, jsonpath, xlsxpath): 86 | def __fullversion(ver): 87 | arr = ver.split('-') 88 | a, b, c = (arr[0].split('.') + ['0', '0', '0'])[:3] 89 | d = arr[1] if len(arr) > 1 else '00000' 90 | e = arr[2] if len(arr) > 2 else '0' 91 | return f'{a}.{b}.{c}-{d}-{e}' 92 | 93 | platforms_yml = os.path.join(workpath, "opt", "rr", "platforms.yml") 94 | with open(platforms_yml, "r") as f: 95 | data = yaml.safe_load(f) 96 | platforms = data.get("platforms", []) 97 | 98 | adapter = HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504])) 99 | session = requests.Session() 100 | session.mount("http://", adapter) 101 | session.mount("https://", adapter) 102 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 103 | 104 | try: 105 | url = "http://update7.synology.com/autoupdate/genRSS.php?include_beta=1" 106 | #url = "https://update7.synology.com/autoupdate/genRSS.php?include_beta=1" 107 | 108 | req = session.get(url, timeout=10, verify=False) 109 | req.encoding = "utf-8" 110 | p = re.compile(r"(.*?).*?(.*?)", re.MULTILINE | re.DOTALL) 111 | data = p.findall(req.text) 112 | except Exception as e: 113 | click.echo(f"Error: {e}") 114 | return 115 | 116 | models = [] 117 | for item in data: 118 | if not "DSM" in item[1]: 119 | continue 120 | arch = item[0].split("_")[1] 121 | name = item[1].split("/")[-1].split("_")[1].replace("%2B", "+") 122 | if arch not in platforms: 123 | continue 124 | if name in models: 125 | continue 126 | models.append(name) 127 | 128 | pats = {} 129 | for M in models: 130 | pats[M] = {} 131 | version = '7' 132 | urlInfo = "https://www.synology.com/api/support/findDownloadInfo?lang=en-us" 133 | urlSteps = "https://www.synology.com/api/support/findUpgradeSteps?" 134 | #urlInfo = "https://www.synology.cn/api/support/findDownloadInfo?lang=zh-cn" 135 | #urlSteps = "https://www.synology.cn/api/support/findUpgradeSteps?" 136 | 137 | major = f"&major={version.split('.')[0]}" if len(version.split('.')) > 0 else "" 138 | minor = f"&minor={version.split('.')[1]}" if len(version.split('.')) > 1 else "" 139 | try: 140 | req = session.get(f"{urlInfo}&product={M.replace('+', '%2B')}{major}{minor}", timeout=10, verify=False) 141 | req.encoding = "utf-8" 142 | data = json.loads(req.text) 143 | except Exception as e: 144 | click.echo(f"Error: {e}") 145 | continue 146 | 147 | build_ver = data['info']['system']['detail'][0]['items'][0]['build_ver'] 148 | build_num = data['info']['system']['detail'][0]['items'][0]['build_num'] 149 | buildnano = data['info']['system']['detail'][0]['items'][0]['nano'] 150 | V = __fullversion(f"{build_ver}-{build_num}-{buildnano}") 151 | if V not in pats[M]: 152 | pats[M][V] = { 153 | 'url': data['info']['system']['detail'][0]['items'][0]['files'][0]['url'].split('?')[0], 154 | 'sum': data['info']['system']['detail'][0]['items'][0]['files'][0].get('checksum', '0' * 32) 155 | } 156 | 157 | from_ver = min(I['build'] for I in data['info']['pubVers']) 158 | 159 | for I in data['info']['productVers']: 160 | if not I['version'].startswith(version): 161 | continue 162 | if not major or not minor: 163 | majorTmp = f"&major={I['version'].split('.')[0]}" if len(I['version'].split('.')) > 0 else "" 164 | minorTmp = f"&minor={I['version'].split('.')[1]}" if len(I['version'].split('.')) > 1 else "" 165 | try: 166 | reqTmp = session.get(f"{urlInfo}&product={M.replace('+', '%2B')}{majorTmp}{minorTmp}", timeout=10, verify=False) 167 | reqTmp.encoding = "utf-8" 168 | dataTmp = json.loads(reqTmp.text) 169 | except Exception as e: 170 | click.echo(f"Error: {e}") 171 | continue 172 | 173 | build_ver = dataTmp['info']['system']['detail'][0]['items'][0]['build_ver'] 174 | build_num = dataTmp['info']['system']['detail'][0]['items'][0]['build_num'] 175 | buildnano = dataTmp['info']['system']['detail'][0]['items'][0]['nano'] 176 | V = __fullversion(f"{build_ver}-{build_num}-{buildnano}") 177 | if V not in pats[M]: 178 | pats[M][V] = { 179 | 'url': dataTmp['info']['system']['detail'][0]['items'][0]['files'][0]['url'].split('?')[0], 180 | 'sum': dataTmp['info']['system']['detail'][0]['items'][0]['files'][0].get('checksum', '0' * 32) 181 | } 182 | 183 | for J in I['versions']: 184 | to_ver = J['build'] 185 | try: 186 | reqSteps = session.get(f"{urlSteps}&product={M.replace('+', '%2B')}&from_ver={from_ver}&to_ver={to_ver}", timeout=10, verify=False) 187 | if reqSteps.status_code != 200: 188 | continue 189 | reqSteps.encoding = "utf-8" 190 | dataSteps = json.loads(reqSteps.text) 191 | except Exception as e: 192 | click.echo(f"Error: {e}") 193 | continue 194 | 195 | for S in dataSteps['upgrade_steps']: 196 | if not S.get('full_patch') or not S['build_ver'].startswith(version): 197 | continue 198 | V = __fullversion(f"{S['build_ver']}-{S['build_num']}-{S['nano']}") 199 | if V not in pats[M]: 200 | reqPat = session.head(S['files'][0]['url'].split('?')[0], timeout=10, verify=False) 201 | if reqPat.status_code == 403: 202 | continue 203 | pats[M][V] = { 204 | 'url': S['files'][0]['url'].split('?')[0], 205 | 'sum': S['files'][0].get('checksum', '0' * 32) 206 | } 207 | 208 | if jsonpath: 209 | with open(jsonpath, "w") as f: 210 | json.dump(pats, f, indent=4, ensure_ascii=False) 211 | if xlsxpath: 212 | wb = Workbook() 213 | ws = wb.active 214 | ws.append(["Model", "version", "url", "sum"]) 215 | for k1, v1 in pats.items(): 216 | for k2, v2 in v1.items(): 217 | ws.append([k1, k2, v2["url"], v2["sum"]]) 218 | wb.save(xlsxpath) 219 | 220 | 221 | @cli.command() 222 | @click.option("-w", "--workpath", type=str, required=True, help="The workpath of RR.") 223 | @click.option("-j", "--jsonpath", type=str, required=True, help="The output path of jsonfile.") 224 | @click.option("-x", "--xlsxpath", type=str, required=False, help="The output path of xlsxfile.") 225 | def getaddons(workpath, jsonpath, xlsxpath): 226 | AS = glob.glob(os.path.join(workpath, "mnt", "p3", "addons", "*", "manifest.yml")) 227 | AS.sort() 228 | addons = {} 229 | for A in AS: 230 | with open(A, "r") as file: 231 | A_data = yaml.safe_load(file) 232 | A_name = A_data.get("name", "") 233 | A_system = A_data.get("system", False) 234 | A_description = A_data.get("description", {"en_US": "Unknown", "zh_CN": "Unknown"}) 235 | addons[A_name] = {"system": A_system, "description": A_description} 236 | if jsonpath: 237 | with open(jsonpath, "w") as f: 238 | json.dump(addons, f, indent=4, ensure_ascii=False) 239 | if xlsxpath: 240 | wb = Workbook() 241 | ws = wb.active 242 | ws.append(["Name", "system", "en_US", "zh_CN"]) 243 | for k1, v1 in addons.items(): 244 | ws.append([k1, v1.get("system", False), v1.get("description").get("en_US", ""), v1.get("description").get("zh_CN", "")]) 245 | wb.save(xlsxpath) 246 | 247 | 248 | @cli.command() 249 | @click.option("-w", "--workpath", type=str, required=True, help="The workpath of RR.") 250 | @click.option("-j", "--jsonpath", type=str, required=True, help="The output path of jsonfile.") 251 | @click.option("-x", "--xlsxpath", type=str, required=False, help="The output path of xlsxfile.") 252 | def getmodules(workpath, jsonpath, xlsxpath): 253 | MS = glob.glob(os.path.join(workpath, "mnt", "p3", "modules", "*.tgz")) 254 | MS.sort() 255 | modules = {} 256 | TMP_PATH = "/tmp/modules" 257 | if os.path.exists(TMP_PATH): 258 | shutil.rmtree(TMP_PATH) 259 | for M in MS: 260 | M_name = os.path.splitext(os.path.basename(M))[0] 261 | M_modules = {} 262 | os.makedirs(TMP_PATH) 263 | with tarfile.open(M, "r") as tar: 264 | tar.extractall(TMP_PATH) 265 | KS = glob.glob(os.path.join(TMP_PATH, "*.ko")) 266 | KS.sort() 267 | for K in KS: 268 | K_name = os.path.splitext(os.path.basename(K))[0] 269 | K_info = kmodule.modinfo(K, basedir=os.path.dirname(K), kernel=None)[0] 270 | K_description = K_info.get("description", "") 271 | K_depends = K_info.get("depends", "") 272 | M_modules[K_name] = {"description": K_description, "depends": K_depends} 273 | modules[M_name] = M_modules 274 | if os.path.exists(TMP_PATH): 275 | shutil.rmtree(TMP_PATH) 276 | if jsonpath: 277 | with open(jsonpath, "w") as file: 278 | json.dump(modules, file, indent=4, ensure_ascii=False) 279 | if xlsxpath: 280 | wb = Workbook() 281 | ws = wb.active 282 | ws.append(["Name", "Arch", "description", "depends"]) 283 | for k1, v1 in modules.items(): 284 | for k2, v2 in v1.items(): 285 | ws.append([k2, k1, v2["description"], v2["depends"]]) 286 | wb.save(xlsxpath) 287 | 288 | 289 | if __name__ == "__main__": 290 | cli() 291 | -------------------------------------------------------------------------------- /scripts/func.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | # sudo apt install -y locales busybox dialog gettext sed gawk jq curl 9 | # sudo apt install -y python-is-python3 python3-pip libelf-dev qemu-utils cpio xz-utils lz4 lzma bzip2 gzip zstd 10 | 11 | [ -n "${1}" ] && export TOKEN="${1}" 12 | 13 | REPO="https://api.github.com/repos/RROrg" 14 | 15 | # Convert po2mo 16 | # $1 path 17 | function convertpo2mo() { 18 | echo "Convert po2mo begin" 19 | local DEST_PATH="${1:-lang}" 20 | while read -r P; do 21 | # Use msgfmt command to compile the .po file into a binary .mo file 22 | echo "msgfmt ${P} to ${P/.po/.mo}" 23 | msgfmt "${P}" -o "${P/.po/.mo}" 24 | done <<<"$(find "${DEST_PATH}" -type f -name 'rr.po')" 25 | echo "Convert po2mo end" 26 | } 27 | 28 | # Get extractor 29 | # $1 path 30 | function getExtractor() { 31 | echo "Getting syno extractor begin" 32 | local DEST_PATH="${1:-extractor}" 33 | local CACHE_DIR="/tmp/pat" 34 | rm -rf "${CACHE_DIR}" 35 | mkdir -p "${CACHE_DIR}" 36 | # Download pat file 37 | # global.synologydownload.com, global.download.synology.com, cndl.synology.cn 38 | local PAT_URL="https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_DS3622xs%2B_42218.pat" 39 | local PAT_FILE="DSM_DS3622xs+_42218.pat" 40 | local STATUS 41 | STATUS=$(curl -#L -w "%{http_code}" "${PAT_URL}" -o "${CACHE_DIR}/${PAT_FILE}") 42 | if [ $? -ne 0 ] || [ "${STATUS:-0}" -ne 200 ]; then 43 | echo "[E] DSM_DS3622xs%2B_42218.pat download error!" 44 | rm -rf "${CACHE_DIR}" 45 | exit 1 46 | fi 47 | 48 | mkdir -p "${CACHE_DIR}/ramdisk" 49 | tar -C "${CACHE_DIR}/ramdisk/" -xf "${CACHE_DIR}/${PAT_FILE}" "rd.gz" 2>&1 50 | if [ $? -ne 0 ]; then 51 | echo "[E] extractor rd.gz error!" 52 | rm -rf "${CACHE_DIR}" 53 | exit 1 54 | fi 55 | (cd "${CACHE_DIR}/ramdisk" && xz -dc <"rd.gz" | cpio -idm) >/dev/null 2>&1 || true 56 | 57 | rm -rf "${DEST_PATH}" 58 | mkdir -p "${DEST_PATH}" 59 | 60 | # Copy only necessary files 61 | for f in libcurl.so.4 libmbedcrypto.so.5 libmbedtls.so.13 libmbedx509.so.1 libmsgpackc.so.2 libsodium.so libsynocodesign-ng-virtual-junior-wins.so.7; do 62 | cp -f "${CACHE_DIR}/ramdisk/usr/lib/${f}" "${DEST_PATH}" 63 | done 64 | cp -f "${CACHE_DIR}/ramdisk/usr/syno/bin/scemd" "${DEST_PATH}/syno_extract_system_patch" 65 | 66 | # Clean up 67 | rm -rf "${CACHE_DIR}" 68 | echo "Getting syno extractor end" 69 | } 70 | 71 | # Get latest Buildroot 72 | # $1 path 73 | # $2 (true|false[d]) include prerelease 74 | function getBuildroot() { 75 | echo "Getting Buildroot begin" 76 | local DEST_PATH="${1:-buildroot}" 77 | local CACHE_DIR="/tmp/buildroot" 78 | local CACHE_FILE="/tmp/buildroot.zip" 79 | rm -f "${CACHE_FILE}" 80 | local TAG 81 | if [ "${2}" = "true" ]; then 82 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-buildroot/releases" | jq -r ".[].tag_name" | sort -rV | head -1) 83 | else 84 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-buildroot/releases/latest" | jq -r ".tag_name") 85 | fi 86 | while read -r ID NAME; do 87 | if [ "${NAME}" = "buildroot-${TAG}.zip" ]; then 88 | local STATUS 89 | STATUS=$(curl -kL -w "%{http_code}" -H "Authorization: token ${TOKEN}" -H "Accept: application/octet-stream" "${REPO}/rr-buildroot/releases/assets/${ID}" -o "${CACHE_FILE}") 90 | echo "TAG=${TAG}; Status=${STATUS}" 91 | [ ${STATUS:-0} -ne 200 ] && exit 1 92 | fi 93 | done <<<"$(curl -skL -H "Authorization: Bearer ${TOKEN}" "${REPO}/rr-buildroot/releases/tags/${TAG}" | jq -r '.assets[] | "\(.id) \(.name)"')" 94 | # Unzip Buildroot 95 | rm -rf "${CACHE_DIR}" 96 | mkdir -p "${CACHE_DIR}" 97 | unzip "${CACHE_FILE}" -d "${CACHE_DIR}" 98 | mkdir -p "${DEST_PATH}" 99 | mv -f "${CACHE_DIR}/bzImage-rr" "${DEST_PATH}" 100 | mv -f "${CACHE_DIR}/initrd-rr" "${DEST_PATH}" 101 | rm -rf "${CACHE_DIR}" 102 | rm -f "${CACHE_FILE}" 103 | echo "Getting Buildroot end" 104 | } 105 | 106 | # Get latest CKs 107 | # $1 path 108 | # $2 (true|false[d]) include prerelease 109 | function getCKs() { 110 | echo "Getting CKs begin" 111 | local DEST_PATH="${1:-cks}" 112 | local CACHE_FILE="/tmp/rr-cks.zip" 113 | rm -f "${CACHE_FILE}" 114 | local TAG 115 | if [ "${2}" = "true" ]; then 116 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-cks/releases" | jq -r ".[].tag_name" | sort -rV | head -1) 117 | else 118 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-cks/releases/latest" | jq -r ".tag_name") 119 | fi 120 | while read -r ID NAME; do 121 | if [ "${NAME}" = "rr-cks-${TAG}.zip" ]; then 122 | local STATUS 123 | STATUS=$(curl -kL -w "%{http_code}" -H "Authorization: token ${TOKEN}" -H "Accept: application/octet-stream" "${REPO}/rr-cks/releases/assets/${ID}" -o "${CACHE_FILE}") 124 | echo "TAG=${TAG}; Status=${STATUS}" 125 | [ ${STATUS:-0} -ne 200 ] && exit 1 126 | fi 127 | done <<<"$(curl -skL -H "Authorization: Bearer ${TOKEN}" "${REPO}/rr-cks/releases/tags/${TAG}" | jq -r '.assets[] | "\(.id) \(.name)"')" 128 | [ ! -f "${CACHE_FILE}" ] && exit 1 129 | # Unzip CKs 130 | rm -rf "${DEST_PATH}" 131 | mkdir -p "${DEST_PATH}" 132 | unzip "${CACHE_FILE}" -d "${DEST_PATH}" 133 | rm -f "${CACHE_FILE}" 134 | echo "Getting CKs end" 135 | } 136 | 137 | # Get latest LKMs 138 | # $1 path 139 | # $2 (true|false[d]) include prerelease 140 | function getLKMs() { 141 | echo "Getting LKMs begin" 142 | local DEST_PATH="${1:-lkms}" 143 | local CACHE_FILE="/tmp/rp-lkms.zip" 144 | rm -f "${CACHE_FILE}" 145 | local TAG 146 | if [ "${2}" = "true" ]; then 147 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-lkms/releases" | jq -r ".[].tag_name" | sort -rV | head -1) 148 | else 149 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-lkms/releases/latest" | jq -r ".tag_name") 150 | fi 151 | while read -r ID NAME; do 152 | if [ "${NAME}" = "rp-lkms-${TAG}.zip" ]; then 153 | local STATUS 154 | STATUS=$(curl -kL -w "%{http_code}" -H "Authorization: token ${TOKEN}" -H "Accept: application/octet-stream" "${REPO}/rr-lkms/releases/assets/${ID}" -o "${CACHE_FILE}") 155 | echo "TAG=${TAG}; Status=${STATUS}" 156 | [ ${STATUS:-0} -ne 200 ] && exit 1 157 | fi 158 | done <<<"$(curl -skL -H "Authorization: Bearer ${TOKEN}" "${REPO}/rr-lkms/releases/tags/${TAG}" | jq -r '.assets[] | "\(.id) \(.name)"')" 159 | [ ! -f "${CACHE_FILE}" ] && exit 1 160 | # Unzip LKMs 161 | rm -rf "${DEST_PATH}" 162 | mkdir -p "${DEST_PATH}" 163 | unzip "${CACHE_FILE}" -d "${DEST_PATH}" 164 | rm -f "${CACHE_FILE}" 165 | echo "Getting LKMs end" 166 | } 167 | 168 | # Get latest addons and install them 169 | # $1 path 170 | # $2 (true|false[d]) include prerelease 171 | function getAddons() { 172 | echo "Getting Addons begin" 173 | local DEST_PATH="${1:-addons}" 174 | local CACHE_DIR="/tmp/addons" 175 | local CACHE_FILE="/tmp/addons.zip" 176 | local TAG 177 | if [ "${2}" = "true" ]; then 178 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-addons/releases" | jq -r ".[].tag_name" | sort -rV | head -1) 179 | else 180 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-addons/releases/latest" | jq -r ".tag_name") 181 | fi 182 | while read -r ID NAME; do 183 | if [ "${NAME}" = "addons-${TAG}.zip" ]; then 184 | local STATUS 185 | STATUS=$(curl -kL -w "%{http_code}" -H "Authorization: token ${TOKEN}" -H "Accept: application/octet-stream" "${REPO}/rr-addons/releases/assets/${ID}" -o "${CACHE_FILE}") 186 | echo "TAG=${TAG}; Status=${STATUS}" 187 | [ ${STATUS:-0} -ne 200 ] && exit 1 188 | fi 189 | done <<<"$(curl -skL -H "Authorization: Bearer ${TOKEN}" "${REPO}/rr-addons/releases/tags/${TAG}" | jq -r '.assets[] | "\(.id) \(.name)"')" 190 | [ ! -f "${CACHE_FILE}" ] && exit 1 191 | rm -rf "${DEST_PATH}" 192 | mkdir -p "${DEST_PATH}" 193 | # Install Addons 194 | rm -rf "${CACHE_DIR}" 195 | mkdir -p "${CACHE_DIR}" 196 | unzip "${CACHE_FILE}" -d "${CACHE_DIR}" 197 | echo "Installing addons to ${DEST_PATH}" 198 | [ -f "/tmp/addons/VERSION" ] && cp -f "/tmp/addons/VERSION" "${DEST_PATH}/" 199 | for F in ${CACHE_DIR}/*.addon; do 200 | [ ! -e "${F}" ] && continue 201 | ADDON=$(basename "${F}" .addon) 202 | # shellcheck disable=SC2115 203 | rm -rf "${DEST_PATH}/${ADDON}" 204 | mkdir -p "${DEST_PATH}/${ADDON}" 205 | echo "Extracting ${F} to ${DEST_PATH}/${ADDON}" 206 | tar -xaf "${F}" -C "${DEST_PATH}/${ADDON}" 207 | rm -f "${F}" 208 | done 209 | rm -rf "${CACHE_DIR}" 210 | rm -f "${CACHE_FILE}" 211 | echo "Getting Addons end" 212 | } 213 | 214 | # Get latest modules 215 | # $1 path 216 | # $2 (true|false[d]) include prerelease 217 | function getModules() { 218 | echo "Getting Modules begin" 219 | local DEST_PATH="${1:-addons}" 220 | local CACHE_FILE="/tmp/modules.zip" 221 | rm -f "${CACHE_FILE}" 222 | local TAG 223 | if [ "${2}" = "true" ]; then 224 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-modules/releases" | jq -r ".[].tag_name" | sort -rV | head -1) 225 | else 226 | TAG=$(curl -skL -H "Authorization: token ${TOKEN}" "${REPO}/rr-modules/releases/latest" | jq -r ".tag_name") 227 | fi 228 | while read -r ID NAME; do 229 | if [ "${NAME}" = "modules-${TAG}.zip" ]; then 230 | local STATUS 231 | STATUS=$(curl -kL -w "%{http_code}" -H "Authorization: token ${TOKEN}" -H "Accept: application/octet-stream" "${REPO}/rr-modules/releases/assets/${ID}" -o "${CACHE_FILE}") 232 | echo "TAG=${TAG}; Status=${STATUS}" 233 | [ ${STATUS:-0} -ne 200 ] && exit 1 234 | fi 235 | done <<<"$(curl -skL -H "Authorization: Bearer ${TOKEN}" "${REPO}/rr-modules/releases/tags/${TAG}" | jq -r '.assets[] | "\(.id) \(.name)"')" 236 | [ ! -f "${CACHE_FILE}" ] && exit 1 237 | # Unzip Modules 238 | rm -rf "${DEST_PATH}" 239 | mkdir -p "${DEST_PATH}" 240 | unzip "${CACHE_FILE}" -d "${DEST_PATH}" 241 | rm -f "${CACHE_FILE}" 242 | echo "Getting Modules end" 243 | } 244 | 245 | # repack initrd 246 | # $1 initrd file 247 | # $2 plugin path 248 | # $3 output file 249 | function repackInitrd() { 250 | local INITRD_FILE="${1}" 251 | local PLUGIN_PATH="${2}" 252 | local OUTPUT_PATH="${3:-${INITRD_FILE}}" 253 | 254 | [ -z "${INITRD_FILE}" ] || [ ! -f "${INITRD_FILE}" ] && exit 1 255 | [ -z "${PLUGIN_PATH}" ] || [ ! -d "${PLUGIN_PATH}" ] && exit 1 256 | 257 | INITRD_FILE="$(realpath "${INITRD_FILE}")" 258 | PLUGIN_PATH="$(realpath "${PLUGIN_PATH}")" 259 | OUTPUT_PATH="$(realpath "${OUTPUT_PATH}")" 260 | 261 | local RDXZ_PATH="rdxz_tmp" 262 | mkdir -p "${RDXZ_PATH}" 263 | local INITRD_FORMAT 264 | INITRD_FORMAT=$(file -b --mime-type "${INITRD_FILE}") 265 | 266 | case "${INITRD_FORMAT}" in 267 | *'x-cpio'*) (cd "${RDXZ_PATH}" && sudo cpio -idm <"${INITRD_FILE}") >/dev/null 2>&1 ;; 268 | *'x-xz'*) (cd "${RDXZ_PATH}" && xz -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 269 | *'x-lz4'*) (cd "${RDXZ_PATH}" && lz4 -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 270 | *'x-lzma'*) (cd "${RDXZ_PATH}" && lzma -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 271 | *'x-bzip2'*) (cd "${RDXZ_PATH}" && bzip2 -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 272 | *'gzip'*) (cd "${RDXZ_PATH}" && gzip -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 273 | *'zstd'*) (cd "${RDXZ_PATH}" && zstd -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;; 274 | *) ;; 275 | esac 276 | 277 | sudo cp -rf "${PLUGIN_PATH}/"* "${RDXZ_PATH}/" 278 | [ -f "${OUTPUT_PATH}" ] && rm -rf "${OUTPUT_PATH}" 279 | # shellcheck disable=SC2024 280 | case "${INITRD_FORMAT}" in 281 | *'x-cpio'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root >"${OUTPUT_PATH}") >/dev/null 2>&1 ;; 282 | *'x-xz'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | xz -9 -C crc32 -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;; 283 | *'x-lz4'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | lz4 -9 -l -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;; 284 | *'x-lzma'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | lzma -9 -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;; 285 | *'x-bzip2'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | bzip2 -9 -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;; 286 | *'gzip'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | gzip -9 -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;; 287 | *'zstd'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | zstd -19 -T0 -f -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;; 288 | *) ;; 289 | esac 290 | sudo rm -rf "${RDXZ_PATH}" 291 | } 292 | 293 | # resizeimg 294 | # $1 input file 295 | # $2 changsize MB eg: +50M -50M 296 | # $3 output file 297 | function resizeImg() { 298 | local INPUT_FILE="${1}" 299 | local CHANGE_SIZE="${2}" 300 | local OUTPUT_FILE="${3:-${INPUT_FILE}}" 301 | 302 | [ -z "${INPUT_FILE}" ] || [ ! -f "${INPUT_FILE}" ] && exit 1 303 | [ -z "${CHANGE_SIZE}" ] && exit 1 304 | 305 | INPUT_FILE="$(realpath "${INPUT_FILE}")" 306 | OUTPUT_FILE="$(realpath "${OUTPUT_FILE}")" 307 | 308 | local SIZE=$(($(du -sm "${INPUT_FILE}" 2>/dev/null | awk '{print $1}')$(echo "${CHANGE_SIZE}" | sed 's/M//g; s/b//g'))) 309 | [ "${SIZE:-0}" -lt 0 ] && exit 1 310 | 311 | if [ ! "${INPUT_FILE}" = "${OUTPUT_FILE}" ]; then 312 | sudo cp -f "${INPUT_FILE}" "${OUTPUT_FILE}" 313 | fi 314 | 315 | sudo truncate -s ${SIZE}M "${OUTPUT_FILE}" 316 | echo -e "d\n\nn\n\n\n\n\nn\nw" | sudo fdisk "${OUTPUT_FILE}" >/dev/null 2>&1 317 | local LOOPX LOOPXPY 318 | LOOPX=$(sudo losetup -f) 319 | sudo losetup -P "${LOOPX}" "${OUTPUT_FILE}" 320 | LOOPXPY="$(find "${LOOPX}p"* -maxdepth 0 2>/dev/null | sort -n | tail -1)" 321 | sudo e2fsck -fp "${LOOPXPY:-${LOOPX}p3}" 322 | sudo resize2fs "${LOOPXPY:-${LOOPX}p3}" 323 | sudo losetup -d "${LOOPX}" 324 | } 325 | 326 | # createvmx 327 | # $1 bootloader file 328 | # $2 vmx name 329 | function createvmx() { 330 | local BLIMAGE=${1} 331 | local VMNAME=${2} 332 | 333 | if ! type qemu-img >/dev/null 2>&1; then 334 | sudo apt install -y qemu-utils 335 | fi 336 | 337 | # Convert raw image to VMDK 338 | rm -rf "VMX_${VMNAME}" 339 | mkdir -p "VMX_${VMNAME}" 340 | qemu-img convert -O vmdk -o 'adapter_type=lsilogic,subformat=streamOptimized,compat6' "${BLIMAGE}" "VMX_${VMNAME}/${VMNAME}-disk1.vmdk" 341 | qemu-img create -f vmdk "VMX_${VMNAME}/${VMNAME}-disk2.vmdk" "32G" 342 | 343 | # Create VM configuration 344 | cat <<_EOF_ >"VMX_${VMNAME}/${VMNAME}.vmx" 345 | .encoding = "UTF-8" 346 | config.version = "8" 347 | virtualHW.version = "17" 348 | displayName = "${VMNAME}" 349 | annotation = "https://github.com/RROrg/rr" 350 | guestOS = "ubuntu-64" 351 | firmware = "efi" 352 | mks.enable3d = "TRUE" 353 | pciBridge0.present = "TRUE" 354 | pciBridge4.present = "TRUE" 355 | pciBridge4.virtualDev = "pcieRootPort" 356 | pciBridge4.functions = "8" 357 | pciBridge5.present = "TRUE" 358 | pciBridge5.virtualDev = "pcieRootPort" 359 | pciBridge5.functions = "8" 360 | pciBridge6.present = "TRUE" 361 | pciBridge6.virtualDev = "pcieRootPort" 362 | pciBridge6.functions = "8" 363 | pciBridge7.present = "TRUE" 364 | pciBridge7.virtualDev = "pcieRootPort" 365 | pciBridge7.functions = "8" 366 | vmci0.present = "TRUE" 367 | hpet0.present = "TRUE" 368 | nvram = "${VMNAME}.nvram" 369 | virtualHW.productCompatibility = "hosted" 370 | powerType.powerOff = "soft" 371 | powerType.powerOn = "soft" 372 | powerType.suspend = "soft" 373 | powerType.reset = "soft" 374 | tools.syncTime = "FALSE" 375 | sound.autoDetect = "TRUE" 376 | sound.fileName = "-1" 377 | sound.present = "TRUE" 378 | numvcpus = "2" 379 | cpuid.coresPerSocket = "1" 380 | vcpu.hotadd = "TRUE" 381 | memsize = "4096" 382 | mem.hotadd = "TRUE" 383 | usb.present = "TRUE" 384 | ehci.present = "TRUE" 385 | usb_xhci.present = "TRUE" 386 | svga.graphicsMemoryKB = "8388608" 387 | usb.vbluetooth.startConnected = "TRUE" 388 | extendedConfigFile = "${VMNAME}.vmxf" 389 | floppy0.present = "FALSE" 390 | ethernet0.addressType = "generated" 391 | ethernet0.virtualDev = "vmxnet3" 392 | ethernet0.connectionType = "nat" 393 | ethernet0.allowguestconnectioncontrol = "true" 394 | ethernet0.present = "TRUE" 395 | serial0.fileType = "file" 396 | serial0.fileName = "serial0.log" 397 | serial0.present = "TRUE" 398 | sata0.present = "TRUE" 399 | sata0:0.fileName = "${VMNAME}-disk1.vmdk" 400 | sata0:0.present = "TRUE" 401 | sata0:1.fileName = "${VMNAME}-disk2.vmdk" 402 | sata0:1.present = "TRUE" 403 | _EOF_ 404 | 405 | } 406 | 407 | # convertvmx 408 | # $1 bootloader file 409 | # $2 vmx file 410 | function convertvmx() { 411 | local BLIMAGE=${1} 412 | local VMXPATH=${2} 413 | local VMNAME 414 | BLIMAGE="$(realpath "${BLIMAGE}")" 415 | VMXPATH="$(realpath "${VMXPATH}")" 416 | VMNAME="$(basename "${VMXPATH}" .vmx)" 417 | 418 | createvmx "${BLIMAGE}" "${VMNAME}" 419 | 420 | rm -rf "${VMXPATH}" 421 | mv -f "VMX_${VMNAME}" "${VMXPATH}" 422 | } 423 | 424 | # convertova 425 | # $1 bootloader file 426 | # $2 ova file 427 | function convertova() { 428 | local BLIMAGE=${1} 429 | local OVAPATH=${2} 430 | local VMNAME 431 | 432 | BLIMAGE="$(realpath "${BLIMAGE}")" 433 | OVAPATH="$(realpath "${OVAPATH}")" 434 | VMNAME="$(basename "${OVAPATH}" .ova)" 435 | 436 | createvmx "${BLIMAGE}" "${VMNAME}" 437 | 438 | # Download and install ovftool if it doesn't exist 439 | if [ ! -x ovftool/ovftool ]; then 440 | rm -rf ovftool ovftool.zip 441 | curl -skL https://github.com/rgl/ovftool-binaries/raw/main/archive/VMware-ovftool-4.6.0-21452615-lin.x86_64.zip -o ovftool.zip 442 | if [ $? -ne 0 ]; then 443 | echo "Failed to download ovftool" 444 | exit 1 445 | fi 446 | unzip ovftool.zip -d . >/dev/null 2>&1 447 | if [ $? -ne 0 ]; then 448 | echo "Failed to extract ovftool" 449 | exit 1 450 | fi 451 | chmod +x ovftool/ovftool 452 | fi 453 | 454 | rm -f "${OVAPATH}" 455 | ovftool/ovftool "VMX_${VMNAME}/${VMNAME}.vmx" "${OVAPATH}" 456 | rm -rf "VMX_${VMNAME}" 457 | } 458 | 459 | # createvmc 460 | # $1 vhd file 461 | # $2 vmc file 462 | function createvmc() { 463 | local BLIMAGE=${1:-rr.vhd} 464 | local VMCPATH=${2:-rr.vmc} 465 | 466 | BLIMAGE="$(basename "${BLIMAGE}")" 467 | VMCPATH="$(realpath "${VMCPATH}")" 468 | 469 | cat <<_EOF_ >"${VMCPATH}" 470 | 471 | 472 | 2.0 473 | 474 | 475 | 4096 476 | 477 | 478 | 479 | 480 | 481 | 1 482 | 483 | ${BLIMAGE} 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | _EOF_ 492 | } 493 | -------------------------------------------------------------------------------- /scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | bs4 2 | click 3 | kmodule 4 | requests 5 | requests-toolbelt 6 | openpyxl 7 | qrcode[pil] 8 | beautifulsoup4 -------------------------------------------------------------------------------- /sourcebuild.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (C) 2022 Ing 4 | # 5 | # This is free software, licensed under the MIT License. 6 | # See /LICENSE for more information. 7 | # 8 | # sudo apt update 9 | # sudo apt install -y locales busybox dialog gettext sed gawk jq curl 10 | # sudo apt install -y python-is-python3 python3-pip libelf-dev qemu-utils dosfstools cpio xz-utils lz4 lzma bzip2 gzip zstd 11 | # # sudo snap install yq 12 | # if ! type yq >/dev/null 2>&1 || ! yq --version 2>/dev/null | grep -q "v4."; then 13 | # sudo curl -kL https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -o /usr/bin/yq && sudo chmod a+x /usr/bin/yq 14 | # fi 15 | # 16 | # # Backup the original python3 executable. 17 | # sudo mv -f "$(realpath $(which python3))/EXTERNALLY-MANAGED" "$(realpath $(which python3))/EXTERNALLY-MANAGED.bak" 2>/dev/null || true 18 | # sudo pip3 install -U click requests requests-toolbelt qrcode[pil] beautifulsoup4 19 | # 20 | # sudo locale-gen ar_SA.UTF-8 de_DE.UTF-8 en_US.UTF-8 es_ES.UTF-8 fr_FR.UTF-8 ja_JP.UTF-8 ko_KR.UTF-8 ru_RU.UTF-8 th_TH.UTF-8 tr_TR.UTF-8 uk_UA.UTF-8 vi_VN.UTF-8 zh_CN.UTF-8 zh_HK.UTF-8 zh_TW.UTF-8 21 | # 22 | # export TOKEN="${1}" 23 | # 24 | 25 | if [ "$(id -u)" -ne 0 ]; then 26 | echo "This script must be run as root" 27 | exit 1 28 | fi 29 | 30 | . scripts/func.sh "${TOKEN}" 31 | 32 | echo "Get extractor" 33 | getCKs "files/mnt/p3/cks" "true" 34 | getLKMs "files/mnt/p3/lkms" "true" 35 | getAddons "files/mnt/p3/addons" "true" 36 | getModules "files/mnt/p3/modules" "true" 37 | getBuildroot "files/mnt/p3" "true" 38 | getExtractor "files/mnt/p3/extractor" 39 | 40 | echo "Repack initrd" 41 | convertpo2mo "files/initrd/opt/rr/lang" 42 | repackInitrd "files/mnt/p3/initrd-rr" "files/initrd" 43 | 44 | if [ -n "${1}" ]; then 45 | LOADER_DISK="LOCALBUILD" 46 | CHROOT_PATH="$(realpath files)" 47 | export LOADER_DISK="LOCALBUILD" 48 | export CHROOT_PATH="${CHROOT_PATH}" 49 | ( 50 | cd "${CHROOT_PATH}/initrd/opt/rr" || exit 1 51 | ./init.sh 52 | ./menu.sh modelMenu "${1}" 53 | ./menu.sh productversMenu "${2:-7.2}" 54 | ./menu.sh make -1 55 | ./menu.sh cleanCache -1 56 | ) 57 | fi 58 | 59 | IMAGE_FILE="rr.img" 60 | gzip -dc "files/initrd/opt/rr/grub.img.gz" >"${IMAGE_FILE}" 61 | fdisk -l "${IMAGE_FILE}" 62 | 63 | LOOPX=$(sudo losetup -f) 64 | sudo losetup -P "${LOOPX}" "${IMAGE_FILE}" 65 | 66 | # Check partitions and ignore errors 67 | fsck.vfat -aw "${LOOPX}p1" >/dev/null 2>&1 || true 68 | fsck.ext2 -p "${LOOPX}p2" >/dev/null 2>&1 || true 69 | fsck.ext4 -p "${LOOPX}p3" >/dev/null 2>&1 || true 70 | 71 | for i in {1..3}; do 72 | [ ! -d "files/mnt/p${i}" ] && continue 73 | 74 | rm -rf "/tmp/mnt/p${i}" 75 | mkdir -p "/tmp/mnt/p${i}" 76 | 77 | echo "Mounting ${LOOPX}p${i}" 78 | sudo mount "${LOOPX}p${i}" "/tmp/mnt/p${i}" || { 79 | echo "Can't mount ${LOOPX}p${i}." 80 | break 81 | } 82 | echo "Copying files to ${LOOPX}p${i}" 83 | [ ${i} -eq 1 ] && sudo cp -af "files/mnt/p${i}/"{.locale,.timezone} "/tmp/mnt/p${i}/" 2>/dev/null || true 84 | sudo cp -rf "files/mnt/p${i}/"* "/tmp/mnt/p${i}" || true 85 | 86 | sudo sync 87 | 88 | echo "Unmounting ${LOOPX}p${i}" 89 | sudo umount "/tmp/mnt/p${i}" || { 90 | echo "Can't umount ${LOOPX}p${i}." 91 | break 92 | } 93 | rm -rf "/tmp/mnt/p${i}" 94 | done 95 | 96 | sudo losetup --detach "${LOOPX}" 97 | 98 | resizeImg "${IMAGE_FILE}" "+2560M" 99 | 100 | # convertova "${IMAGE_FILE}" "${IMAGE_FILE/.img/.ova}" 101 | 102 | # update.zip 103 | sha256sum update-list.yml update-check.sh >sha256sum 104 | zip -9j "update.zip" update-list.yml update-check.sh 105 | while read -r F; do 106 | if [ -d "${F}" ]; then 107 | FTGZ="$(basename "${F}").tgz" 108 | tar -zcf "${FTGZ}" -C "${F}" . 109 | sha256sum "${FTGZ}" >>sha256sum 110 | zip -9j "update.zip" "${FTGZ}" 111 | rm -f "${FTGZ}" 112 | else 113 | (cd "$(dirname "${F}")" && sha256sum "$(basename "${F}")") >>sha256sum 114 | zip -9j "update.zip" "${F}" 115 | fi 116 | done <<<"$(yq '.replace | explode(.) | to_entries | map([.key])[] | .[]' update-list.yml)" 117 | zip -9j "update.zip" sha256sum 118 | -------------------------------------------------------------------------------- /update-check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # rr 4 | [ "rr" = "$(hostname)" ] && exit 0 # in RR 5 | [ -f "/usr/rr/VERSION" ] && exit 0 # in DSM 6 | 7 | exit 1 8 | -------------------------------------------------------------------------------- /update-list.yml: -------------------------------------------------------------------------------- 1 | remove: 2 | replace: 3 | "files/mnt/p1/RR_VERSION": "/mnt/p1/RR_VERSION" 4 | "files/mnt/p1/boot/grub/grub.cfg": "/mnt/p1/boot/grub/grub.cfg" 5 | "files/mnt/p1/boot/grub/logo.png": "/mnt/p1/boot/grub/logo.png" 6 | "files/mnt/p1/boot/grub/memtest": "/mnt/p1/boot/grub/memtest" 7 | "files/mnt/p1/EFI/BOOT/SynoBootLoader.conf": "/mnt/p1/EFI/BOOT/SynoBootLoader.conf" 8 | "files/mnt/p1/EFI/BOOT/SynoBootLoader.efi": "/mnt/p1/EFI/BOOT/SynoBootLoader.efi" 9 | "files/mnt/p3/bzImage-rr": "/mnt/p3/bzImage-rr" 10 | "files/mnt/p3/initrd-rr": "/mnt/p3/initrd-rr" 11 | --------------------------------------------------------------------------------