├── .gitignore ├── .rubocop.yml ├── Dockerfile ├── LICENSE ├── README.md ├── compress.rb ├── copy.rb ├── decompress.rb ├── dep.txt ├── fetch.rb ├── fstab.rb ├── image.rb ├── initrd.sh ├── main.rb ├── mount.rb ├── overlay.sh ├── resize.rb ├── size.rb ├── template.sh └── vendor-resources ├── friendlyelec-r6s ├── mjr ├── r6s ├── r6s-img ├── r6s-mjr └── root │ ├── config.sh │ ├── mjr.sh │ └── rk-vendor.sh ├── intel-edison ├── etc │ ├── apt │ │ └── apt.conf │ ├── fstab │ ├── fw_env.config │ └── hostname ├── root │ └── config.sh ├── tmp │ └── resize-helper_0.12_all.deb └── usr │ └── bin │ └── configure_edison ├── mars-a1 ├── etc │ ├── hostname │ └── resolv.conf ├── home │ └── ubuntu │ │ └── Desktop │ │ └── marspc.desktop └── usr │ └── share │ ├── backgrounds │ └── mars │ │ ├── block.jpg │ │ ├── cosmo.jpg │ │ ├── hexagon.jpg │ │ ├── home.jpg │ │ ├── planet.jpg │ │ └── wave.jpg │ └── icons │ └── mars │ └── marspc.png └── visionfive-2 ├── root ├── config.sh └── suse.sh ├── vf2 ├── vf2-deb └── vf2-fd /.gitignore: -------------------------------------------------------------------------------- 1 | cache/ 2 | temp/ 3 | rootfs/ 4 | 5 | *.ext4 6 | *.ext4* 7 | 8 | *.img 9 | *.img* 10 | 11 | mars*/ 12 | edison/ 13 | licheerv/ 14 | binary/ 15 | rk-vendor/ 16 | merged/ 17 | diff/ 18 | work/ 19 | 20 | linux/ 21 | boot-img/ 22 | initrd/ 23 | boot/ 24 | firmware/ 25 | modules/ 26 | origin*/ 27 | 28 | ub-*/ 29 | fd-*/ 30 | suse-*/ 31 | suse/ 32 | gentoo*/ 33 | arch/ 34 | alpine*/ 35 | 36 | fstab 37 | *.scr 38 | *.scr.bak 39 | *.script -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | TargetRubyVersion: 2.6 3 | DefaultFormatter: simple 4 | 5 | Layout/IndentationWidth: 6 | Width: 4 7 | 8 | Layout/LineLength: 9 | Max: 120 10 | 11 | Style/Not: 12 | Enabled: false 13 | 14 | Style/AndOr: 15 | Enabled: false 16 | 17 | Style/IfUnlessModifier: 18 | Enabled: false 19 | 20 | Style/RedundantReturn: 21 | Enabled: false 22 | 23 | Style/StringLiterals: 24 | Enabled: true 25 | EnforcedStyle: double_quotes 26 | 27 | Style/StringLiteralsInInterpolation: 28 | Enabled: true 29 | EnforcedStyle: double_quotes 30 | 31 | Naming/FileName: 32 | Enabled: false 33 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | ARG DEBIAN_FRONTEND=noninteractive 4 | ENV TZ=Asia/Shanghai 5 | 6 | RUN set -e \ 7 | && sed -i "s/# deb-src/deb-src/g" /etc/apt/sources.list \ 8 | && apt-get update 9 | 10 | RUN set -e \ 11 | && apt-get install --no-install-recommends -y \ 12 | sudo 13 | 14 | RUN useradd -c 'ubuntu' -m -d /home/ubuntu -s /bin/bash ubuntu 15 | RUN set -e \ 16 | && sed -i '/\%sudo/ c \%sudo ALL=(ALL) NOPASSWD: ALL' /etc/sudoers \ 17 | && usermod -aG sudo ubuntu 18 | 19 | RUN set -e \ 20 | && apt-get install --no-install-recommends -y \ 21 | 22 | # Project 23 | git-core \ 24 | ruby \ 25 | qemu-user-static \ 26 | libvirt-daemon-system \ 27 | 28 | # compress.rb 29 | xz-utils \ 30 | 31 | # copy.rb 32 | 33 | # decompress.rb 34 | unzip \ 35 | p7zip-full \ 36 | zstd \ 37 | cpio \ 38 | 39 | # fetch.rb 40 | wget \ 41 | 42 | # fstab.rb 43 | btrfs-progs \ 44 | dosfstools \ 45 | exfat-utils \ 46 | ntfs-3g \ 47 | 48 | #image.rb 49 | u-boot-tools \ 50 | 51 | # main.rb 52 | 53 | # mount.rb 54 | fdisk 55 | 56 | # resize.rb 57 | 58 | # size.rb 59 | 60 | USER ubuntu 61 | WORKDIR /home/ubuntu/ 62 | 63 | ENTRYPOINT ["/bin/bash"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rootfs-tools 2 | 3 | > build workflow for rootfs images 4 | 5 | ## Prepare 6 | 7 | ``` 8 | sudo apt update 9 | sudo apt install $(cat dep.txt) 10 | 11 | sudo systemctl enable --now libvirtd 12 | ``` 13 | 14 | ref: https://wiki.gentoo.org/wiki/RISC-V_Qemu_setup 15 | 16 | ## Run 17 | 18 | ``` 19 | sudo ruby main.rb 20 | ``` 21 | 22 | But it may be not fit to you, just run `CMD` in the scripts. 23 | 24 | ## More 25 | 26 | ### why qemu? 27 | 28 | `qemu-user-static` for cross-arch chroot supporting, 29 | 30 | like you need `qemu-aarch64` runing an `aarch64` binary on x86_64 host. 31 | 32 | ### Guide 33 | 34 | - Image 35 | 36 | Build which kind of disk image (single partition or combined image) deps the devkit needs. 37 | 38 | You can just edit the origin disk image if disk space is ok. 39 | 40 | Otherwise you may need create a new blank image by `dd`. 41 | 42 | Combined image aslo can be created by `dd`, you just need load disk layout file by `fdisk`. 43 | 44 | - Porting 45 | 46 | Porting linux distro, you need the `kernel` `firmware` `fstab` etc, so backup them first of all. 47 | 48 | Then copy the prebuilt linux distro `root` files. 49 | 50 | After file operation, you may need some configuration, like user password, extra software. 51 | 52 | Then flash it, boot it, debug it, re-edit someting... 53 | 54 | ## Wishing 55 | 56 | It's pretty easy task after this tool handling some **dirty work**, so have fun! 57 | 58 | ## Sponsors 59 | 60 | [CNRV](https://riscv.org/blog-chinese/2022/11/cnrv-devboard-hacks/) 62 | [Your Logo](#sponsors) 63 | [Your Logo](#sponsors) 64 | 65 | [Your Logo](#sponsors) 66 | [Your Logo](#sponsors) 67 | [Your Logo](#sponsors) 68 | 69 | ## License 70 | 71 | MPL-2.0 72 | -------------------------------------------------------------------------------- /compress.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | def xz(src) 4 | `xz -kzvfT0 #{src}` 5 | end 6 | -------------------------------------------------------------------------------- /copy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "./decompress" 4 | 5 | class Copy 6 | @temp_dir = "temp" 7 | def initialize(src, dest) 8 | @src = src 9 | @dest = dest 10 | 11 | @pwd = Dir.pwd 12 | `mkdir -p #{@pwd}/#{@temp_dir}` 13 | end 14 | 15 | class << self 16 | # ls -d1 */ 17 | def Fedora(src, dest) 18 | @pwd = Dir.pwd 19 | 20 | `mkdir -p #{@temp_dir}/Fedora` 21 | Decompress.untar "#{@temp_dir}/Fedora", src 22 | Dir.chdir "#{@temp_dir}/Fedora" do 23 | inner = `ls -d1 */`.delete "\/\n" 24 | puts "#{inner}/layer.tar" 25 | if File.exist? "#{inner}/layer.tar" 26 | Decompress.done "#{inner}/layer.tar" if Decompress.untar "#{@pwd}/#{dest}", "#{inner}/layer.tar" 27 | else 28 | puts "layer.tar not exist" 29 | end 30 | end 31 | end 32 | 33 | def Arch(src, dest) 34 | @pwd = Dir.pwd 35 | 36 | `mkdir -p #{@temp_dir}/Arch` 37 | Decompress.ungz "#{@temp_dir}/Arch", src 38 | Dir.chdir "#{@temp_dir}/Arch" do 39 | inner = `ls -d1 */`.delete "\/\n" 40 | return system("sudo cp -a #{inner}/* #{@pwd}/#{dest}") 41 | end 42 | end 43 | end 44 | end 45 | 46 | # https://launchpad.net/~canonical-kernel-team/+archive/ubuntu/ppa/+build/24173564 47 | def copy_kernel(src, dest, extra = [], no_default = false) 48 | file_paths = %w[ 49 | /boot/ 50 | /lib/firmware/ 51 | /lib/modprobe.d/ 52 | /lib/modules/ 53 | /usr/lib/linux/ 54 | 55 | /etc/fstab 56 | ] 57 | file_paths = [] if no_default 58 | file_paths += extra 59 | 60 | # exec_dir = Dir.pwd 61 | 62 | `mkdir -p #{dest}` 63 | Dir.chdir dest do 64 | file_paths.each do |file_path| 65 | cp_src = "#{src}#{file_path}" 66 | dest_path = file_path.delete_prefix("/") 67 | 68 | # is_file = if dest_path.end_with?('/') 69 | # false 70 | # else 71 | # true 72 | # end 73 | 74 | parent_arr = dest_path.split("/") 75 | parent_arr.pop 76 | # p parent_arr 77 | 78 | parent_dir = case parent_arr.size 79 | when 0 80 | "" 81 | when 1 82 | parent_arr[0] 83 | else 84 | parent_arr.join("/") 85 | end 86 | 87 | if parent_dir != "" 88 | `mkdir -p #{parent_dir}` 89 | Dir.chdir parent_dir do 90 | puts Dir.pwd 91 | 92 | cmd = "cp -a #{cp_src} ." 93 | puts cmd 94 | system cmd 95 | puts 96 | end 97 | else 98 | puts Dir.pwd 99 | 100 | cmd = "cp -a #{cp_src} ." 101 | puts cmd 102 | system cmd 103 | puts 104 | end 105 | end 106 | end 107 | end 108 | 109 | # copy_map = { 110 | # "0": "1", 111 | # "2": "2" 112 | # } 113 | def copy_par(src, dest, copy_map = nil) 114 | if copy_map.nil? 115 | print `ls -d1 #{src}p*` 116 | puts 117 | 118 | puts "which partition(s) you want copy:" 119 | puts "(eg: 1, 3,4)" 120 | pars = gets.delete_suffix("\n").delete(" ").split(",") 121 | pars.each do |par| 122 | dd_src = `ls -d1 #{src}*#{par}`.delete_suffix("\n") 123 | dd_dest = `ls -d1 #{dest}*#{par}`.delete_suffix("\n") 124 | cmd = "dd if=#{dd_src} of=#{dd_dest}" 125 | puts cmd 126 | system cmd 127 | end 128 | else 129 | copy_map.each do |par_s, par_d| 130 | dd_src = `ls -d1 #{src}*#{par_s}`.delete_suffix("\n") 131 | dd_dest = `ls -d1 #{dest}*#{par_d}`.delete_suffix("\n") 132 | cmd = "dd if=#{dd_src} of=#{dd_dest}" 133 | puts cmd 134 | system cmd 135 | end 136 | end 137 | end 138 | 139 | if __FILE__ == $0 140 | # Copy.Fedora "cache/Fedora-Container-Base-36-1.5.x86_64.tar.xz", "fd-36" 141 | # Copy.Arch "cache/archlinux-bootstrap-2022.09.03-x86_64.tar.gz", "arch" 142 | 143 | l_extra = %w[ 144 | /usr/lib/linux-allwinner-5.17-tools-5.17.0-1003/ 145 | /usr/lib/libcpupower.so.5.17.0-1003 146 | /usr/lib/linux-tools/ 147 | ] 148 | 149 | v_extra = %w[ 150 | /usr/lib/linux-image-5.15.0-starfive/ 151 | ] 152 | 153 | extlinux_uEnv = %w[ 154 | /boot/extlinux/ 155 | /boot/uEnv.txt 156 | ] 157 | 158 | r_extra = %w[ 159 | /lib/firmware/ 160 | /lib/modules/ 161 | ] 162 | 163 | r_map = { 164 | "2": "8", 165 | } 166 | # copy_kernel "/media/ubuntu/rootfs", "origin", r_extra, true 167 | # copy_kernel "/home/ubuntu/vscode/rootfs-tools/origin", "rootfs" 168 | 169 | copy_par "/dev/loop14", "/dev/loop15", r_map 170 | end -------------------------------------------------------------------------------- /decompress.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Decompress 4 | def initialize(dir, file) 5 | @dir = dir 6 | @file = file 7 | end 8 | 9 | class << self 10 | def unzip(dir, file) 11 | return system("unzip -d #{dir} #{file}") 12 | end 13 | 14 | def untar(dir, file) 15 | return system("tar -C #{dir} -xvf #{file}") 16 | end 17 | 18 | def ungz(dir, file) 19 | return system("tar -C #{dir} -zxvf #{file}") 20 | end 21 | 22 | def un7z(dir, file) 23 | return system("7z x -o#{dir} #{file}") 24 | end 25 | 26 | # https://www.cnblogs.com/Andy-Lv/p/5304247.html 27 | def uncpio(dir, file) 28 | pwd_file = "#{Dir.pwd}/#{file}" 29 | # puts pwd_file 30 | Dir.chdir dir do 31 | return system("cpio -i < #{pwd_file}") 32 | end 33 | end 34 | 35 | def done(file) 36 | puts "decompress #{file} done" 37 | end 38 | end 39 | 40 | def matcher 41 | ext = File.extname(@file) 42 | # puts ext 43 | case ext 44 | when ".zip" 45 | Decompress.done @file if Decompress.unzip @dir, @file 46 | when ".tar", ".xz", ".zst" 47 | Decompress.done @file if Decompress.untar @dir, @file 48 | when ".tgz", ".gz" 49 | Decompress.done @file if Decompress.ungz @dir, @file 50 | when ".7z" 51 | Decompress.done @file if Decompress.un7z @dir, @file 52 | else 53 | if @file.end_with? "initrd" 54 | Decompress.done @file if Decompress.uncpio @dir, @file 55 | else 56 | puts "unknown compress format for: #{@file}" 57 | end 58 | end 59 | end 60 | end 61 | 62 | # list = ["cache/ubuntu-base-22.04-base-amd64.tar.gz", "1.a.tgz", "2.tar.xz", "3.c.zip", "4.d.tgz", "5.e.7z"] 63 | 64 | # for f in list 65 | # d = Decompress.new "testdir", f 66 | # d.matcher 67 | # end 68 | 69 | if __FILE__ == $0 70 | d = Decompress.new "temp/test", "cache/initrd" 71 | d.matcher 72 | end 73 | -------------------------------------------------------------------------------- /dep.txt: -------------------------------------------------------------------------------- 1 | git-core 2 | ruby 3 | qemu-user-static 4 | libvirt-daemon-system 5 | 6 | xz-utils 7 | 8 | unzip 9 | p7zip-full 10 | zstd 11 | cpio 12 | 13 | wget 14 | 15 | btrfs-progs 16 | dosfstools 17 | exfat-utils 18 | ntfs-3g 19 | 20 | u-boot-tools 21 | 22 | fdisk 23 | -------------------------------------------------------------------------------- /fetch.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | REL = "22.04" 4 | CODENAME = "jammy" 5 | ARCH = "amd64" 6 | 7 | def fetch_ubuntu_base(cache_dir) 8 | url = "https://cdimage.ubuntu.com/ubuntu-base/releases/#{REL}/release" 9 | file = "ubuntu-base-#{REL}-base-#{ARCH}.tar.gz" 10 | sha256 = "#{url}/SHA256SUMS" 11 | 12 | unless File.exist?("#{cache_dir}/#{file}") 13 | `wget #{url}/#{file} -P #{cache_dir}` 14 | end 15 | 16 | `curl -L #{sha256} >> #{cache_dir}/SHA256SUMS` 17 | end 18 | 19 | def fetch_ubuntu_minimal(cache_dir) 20 | url = "https://cloud-images.ubuntu.com/minimal/releases/#{CODENAME}/release/" 21 | file = "ubuntu-#{REL}-minimal-cloudimg-#{ARCH}-root.tar.xz" 22 | sha256 = "#{url}/SHA256SUMS" 23 | 24 | unless File.exist?("#{cache_dir}/#{file}") 25 | `wget #{url}/#{file} -P #{cache_dir}` 26 | end 27 | 28 | `curl -L #{sha256} >> #{cache_dir}/SHA256SUMS` 29 | end 30 | -------------------------------------------------------------------------------- /fstab.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # https://wiki.gentoo.org/wiki//etc/fstab 4 | # https://wiki.archlinux.org/title/fstab 5 | # https://wiki.archlinux.org/title/persistent_block_device_naming 6 | 7 | def label_to(par, label) 8 | output = `mount | grep #{par}`.chomp 9 | type = output.split(" ")[4] 10 | case type 11 | when "swap" 12 | `swaplabel -L '#{label}' #{par}` 13 | when "ext2", "ext3", "ext4" 14 | `e2label #{par} '#{label}'` 15 | when "fat", "vfat" 16 | `fatlabel #{par} '#{label}'` 17 | when "btrfs" 18 | `btrfs filesystem label #{par} '#{label}'` 19 | when "exfat" 20 | `exfatlabel #{par} '#{label}'` 21 | when "ntfs" 22 | `ntfslabel #{par} '#{label}'` 23 | else 24 | puts "Not supported FS type" 25 | end 26 | end 27 | 28 | if __FILE__ == $0 29 | label_to("/dev/sdc8", "cloudimg-rootfs") 30 | end 31 | -------------------------------------------------------------------------------- /image.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # https://wiki.ubuntu.com/ARM/EditBootscr 4 | def de_uboot_scr(scr, script = nil) 5 | if script.nil? 6 | script = if scr.end_with?(".scr") 7 | "#{scr}ipt" 8 | else 9 | "#{scr}.script" 10 | end 11 | end 12 | 13 | `dd if=#{scr} of=#{script} bs=72 skip=1` 14 | end 15 | 16 | # https://manpages.ubuntu.com/manpages/jammy/man1/mkimage.1.html 17 | def mk_uboot_scr(script, scr = nil, arch = "arm", comp = "none") 18 | if scr.nil? 19 | scr = if script.end_with?(".script") 20 | script.delete_suffix("ipt") 21 | else 22 | "#{script}.scr" 23 | end 24 | end 25 | 26 | # mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image 27 | # mkimage -T list 28 | `mkimage -A #{arch} -T script -C #{comp} -d #{script} #{scr}` 29 | end 30 | 31 | # https://manpages.ubuntu.com/manpages/jammy/en/man1/dd.1posix.html 32 | # https://manpages.ubuntu.com/manpages/jammy/man8/mkfs.8.html 33 | # https://manpages.ubuntu.com/manpages/jammy/man8/mkfs.ext4.8.html 34 | # https://manpages.ubuntu.com/manpages/jammy/en/man8/sfdisk.8.html 35 | def mk_rootfs(img, block_count, *opt, **args) 36 | block_size = opt[0] || args[:block_size] 37 | layout = opt[1] || args[:layout] 38 | mkfs_cmd = opt[2] || args[:mkfs_cmd] 39 | 40 | dd_bs = if block_size.nil? or block_size.empty? 41 | "" 42 | else 43 | # cmd_opt in func 44 | # should end with ' ' 45 | # so we get log with good formatting 46 | "bs=#{block_size} " 47 | end 48 | 49 | dd_cmd = "dd if=/dev/zero of=#{img} count=0 seek=#{block_count} #{dd_bs}" 50 | puts dd_cmd 51 | system dd_cmd 52 | 53 | if layout.nil? or layout.empty? 54 | if mkfs_cmd != nil 55 | cmd = "#{mkfs_cmd} #{img}" 56 | puts cmd 57 | system cmd 58 | end 59 | else 60 | cmd = "sfdisk #{img} < #{layout}" 61 | puts cmd 62 | system cmd 63 | end 64 | end 65 | 66 | if __FILE__ == $0 67 | # de_uboot_scr "boot.scr" 68 | 69 | # mk_uboot_scr "boot.script" 70 | # mk_uboot_scr "boot.script", "abc.scr" 71 | 72 | # mk_rootfs "test-MB.img", 2100, "1MB" 73 | # mk_rootfs "test-MiB.img", 2001, "1MiB" 74 | # mk_rootfs "test-MB.img", 2100, "1MB", "vf2" 75 | # mk_rootfs "test-MiB.img", 2001, "1MiB", "vf2" 76 | # mk_rootfs "test.img", 4096100, "" ,"vf2" 77 | # mk_rootfs "test.img", 4096100, nil, "vf2" 78 | # mk_rootfs "test.img", 4096100, nil, nil, "mkfs.ext4 -F" 79 | mk_rootfs "test.img", 4096100, layout: "vf2" 80 | end 81 | -------------------------------------------------------------------------------- /initrd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # https://www.cnblogs.com/shineshqw/articles/2336842.html 4 | # https://linuxconfig.org/how-to-create-and-extract-cpio-archives-on-linux-examples 5 | 6 | find initrd/ -depth -print0 | cpio -ocv0 | gzip -9 > temp/initrd 7 | -------------------------------------------------------------------------------- /main.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "./fetch" 4 | require "./decompress" 5 | require "./size" 6 | require "./mount" 7 | 8 | CACHE_DIR = "cache" 9 | ROOT_PKG = "ubuntu-22.04-minimal-cloudimg-amd64-root.tar.xz" 10 | TEMP_ROOTFS_DIR = "ub-22" 11 | ROOTFS_DIR = "rootfs" 12 | ROOTFS_IMG = "edison-image-edison.ext4" 13 | 14 | def main 15 | `mkdir -p #{CACHE_DIR} #{TEMP_ROOTFS_DIR} #{ROOTFS_DIR}` 16 | fetch_ubuntu_base CACHE_DIR 17 | fetch_ubuntu_minimal CACHE_DIR 18 | `sha256sum -c #{CACHE_DIR}/SHA256SUMS` 19 | 20 | d = Decompress.new TEMP_ROOTFS_DIR, "#{CACHE_DIR}/#{ROOT_PKG}" 21 | d.matcher 22 | 23 | `cp -a boot #{TEMP_ROOTFS_DIR}` 24 | `cp -a firmware #{TEMP_ROOTFS_DIR}/lib` 25 | `cp -a modules #{TEMP_ROOTFS_DIR}/lib` 26 | 27 | `cp -a vendor-resources/intel-edison/* #{TEMP_ROOTFS_DIR}` 28 | 29 | mountDev TEMP_ROOTFS_DIR 30 | `sudo chroot #{TEMP_ROOTFS_DIR} /bin/bash -c /root/config.sh` 31 | unmountDev TEMP_ROOTFS_DIR 32 | 33 | s = Size.new TEMP_ROOTFS_DIR, 100, 100, "/dev/sda1" 34 | size = s.GetSize 35 | `dd if=/dev/zero of=#{ROOTFS_IMG} bs=1MB count=0 seek=#{size}` 36 | `mkfs.ext4 -F #{ROOTFS_IMG}` 37 | `tune2fs -c0 -i0 #{ROOTFS_IMG}` 38 | 39 | mountImage ROOTFS_IMG, ROOTFS_DIR 40 | `sudo cp -a #{TEMP_ROOTFS_DIR}/* #{ROOTFS_DIR}` 41 | unmountImage ROOTFS_DIR 42 | end 43 | 44 | main 45 | -------------------------------------------------------------------------------- /mount.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | def mountImage(img, path) 4 | puts "mounting image #{img} on #{path}" 5 | `mount -o loop #{img} #{path}` 6 | end 7 | 8 | def unmountImage(path) 9 | puts "unmounting image on #{path}" 10 | `umount #{path}` 11 | end 12 | 13 | # ref: https://wiki.alpinelinux.org/wiki/How_to_make_a_cross_architecture_chroot 14 | def mountDev(path) 15 | puts "mounting /dev on #{path}" 16 | `mount -t proc /proc #{path}/proc` 17 | `mount -t sysfs /sys #{path}/sys` 18 | `mount -o bind /dev #{path}/dev` 19 | `mount -o bind /dev/pts #{path}/dev/pts` 20 | `mount -o bind /run #{path}/run` 21 | end 22 | 23 | def unmountDev(path) 24 | puts "unmounting /dev on #{path}" 25 | `umount #{path}/proc` 26 | `umount #{path}/sys` 27 | `umount #{path}/dev/pts` 28 | `umount #{path}/dev` 29 | `umount #{path}/run` 30 | end 31 | 32 | # https://askubuntu.com/questions/69363/mount-single-partition-from-image-of-entire-disk-device 33 | def getImageLoops(img) 34 | cmd = "losetup | grep #{img}" 35 | IO.popen(cmd) do |r| 36 | lines = r.readlines 37 | return nil if lines.empty? 38 | 39 | loops = [] 40 | lines.each do |line| 41 | lo = line.delete_suffix("\n").split(" ").first 42 | loops.push lo 43 | end 44 | return loops 45 | end 46 | end 47 | 48 | def mountLoop(img, *opt) 49 | loop_dev = opt[0] 50 | offset = opt[1] 51 | 52 | unless loop_dev.nil? 53 | if !offset.nil? 54 | `losetup -o #{offset} #{loop_dev} #{img}` 55 | else 56 | `losetup #{loop_dev} #{img}` 57 | end 58 | return loop_dev 59 | end 60 | 61 | output = `losetup -Pf --show #{img}` 62 | return output.delete_suffix("\n") 63 | end 64 | 65 | def mountCombinedImage(img, path = nil, *opt) 66 | par = opt[0] 67 | loop_dev = opt[1] 68 | 69 | if loop_dev.nil? 70 | loop_dev = mountLoop img 71 | else 72 | mountLoop img, loop_dev 73 | end 74 | 75 | if path != nil 76 | system "fdisk -l #{img}" 77 | 78 | if par.nil? 79 | print "which partition to mount: " 80 | par = gets.delete_suffix("\n") 81 | # p par 82 | end 83 | 84 | loop_par = "#{loop_dev}p#{par}" 85 | 86 | puts "mounting #{loop_par} on #{path}" 87 | `mount #{loop_par} #{path}` 88 | else 89 | puts "#{img} mounted on #{loop_dev}" 90 | end 91 | end 92 | 93 | def unmountCombinedImage(img) 94 | loops = getImageLoops img 95 | loops.each do |lo| 96 | puts "unmounting combined image on #{lo}" 97 | `losetup -d #{lo}` 98 | end 99 | end 100 | 101 | if __FILE__ == $0 102 | # img = "ubuntu-core-gnome.img" 103 | # path = "mars-A1-ub18-core" 104 | 105 | img = "vf2.img" 106 | path = "rootfs" 107 | 108 | # mountImage img, path 109 | # mountCombinedImage img, path 110 | # mountDev path 111 | 112 | # unmountDev path 113 | # puts "waiting for 3s" 114 | # sleep 3 115 | unmountImage path 116 | # unmountCombinedImage img 117 | 118 | img2 = 'starfive-jh7110-VF2-VF2_515_v2.3.0-55.img' 119 | # mountCombinedImage img2, "vf-de" 120 | unmountImage "vf-de" 121 | 122 | # mountCombinedImage img2 123 | # mountCombinedImage img 124 | unmountCombinedImage img2 125 | unmountCombinedImage img 126 | end -------------------------------------------------------------------------------- /overlay.sh: -------------------------------------------------------------------------------- 1 | mount -t overlay -o lowerdir=ub-22:binary,upperdir=rk-vendor,workdir=work overlay rootfs -------------------------------------------------------------------------------- /resize.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | def resizeImage(img, size) 4 | `e2fsck -f #{img}` 5 | `resize2fs #{img} #{size}` 6 | # re-format to update inodes 7 | `mkfs.ext4 -F #{img}` 8 | end 9 | -------------------------------------------------------------------------------- /size.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Size 4 | @ratio = 4 5 | @block_size = 4096 6 | 7 | def initialize(temp_rootfs_dir, extra_inode, extra_size_MB, *rootfs_dev) 8 | @rDir = temp_rootfs_dir.to_s || "" 9 | @eInode = extra_inode.to_i || 0 10 | @eSizeM = extra_size_MB.to_i || 0 11 | @rDev = rootfs_dev[0].to_s || "" 12 | end 13 | 14 | class << self 15 | def BtoK(size) 16 | return size / 1024 17 | end 18 | 19 | def KtoM(size) 20 | return size / 1024 21 | end 22 | 23 | def MtoG(size) 24 | return size / 1024 25 | end 26 | 27 | # sudo tune2fs -l /dev/nvme0n1p4 28 | # 29 | # Blocks per group: 32768 30 | # Inodes per group: 8192 31 | # 32 | # 4 = 32768 / 8192 33 | def InodeToBlock(inode) 34 | return inode * @ratio 35 | end 36 | 37 | # Block size: 4096 38 | def BlockToB(block) 39 | return block * @block_size 40 | end 41 | 42 | def BlockToK(block) 43 | return BtoK(BlockToB(block)) 44 | end 45 | 46 | def InodeToK(inode) 47 | return BlockToK(InodeToBlock(inode)) 48 | end 49 | 50 | def BlockToM(block) 51 | return KtoM(BlockToK(block)) 52 | end 53 | 54 | def InodeToM(inode) 55 | return KtoM(InodeToK(inode)) 56 | end 57 | 58 | # sudo find . -printf "%h\n" | cut -d / -f -2 | sort | uniq -c | sort -rn 59 | def DirInode(dir) 60 | output = `sudo find #{dir}/.. -printf "%h\n" | cut -d / -f -2 | sort | uniq -c | sort -rn | grep #{dir}` 61 | inode = output.split(" ").first 62 | # puts inode 63 | return inode.to_i 64 | end 65 | 66 | def DirSizeK(dir) 67 | output = `sudo du -d0 #{dir}` 68 | size = output.split(" ").first 69 | # puts size 70 | return size.to_i 71 | end 72 | 73 | def DirSizeM(dir) 74 | return KtoM(DirSizeK(dir)) 75 | end 76 | 77 | def DirInodeK(dir) 78 | result = InodeToK(DirInode(dir)) 79 | # puts result 80 | return result 81 | end 82 | 83 | def DirInodeM(dir) 84 | return KtoM(DirInodeK(dir)) 85 | end 86 | 87 | def Bigger(num_a, num_b) 88 | return num_a if num_a >= num_b 89 | 90 | return num_b 91 | end 92 | end 93 | 94 | def GetRatio 95 | if @rDev.empty? 96 | puts "missing disk device ARG" 97 | return false 98 | end 99 | 100 | output1 = `sudo tune2fs -l #{@rDev} | grep 'Blocks per group'` 101 | output2 = `sudo tune2fs -l #{@rDev} | grep 'Inodes per group'` 102 | 103 | return false if output1.empty? or output2.empty? 104 | 105 | blocks = output1.split(" ").last 106 | inodes = output2.split(" ").last 107 | ratio = blocks.to_i.fdiv(inodes.to_i) 108 | # puts ratio 109 | return ratio 110 | end 111 | 112 | def GetBlockSize 113 | if @rDev.empty? 114 | puts "missing disk device ARG" 115 | return false 116 | end 117 | 118 | output = `sudo tune2fs -l #{@rDev} | grep 'Block size'` 119 | return false if output.empty? 120 | 121 | size = output.split(" ").last 122 | # puts size 123 | return size.to_i 124 | end 125 | 126 | def GetSize 127 | unless @rDev.empty? 128 | @ratio = self.GetRatio || @ratio 129 | @block_size = self.GetBlockSize || @block_size 130 | end 131 | 132 | if @rDir.empty? 133 | puts "missing directory ARG" 134 | return false 135 | end 136 | 137 | rInode = Size.DirInode @rDir 138 | rSizeM = Size.DirSizeM @rDir 139 | 140 | aInodeM = Size.InodeToM(rInode + @eInode) 141 | aSizeM = rSizeM + @eSizeM 142 | 143 | # puts aInodeM 144 | return Size.Bigger(aInodeM.ceil(-1), aSizeM.ceil(-1)) 145 | end 146 | end 147 | 148 | # dir = "ub-22" 149 | # dev = "" 150 | 151 | # s = Size.new dir, 100, 100 152 | 153 | # puts s.GetRatio 154 | # puts s.GetBlockSize 155 | # puts s.GetSize 156 | 157 | # for n in 1..10 158 | # s = Size.new "", 0, 0, "/dev/mmcblk0p#{n}" 159 | # puts "/dev/mmcblk0p#{n} #{s.GetRatio}" 160 | # end 161 | 162 | # sudo ruby size.rb 2>/dev/null 163 | -------------------------------------------------------------------------------- /template.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | main() { 6 | apt-get update 7 | apt-get install -y 8 | } 9 | 10 | main "$@" 11 | -------------------------------------------------------------------------------- /vendor-resources/friendlyelec-r6s/mjr: -------------------------------------------------------------------------------- 1 | label: gpt 2 | label-id: 837CB2D9-B9E9-4232-9967-880913144D47 3 | device: cache/Manjaro-ARM-gnome-generic-22.12.img 4 | unit: sectors 5 | first-lba: 34 6 | last-lba: 14815198 7 | sector-size: 512 8 | 9 | cache/Manjaro-ARM-gnome-generic-22.12.img1 : start= 2048, size= 997376, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=069CB19B-E0B2-4CB8-A53F-37FCE9C6EAE7, name="primary" 10 | cache/Manjaro-ARM-gnome-generic-22.12.img2 : start= 999424, size= 13813760, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=1B17A334-53C8-4A52-A9A9-38542BA1A14B, name="primary" 11 | -------------------------------------------------------------------------------- /vendor-resources/friendlyelec-r6s/r6s: -------------------------------------------------------------------------------- 1 | # rootfs 8G on 32G SD card 2 | label: gpt 3 | label-id: 73987B6B-4974-4C94-A3E8-58AB2EB7A946 4 | device: /dev/sdc 5 | unit: sectors 6 | first-lba: 34 7 | last-lba: 61067230 8 | 9 | /dev/sdc1 : start= 16384, size= 8192, type=F808D051-1602-4DCD-9452-F9637FEFC49A, uuid=B750E44E-833F-4A30-C38C-B117241D84D4, name="uboot" 10 | /dev/sdc2 : start= 24576, size= 8192, type=C6D08308-E418-4124-8890-F8411E3D8D87, uuid=A1C81622-7741-47AD-B846-C6972488D396, name="misc" 11 | /dev/sdc3 : start= 32768, size= 8192, type=2A583E58-486A-4BD4-ACE4-8D5454E97F5C, uuid=43784A32-A03D-4ADE-92C6-EDE64FF9B794, name="dtbo" 12 | /dev/sdc4 : start= 40960, size= 32768, type=6115F139-4F47-4BAF-8D23-B6957EAEE4B3, uuid=000B305F-484A-4582-9090-4AD0099D47BD, name="resource" 13 | /dev/sdc5 : start= 73728, size= 81920, type=A83FBA16-D354-45C5-8B44-3EC50832D363, uuid=24EEB649-277F-4C11-FFEB-D9F20027A83B, name="kernel" 14 | /dev/sdc6 : start= 155648, size= 65536, type=500E2214-B72D-4CC3-D7C1-8419260130F5, uuid=1CAC805F-726A-495A-FD35-821355A6E7E8, name="boot" 15 | /dev/sdc7 : start= 221184, size= 65536, type=E099DA71-5450-44EA-AA9F-1B771C582805, uuid=2BFEE623-D83C-426A-AB80-21732C9BB7D3, name="recovery" 16 | /dev/sdc8 : start= 286720, size= 15728640, type=AF12D156-5D5B-4EE3-B415-8D492CA12EA9, uuid=B2AF085D-A675-48C6-C437-F6D557FF4744, name="rootfs" 17 | /dev/sdc9 : start= 16015360, size= 45051870, type=8EB9EE49-E963-4BB6-FD75-F30618DF9DCD, uuid=2D9E7B61-1B31-47E7-EE0D-8CEC26D42EF6, name="userdata" 18 | -------------------------------------------------------------------------------- /vendor-resources/friendlyelec-r6s/r6s-img: -------------------------------------------------------------------------------- 1 | label: gpt 2 | label-id: 73987B6B-4974-4C94-A3E8-58AB2EB7A946 3 | device: rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img 4 | unit: sectors 5 | first-lba: 34 6 | last-lba: 15234340 7 | 8 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img1 : start= 16384, size= 8192, type=F808D051-1602-4DCD-9452-F9637FEFC49A, uuid=B750E44E-833F-4A30-C38C-B117241D84D4, name="uboot" 9 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img2 : start= 24576, size= 8192, type=C6D08308-E418-4124-8890-F8411E3D8D87, uuid=A1C81622-7741-47AD-B846-C6972488D396, name="misc" 10 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img3 : start= 32768, size= 8192, type=2A583E58-486A-4BD4-ACE4-8D5454E97F5C, uuid=43784A32-A03D-4ADE-92C6-EDE64FF9B794, name="dtbo" 11 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img4 : start= 40960, size= 32768, type=6115F139-4F47-4BAF-8D23-B6957EAEE4B3, uuid=000B305F-484A-4582-9090-4AD0099D47BD, name="resource" 12 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img5 : start= 73728, size= 81920, type=A83FBA16-D354-45C5-8B44-3EC50832D363, uuid=24EEB649-277F-4C11-FFEB-D9F20027A83B, name="kernel" 13 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img6 : start= 155648, size= 65536, type=500E2214-B72D-4CC3-D7C1-8419260130F5, uuid=1CAC805F-726A-495A-FD35-821355A6E7E8, name="boot" 14 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img7 : start= 221184, size= 65536, type=E099DA71-5450-44EA-AA9F-1B771C582805, uuid=2BFEE623-D83C-426A-AB80-21732C9BB7D3, name="recovery" 15 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img8 : start= 286720, size= 7864320, type=AF12D156-5D5B-4EE3-B415-8D492CA12EA9, uuid=B2AF085D-A675-48C6-C437-F6D557FF4744, name="rootfs" 16 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img9 : start= 8151040, size= 7083301, type=8EB9EE49-E963-4BB6-FD75-F30618DF9DCD, uuid=2D9E7B61-1B31-47E7-EE0D-8CEC26D42EF6, name="userdata" 17 | -------------------------------------------------------------------------------- /vendor-resources/friendlyelec-r6s/r6s-mjr: -------------------------------------------------------------------------------- 1 | # rootfs 7G 2 | label: gpt 3 | label-id: 73987B6B-4974-4C94-A3E8-58AB2EB7A946 4 | device: rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img 5 | unit: sectors 6 | first-lba: 34 7 | last-lba: 15234340 8 | 9 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img1 : start= 16384, size= 8192, type=F808D051-1602-4DCD-9452-F9637FEFC49A, uuid=B750E44E-833F-4A30-C38C-B117241D84D4, name="uboot" 10 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img2 : start= 24576, size= 8192, type=C6D08308-E418-4124-8890-F8411E3D8D87, uuid=A1C81622-7741-47AD-B846-C6972488D396, name="misc" 11 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img3 : start= 32768, size= 8192, type=2A583E58-486A-4BD4-ACE4-8D5454E97F5C, uuid=43784A32-A03D-4ADE-92C6-EDE64FF9B794, name="dtbo" 12 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img4 : start= 40960, size= 32768, type=6115F139-4F47-4BAF-8D23-B6957EAEE4B3, uuid=000B305F-484A-4582-9090-4AD0099D47BD, name="resource" 13 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img5 : start= 73728, size= 81920, type=A83FBA16-D354-45C5-8B44-3EC50832D363, uuid=24EEB649-277F-4C11-FFEB-D9F20027A83B, name="kernel" 14 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img6 : start= 155648, size= 65536, type=500E2214-B72D-4CC3-D7C1-8419260130F5, uuid=1CAC805F-726A-495A-FD35-821355A6E7E8, name="boot" 15 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img7 : start= 221184, size= 65536, type=E099DA71-5450-44EA-AA9F-1B771C582805, uuid=2BFEE623-D83C-426A-AB80-21732C9BB7D3, name="recovery" 16 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img8 : start= 286720, size= 13813760, type=AF12D156-5D5B-4EE3-B415-8D492CA12EA9, uuid=B2AF085D-A675-48C6-C437-F6D557FF4744, name="rootfs" 17 | rk3588-sd-ubuntu-jammy-desktop-5.10-arm64-20221213.img9 : start= 14100480, size= 1133860, type=8EB9EE49-E963-4BB6-FD75-F30618DF9DCD, uuid=2D9E7B61-1B31-47E7-EE0D-8CEC26D42EF6, name="userdata" 18 | -------------------------------------------------------------------------------- /vendor-resources/friendlyelec-r6s/root/config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | add_ubuntu() { 6 | useradd -G sudo -d /home/ubuntu -m -s /bin/bash ubuntu 7 | echo "ubuntu:ubuntu" | chpasswd 8 | echo "root:root" | chpasswd 9 | } 10 | 11 | add_lang_pack() { 12 | apt-get install -y language-pack-en-base 13 | apt-get install -y dialog apt-utils 14 | } 15 | 16 | install_software() { 17 | apt-get install -y dnsutils file htop ifupdown iputils-ping lshw lsof nano net-tools network-manager openssh-server rfkill tree u-boot-tools wget wireless-tools wpasupplicant 18 | } 19 | 20 | set_sshd_config() { 21 | cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig 22 | sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config 23 | sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config 24 | } 25 | 26 | main() { 27 | export DEBIAN_FRONTEND="noninteractive" 28 | 29 | # apt-get update 30 | 31 | # add_lang_pack 32 | # install_software 33 | # set_sshd_config 34 | # rm -rf /var/lib/apt/* 35 | 36 | add_ubuntu 37 | # systemctl enable getty@ttyS2.service 38 | 39 | touch /etc/cloud/cloud-init.disabled 40 | apt autoremove --purge snapd 41 | 42 | unset DEBIAN_FRONTEND 43 | } 44 | 45 | main "$@" 46 | -------------------------------------------------------------------------------- /vendor-resources/friendlyelec-r6s/root/mjr.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | add_user() { 6 | useradd -G sudo -d /home/manjaro -m -s /bin/bash manjaro 7 | echo "manjaro:manjaro" | chpasswd 8 | echo "root:root" | chpasswd 9 | } 10 | 11 | set_sshd_config() { 12 | cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig 13 | sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config 14 | sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config 15 | } 16 | 17 | main() { 18 | add_user 19 | } 20 | 21 | main "$@" 22 | -------------------------------------------------------------------------------- /vendor-resources/friendlyelec-r6s/root/rk-vendor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | main() { 6 | # apt-get update 7 | # apt-get upgrade -y 8 | 9 | chmod o+x /usr/lib/dbus-1.0/dbus-daemon-launch-helper 10 | chmod +x /etc/rc.local 11 | 12 | export APT_INSTALL="apt-get install -fy --allow-downgrades" 13 | 14 | #---------------power management -------------- 15 | ${APT_INSTALL} pm-utils triggerhappy 16 | cp /etc/Powermanager/triggerhappy.service /lib/systemd/system/triggerhappy.service 17 | 18 | #---------------Rga-------------- 19 | ${APT_INSTALL} /packages/rga/*.deb 20 | 21 | echo -e "\033[36m Setup Video.................... \033[0m" 22 | ${APT_INSTALL} gstreamer1.0-plugins-bad gstreamer1.0-plugins-base gstreamer1.0-tools gstreamer1.0-alsa \ 23 | gstreamer1.0-plugins-base-apps qtmultimedia5-examples 24 | 25 | ${APT_INSTALL} /packages/mpp/* 26 | ${APT_INSTALL} /packages/gst-rkmpp/*.deb 27 | ${APT_INSTALL} /packages/gstreamer/*.deb 28 | ${APT_INSTALL} /packages/gst-plugins-base1.0/*.deb 29 | ${APT_INSTALL} /packages/gst-plugins-bad1.0/*.deb 30 | ${APT_INSTALL} /packages/gst-plugins-good1.0/*.deb 31 | 32 | #---------Camera--------- 33 | echo -e "\033[36m Install camera.................... \033[0m" 34 | ${APT_INSTALL} cheese v4l-utils 35 | ${APT_INSTALL} /packages/rkisp/*.deb 36 | ${APT_INSTALL} /packages/rkaiq/*.deb 37 | ${APT_INSTALL} /packages/libv4l/*.deb 38 | 39 | #---------Xserver--------- 40 | echo -e "\033[36m Install Xserver.................... \033[0m" 41 | ${APT_INSTALL} /packages/xserver/*.deb 42 | 43 | #---------------Openbox-------------- 44 | echo -e "\033[36m Install openbox.................... \033[0m" 45 | ${APT_INSTALL} /packages/openbox/*.deb 46 | 47 | #---------update chromium----- 48 | ${APT_INSTALL} /packages/chromium/*.deb 49 | 50 | #------------------libdrm------------ 51 | echo -e "\033[36m Install libdrm.................... \033[0m" 52 | ${APT_INSTALL} /packages/libdrm/*.deb 53 | 54 | #------------------libdrm-cursor------------ 55 | echo -e "\033[36m Install libdrm-cursor.................... \033[0m" 56 | ${APT_INSTALL} /packages/libdrm-cursor/*.deb 57 | 58 | # Only preload libdrm-cursor for X 59 | sed -i "/libdrm-cursor.so/d" /etc/ld.so.preload 60 | sed -i "1aexport LD_PRELOAD=libdrm-cursor.so.1" /usr/bin/X 61 | 62 | #------------------pcmanfm------------ 63 | echo -e "\033[36m Install pcmanfm.................... \033[0m" 64 | ${APT_INSTALL} /packages/pcmanfm/*.deb 65 | 66 | #------------------rkwifibt------------ 67 | echo -e "\033[36m Install rkwifibt.................... \033[0m" 68 | ${APT_INSTALL} /packages/rkwifibt/*.deb 69 | ln -s /system/etc/firmware /vendor/etc/ 70 | 71 | if [ "$VERSION" == "debug" ]; then 72 | #------------------glmark2------------ 73 | echo -e "\033[36m Install glmark2.................... \033[0m" 74 | ${APT_INSTALL} /packages/glmark2/*.deb 75 | fi 76 | 77 | echo -e "\033[36m Install synaptic/onboard.................... \033[0m" 78 | ${APT_INSTALL} synaptic onboard 79 | 80 | echo -e "\033[36m Install network vpn.................... \033[0m" 81 | ${APT_INSTALL} network-manager-l2tp network-manager-openvpn network-manager-pptp network-manager-strongswan network-manager-vpnc 82 | apt install -fy network-manager-gnome --reinstall 83 | 84 | #------------------pulseaudio--------- 85 | echo -e "\033[36m Install pulseaudio................. \033[0m" 86 | no|apt-get install -fy --allow-downgrades /packages/pulseaudio/*.deb 87 | 88 | # mark package to hold 89 | apt list --installed | grep -v oldstable | cut -d/ -f1 | xargs apt-mark hold 90 | 91 | #---------------Custom Script-------------- 92 | systemctl mask systemd-networkd-wait-online.service 93 | systemctl mask NetworkManager-wait-online.service 94 | rm /lib/systemd/system/wpa_supplicant@.service 95 | 96 | #---------------Clean-------------- 97 | # rm -rf /var/cache/apt/archives/*.deb 98 | # rm -rf /var/lib/apt/lists/* 99 | } 100 | 101 | main "$@" 102 | -------------------------------------------------------------------------------- /vendor-resources/intel-edison/etc/apt/apt.conf: -------------------------------------------------------------------------------- 1 | APT::Get::Install-Recommends "false"; 2 | APT::Get::Install-Suggests "false"; -------------------------------------------------------------------------------- /vendor-resources/intel-edison/etc/fstab: -------------------------------------------------------------------------------- 1 | rootfs / auto nodev,noatime,discard,barrier=1,data=ordered,noauto_da_alloc 1 1 2 | proc /proc proc defaults 0 0 3 | devpts /dev/pts devpts mode=0620,gid=5 0 0 4 | usbdevfs /proc/bus/usb usbdevfs auto 0 0 5 | tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0 6 | tmpfs /var/volatile tmpfs defaults 0 0 7 | 8 | /dev/disk/by-partlabel/boot /boot auto noauto,x-systemd.automount,nosuid,nodev,noatime,discard 1 1 9 | #/dev/disk/by-partlabel/home /home auto noauto,x-systemd.automount,nosuid,nodev,noatime,discard,barrier=1,data=ordered,noauto_da_alloc 1 1 10 | -------------------------------------------------------------------------------- /vendor-resources/intel-edison/etc/fw_env.config: -------------------------------------------------------------------------------- 1 | # Configuration file for fw_(printenv/setenv) utility. 2 | # Up to two entries are valid, in this case the redundant 3 | # environment sector is assumed present. 4 | # Notice, that the "Number of sectors" is not required on NOR and SPI-dataflash. 5 | # Futhermore, if the Flash sector size is ommitted, this value is assumed to 6 | # be the same as the Environment size, which is valid for NOR and SPI-dataflash 7 | 8 | # MTD device name Device offset Env. size Flash sector size Number of sectors 9 | # On Edison, the u-boot environments are located on partitions 2 and 4 and both have a size of 64kB 10 | /dev/mmcblk0p2 0x0000 0x10000 11 | /dev/mmcblk0p4 0x0000 0x10000 12 | -------------------------------------------------------------------------------- /vendor-resources/intel-edison/etc/hostname: -------------------------------------------------------------------------------- 1 | edison -------------------------------------------------------------------------------- /vendor-resources/intel-edison/root/config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | add_ubuntu() { 6 | useradd -G sudo -d /home/ubuntu -m -s /bin/bash ubuntu 7 | echo "ubuntu:ubuntu" | chpasswd 8 | echo "root:root" | chpasswd 9 | } 10 | 11 | add_lang_pack() { 12 | apt-get install -y language-pack-en-base 13 | apt-get install -y dialog apt-utils 14 | } 15 | 16 | install_software() { 17 | apt-get install -y dnsutils file htop ifupdown iputils-ping lshw lsof nano net-tools network-manager openssh-server rfkill tree u-boot-tools wget wireless-tools wpasupplicant 18 | apt-get install /tmp/resize-helper_0.12_all.deb 19 | } 20 | 21 | set_sshd_config() { 22 | cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig 23 | sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config 24 | sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config 25 | } 26 | 27 | main() { 28 | export DEBIAN_FRONTEND="noninteractive" 29 | 30 | apt-get update 31 | 32 | # add_lang_pack 33 | install_software 34 | set_sshd_config 35 | rm -rf /var/lib/apt/* 36 | 37 | add_ubuntu 38 | systemctl enable getty@ttyS2.service 39 | 40 | unset DEBIAN_FRONTEND 41 | } 42 | 43 | main "$@" 44 | -------------------------------------------------------------------------------- /vendor-resources/intel-edison/tmp/resize-helper_0.12_all.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/initdc/rootfs-tools/65393a5f8c65cc7e4d7055152a6c1ce09ebcf0d2/vendor-resources/intel-edison/tmp/resize-helper_0.12_all.deb -------------------------------------------------------------------------------- /vendor-resources/intel-edison/usr/bin/configure_edison: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (c) 2014, Intel Corporation. 4 | # Copyright (c) 2020, Ferry Toth and Matthias Dieter Wallnöfer 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms and conditions of the GNU Lesser General Public License, 8 | # version 2.1, as published by the Free Software Foundation. 9 | # 10 | # This program is distributed in the hope it will be useful, but WITHOUT ANY 11 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 13 | # more details. 14 | # 15 | 16 | import os 17 | import sys 18 | from sys import stdout 19 | import time 20 | import termios 21 | import fcntl 22 | import subprocess 23 | import argparse 24 | import re 25 | import socket 26 | import struct 27 | from array import * 28 | import configparser 29 | from bottle import route, run, debug, template, request, static_file, redirect 30 | import datetime 31 | from datetime import timedelta 32 | 33 | WSREGEX = re.compile(r"\s+") 34 | STATE_DIR = '/var/lib/edison_config_tools' 35 | HOST_AP_MODE_FILE = "/.start-in-host-ap-mode" 36 | CONNMAN_SETTINGS = "/var/lib/connman/settings" 37 | CONNMAN_SERVICES = "/var/lib/connman/wifi.config" 38 | 39 | # Types 40 | ####################################### 41 | class classHostName: 42 | Old = "" 43 | New = "" 44 | Valid = False 45 | Changed = False 46 | Tooltip = "" 47 | 48 | class classWired: 49 | Type = "" 50 | Mode = "" 51 | NewMode = "" 52 | IP = "" 53 | Changed = False 54 | 55 | class classWifiAP: 56 | Name = "" 57 | Passphrase = "" 58 | NewMode = "" 59 | IP = "" 60 | Changed = False 61 | Enabled = False 62 | 63 | class classSettings: 64 | HostName = classHostName() 65 | Wired = classWired() 66 | BT = classWifiAP() 67 | Wifi = classWifiAP() 68 | AP = classWifiAP() 69 | 70 | class text_colors: 71 | CYAN = '\033[96m' 72 | MAGENTA = '\033[95m' 73 | BLUE = '\033[94m' 74 | YELLOW = '\033[93m' 75 | GREEN = '\033[92m' 76 | RED = '\033[91m' 77 | END = '\033[0m' 78 | 79 | # Helpers 80 | ####################################### 81 | def _checkName(newName): 82 | length = len(newName) 83 | if length < 1 or length > 63: 84 | return -1 85 | if newName[0] == '-' or newName[length - 1] == '-': 86 | return -2 87 | for i in range(length): 88 | if not newName[i].isalnum() and newName[i] != '-': 89 | return -3 90 | return 0 91 | 92 | def _changeHostName(newName): 93 | hostname_file = open('/etc/hostname','w') 94 | hostname_file.write(newName + "\n") 95 | hostname_file.close() 96 | subprocess.call("hostname -F /etc/hostname", shell=True) 97 | 98 | def _getDefaultSSID(): 99 | data = os.popen("cat /sys/class/net/wlan0/address | tr '[:lower:]' '[:upper:]'").read() 100 | APSSID = "EDISON-" + data[12:14] +"-" + data[15:17] 101 | return APSSID 102 | 103 | def _getAPSSID(): 104 | ConnmanSettings = configparser.ConfigParser() 105 | ConnmanSettings.optionxform=str 106 | ConnmanSettings.read(CONNMAN_SETTINGS) 107 | APSSID = ConnmanSettings.get('WiFi', 'Tethering.Identifier', fallback='') 108 | APPassword = ConnmanSettings.get('WiFi', 'Tethering.Passphrase', fallback='') 109 | 110 | if APSSID == "": 111 | if APPassword == "": 112 | APPassword = os.popen("cat /factory/serial_number").read() 113 | subprocess.check_output("connmanctl tether wifi off '" + _getDefaultSSID() + "' '" + APPassword + "'", shell=True) 114 | return APSSID 115 | 116 | def _changeAPSSID(newName): 117 | ConnmanSettings = configparser.ConfigParser() 118 | ConnmanSettings.optionxform=str 119 | ConnmanSettings.read(CONNMAN_SETTINGS) 120 | APPassword = ConnmanSettings.get('WiFi', 'Tethering.Passphrase', fallback='') 121 | if APPassword == "": 122 | APPassword = os.popen("cat /factory/serial_number").read() 123 | subprocess.check_output("connmanctl tether wifi off '" + newName + "' '" + APPassword + "'", shell=True) 124 | 125 | def _changeAPPassword(newPass): 126 | subprocess.check_output("connmanctl tether wifi off '" + _getAPSSID() + "' '" + newPass + "'", shell=True) 127 | 128 | def _changeAPCredentials(newName, newPass): 129 | subprocess.check_output("connmanctl tether wifi off '" + newName + "' '" + newPass + "'", shell=True) 130 | 131 | def _getWiFiMode(): 132 | modestr = '' 133 | try: 134 | modestr = subprocess.check_output('connmanctl technologies', shell=True) 135 | except subprocess.CalledProcessError: 136 | return "Err" 137 | except Exception as inst: 138 | return "Err" 139 | 140 | modestr = str(modestr, 'utf-8') 141 | modestr = "[Wifi]" + modestr.split('/net/connman/technology/wifi')[1].split('/net/connman/technology')[0].replace(' ','') 142 | Section = configparser.ConfigParser() 143 | Section.optionxform=str 144 | Section.read_string(modestr) 145 | if Section['Wifi']['Connected'] == 'True': 146 | return "Connected" 147 | if Section['Wifi']['Tethering'] == 'True': 148 | return "AP" 149 | if Section['Wifi']['Powered'] == 'True': 150 | return "Powered" 151 | return "Off" 152 | 153 | def _getWiredMode(): 154 | modestr = '' 155 | try: 156 | modestr = subprocess.check_output('connmanctl technologies', shell=True) 157 | except subprocess.CalledProcessError: 158 | return "Err" 159 | except Exception as inst: 160 | return "Err" 161 | 162 | modestr = str(modestr, 'utf-8') 163 | if modestr.find("ethernet") == -1: 164 | return "None" 165 | modestr = "[Wired]" + modestr.split('/net/connman/technology/ethernet')[1].split('/net/connman/technology')[0].replace(' ','') 166 | Section = configparser.ConfigParser() 167 | Section.optionxform=str 168 | Section.read_string(modestr) 169 | if Section['Wired']['Connected'] == 'True': 170 | return "Connected" 171 | if Section['Wired']['Powered'] == 'True': 172 | return "Powered" 173 | return "Off" 174 | 175 | def _getBTMode(): 176 | modestr = '' 177 | try: 178 | modestr = subprocess.check_output('connmanctl technologies', shell=True) 179 | except subprocess.CalledProcessError: 180 | return "Err" 181 | except Exception as inst: 182 | return "Err" 183 | 184 | modestr = str(modestr, 'utf-8') 185 | if modestr.find("bluetooth") == -1: 186 | return "None" 187 | modestr = "[Bluetooth]" + modestr.split('/net/connman/technology/bluetooth')[1].split('/net/connman/technology')[0].replace(' ','') 188 | Section = configparser.ConfigParser() 189 | Section.optionxform=str 190 | Section.read_string(modestr) 191 | if Section['Bluetooth']['Connected'] == 'True': 192 | return "Connected" 193 | if Section['Bluetooth']['Powered'] == 'True': 194 | return "Powered" 195 | return "Off" 196 | 197 | def _getGadgetMode(): 198 | modestr = '' 199 | modestr = subprocess.run('lsusb', shell=False, stderr=subprocess.PIPE) 200 | modestr = str(modestr.stderr, 'utf-8') 201 | if modestr.find("root hub") >= 0: 202 | return "None" 203 | 204 | modestr = '' 205 | try: 206 | modestr = subprocess.check_output('connmanctl technologies', shell=True) 207 | except subprocess.CalledProcessError: 208 | return "Err" 209 | except Exception as inst: 210 | return "Err" 211 | 212 | modestr = str(modestr, 'utf-8') 213 | if modestr.find("gadget") == -1: 214 | return "None" 215 | modestr = "[Wired]" + modestr.split('/net/connman/technology/gadget')[1].split('/net/connman/technology')[0].replace(' ','') 216 | Section = configparser.ConfigParser() 217 | Section.optionxform=str 218 | Section.read_string(modestr) 219 | if Section['Wired']['Connected'] == 'True': 220 | return "Connected" 221 | if Section['Wired']['Powered'] == 'True': 222 | return "Powered" 223 | return "Off" 224 | 225 | def _setWiFiMode(Mode): 226 | CurrentMode = _getWiFiMode() 227 | if CurrentMode == 'Err': 228 | return 229 | if Mode == 'Off': 230 | if CurrentMode != 'Off': 231 | subprocess.check_output("connmanctl disable wifi", shell=True) 232 | elif Mode == 'Powered': 233 | if CurrentMode == 'Off': 234 | subprocess.check_output("connmanctl enable wifi", shell=True) 235 | elif CurrentMode == 'AP': 236 | subprocess.check_output("connmanctl tether wifi off", shell=True) 237 | elif Mode == 'AP': 238 | if CurrentMode == 'Off': 239 | subprocess.check_output("connmanctl enable wifi", shell=True) 240 | time.sleep(1) 241 | subprocess.check_output("connmanctl tether wifi on", shell=True) 242 | time.sleep(1) 243 | return 244 | 245 | def _setBTMode(Mode): 246 | CurrentMode = _getBTMode() 247 | if CurrentMode == 'Err': 248 | return 249 | if Mode == 'Off': 250 | if CurrentMode != 'Off': 251 | subprocess.check_output("connmanctl disable bluetooth", shell=True) 252 | elif Mode == 'Powered': 253 | if CurrentMode == 'Off': 254 | subprocess.check_output("connmanctl enable bluetooth", shell=True) 255 | time.sleep(1) 256 | return 257 | 258 | def _setGadgetMode(Mode): 259 | CurrentMode = _getGadgetMode() 260 | if CurrentMode == 'Err': 261 | return 262 | if Mode == 'Off': 263 | if CurrentMode != 'Off': 264 | subprocess.check_output("connmanctl disable gadget", shell=True) 265 | elif Mode == 'Powered': 266 | if CurrentMode == 'Off': 267 | subprocess.check_output("connmanctl enable gadget", shell=True) 268 | time.sleep(1) 269 | return 270 | 271 | def _changeRootPassword(newPass): 272 | echoSub = subprocess.Popen(["echo", "root:" + newPass], stdout=subprocess.PIPE) 273 | chpasswdSub = subprocess.Popen(["chpasswd"], stdin=echoSub.stdout, stdout=subprocess.PIPE) 274 | echoSub.stdout.close() # Allow echoSub to receive a SIGPIPE if chpasswdSub exits. 275 | chpasswdSub.communicate()[0] 276 | 277 | def _getHostName(): 278 | return(str(subprocess.check_output('hostname', shell=True).strip(), 'utf-8')) 279 | 280 | def _getIFaceIP(iface): 281 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 282 | try: 283 | return socket.inet_ntoa(fcntl.ioctl( 284 | s.fileno(), 285 | 0x8915, # SIOCGIFADDR 286 | struct.pack('256s', iface[:15].encode('utf-8')) 287 | )[20:24]) 288 | except OSError: 289 | return "None" 290 | finally: 291 | s.close() 292 | 293 | def _scanForNetworks(): 294 | global lastScanned 295 | global _cachedServices 296 | connection = [] 297 | now = datetime.datetime.now() 298 | if((now - lastScanned) > timedelta(seconds = 30)): 299 | lastScanned = now 300 | subprocess.check_output("connmanctl scan wifi", shell=True) 301 | connection.append(("", "Scanning, please wait 10 seconds", "")) 302 | else: 303 | connection = _getServices("wifi") 304 | _cachedServices = connection 305 | return connection 306 | 307 | def _getServices(type): 308 | data = subprocess.getoutput("connmanctl services | grep '" + type + "'") 309 | data = data.split("\n") 310 | 311 | connection = [] 312 | for i in range(len(data)): 313 | (left, seperator, session) = data[i].rpartition(' ') 314 | ssid = left[4:].rstrip() 315 | flags = left[:4].rstrip() 316 | if ssid != "": 317 | connection.append((flags, ssid, session)) 318 | return connection 319 | 320 | def _getPrivateService(type): 321 | data = subprocess.getoutput("connmanctl services | grep '" + type + "'") 322 | data = data.split("\n") 323 | 324 | for i in range(len(data)): 325 | (left, _, session) = data[i].rpartition(' ') 326 | ssid = left[4:].rstrip() 327 | if ssid == "": 328 | return session 329 | 330 | def _getCachedService(service): 331 | global _cachedServices 332 | 333 | for i in _cachedServices: 334 | if i[2] == service: 335 | return i[1] 336 | 337 | def _getIFace(service): 338 | data = subprocess.getoutput("connmanctl services '" + service[2] + "'| grep Ethernet") 339 | return re.compile(r"Interface=(\w+)").search(data)[1] 340 | 341 | def _selectNetwork(service): 342 | data = subprocess.getoutput("connmanctl connect '" + service + "'") 343 | if data.startswith("Error") and not data.endswith("In progress"): 344 | print(text_colors.RED + data + text_colors.END) 345 | return False 346 | else: 347 | print(text_colors.GREEN + data + text_colors.END) 348 | return True 349 | 350 | def _store(WiFi_Network, WiFi_Name, WiFi_Passphrase, WiFi_Identity=None): 351 | ConnmanServices = configparser.ConfigParser() 352 | ConnmanServices.optionxform=str 353 | ConnmanServices.read(CONNMAN_SERVICES) 354 | service = WiFi_Network 355 | service.replace(" ", "") 356 | print(service) 357 | if ConnmanServices.get("service_" + service, "Name", fallback="") == "": 358 | ConnmanServices["service_" + service] = {} 359 | if WiFi_Passphrase != "!@#$%^&*": 360 | ConnmanServices["service_" + service]["Type"] = "wifi" 361 | ConnmanServices["service_" + service]["Name"] = WiFi_Name 362 | ConnmanServices["service_" + service]["SSID"] = WiFi_Name.encode("utf-8").hex() 363 | if WiFi_Passphrase is not None: 364 | ConnmanServices["service_" + service]["Passphrase"] = WiFi_Passphrase 365 | if WiFi_Identity is not None: 366 | ConnmanServices["service_" + service]["Identity"] = WiFi_Identity 367 | with open(CONNMAN_SERVICES, 'w') as configfile: 368 | ConnmanServices.write(configfile) 369 | 370 | # Main Functions 371 | ####################################### 372 | def _getch(): 373 | fd = sys.stdin.fileno() 374 | 375 | oldterm = termios.tcgetattr(fd) 376 | newattr = termios.tcgetattr(fd) 377 | newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO 378 | termios.tcsetattr(fd, termios.TCSANOW, newattr) 379 | 380 | try: 381 | while 1: 382 | try: 383 | c = sys.stdin.read(1) 384 | break 385 | except IOError: pass 386 | finally: 387 | termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm) 388 | return c 389 | 390 | def _getPassword(prompt): 391 | stdout.write(prompt) 392 | stdout.flush() 393 | pw = "" 394 | 395 | while 1: 396 | c = _getch() 397 | if c == '\r' or c == '\n': 398 | break 399 | if c == '\003': 400 | raise KeyboardInterrupt 401 | if c == '\x08' or c == '\x7f': 402 | if len(pw): 403 | pw = pw[:-1] 404 | stdout.write('\x08') 405 | stdout.write('\x20') 406 | stdout.write('\x08') 407 | else: 408 | pw = pw + c 409 | stdout.write("*") 410 | stdout.flush() 411 | stdout.write('\r') 412 | stdout.write('\n') 413 | return pw 414 | 415 | def _verified(selection): 416 | verify = input("Is " + text_colors.MAGENTA + selection + text_colors.END + " correct? " + text_colors.YELLOW + "[Y or N]" + text_colors.END + ": ") 417 | if verify == "Y" or verify == "y": 418 | return 1 419 | elif verify == "N" or verify == "n": 420 | return 0 421 | else: 422 | while 1: 423 | verify = input("Please enter either " + text_colors.YELLOW + "[Y or N]" + text_colors.END + ": ") 424 | if verify == "Y" or verify == "y": 425 | return 1 426 | elif verify == "N" or verify == "n": 427 | return 0 428 | 429 | def reset(stage): 430 | subprocess.call("clear", shell=True) 431 | print(text_colors.CYAN + "\nConfigure Edison: " + stage + "\n" + text_colors.END) 432 | 433 | def setEdisonHostname(): 434 | while 1: 435 | name = input("Give this Edison a unique name.\nThis will be used for the access point SSID and mDNS address.\nMake it at least five characters long (leave empty to skip): ") 436 | if (WSREGEX.search(name)): 437 | print("") 438 | print('Hostname must not contain whitespaces. Please try again.') 439 | print("") 440 | elif (len(name) == 0): 441 | print("Skipping name change...") 442 | break 443 | elif (len(name) > 4): 444 | if _verified(name): 445 | print("") 446 | break 447 | else: 448 | print("") 449 | else: 450 | print("") 451 | print('\"' + name + '\" is too short. Please try again.') 452 | print("") 453 | 454 | if len(name) > 0: 455 | changeName(name) 456 | 457 | def setEdisonPassword(): 458 | while 1: 459 | password = _getPassword("Enter a new password (leave empty to abort)\nThis will be used to connect to the access point and login to the device.\nPassword: \t") 460 | if (password == _getPassword("Please enter the password again: \t")): 461 | if (WSREGEX.search(password)): 462 | print("") 463 | print('The device password must not contain whitespaces. Please try again.') 464 | print("") 465 | elif len(password) == 0: 466 | print("Skipping password change.") 467 | return 468 | elif len(password) < 8 or len(password) > 63: 469 | print("") 470 | print("The device password must be between 8 and 63 characters long. Please try again.") 471 | print("") 472 | else: 473 | break 474 | else: 475 | print("") 476 | print("The passwords do not match. Please try again.") 477 | print("") 478 | 479 | changePassword(password) 480 | print("The device password has been changed.\n") 481 | 482 | def _selectWifiMenu(ssid_keys): 483 | i = 2 484 | print("0 :\tRescan for networks") 485 | print("1 :\tExit WiFi Setup") 486 | print("2 :\tManually input a hidden SSID") 487 | for ssid in ssid_keys: 488 | i = i + 1 489 | print(i, ":\t", ssid[1]) 490 | 491 | print("") 492 | choice = -1 493 | while 1: 494 | try: 495 | if i == 2: 496 | choice = int(input("\nEnter 0 to rescan for networks.\nEnter 1 to exit.\nEnter 2 to input a hidden network SSID: ")) 497 | elif i == 3: 498 | choice = int(input("\nEnter 0 to rescan for networks.\nEnter 1 to exit.\nEnter 2 to input a hidden network SSID.\nEnter 3 to choose %s: " % ssid_keys[0])) 499 | else: 500 | choice = int(input("\nEnter 0 to rescan for networks.\nEnter 1 to exit.\nEnter 2 to input a hidden network SSID.\nEnter a number between 3 to %s to choose one of the listed network SSIDs: " % i)) 501 | except TypeError: 502 | choice = -1 503 | except ValueError: 504 | choice = -1 505 | 506 | if choice == 0: 507 | break 508 | elif choice == 1: 509 | sys.exit(0) 510 | elif choice == 2: 511 | break 512 | elif choice > 2 and choice <= i and _verified(ssid_keys[choice-3][1]): 513 | break 514 | return choice 515 | 516 | def _getNetworkIdentity(): 517 | return input("Please enter the network username: ") 518 | 519 | def _getNetworkPassword(): 520 | pw = '' 521 | while len(pw) == 0: 522 | pw = _getPassword("What is the network password?: ") 523 | return pw 524 | 525 | def _configureHiddenNetwork(ssid): 526 | service = _getPrivateService('wifi') 527 | 528 | print(''' 529 | 0: OPEN 530 | 1: WEP 531 | 2: WPA-Personal (PSK) 532 | 3: WPA-Enterprise (EAP) 533 | ''') 534 | while 1: 535 | try: 536 | security = int(input("Select the type of security [0 to 3]: ")) 537 | except TypeError: 538 | security = -1 539 | except ValueError: 540 | security = -1 541 | 542 | if security == 0: 543 | _store(service, ssid, None) 544 | break 545 | elif security == 1: 546 | password = '' 547 | while len(password) != 5 and len(password) != 13: 548 | print("Password must be either 5 or 13 characters.") 549 | password = _getNetworkPassword() 550 | _store(service, ssid, password) 551 | break 552 | elif security == 2: 553 | password = '' 554 | while len(password) < 8 or len(password) > 63: 555 | print("Password must be between 8 and 63 characters.") 556 | password = _getNetworkPassword() 557 | _store(service, ssid, password) 558 | break 559 | elif security == 3: 560 | identity = _getNetworkIdentity() 561 | password = _getNetworkPassword() 562 | _store(service, ssid, password, identity) 563 | break 564 | else: 565 | print("Invalid input.") 566 | 567 | return _selectNetwork(service) 568 | 569 | def _configureNetwork(choice,ssid_keys): 570 | service = ssid_keys[choice-3][2] 571 | 572 | if service.endswith("_none"): 573 | return _selectNetwork(service) 574 | elif service.endswith("_wep"): 575 | identity = None 576 | password = '' 577 | while len(password) != 5 and len(password) != 13: 578 | print("Password must be either 5 or 13 characters.") 579 | password = _getNetworkPassword() 580 | elif service.endswith("_psk") or service.endswith("_wpa") or service.endswith("_rsn"): 581 | identity = None 582 | password = '' 583 | while len(password) < 8 or len(password) > 63: 584 | print("Password must be between 8 and 63 characters.") 585 | password = _getNetworkPassword() 586 | elif service.endswith("_ieee8021x"): 587 | identity = _getNetworkIdentity() 588 | password = _getNetworkPassword() 589 | 590 | _store(service, ssid_keys[choice-3][1], password, identity) 591 | return _selectNetwork(service) 592 | 593 | def configureNetworkAP(changewifi): 594 | ssid = changewifi[0] 595 | password = changewifi[1] 596 | 597 | if WSREGEX.search(ssid) or WSREGEX.search(password): 598 | print("The SSID and the password must not contain whitespaces.") 599 | return False 600 | if len(ssid) == 0: 601 | print("SSID must not be empty.") 602 | return False 603 | if len(password) < 8 or len(password) > 63: 604 | print("Password must be between 8 and 63 characters.") 605 | return False 606 | 607 | _changeAPCredentials(ssid, password) 608 | return True 609 | 610 | def _checkNetwork(): 611 | i = 60 612 | while 1: 613 | waiting = "Connecting: %s seconds left \r" % i 614 | stdout.write(waiting) 615 | stdout.flush() 616 | time.sleep(1) 617 | address = _getIFaceIP("wlan0") 618 | if address != 'None': 619 | print("Done. Please connect your laptop or PC to the same network as this device and go to " + \ 620 | text_colors.CYAN + "http://" + address + text_colors.END + " or " + text_colors.CYAN + \ 621 | "http://" + _getHostName() + ".local" + text_colors.END + \ 622 | " in your browser.") 623 | break 624 | if i == 0: 625 | print("Not connected. Something went wrong.") 626 | break 627 | i = i-1 628 | 629 | def connectNetwork(): 630 | ssid = "" 631 | _setWiFiMode("Powered") 632 | 633 | while 1: 634 | reset("WiFi Connection") 635 | 636 | while True: 637 | ssid_keys = _scanForNetworks() 638 | if len(ssid_keys) > 0 and ssid_keys[0][1] == "Scanning, please wait 10 seconds": 639 | print(ssid_keys[0][1]) 640 | time.sleep(10) 641 | else: 642 | break 643 | 644 | choice = _selectWifiMenu(ssid_keys) 645 | 646 | #choice is validated within selectNetwork. 647 | if choice == 2: 648 | while 1: 649 | ssid = input("Please enter the hidden network SSID: ") 650 | if _verified(ssid): 651 | break 652 | if _configureHiddenNetwork(ssid): 653 | break 654 | elif choice > 2: 655 | if _configureNetwork(choice, ssid_keys): 656 | break 657 | 658 | # for error messages 659 | time.sleep(5) 660 | 661 | _checkNetwork() 662 | disableOneTimeSetup(True) 663 | 664 | def showWiFiIP(): 665 | if _getWiFiMode() == 'AP': 666 | return _getIFaceIP("tether") 667 | ipstr = _getIFaceIP('wlan0') 668 | if ipstr == 'None': 669 | print("No IP address found. Device not connected?") 670 | return ipstr 671 | 672 | def showWiFiMode(): 673 | Mode = _getWiFiMode() 674 | if Mode == 'Err': 675 | print("Connman error") 676 | return Mode 677 | 678 | def isRestartWithAPSet(): 679 | try: 680 | ret_value = subprocess.call("mkdir -p /update", shell=True) 681 | if ret_value != 0: 682 | print("Could not create destination folder.") 683 | return False 684 | except Exception as inst: 685 | print("Could not create destination folder.") 686 | print(type(inst), file=sys.stderr) 687 | print(inst, file=sys.stderr) 688 | return False 689 | 690 | try: 691 | ret_value = subprocess.call("losetup -o 8192 /dev/loop0 /dev/disk/by-partlabel/update", shell=True) 692 | if ret_value != 0: 693 | print("Could not setup loop device") 694 | return False 695 | except Exception as inst: 696 | print("Could not setup loop device") 697 | print(type(inst), file=sys.stderr) 698 | print(inst, file=sys.stderr) 699 | return False 700 | 701 | try: 702 | ret_value = subprocess.call("mount /dev/loop0 /update", shell=True) 703 | if ret_value != 0: 704 | print("Could not perform mount operation.") 705 | return False 706 | except Exception as inst: 707 | print("Could not perform mount operation.") 708 | print(type(inst), file=sys.stderr) 709 | print(inst, file=sys.stderr) 710 | return False 711 | 712 | if os.path.isfile("/update" + HOST_AP_MODE_FILE): 713 | ap_mode = True 714 | else: 715 | ap_mode = False 716 | try: 717 | ret_value = subprocess.call("umount /update", shell=True) 718 | if ret_value != 0: 719 | print("Could not perform umount operation.") 720 | return False 721 | except Exception as inst: 722 | print("Could not perform umount operation.") 723 | print(type(inst), file=sys.stderr) 724 | print(inst, file=sys.stderr) 725 | return False 726 | try: 727 | ret_value = subprocess.call("rmdir /update", shell=True) 728 | if ret_value != 0: 729 | print("Could not delete destination folder.") 730 | return False 731 | except Exception as inst: 732 | print("Could not delete destination folder.") 733 | print(type(inst), file=sys.stderr) 734 | print(inst, file=sys.stderr) 735 | return False 736 | 737 | return ap_mode 738 | 739 | def _decideToConnect(): 740 | while 1: 741 | verify = input("Do you want to set up wifi? " + text_colors.YELLOW + "[Y or N]" + text_colors.END + ": ") 742 | if verify == "y" or verify == "Y": 743 | return 1 744 | elif verify == "n" or verify == "N": 745 | return 0 746 | else: 747 | print("I need Y or N as a reply.") 748 | 749 | def full(): 750 | reset("Device Password") 751 | setEdisonPassword() 752 | reset("Device Name") 753 | setEdisonHostname() 754 | if _decideToConnect(): 755 | connectNetwork() 756 | else: 757 | print("Done.\n") 758 | 759 | def enableOneTimeSetup(persist): 760 | subprocess.call("systemctl restart blink-led", shell=True) 761 | _setWiFiMode("Off") 762 | 763 | print("Restarting WiFi access point. Please wait until the AP appears...\n") 764 | 765 | if persist: 766 | subprocess.call("systemctl enable blink-led &> /dev/null", shell=True) 767 | 768 | _setWiFiMode("AP") 769 | myssid = _getAPSSID() 770 | 771 | print("From your PC or laptop, connect to the", "'" + myssid + "' network ") 772 | print("and visit", "'" + _getHostName() + ".local' in the browser") 773 | 774 | def disableOneTimeSetup(persist): 775 | subprocess.call("systemctl stop blink-led &> /dev/null", shell=True) 776 | _setWiFiMode("Off") 777 | 778 | if persist: 779 | subprocess.call("systemctl disable blink-led &> /dev/null", shell=True) 780 | 781 | _setWiFiMode("Powered") 782 | 783 | def toggleOneTimeSetup(persist): 784 | if _getWiFiMode() == "AP": 785 | disableOneTimeSetup(persist) 786 | else: 787 | enableOneTimeSetup(persist) 788 | 789 | def changePassword(newPass): 790 | if WSREGEX.search(newPass): 791 | print("New password contains whitespaces. Ignoring") 792 | return 793 | 794 | _changeRootPassword(newPass) 795 | if len(newPass) > 0: 796 | _changeAPPassword(newPass) 797 | 798 | if (not os.path.isfile(STATE_DIR + "/password-setup.done")): 799 | pass_done = open(STATE_DIR + "/password-setup.done", "w") 800 | pass_done.write("Indicates that password has been changed via oobe.\n") 801 | pass_done.close() 802 | print("First-time root password setup complete. Enabling SSH on WiFi interface.") 803 | subprocess.call("sed -i 's/^BindToDevice=/# BindToDevice=/g' /lib/systemd/system/sshd.socket ; sync ; systemctl daemon-reload; systemctl restart sshd.socket", shell=True) 804 | 805 | def changeName(newName): 806 | if _checkName(newName) < 0: 807 | print("Invalid new name. Ignoring") 808 | return 809 | _changeHostName(newName) 810 | _changeAPSSID(newName) 811 | 812 | def showNames(): 813 | hostname = _getHostName() 814 | ssid = _getAPSSID() 815 | default_ssid = _getDefaultSSID() 816 | print('{"hostname": "' + hostname + '", "ssid": "' + ssid + '", "default_ssid": "' + default_ssid + '"}') 817 | 818 | # Web Interface 819 | ####################################### 820 | @route('/') 821 | def main_form(): 822 | print(request['REMOTE_ADDR']) 823 | return template('index' ) 824 | 825 | @route('/', method='POST') 826 | def do_main_form(): 827 | control = request.forms.get('button') 828 | print(control) 829 | redirect('/') 830 | 831 | @route('/activate') 832 | def activate(): 833 | global Settings 834 | if Settings.HostName.Changed and Settings.HostName.Valid: 835 | hostname = Settings.HostName.New 836 | else: 837 | hostname = _getHostName() 838 | return template('activate', hostname = hostname, \ 839 | nameChange = Settings.HostName.Changed, wiredChange = Settings.Wired.Changed, \ 840 | btChange = Settings.BT.Changed, wifiChange = Settings.Wifi.Changed, \ 841 | apChange = Settings.AP.Changed) 842 | 843 | @route('/activate', method='POST') 844 | def do_activate_form(): 845 | global Settings 846 | if Settings.HostName.Changed and Settings.HostName.Valid: 847 | _changeHostName(Settings.HostName.New) 848 | Settings.HostName.Changed = False 849 | if Settings.Wired.Changed: 850 | if Settings.Wired.NewMode == "checked": 851 | _setGadgetMode("Powered") 852 | else: 853 | _setGadgetMode("Off") 854 | Settings.Wired.Changed = False 855 | if Settings.BT.Changed: 856 | if Settings.BT.NewMode == "checked": 857 | new_BTMode = "Powered" 858 | else: 859 | new_BTMode = "Off" 860 | _setBTMode(new_BTMode) 861 | BTMode = _getBTMode() 862 | if Settings.BT.Name is not None and BTMode == "Powered" or BTMode == "Connected": 863 | _selectNetwork(Settings.BT.Name) 864 | Settings.BT.Changed = False 865 | if Settings.Wifi.Changed: 866 | if Settings.Wifi.NewMode == "checked": 867 | new_WiFiMode = "Powered" 868 | else: 869 | new_WiFiMode = "Off" 870 | _setWiFiMode(new_WiFiMode) 871 | WiFiMode = _getWiFiMode() 872 | if Settings.Wifi.Name is not None and WiFiMode == "Powered" or WiFiMode == "Connected": 873 | WiFi_ServiceName = _getCachedService(Settings.Wifi.Name) 874 | _store(Settings.Wifi.Name, WiFi_ServiceName, Settings.Wifi.Passphrase) 875 | Settings.Wifi.Passphrase = "" 876 | _selectNetwork(Settings.Wifi.Name) 877 | Settings.Wifi.Changed = False 878 | if Settings.AP.Changed: 879 | if Settings.AP.Name != "": 880 | _changeAPSSID(Settings.AP.Name) 881 | if Settings.AP.Passphrase != "": 882 | _changeAPPassword(Settings.AP.Passphrase) 883 | Settings.AP.Passphrase = "" 884 | if Settings.AP.Enabled: 885 | enableOneTimeSetup(False) 886 | else: 887 | disableOneTimeSetup(False) 888 | Settings.AP.Changed = False 889 | 890 | redirect('/name') 891 | 892 | @route('/name') 893 | def name_form(): 894 | global Settings 895 | Settings.HostName.Old = _getHostName() 896 | if not Settings.HostName.Changed: 897 | hostname = Settings.HostName.Old 898 | tooltip = "Names consist of 'a-z', '0-9', '-'" 899 | checked = "" 900 | else: 901 | hostname = Settings.HostName.New 902 | tooltip = Settings.HostName.Tooltip 903 | if Settings.HostName.Valid: 904 | checked = "font-weight: bold; " 905 | else: 906 | checked = "border:3px; border-style:solid; border-color:red; padding: 1em; " 907 | 908 | return template('name', hostname_checked = checked, hostname_tooltip = tooltip, \ 909 | hostname = hostname) 910 | 911 | @route('/name', method='POST') 912 | def do_name_form(): 913 | global Settings 914 | Settings.HostName.New = request.forms.get('hostname') 915 | Settings.HostName.Changed = False 916 | if Settings.HostName.New != Settings.HostName.Old: 917 | Settings.HostName.Changed = True 918 | # update done in do_activate_form() 919 | Settings.HostName.Valid = False 920 | check = _checkName(Settings.HostName.New) 921 | if check == 0: 922 | Settings.HostName.Valid = True 923 | Settings.HostName.Tooltip = "Valid host name" 924 | elif check == -1: 925 | Settings.HostName.Tooltip = "Incorrect length" 926 | elif check == -2: 927 | Settings.HostName.Tooltip = "Can not start or end with '-'" 928 | elif check == -3: 929 | Settings.HostName.Tooltip = "Can not contain other then 'a-z', '0-9', '-'" 930 | redirect('/name') 931 | 932 | @route('/wired') 933 | def wired_form(): 934 | global Settings 935 | Host_IP = request['REMOTE_ADDR'] 936 | Net = _getGadgetMode() 937 | if Net == "None": 938 | Net = _getWiredMode() 939 | if Net == "None": 940 | Settings.Wired.Type = "No ethernet available" 941 | Settings.Wired.Mode = "" 942 | elif Net == "Powered": 943 | Settings.Wired.Type = "Ethernet dongle" 944 | Settings.Wired.Mode = "checked" 945 | elif Net == "Connected": 946 | Settings.Wired.Type = "Ethernet dongle" 947 | Settings.Wired.Mode = "checked" 948 | else: 949 | Settings.Wired.Type = "An error has occured" 950 | Settings.Wired.Mode = "" 951 | elif Net == "Powered": 952 | Settings.Wired.Type = "Ethernet over USB (OTG)" 953 | Settings.Wired.Mode = "checked" 954 | elif Net == "Connected": 955 | Settings.Wired.Type = "Ethernet over USB (OTG)" 956 | Settings.Wired.Mode = "checked" 957 | elif Net == "Off": 958 | Settings.Wired.Type = "Ethernet over USB (OTG)" 959 | Settings.Wired.Mode = "" 960 | else: 961 | Settings.Wired.Type = "An error has occured" 962 | Settings.Wired.Mode = "" 963 | 964 | connections = _getServices("Wired") 965 | if connections: 966 | ConnState = connections[0][0] 967 | else: 968 | ConnState = "" 969 | Wired_State = "" 970 | 971 | Settings.Wired.IP = "Unknown" 972 | if Net == "Connected": 973 | if "O" in ConnState: 974 | Wired_State = "Primary connection verified On Line" 975 | elif "R" in ConnState: 976 | Wired_State = "Fall back connection standby" 977 | Settings.Wired.IP = _getIFaceIP(_getIFace(connections[0])) 978 | elif Net == "Powered": 979 | if "*" in ConnState: 980 | Wired_State = "Connection available" 981 | else: 982 | Wired_State = "Not plugged" 983 | Settings.Wired.IP = "Unconnected" 984 | 985 | return template('wired', Wired_Type = Settings.Wired.Type, Wired_IP = Settings.Wired.IP, \ 986 | Wired_Mode = Settings.Wired.NewMode if Settings.Wired.Changed else Settings.Wired.Mode, \ 987 | Wired_State = Wired_State, Host_IP = Host_IP) 988 | 989 | @route('/wired', method='POST') 990 | def do_wired_form(): 991 | global Settings 992 | Settings.Wired.NewMode = request.forms.get('Wired_Mode', '') 993 | Settings.Wired.Changed = False 994 | if Settings.Wired.NewMode != Settings.Wired.Mode: 995 | Settings.Wired.Changed = True 996 | # update done in do_activate_form() 997 | redirect('/wired') 998 | 999 | @route('/bt') 1000 | def bt_form(): 1001 | global Settings 1002 | Host_IP = request['REMOTE_ADDR'] 1003 | Net = _getBTMode() 1004 | 1005 | BT_Mode = "" 1006 | if Net == "Powered" or Net == "Connected": 1007 | BT_Mode = "checked" 1008 | 1009 | connections = _getServices("bluetooth") 1010 | if connections: 1011 | ConnState = connections[0][0] 1012 | else: 1013 | ConnState = "" 1014 | BT_State = "" 1015 | 1016 | Settings.BT.IP = "Unknown" 1017 | if Net == "Connected": 1018 | if "O" in ConnState: 1019 | BT_State = "Primary connection verified On Line" 1020 | elif "R" in ConnState: 1021 | BT_State = "Fall back connection standby" 1022 | Settings.BT.IP = _getIFaceIP(_getIFace(connections[0])) 1023 | elif Net == "Powered": 1024 | if "*" in ConnState: 1025 | BT_State = "Connection available" 1026 | else: 1027 | BT_State = "Not plugged" 1028 | Settings.BT.IP = "Unconnected" 1029 | 1030 | return template('bt', rows = connections, BT_IP = Settings.BT.IP, \ 1031 | BT_Mode = Settings.BT.NewMode if Settings.BT.Changed else BT_Mode, \ 1032 | BT_State = BT_State, Host_IP = Host_IP) 1033 | 1034 | @route('/bt', method='POST') 1035 | def do_bt_form(): 1036 | global Settings 1037 | Settings.BT.NewMode = request.forms.get('BT_Mode', '') 1038 | Settings.BT.Name = request.forms.get('newbts') 1039 | 1040 | Settings.BT.Changed = True 1041 | # update done in do_activate_form() 1042 | redirect('/bt') 1043 | 1044 | @route('/wireless') 1045 | @route('/wirelessr') 1046 | def wireless_form(): 1047 | global Settings 1048 | Host_IP = request['REMOTE_ADDR'] 1049 | WiFi_mode = "" 1050 | Settings.Wifi.IP = "WiFi is currently not powered" 1051 | WiFiMode = _getWiFiMode() 1052 | WiFi_State = "" 1053 | ReloadMode = False 1054 | 1055 | if WiFiMode == "Connected": 1056 | WiFi_mode = "checked" 1057 | Settings.Wifi.IP = _getIFaceIP("wlan0") 1058 | elif WiFiMode == "Powered": 1059 | Settings.Wifi.IP = "WiFi is powered but inactive" 1060 | 1061 | connections = [] 1062 | if WiFiMode == "Powered" or WiFiMode == "Connected": 1063 | connections = _scanForNetworks() 1064 | print(connections) 1065 | if len(connections) > 0 and connections[0][1] == "Scanning, please wait 10 seconds": 1066 | WiFi_State = "Scanning" 1067 | ReloadMode = True 1068 | else: 1069 | if WiFiMode == "Connected": 1070 | ConnState = connections[0][0] 1071 | if "O" in ConnState: 1072 | WiFi_State = "Primary connection verified On Line" 1073 | elif "R" in ConnState: 1074 | WiFi_State = "Fall back connection standby" 1075 | 1076 | if ReloadMode == True: 1077 | return template('wirelessr', 1078 | WiFi_mode = Settings.Wifi.NewMode if Settings.Wifi.Changed else WiFi_mode, 1079 | rows = connections, WiFi_IP = Settings.Wifi.IP, WiFi_Passphrase = "!@#$%^&*", 1080 | WiFi_State = WiFi_State, Host_IP = Host_IP) 1081 | else: 1082 | return template('wireless', 1083 | WiFi_mode = Settings.Wifi.NewMode if Settings.Wifi.Changed else WiFi_mode, 1084 | rows = connections, WiFi_IP = Settings.Wifi.IP, WiFi_Passphrase = "!@#$%^&*", 1085 | WiFi_State = WiFi_State, Host_IP = Host_IP) 1086 | 1087 | @route('/wireless', method='POST') 1088 | def do_wireless_form(): 1089 | global Settings 1090 | Settings.Wifi.NewMode = request.forms.get('WiFi_mode', '') 1091 | Settings.Wifi.Name = request.forms.get('newwifis') 1092 | Settings.Wifi.Passphrase = request.forms.get('WiFipassphrase') 1093 | 1094 | Settings.Wifi.Changed = True 1095 | Settings.AP.Changed = False # AP and wifi activation are mutually exclusive 1096 | # update done in do_activate_form() 1097 | redirect('/wireless') 1098 | 1099 | @route('/ap') 1100 | def ap_form(): 1101 | global Settings 1102 | 1103 | AP_name = _getAPSSID() 1104 | hostname = _getHostName() 1105 | 1106 | if _getWiFiMode() == "AP": 1107 | AP_mode = "checked" 1108 | AP_IP = "Access Point " + AP_name + " is currently on IP address: " + _getIFaceIP("tether") 1109 | else: 1110 | AP_mode = "" 1111 | AP_IP = "Access Point is currently OFF" 1112 | 1113 | return template('ap', hostname = hostname, 1114 | AP_mode = Settings.AP.NewMode if Settings.AP.Changed else AP_mode, 1115 | AP_name = Settings.AP.Name if Settings.AP.Changed else AP_name, 1116 | AP_passphrase = "", AP_IP = AP_IP) 1117 | 1118 | @route('/ap', method='POST') 1119 | def do_ap_form(): 1120 | global Settings 1121 | Settings.AP.NewMode = request.forms.get('AP_mode', '') 1122 | AP_name = request.forms.get('AP_name') 1123 | AP_passphrase = request.forms.get('AP_passphrase') 1124 | 1125 | Settings.AP.Changed = False 1126 | if _getWiFiMode() != "AP" and Settings.AP.NewMode == "checked": 1127 | Settings.AP.Changed = True 1128 | Settings.AP.Enabled = True 1129 | # update done in do_activate_form() 1130 | 1131 | if AP_name != Settings.AP.Name: 1132 | if WSREGEX.search(AP_name): 1133 | return "The SSID must not contain whitespaces." 1134 | if len(AP_name) == 0: 1135 | return "The SSID must not be empty." 1136 | Settings.AP.Name = AP_name 1137 | if AP_passphrase != "": 1138 | if WSREGEX.search(AP_passphrase): 1139 | return "The passphrase must not contain whitespaces." 1140 | if len(AP_passphrase) < 8 or len(AP_passphrase) > 63: 1141 | return "The passphrase must be between 8 and 63 characters." 1142 | Settings.AP.Passphrase = AP_passphrase 1143 | AP_passphrase = None 1144 | elif _getWiFiMode() == "AP" and Settings.AP.NewMode == "": 1145 | Settings.AP.Changed = True 1146 | Settings.AP.Enabled = False 1147 | # update done in do_activate_form() 1148 | if Settings.AP.Changed: 1149 | Settings.Wifi.Changed = False # AP and wifi activation are mutually exclusive 1150 | 1151 | redirect('/ap') 1152 | 1153 | @route('/img/') 1154 | def send_image(filename): 1155 | return static_file(filename, root='img', mimetype='image/png') 1156 | 1157 | @route('/img/') 1158 | def send_image(filename): 1159 | return static_file(filename, root='img', mimetype='image/svg+xml') 1160 | 1161 | @route('/css/') 1162 | def send_static(filename): 1163 | return static_file(filename, root='css') 1164 | 1165 | @route('/script/') 1166 | def send_static(filename): 1167 | return static_file(filename, root='script') 1168 | 1169 | @route('/') 1170 | def send_image(filename): 1171 | return static_file(filename, root='img', mimetype='image/x-icon') 1172 | 1173 | # Main 1174 | ####################################### 1175 | def main(): 1176 | global lastScanned 1177 | global Settings 1178 | lastScanned = datetime.datetime.min 1179 | Settings = classSettings() 1180 | 1181 | parser = argparse.ArgumentParser(prog='configure_edison') 1182 | 1183 | parser.add_argument('--restartWithAP', dest='restartwithap', help=argparse.SUPPRESS, action='store_true', default=False) 1184 | parser.add_argument('--persist', dest='persist', help=argparse.SUPPRESS, action='store_true', default=False) 1185 | 1186 | root_group = parser.add_mutually_exclusive_group() 1187 | 1188 | group_interactive = root_group.add_mutually_exclusive_group() 1189 | group_interactive.add_argument('--setup', dest='setup', help='Goes through changing the device name, password, and wifi options', action='store_true', default=False) 1190 | group_interactive.add_argument('--name', dest='name', help='Changes the device name', action='store_true', default=False) 1191 | group_interactive.add_argument('--password', dest='password', help='Changes the device password', action='store_true', default=False) 1192 | group_interactive.add_argument('--wifi', dest='wifi', help='Changes the wifi options', action='store_true', default=False) 1193 | 1194 | group_non_interactive = root_group.add_mutually_exclusive_group() 1195 | group_non_interactive.add_argument('--isRestartWithAPSet', dest='isrestartwithapset', help=argparse.SUPPRESS, action='store_true', default=False) 1196 | group_non_interactive.add_argument('--showWiFiIP', dest='showwifiip', help='IP address associated with the wireless interface', action='store_true', default=False) 1197 | group_non_interactive.add_argument('--showWiFiMode', dest='showwifimode', help='Show current mode for the wireless interface', action='store_true', default=False) 1198 | group_non_interactive.add_argument('--disableOneTimeSetup', dest='disableonetimesetup', help='Disable one-time setup with WiFi access point and enable WiFi client mode. \ 1199 | Append --persist to retain this setting after reboot', action='store_true', default=False) 1200 | group_non_interactive.add_argument('--enableOneTimeSetup', dest='enableonetimesetup', help='Enable one-time setup with WiFi access point and disable WiFi client mode. \ 1201 | Append --persist to retain this setting after reboot', action='store_true', default=False) 1202 | group_non_interactive.add_argument('--toggleOneTimeSetup', dest='toggleonetimesetup', help='Switch between one-time setup with WiFi access point and WiFi client mode, and visa-versa. \ 1203 | Append --persist to retain this setting after reboot', action='store_true', default=False) 1204 | group_non_interactive.add_argument('--changePassword', metavar='password', dest='changepassword', const='', help=argparse.SUPPRESS, nargs='?') 1205 | group_non_interactive.add_argument('--changeName', metavar='name', dest='changename', help=argparse.SUPPRESS, nargs=1) 1206 | group_non_interactive.add_argument('--changeWiFi', metavar='SSID password', dest='changewifi', help=argparse.SUPPRESS, nargs=2) 1207 | group_non_interactive.add_argument('--showNames', dest='shownames', help='Show device name and SSID', action='store_true', default=False) 1208 | group_non_interactive.add_argument('--webInterface', dest='webInterface', help='Start a web server', action='store_true', default=False) 1209 | 1210 | if len(sys.argv)==1: 1211 | parser.print_help() 1212 | sys.exit(1) 1213 | 1214 | args = parser.parse_args() 1215 | 1216 | if args.name: 1217 | reset("Device Name") 1218 | setEdisonHostname() 1219 | 1220 | if args.password: 1221 | reset("Device Password") 1222 | setEdisonPassword() 1223 | 1224 | if args.wifi: 1225 | connectNetwork() 1226 | if not os.path.isfile(STATE_DIR + "/password-setup.done"): 1227 | print("Warning: SSH is not yet enabled on the wireless interface. To enable SSH access to this device via wireless run configure_edison --password first.") 1228 | 1229 | if args.setup: 1230 | full() 1231 | 1232 | if args.shownames: 1233 | showNames() 1234 | 1235 | if args.isrestartwithapset: 1236 | print(isRestartWithAPSet()) 1237 | 1238 | if args.changepassword != None: 1239 | changePassword(args.changepassword) 1240 | 1241 | if args.changename != None: 1242 | changeName(args.changename[0]) 1243 | 1244 | if args.showwifiip: 1245 | print(showWiFiIP()) 1246 | 1247 | if args.showwifimode: 1248 | print(showWiFiMode()) 1249 | 1250 | if args.enableonetimesetup: 1251 | enableOneTimeSetup(args.persist) 1252 | 1253 | if args.disableonetimesetup: 1254 | disableOneTimeSetup(args.persist) 1255 | 1256 | if args.toggleonetimesetup: 1257 | toggleOneTimeSetup(args.persist) 1258 | 1259 | if args.changewifi: 1260 | if configureNetworkAP(args.changewifi): 1261 | enableOneTimeSetup(False) 1262 | 1263 | if args.webInterface: 1264 | os.chdir(os.path.dirname('/usr/lib/edison_config_tools/public/')) 1265 | debug(False) 1266 | run(host='0.0.0.0', port=80) 1267 | 1268 | #print 'restartwithap = ',args.restartwithap 1269 | #print 'persist = ',args.persist 1270 | #print 'setup = ',args.setup 1271 | #print 'name = ',args.name 1272 | #print 'password = ',args.password 1273 | #print 'wifi = ',args.wifi 1274 | 1275 | #print 'showwifiip = ',args.showwifiip 1276 | #print 'disableonetimesetup = ',args.disableonetimesetup 1277 | #print 'enableonetimesetup = ',args.enableonetimesetup 1278 | #print 'changepassword = ',args.changepassword 1279 | 1280 | #print 'changename = ',args.changename 1281 | 1282 | if __name__ == "__main__": 1283 | main() 1284 | -------------------------------------------------------------------------------- /vendor-resources/mars-a1/etc/hostname: -------------------------------------------------------------------------------- 1 | marspc -------------------------------------------------------------------------------- /vendor-resources/mars-a1/etc/resolv.conf: -------------------------------------------------------------------------------- 1 | nameserver 94.140.14.140 2 | nameserver 1.0.0.1 -------------------------------------------------------------------------------- /vendor-resources/mars-a1/home/ubuntu/Desktop/marspc.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=MARSPC™ 3 | Comment=Homepage of MARSPC™ 4 | Icon=/usr/share/icons/mars/marspc.png 5 | Type=Application 6 | Exec=xdg-open https://pc.arm.li/ 7 | -------------------------------------------------------------------------------- /vendor-resources/mars-a1/usr/share/backgrounds/mars/block.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/initdc/rootfs-tools/65393a5f8c65cc7e4d7055152a6c1ce09ebcf0d2/vendor-resources/mars-a1/usr/share/backgrounds/mars/block.jpg -------------------------------------------------------------------------------- /vendor-resources/mars-a1/usr/share/backgrounds/mars/cosmo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/initdc/rootfs-tools/65393a5f8c65cc7e4d7055152a6c1ce09ebcf0d2/vendor-resources/mars-a1/usr/share/backgrounds/mars/cosmo.jpg -------------------------------------------------------------------------------- /vendor-resources/mars-a1/usr/share/backgrounds/mars/hexagon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/initdc/rootfs-tools/65393a5f8c65cc7e4d7055152a6c1ce09ebcf0d2/vendor-resources/mars-a1/usr/share/backgrounds/mars/hexagon.jpg -------------------------------------------------------------------------------- /vendor-resources/mars-a1/usr/share/backgrounds/mars/home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/initdc/rootfs-tools/65393a5f8c65cc7e4d7055152a6c1ce09ebcf0d2/vendor-resources/mars-a1/usr/share/backgrounds/mars/home.jpg -------------------------------------------------------------------------------- /vendor-resources/mars-a1/usr/share/backgrounds/mars/planet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/initdc/rootfs-tools/65393a5f8c65cc7e4d7055152a6c1ce09ebcf0d2/vendor-resources/mars-a1/usr/share/backgrounds/mars/planet.jpg -------------------------------------------------------------------------------- /vendor-resources/mars-a1/usr/share/backgrounds/mars/wave.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/initdc/rootfs-tools/65393a5f8c65cc7e4d7055152a6c1ce09ebcf0d2/vendor-resources/mars-a1/usr/share/backgrounds/mars/wave.jpg -------------------------------------------------------------------------------- /vendor-resources/mars-a1/usr/share/icons/mars/marspc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/initdc/rootfs-tools/65393a5f8c65cc7e4d7055152a6c1ce09ebcf0d2/vendor-resources/mars-a1/usr/share/icons/mars/marspc.png -------------------------------------------------------------------------------- /vendor-resources/visionfive-2/root/config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | add_ubuntu() { 6 | useradd -G sudo -d /home/ubuntu -m -s /bin/bash ubuntu 7 | echo "ubuntu:ubuntu" | chpasswd 8 | echo "root:root" | chpasswd 9 | } 10 | 11 | add_lang_pack() { 12 | apt-get install -y language-pack-en-base 13 | apt-get install -y dialog apt-utils 14 | } 15 | 16 | install_software() { 17 | apt-get install -y dnsutils file htop ifupdown iputils-ping lshw lsof nano net-tools network-manager openssh-server rfkill tree u-boot-tools wget wireless-tools wpasupplicant 18 | apt-get install /tmp/resize-helper_0.12_all.deb 19 | } 20 | 21 | set_sshd_config() { 22 | cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig 23 | sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config 24 | sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config 25 | } 26 | 27 | main() { 28 | export DEBIAN_FRONTEND="noninteractive" 29 | 30 | # apt-get update 31 | 32 | # add_lang_pack 33 | # install_software 34 | set_sshd_config 35 | # rm -rf /var/lib/apt/* 36 | 37 | add_ubuntu 38 | # systemctl enable getty@ttyS2.service 39 | 40 | unset DEBIAN_FRONTEND 41 | } 42 | 43 | main "$@" 44 | -------------------------------------------------------------------------------- /vendor-resources/visionfive-2/root/suse.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | change_hostname() { 6 | hostnamectl hostname 'visionfive2' 7 | } 8 | 9 | add_wheel() { 10 | groupadd wheel 11 | sed -i 's/# \%wheel ALL=(ALL:ALL) NOPASSWD: ALL/\%wheel ALL=(ALL:ALL) NOPASSWD: ALL/g' /etc/sudoers 12 | } 13 | 14 | add_suse() { 15 | useradd suse -m -G wheel -s /bin/bash 16 | echo "suse:byinitdc" | chpasswd 17 | echo "root:Byinitdc" | chpasswd 18 | } 19 | 20 | install_software() { 21 | zypper install -y htop lshw nano net-tools tree git-core 22 | } 23 | 24 | main() { 25 | install_software 26 | change_hostname 27 | add_wheel 28 | add_suse 29 | } 30 | 31 | main "$@" 32 | -------------------------------------------------------------------------------- /vendor-resources/visionfive-2/vf2: -------------------------------------------------------------------------------- 1 | # dd if=/dev/zero of=vf2.img bs=1MB count=0 seek=2100 2 | label: gpt 3 | label-id: 58F2E40C-030E-48C2-95C2-0A45030AB01B 4 | device: vf2.img 5 | unit: sectors 6 | first-lba: 4096 7 | last-lba: 4096000 8 | 9 | sdcard.img1 : start= 4096, size= 4096, type=2E54B353-1271-4842-806F-E436D6AF6985, uuid=A5FEEF7A-E974-471E-B074-9D446B82D2EB, name="spl" 10 | sdcard.img2 : start= 8192, size= 8192, type=5B193300-FC78-40CD-8002-E86C45580B47, uuid=19A94EDA-2B35-450D-B9AF-13BB67C688F1, name="uboot" 11 | sdcard.img3 : start= 16384, size= 598016, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=98DCCB94-E0B4-48C1-8719-0ECD22AF25BA, name="image" 12 | sdcard.img4 : start= 614400, size= 3481600, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=ABD24574-D2AB-48E7-AC81-EE9FD5D9E3BF, name="root", attrs="LegacyBIOSBootable" 13 | -------------------------------------------------------------------------------- /vendor-resources/visionfive-2/vf2-deb: -------------------------------------------------------------------------------- 1 | # dd if=/dev/zero of=vf2.img bs=1MB count=0 seek=2100 2 | label: gpt 3 | label-id: 6BEBB43B-65F5-4057-BC3A-D9B242D06F29 4 | device: vf2.img 5 | unit: sectors 6 | first-lba: 34 7 | last-lba: 4096000 8 | 9 | vf2.img1 : start= 2048, size= 32768, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=5F7FD372-5546-44DF-B018-A077758CEE2F 10 | vf2.img2 : start= 34816, size= 204800, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=BDC51E7D-66F3-4BA4-AC93-ADF2E8850928 11 | vf2.img3 : start= 239616, size= 3856384, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=3D4C02EB-9C28-46A1-A86B-71666EF51CDB, attrs="LegacyBIOSBootable" 12 | -------------------------------------------------------------------------------- /vendor-resources/visionfive-2/vf2-fd: -------------------------------------------------------------------------------- 1 | # dd if=/dev/zero of=vf2.img bs=1MB count=0 seek=8500 2 | label: gpt 3 | label-id: 58F2E40C-030E-48C2-95C2-0A45030AB01B 4 | device: vf2.img 5 | unit: sectors 6 | first-lba: 4096 7 | last-lba: 16599040 8 | 9 | sdcard.img1 : start= 4096, size= 4096, type=2E54B353-1271-4842-806F-E436D6AF6985, uuid=A5FEEF7A-E974-471E-B074-9D446B82D2EB, name="spl" 10 | sdcard.img2 : start= 8192, size= 8192, type=5B193300-FC78-40CD-8002-E86C45580B47, uuid=19A94EDA-2B35-450D-B9AF-13BB67C688F1, name="uboot" 11 | sdcard.img3 : start= 16384, size= 598016, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=98DCCB94-E0B4-48C1-8719-0ECD22AF25BA, name="image" 12 | sdcard.img4 : start= 614400, size= 15984640, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=ABD24574-D2AB-48E7-AC81-EE9FD5D9E3BF, name="root", attrs="LegacyBIOSBootable" 13 | --------------------------------------------------------------------------------