├── .gitmodules
├── LICENSE
├── README.md
├── VERSION
├── bin
├── yahm-backup
├── yahm-ctl
├── yahm-lxc
├── yahm-module
├── yahm-network
└── yahm-ui
├── share
├── include.sh
├── tools
│ ├── checks
│ │ ├── check_interfaces.sh
│ │ └── check_rfd.sh
│ ├── hmgw
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── eq3
│ │ │ ├── bin
│ │ │ │ └── eq3configcmd
│ │ │ ├── firmware
│ │ │ │ ├── coprocessor_update.eq3
│ │ │ │ └── fwmap
│ │ │ └── lib
│ │ │ │ ├── libLanDeviceUtils.so
│ │ │ │ ├── libUnifiedLanComm.so
│ │ │ │ ├── libelvutils.so
│ │ │ │ └── libeq3config.so
│ │ ├── hmframe.cpp
│ │ ├── hmframe.h
│ │ ├── hmframe.o
│ │ ├── hmlangw
│ │ ├── hmlangw.cpp
│ │ ├── hmlangw.o
│ │ ├── kill-hmlan.sh
│ │ ├── run-hmlan.sh
│ │ └── start-hmlan.sh
│ └── ubi_reader
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── create_build_script.py
│ │ ├── output
│ │ └── .gitignore
│ │ ├── ubi
│ │ ├── __init__.py
│ │ ├── block
│ │ │ ├── __init__.py
│ │ │ ├── layout.py
│ │ │ └── sort.py
│ │ ├── defines.py
│ │ ├── display.py
│ │ ├── headers
│ │ │ ├── __init__.py
│ │ │ └── errors.py
│ │ ├── image.py
│ │ └── volume
│ │ │ └── __init__.py
│ │ ├── ubi_extract.py
│ │ ├── ubi_extract_files.py
│ │ ├── ubi_extract_ubifs.py
│ │ ├── ubi_info.py
│ │ ├── ubi_io
│ │ └── __init__.py
│ │ ├── ubi_utils_info.py
│ │ ├── ubifs
│ │ ├── __init__.py
│ │ ├── defines.py
│ │ ├── log.py
│ │ ├── misc.py
│ │ ├── nodes
│ │ │ ├── __init__.py
│ │ │ └── extract.py
│ │ ├── output.py
│ │ └── walk.py
│ │ ├── ubifs_extract_files.py
│ │ ├── ubifs_info.py
│ │ └── ui
│ │ ├── __init__.py
│ │ └── common.py
└── yahm_completion
└── yahm-init
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "share/tools/Network-Interfaces-Script"]
2 | path = share/tools/Network-Interfaces-Script
3 | url = https://github.com/leonsio/Network-Interfaces-Script.git
4 | [submodule "share/tools/arm-board-detect"]
5 | path = share/tools/arm-board-detect
6 | url = https://github.com/leonsio/arm-board-detect.git
7 | [submodule "share/tools/rpi-source"]
8 | path = share/tools/rpi-source
9 | url = https://github.com/notro/rpi-source
10 | [submodule "share/modules"]
11 | path = share/modules
12 | url = https://github.com/leonsio/YAHM-Module
13 | [submodule "share/firmware"]
14 | path = share/firmware
15 | url = https://github.com/leonsio/YAHM-Firmware
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 |
117 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9WRZHSCVYL6XL) Falls Sie dieses Projekt unterstützen möchten, würde ich mich über einen Pull-Request oder eine Spende: [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9WRZHSCVYL6XL) freuen.
3 |
4 | # YAHM
5 | **Yet Another Homematic Management** - Skripte zur Einrichtung der Homematic CCU2 Oberfläche in einem LXC Container unter Debian basierten Distribution auf ARM-Basis (x86 experimentell).
6 |
7 |
8 | **Bitte lesen Sie diese Dokumentation bis zum Ende durch, bevor Sie die Anwendung installieren**
9 |
10 | Zur Zeit wurde dieses Skript auf folgender Hardware erfolgreich getestet:
11 | * Rapsberry Pi 2/3
12 | * ASUS Tinker Board
13 | * Odroid XU4 (ohne Homematic-IP)
14 | * Orange PI Plus 2 (ohne Homematic-IP)
15 | * Experimentell: x86
16 |
17 | Folgende Betrebssysteme werden aktuell unterstützt:
18 | * Debian Jessie/Stretch (ARM/x86)
19 | * Raspbian Jessie/Stretch
20 | * Armbian (Debian) Stretch
21 | * Experimentell: Ubuntu 16.04
22 |
23 | _(* Die automatische Einrichtung des HM-MOD-RPI-PCB erfolgt ->aktuell<- ausschließlich auf Rapsberry Pi 2/3 und ASUS Tinker Board)_
24 |
25 | **Weitere Informationen und Anleitungen können dem [Wiki](https://github.com/leonsio/YAHM/wiki) bzw. dem [Homematic-Forum](https://homematic-forum.de/forum/viewforum.php?f=67) entnommen werden.**
26 |
27 | # Installation:
28 |
29 | ## Automatisiert:
30 | Es wird automatisch ein aktuelles CCU2 Image installiert und das Netzwerk konfiguriert. Diese Installation ist für wenig erfahrene Benutzer auf einem **frischen minimalen Debian/Raspbian** empfehlenswert. Die frisch installierte CCU2 wird eine IP per DHCP abrufen, diese kann durch **sudo yahm-ctl info** nach dem Start des Containers angezeigt werden.
31 |
32 | ```
33 | wget -nv -O- https://raw.githubusercontent.com/leonsio/YAHM/master/yahm-init | sudo -E bash -s quickinstall -
34 | ```
35 |
36 | **Hinweis:** Für die Unterstützung von Homematic-IP ist Funkmodul (HM-MOD-RPI-PCB) FW-Version ab 2.0.0 notwendig. Falls die Unterstützung nicht gebraucht wird, besteht die Möglichkeit Homematic-IP zu deaktivieren. Eine automatisierte Aktualisierung der HM-MOD-RPI-PCB Modul Firmware erfolgt nicht.
37 |
38 |
39 | ## UI Modus:
40 | "Grafisches" Installationswerkzeug. Diese Möglichkeit ist für wenig bis erfahrene Benutzer geeignet.
41 |
42 | ```
43 | wget -nv -O- https://raw.githubusercontent.com/leonsio/YAHM/master/yahm-init | sudo -E bash -s ui -
44 | ```
45 |
46 | ## Angepasst:
47 |
48 | Mit dieser Methode wird lediglich die aktuelle YAHM Version runtergeladen und unter **/opt/YAHM/bin** installiert, anschließend muss mit Hilfe von YAHM Tools ein [LXC Container](https://github.com/leonsio/YAHM/wiki/YAHM-LXC) mit der jeweiligen gewünschten CCU2 Version angelegt und das [Netzwerk](https://github.com/leonsio/YAHM/wiki/YAHM-Netzwerk) konfiguriert werden. Sollten Sie bereits **andere Anwendungen und Tools** installiert haben, bzw. eine **angepasste Netzerkkonfiguration** besitzen/wünschen ist diese Möglichkeit genau das richtige für Sie.
49 |
50 | ```
51 | wget -nv -O- https://raw.githubusercontent.com/leonsio/YAHM/master/yahm-init | sudo -E bash -
52 | ```
53 |
54 | Folgende Schritte sind **mindestens** notwendig um ein CCU2 Image innerhalb von YAHM zu installieren. Bitte beachten Sie hierfür die Hinweise im [Wiki](https://github.com/leonsio/YAHM/wiki).
55 | Mit diesen Schritten wird ein YAHM-LXC Container in der aktuellsten Version installiert (yahm-lxc install), eine neue Bridge (yahmbr0) angelegt (yahm-network create_bridge) und die Bridge einem Container zugewiesen (yahm-network attach_bridge).
56 |
57 | ```
58 | sudo yahm-lxc install
59 | sudo yahm-network create_bridge
60 | sudo yahm-network attach_bridge
61 | ```
62 |
63 | **Hinweis:** Das Verhalten der jeweiligen Befehle kann durch verschiedene Parameter z.B.: "yahm-lxc **-b 2.17.16** install" an eigene Bedürfnisse angepasst werden, siehe hierzu die Beschreibung der Parameter in [Wiki](https://github.com/leonsio/YAHM/wiki).
64 |
65 | Anschließend kann mit **sudo yahm-ctl start** das Container gestartet werden
66 |
67 | # Updates
68 | Mit **sudo yahm-ctl update** kann YAHM Installation (nicht CCU2 Firmware) jederzeit aktualisiert werden. Für die Aktualisierung der CCU2 Installation, siehe [LXC Container](https://github.com/leonsio/YAHM/wiki/YAHM-LXC)
69 |
70 |
71 | # EQ3 HM-MOD-RPI-PCB Funkmodul
72 | Nach der erfolgreichen Installation von YAHM kann das Funkmodul aktiviert werden, für weitere Informationen siehe [YAHM-Module](https://github.com/leonsio/YAHM/wiki/YAHM-Module)
73 |
74 | ```
75 | yahm-module -m pivccu-driver enable
76 | ```
77 |
78 | **Achtung:** Im Zuge der Installation wird ein Reboot benötigt
79 |
80 | **Hinweis:** Die automatische Konfiguration des Funkmoduls durch das pivccu-driver Modul, erfolgt ->aktuell<- ausschließlich auf einem Raspberry Pi und ASUS Tinker Board. Für die Installation auf einer anderen Hardware sind die Installationsschritte im [Wiki](https://github.com/leonsio/YAHM/wiki/YAHM-Module:-HM-MOD-RPI-PCB) hinterlegt. In Zukunft ist eine Unterstützung für weitere Hardware durch pivccu-driver vorgesehen.
81 |
82 | # Homematic-IP
83 | Die aktuelle CCU2 Firmware (ab 2.15.x) beinhaltet standardmäßig die Unterstützung für Homematic-IP. Die Unterstützung in YAHM wird ab der YAHM Version 1.7 durch das [Homematic-IP Modul](https://github.com/leonsio/YAHM/wiki/YAHM-Module:-Homematic-IP) und ab der Version 1.9 durch das [pivccu-driver](https://github.com/leonsio/YAHM/wiki/YAHM-Module:-PIVCCU-Driver) realisiert.
84 | Die Aktivierung der Unterstützung kann je nach Bedarf erfolgen, wird die Unterstützung für Homematic-IP nicht benötigt **kann** die CCU2 Homematic-IP Funktionalität deaktiviert werden.
85 |
86 | ## Aktivierung von Homematic-IP
87 | * Es existieren aktuell zwei Treiber, die eine Unterstütztung für Homematic-IP ermöglichen. Hinsichtlich des Funktionsumfang unterscheiden sich die Treiber nicht, nur durch die Art der Installation.
88 | * Bei dem alten "homematic-ip" Modul wird das im Raspbian Kernel einkopilierte PL011 UART Treiber durch eine gesharte Version ersetzt, hierzu ist es notwendig den Kernel neu zu kompilieren. Anschließend werden die für den Raspberry Pi bzw. Broadcom Chipsatz erstellte Homematic-IP Module installiert. Dieses Modul unterstützt ausschließlich Raspberry Pi Systeme (Broadcom Chipsatz), somit wird dieser Ansatz nicht länger verfolgt.
89 | * Bei dem neuen "pivccu-driver" wird das bestehende Kernel nicht angefasst, sondern mit Hilfe des Device-Trees das vorhandene PL011 UART Treiber überschrieben. Auf diese Weise ist es nicht länger notwendig das vorhandene Kernel neu zu kompilieren. Auf diese Weise verkürzt sich die Installation von 3-4 Stunden auf 5-10 Minuten. Durch einen generichten Treiber können weitere SoC unterstützt werden, für eine Liste unterstützter Geräte siehe das [piVCCU](https://github.com/alexreinert/piVCCU) Projekt
90 |
91 | ### pivccu-driver Modul
92 | Mit pivccu-driver wird ein generischer Treiber für verschiedene Plattformen installiert, der die Homematic-IP Unterstützung mitbringt, es wird hierbei kein neuer Kernel benötigt, die Installationsdauer beträgt etwa 5-10 Minuten. Es werden jedoch Kernel-Souren benötigt, damit die Treiber gebaut werden können.
93 |
94 | **Achtung:** Im Zuge der Installation wird ein Reboot benötigt
95 |
96 | ```
97 | sudo yahm-module -m pivccu-driver enable
98 | ```
99 |
100 | ### homematic-ip Modul (deprecated)
101 | Für die Unterstützung der Homematic-IP muss das Raspberry Pi Kernel neu kompiliert werden, um das vorhandene PL011 Treiber zu ersetzen, sowie müssen einige Kernel Module eingebunden werden. Alle Schritte werden durch das Homematic-IP Modul automatisch durchgeführt. Eine Interaktion seitens des Benutzers ist nicht notwendig.
102 |
103 | **Achtung:** Die Installation kann zwischen 1 und 4 Stunden dauern
104 |
105 | **Achtung:** Im Zuge der Installation wird ein Reboot benötigt
106 |
107 | ```
108 | sudo yahm-module -m homematic-ip enable
109 | ```
110 |
111 | ## Deaktivierung von Homematic-IP
112 | Damit in der CCU2 Oberfläche keine Fehlermeldungen hinsichtlich **HMIP-RF** bzw. **VirtualDevices** auftauchen und kein Bedarf an der Homematic-IP Unterstützung bestehen, wird empfohlen die Unterstützung von Homematic-IP durch YAHM zu deaktivieren. Alternativ kann die Modul-Firmware auf die Version 2.0.0 und höher aktualisiert werden, in diesem Fall muss das pivccu-driver Modul aktiviert werden.
113 |
114 | ```
115 | sudo yahm-module -f -m homematic-ip disable
116 | ```
117 |
118 | # Hinweise
119 |
120 | ## Mehrfaches Ausführen eines Befehls
121 | Alle Skripte sind so ausgelegt, dass nur fehlende Operationen durchgeführt werden. So wird z.B. das erneute Aktivieren des Homematic-IP Moduls keine Kompilierung des Kernels durchführen, falls die Module bereits vorhanden sind.
122 |
123 | Da es jedoch passieren kann, dass bei der Durchführung einiger Operationen Fehler aufkommen, ist es im ersten Selbsthilfe-Schritt möglich die Skripte ggf mit **-f** Switch auszuführen. Oft sind damit alle Probleme bereits behoben.
124 |
125 | ## Migration von RaspberryMatic > 2.15 zu YAHM
126 | RaspberryMatic aktualisiert automatisch die FW des Funkmoduls auf die Version 2.x inkl. Homematic-IP Support. Damit dieser Funkmodul unter YAHM funktioniert, muss zwingenderweise die Homematic-IP Unterstützung aktiviert werden.
127 |
128 | ## Migration CCU2/LXCCU zu YAHM
129 | Für die Migration von CCU2 bzw. LXCCU zu YAHM bitte folgenden [Wiki-Eintrag](https://github.com/leonsio/YAHM/wiki/Migration-von-CCU-zu-YAHM) beachten. Es müssen keine Geräte neu angelernt werden. Sollten LAN-Gateways im Betrieb sein, muss einmalig unter **EINSTELLUNGEN - SYSTEMSTEUERUNG - LAN GATEWAY** die Zuordnung überprüft/angepasst werden
130 |
131 | ## Kostenfaktor
132 | Dieses Projekt wurde **nicht** dafür entworfen die Anschaffungskosten einer CCU2 zu reduzieren.
133 | Eine Kalkulation mit einen Raspberry Pi (35€) zuzüglich des Funkmoduls (30€), sowie Gehäuse/Netzteil (15€) übersteigt oder gleicht sich den Anschaffungskosten einer CCU2 (ca. 70€).
134 |
135 | Für erfahrene Benutzer mit mehreren hundert Geräten/Programmen reicht die Leistung einer CCU2 nicht aus, für diese Zielgruppe wurde diese Anwendung primär entworfen. Für unerfahrene Benutzer wird weiterhin empfohlen die CCU2 zu erwerben.
136 |
137 | ## Credits
138 | Die Arbeit/Idee basiert auf der Arbeit von [bullshit](https://github.com/bullshit/lxccu) bzw. des [LXCCU](http://www.lxccu.com) Projektes, welches nicht länger aktiv ist.
139 | Overlay und generischer UART Treiber by [piVCCU](https://github.com/alexreinert/piVCCU)
140 |
141 | **Wesentliche Unterschiede zu piVCCU:**
142 | - [x] Unterstützung aktueller/älterer CCU2 Firmware ([Liste unterstützer CCU2-Versionen](https://github.com/leonsio/CCU2-FW))
143 | - [x] Die Installation kann manuell gesteuert werden und wird nicht durch DEB-Installer vorgenommen
144 | - [x] Modulare Bauweise, es können beliebige Module und weitere Anwendungen durch vorhandene und von Community beigesteuerte Module eingebunden werden
145 | - [x] Skript und GUI-Basierte Installation/Konfiuration
146 | - [x] Unterstützung für jeden Raspbian Kernel (per deb oder rpi-update)
147 | - [x] Eingebaute Backup und Restore Funktionen
148 | - [x] Installationsroutine für Einsteiger
149 | - [x] Ein-Klick-Installation (frisches Raspbian vorausgesetzt)
150 | - [x] Skriptgesteuerte Netzwerkkonfiguration
151 | - [ ] Aktuell Unterstützung des HM-MOD-RPI-PCB (ohne IP) nur für Raspberry Pi
152 | - [ ] Keine fertigen SD Images
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 1.9
2 |
--------------------------------------------------------------------------------
/bin/yahm-backup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Leonid Kogan
4 | # Yet Another Homematic Management
5 | #
6 | # Backup & Restore script, create and remove backups form CCU2 container and CCU2 data
7 | #
8 |
9 |
10 | # Hilfe Output
11 | show_help ()
12 | {
13 | cat << EOF
14 | YAHM Backup & Restore Script
15 |
16 | Usage Example:
17 |
18 | ./yahm-backup [FLAG] COMMAND
19 | ./yahm-backup -n mycccu backup_full
20 |
21 | Flags:
22 | -n - LXC container name.
23 | -f - Force operation (no halt on errors).
24 | -v - Verbose output
25 | -d - Backup/Restore file
26 |
27 | Commands:
28 | full_backup - Create a full backup from the LXC container
29 | full_restore - Restore full backup from the LXC container
30 | data_backup - Backup CCU2 data/configuration
31 | data_restore - Restore CCU2 data/configuration
32 | EOF
33 | exit 1
34 | }
35 |
36 | PARAMETER="d:vfn:"
37 | DATA_FILE=""
38 |
39 | # Include laden
40 | source /opt/YAHM/share/include.sh
41 |
42 | # Stop on Errors only if not force
43 | if [ $IS_FORCE -ne 1 ]
44 | then
45 | set -e
46 | fi
47 |
48 |
49 | mkdir -p ${YAHM_TMP}
50 |
51 | full_backup()
52 | {
53 | if [ `check_yahm_installed` -eq 0 ] && [ $IS_FORCE -ne 1 ]
54 | then
55 | die "ERROR: No container installed"
56 | fi
57 |
58 | if [ `check_yahm_name $LXCNAME` -eq 0 ] && [ $IS_FORCE -ne 1 ]
59 | then
60 | die "ERROR: Can not find $LXCNAME container"
61 | fi
62 |
63 | #thkl _ only stop if container is running
64 | if [ $(lxc-info -n ${LXCNAME}|grep STOPPED|wc -l) -eq 0 ]; then
65 | progress "Trying to stop ${LXCNAME} container"
66 | lxc-stop $QUIET -k -n ${LXCNAME}
67 | fi
68 |
69 | installed_version=`get_yahm_version ${LXCNAME}`
70 |
71 | progress "Creating new backup from ${LXCNAME} version ${installed_version}"
72 |
73 | backup_file_name="yahm_backup-${installed_version}.tgz"
74 |
75 | cd /var/lib/lxc
76 |
77 | tar $VERBOSE -czf ${YAHM_TMP}/${backup_file_name} ${LXCNAME}
78 |
79 | info "STATUS: Backup was successfully created: ${YAHM_TMP}/${backup_file_name}"
80 | info "Please start ${LXCNAME} container with 'sudo yahm-ctl -n ${LXCNAME} start' manually"
81 | }
82 |
83 | full_restore()
84 | {
85 | if [ ! -f $DATA_FILE ]
86 | then
87 | die "ERROR: Restore file can not be found, please specify it with -d flag"
88 | fi
89 |
90 | info "Clean up TMP directory"
91 | rm -rf ${YAHM_TMP}/*
92 |
93 | progress "Extracting LXC backup"
94 |
95 | tar $VERBOSE -xzf $DATA_FILE -C ${YAHM_TMP}
96 |
97 | content=$(ls ${YAHM_TMP})
98 |
99 | count=0
100 | for file in $content
101 | do
102 | if [ $count -eq 1 ] ; then
103 | die "ERROR: This does not look like a YAHM backup"
104 | fi
105 | count=$((count+1))
106 | done
107 |
108 | if [ ! -f ${YAHM_TMP}/${content}/config ]
109 | then
110 | die "ERROR: Can not find lxc config file"
111 | else
112 | LXCNAME=$(cat ${YAHM_TMP}/${content}/config | grep lxc.utsname | cut -d " " -f 3 )
113 | LXC_ROOT=/var/lib/lxc/$LXCNAME
114 | LXC_ROOT_FS=/var/lib/lxc/$LXCNAME/root
115 | fi
116 |
117 | if [ -d ${LXC_ROOT} ] && [ $IS_FORCE -ne 1 ]
118 | then
119 | die "ERROR: ${LXC_ROOT} is already present, use -f for overwrite"
120 | else
121 | lxc-stop -k -n ${LXCNAME} || info "No running lxc instance found, continue"
122 | rm -rf ${LXC_ROOT}
123 | fi
124 |
125 | progress "Moving backup to ${LXC_ROOT}"
126 | mv ${YAHM_TMP}/${content} ${LXC_ROOT}
127 |
128 | installed_version=`get_yahm_version ${LXCNAME}`
129 |
130 | info "Clean up"
131 | rm -rf ${YAHM_TMP}/*
132 |
133 | info "STATUS: YAHM version ${installed_version} was successfully restored"
134 | info "Please start ${LXCNAME} container with 'sudo yahm-ctl -n ${LXCNAME} start' manually"
135 | }
136 |
137 | data_backup()
138 | {
139 | if [ `check_yahm_installed` -eq 0 ] && [ $IS_FORCE -ne 1 ]
140 | then
141 | die "ERROR: No container installed"
142 | fi
143 |
144 | if [ `check_yahm_name $LXCNAME` -eq 0 ] && [ $IS_FORCE -ne 1 ]
145 | then
146 | die "ERROR: Can not find $LXCNAME container"
147 | fi
148 |
149 | installed_version=`get_yahm_version ${LXCNAME}`
150 |
151 | info "Clean up TMP directory"
152 | rm -rf ${YAHM_TMP}/*
153 |
154 | echo "VERSION=${installed_version}" > ${YAHM_TMP}/firmware_version
155 |
156 | if [ $(lxc-info -n ${LXCNAME}|grep RUNNING |wc -l) -eq 0 ]
157 | then
158 | die "${LXCNAME} container is not running."
159 | fi
160 |
161 | progress "Ask Rega to save the DOM"
162 | echo "#!/bin/tclsh
163 | load tclrega.so
164 | rega system.Save()" > $LXC_ROOT_FS/opt/regasave.sh
165 | chmod +x $LXC_ROOT_FS/opt/regasave.sh
166 | lxc-attach -n ${LXCNAME} -- ./opt/regasave.sh
167 | rm $LXC_ROOT_FS/opt/regasave.sh
168 |
169 | progress "Creating Backup from /usr/local folder"
170 | cd ${LXC_ROOT_FS}
171 | tar $VERBOSE -czf ${YAHM_TMP}/usr_local.tar.gz usr/local
172 | #sign the stuff so ccu will also accept the backup file
173 | lxc-attach -n ${LXCNAME} -- crypttool -s -t 1 <${YAHM_TMP}/usr_local.tar.gz >${YAHM_TMP}/signature
174 | lxc-attach -n ${LXCNAME} -- crypttool -g -t 1 >${YAHM_TMP}/key_index
175 |
176 | progress "Creating Homematic backup file"
177 | timestamp=$(date +%s)
178 | cd ${YAHM_TMP}
179 | #add data, signature and key_index
180 | tar $VERBOSE -cf ${YAHM_TMP}/homematic-ccu2-${timestamp}.sbk usr_local.tar.gz firmware_version key_index signature
181 |
182 | info "Clean up"
183 | rm -rf ${YAHM_TMP}/usr_local.tar.gz ${YAHM_TMP}/firmware_version ${YAHM_TMP}/key_index ${YAHM_TMP}/signature
184 |
185 | #if there is a -d file move the backup to this file
186 | if [ ! $DATA_FILE ] || [ "$DATA_FILE" = "" ]
187 | then
188 | info "STATUS: CCU2 Backup was successfully created: ${YAHM_TMP}/homematic-ccu2-${timestamp}.sbk"
189 | else
190 |
191 | if [[ -d $DATA_FILE ]]; then
192 | #if -d is path create my own name with day in it
193 | FILENAME="$DATA_FILE/homematic-ccu2_$(date +%d).sbk"
194 | else
195 | #else set FILENAME to -d Arg
196 | FILENAME=$DATA_FILE
197 | fi
198 | mv ${YAHM_TMP}/homematic-ccu2-${timestamp}.sbk $FILENAME
199 | info "STATUS: CCU2 Backup was successfully created: $FILENAME"
200 | fi
201 | }
202 |
203 | data_restore()
204 | {
205 | if [ ! -f $DATA_FILE ] || [ "$DATA_FILE" = "" ]
206 | then
207 | die "ERROR: Restore file can not be found, please specify it with -d flag"
208 | fi
209 |
210 | if [ `check_yahm_name $LXCNAME` -eq 0 ] && [ $IS_FORCE -ne 1 ]
211 | then
212 | die "ERROR: Can not find $LXCNAME container"
213 | fi
214 |
215 | info "Clean up TMP directory"
216 | rm -rf ${YAHM_TMP}/*
217 |
218 | progress "Extracting CCU2 backup"
219 |
220 | tar $VERBOSE -xf $DATA_FILE -C ${YAHM_TMP}
221 |
222 | if [ ! -f ${YAHM_TMP}/usr_local.tar.gz ] || [ ! -f ${YAHM_TMP}/firmware_version ]
223 | then
224 | die "ERROR: This does not look like a CCU2 backup"
225 | fi
226 |
227 | installed_version=`get_yahm_version ${LXCNAME}`
228 | backup_version=$(cat ${YAHM_TMP}/firmware_version | cut -d'=' -f2 )
229 |
230 | if [ $(lxc-info -n ${LXCNAME}|grep RUNNING |wc -l) -eq 1 ]
231 | then
232 | progress "Backup is valid, trying to stop ${LXCNAME} container"
233 | lxc-stop $QUIET -k -n ${LXCNAME}
234 | fi
235 |
236 | info "WARNING: /usr/local folder with all settings inside ${LXCNAME} container will be removed. You have 5 seconds to cancel this operation..."
237 | countdown
238 | info "... to late ;)"
239 |
240 | rm -rf ${LXC_ROOT_FS}/usr/local
241 |
242 | progress "Extracting Backup Data"
243 | tar $VERBOSE -xzf ${YAHM_TMP}/usr_local.tar.gz -C ${LXC_ROOT_FS}
244 |
245 | # progress "Starting ${LXCNAME} container"
246 | # lxc-start -n ${LXCNAME} -d
247 |
248 | info "STATUS: Backup version ${backup_version} was successfully restored into ${LXCNAME} container version ${installed_version}"
249 | info "Please start ${LXCNAME} container with 'sudo yahm-ctl -n ${LXCNAME} start' manually"
250 | }
251 |
252 | if [[ $# != 1 ]]; then
253 | show_help
254 | fi
255 |
256 | for key in "$@"; do
257 | case $key in
258 | full_backup)
259 | full_backup
260 | shift
261 | break;
262 | ;;
263 | full_restore)
264 | full_restore
265 | shift
266 | break;
267 | ;;
268 | data_backup)
269 | data_backup
270 | shift
271 | break;
272 | ;;
273 | data_restore)
274 | data_restore
275 | shift
276 | break;
277 | ;;
278 | *)
279 | show_help
280 | exit 0
281 | ;;
282 | esac
283 | done
284 |
285 |
--------------------------------------------------------------------------------
/bin/yahm-ctl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Leonid Kogan
4 | # Yet Another Homematic Management
5 | #
6 | # Backup & Restore script, create and remove backups form CCU2 container and CCU2 data
7 | #
8 |
9 |
10 | # Stop on Errors
11 | set -e
12 |
13 | # Hilfe Output
14 | show_help ()
15 | {
16 | cat << EOF
17 | YAHM Control Script
18 |
19 | Usage Example:
20 |
21 | ./yahm-ctl [FLAG] COMMAND
22 | ./yahm-ctl -n mycccu start
23 |
24 | Flags:
25 | -n - LXC container name.
26 | -f - Force operation (no halt on errors).
27 | -v - Verbose output
28 |
29 | Commands:
30 | start - Starting LXC container
31 | stop - Stopping LXC container
32 | restart - Restarting LXC container
33 | info - Show LXC information (IP)
34 | join - Enter LXC console
35 | update - Update YAHM installation
36 | fw_update - Update HM-MOD-RPI-PCB Firmware
37 | EOF
38 | exit 1
39 | }
40 |
41 | PARAMETER="vfn:"
42 |
43 | # Include laden
44 | source /opt/YAHM/share/include.sh
45 |
46 | if [[ $# != 1 ]]; then
47 | show_help
48 | fi
49 |
50 | do_start_container()
51 | {
52 | if [ $(lxc-info -n ${LXCNAME}|grep RUNNING |wc -l) -eq 1 ]
53 | then
54 | die "${LXCNAME} container is already running"
55 | fi
56 |
57 | if [ "$BOARD_TYPE" = "Raspberry Pi" ] && [ -e ${LXC_ROOT_MODULES}/hm-mod-rpi-pcb ]
58 | then
59 | echo 0 > /sys/class/gpio/gpio18/value
60 | sleep 0.1
61 | echo 1 > /sys/class/gpio/gpio18/value
62 | fi
63 |
64 | if [ $IS_VERBOSE -eq 1 ]
65 | then
66 | progress "Starting ${LXCNAME} LXC container in debug mode"
67 | lxc-start -n ${LXCNAME}
68 | else
69 | mkdir -p /var/log/yahm
70 | progress "Starting ${LXCNAME} LXC container"
71 | lxc-start $QUIET -n ${LXCNAME} -d -L /var/log/yahm/${LXCNAME}_console.log
72 | fi
73 | }
74 |
75 | do_stop_container()
76 | {
77 | if [ $(lxc-info -n ${LXCNAME}|grep STOPPED|wc -l) -eq 1 ]
78 | then
79 | die "${LXCNAME} container is already stopped"
80 | fi
81 |
82 | if [ "$BOARD_TYPE" = "Raspberry Pi" ] && [ -e ${LXC_ROOT_MODULES}/hm-mod-rpi-pcb ]
83 | then
84 | echo 0 > /sys/class/gpio/gpio18/value
85 | fi
86 |
87 | progress "Stopping ${LXCNAME} LXC container"
88 | lxc-stop $QUIET -k -n ${LXCNAME}
89 | }
90 |
91 | for key in "$@"; do
92 | case $key in
93 | start)
94 | do_start_container
95 | shift
96 | break;
97 | ;;
98 | stop)
99 | do_stop_container
100 | shift
101 | break;
102 | ;;
103 | restart)
104 | do_stop_container
105 | sleep 1
106 | do_start_container
107 | shift
108 | break;
109 | ;;
110 | join)
111 | if [ $(lxc-info -n ${LXCNAME}|grep STOPPED|wc -l) -eq 1 ]
112 | then
113 | die "${LXCNAME} container is stopped, please start it first"
114 | fi
115 | progress "Joining LXC container, you are now inside ${LXCNAME}"
116 | lxc-attach -n ${LXCNAME}
117 | progress "Leaving LXC container, your are now on your host system"
118 | shift
119 | break;
120 | ;;
121 | info|status)
122 | info "YAHM Version: ${YAHM_VERSION}"
123 |
124 | if [ `check_yahm_name $LXCNAME` -eq 0 ] && [ $IS_FORCE -ne 1 ]
125 | then
126 | die "ERROR: Can not find $LXCNAME container"
127 | fi
128 |
129 | CCU2current=`get_yahm_version ${LXCNAME}`
130 | info "CCU2 Version: ${CCU2current}"
131 |
132 | echo ""
133 | if [ -e ${LXC_ROOT_MODULES}/pivccu-driver ] && [ $(lxc-info -n ${LXCNAME}|grep RUNNING |wc -l) -eq 1 ]
134 | then
135 | if [ -f /sys/module/plat_eq3ccu2/parameters/board_extended_info ]
136 | then
137 | info "Module information"
138 | module_serial=$(cat /sys/module/plat_eq3ccu2/parameters/board_serial)
139 | module_firmware=$(cat /sys/module/plat_eq3ccu2/parameters/board_extended_info)
140 | echo "Module Serial: ${module_serial}"
141 | echo "Module Firmware: ${module_firmware}"
142 | echo ""
143 | else
144 | error "Can not read pivccu-driver module information"
145 | fi
146 | fi
147 | info "LXC container information"
148 | lxc-info -n ${LXCNAME}
149 | shift
150 | break;
151 | ;;
152 | fw_update)
153 | # Container muss laufen
154 | if [ $(lxc-info -n ${LXCNAME}|grep STOPPED|wc -l) -eq 1 ]
155 | then
156 | die "ERROR: ${LXCNAME} container is stopped, please start it first"
157 | fi
158 |
159 | progress "Detecting actual firmware version"
160 | if [ -c ${LXC_ROOT_FS}/dev/bcm2835-raw-uart ]
161 | then
162 | dev_int="bcm2835-raw-uart"
163 | elif [ -c ${LXC_ROOT_FS}/dev/mxs_auart_raw.0 ]
164 | then
165 | dev_int="mxs_auart_raw.0"
166 | else
167 | dev_int="ttyAMA0"
168 | fi
169 |
170 | lxc-attach -n ${LXCNAME} -- /etc/init.d/S60multimacd stop 3>&1 1>&2 2>&3 > /dev/null
171 | lxc-attach -n ${LXCNAME} -- /etc/init.d/S61rfd stop 3>&1 1>&2 2>&3 > /dev/null
172 |
173 | # Firmware check
174 | firmware_version=`lxc-attach -n ${LXCNAME} -- /bin/eq3configcmd update-coprocessor -p /dev/${dev_int} -c -v 3>&1 1>&2 2>&3 | grep -Po 'Version: \K[^"]*'`
175 | info "Existing firmware version: ${firmware_version}"
176 |
177 | progress "Downloading firmware files"
178 | mkdir -p ${LXC_ROOT_FS}/firmware/HM-MOD-UART
179 | wget $QUIET -O ${LXC_ROOT_FS}/firmware/HM-MOD-UART/fwmap https://raw.githubusercontent.com/eq-3/occu/master/firmware/HM-MOD-UART/fwmap
180 | wget $QUIET -O ${LXC_ROOT_FS}/firmware/HM-MOD-UART/dualcopro_si1002_update_blhm.eq3 https://github.com/eq-3/occu/raw/master/firmware/HM-MOD-UART/dualcopro_si1002_update_blhm.eq3
181 | cd ${LXC_ROOT_FS}/firmware/HM-MOD-UART
182 | # comment out dual firmware
183 | sed -i '/dualcopro/s/^#//g' fwmap
184 | # comment single firmware
185 | sed -i '/coprocessor/s/^/#/g' fwmap
186 |
187 | new_firmware=$(cat fwmap | grep -v "^#" | grep CCU | awk '$1=$1' | cut -d' ' -f 3)
188 | info "Newest firmware version: ${new_firmware}"
189 |
190 | if [ $(ver ${firmware_version}) -ge $(ver ${new_firmware}) ] && [ $IS_FORCE -ne 1 ]
191 | then
192 | lxc-attach -n ${LXCNAME} -- /etc/init.d/S60multimacd start 3>&1 1>&2 2>&3 > /dev/null
193 | lxc-attach -n ${LXCNAME} -- /etc/init.d/S61rfd start 3>&1 1>&2 2>&3 > /dev/null
194 | die "ERROR: No newer firmware version found, exiting"
195 | fi
196 |
197 | error "WARNING: Trying to update the module firmware to the newest version including homematic-ip support. To cancel this operation type CTRL+C you have 5 seconds..."
198 | countdown
199 | info "... too late ;)"
200 |
201 | progress "Updating firmware this cat take some time, please dont turn off your device"
202 | lxc-attach -n ${LXCNAME} -- eq3configcmd update-coprocessor -p /dev/${dev_int} -t HM-MOD-UART -u -c -d /firmware/HM-MOD-UART
203 | sleep 5
204 | do_stop_container
205 | ;;
206 | update)
207 | cd ${YAHM_DIR}
208 | progress "Updating YAHM installation, for updatate CCU2 please use 'yahm-lxc update'"
209 | git pull --recurse-submodules
210 | progress "Updating all YAHM modules"
211 | git submodule foreach git pull origin master
212 | git submodule foreach git submodule update --init --recursive
213 | progress "Updating CCU2-FW archive"
214 | cd ${YAHM_LIB}
215 | wget $QUIET -N https://raw.githubusercontent.com/leonsio/CCU2-FW/master/fw.list
216 |
217 | # wir machen nur Updates innerhalb von Releases durch
218 | if [ "$GIT_BRANCH" != "develop" ]
219 | then
220 | if [ ! -f $YAHM_DIR/VERSION ]
221 | then
222 | info "YAHM version 1.0 (or below) found"
223 | YAHM_VERSION="1.0"
224 | else
225 | info "YAHM version ${YAHM_VERSION} found"
226 | fi
227 |
228 | if [ $(ver ${NEW_YAHM_VERSION}) -gt $(ver ${YAHM_VERSION}) ]
229 | then
230 | info "New YAHM version ${NEW_YAHM_VERSION} found, updating"
231 |
232 | # Für das nächste Release müsste ich mir was besseres einfallen lassen
233 | if [ -f ${YAHM_DIR}/share/firmware/patches/YAHM/${YAHM_OLD_VERSION}_${NEW_YAHM_VERSION}.sh ]
234 | then
235 | progress "Update File ${YAHM_OLD_VERSION}_${NEW_YAHM_VERSION}.sh found, executing"
236 | ${YAHM_DIR}/share/firmware/patches/YAHM/${YAHM_VERSION}_${NEW_YAHM_VERSION}.sh ${YAHM_DIR}
237 | fi
238 | fi
239 | fi
240 |
241 | shift
242 | break;
243 | ;;
244 | *)
245 | show_help
246 | exit 0
247 | ;;
248 | esac
249 | done
250 |
--------------------------------------------------------------------------------
/bin/yahm-lxc:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Leonid Kogan
4 | # Yet Another Homematic Management
5 | #
6 | # LXC management script, create new lxc container from CCU2 image
7 | #
8 |
9 | # Stop on Errors
10 | set -e
11 |
12 | # Hilfe Output
13 | show_help ()
14 | {
15 | cat << EOF
16 | YAHM LXC management script
17 |
18 | Usage Example:
19 |
20 | ./yahm-lxc [FLAG] COMMAND
21 | ./yahm-lxc -n mycccu install
22 |
23 | Flags:
24 | -n - LXC container name.
25 | -f - Force operation (no halt on errors).
26 | -v - Verbose output
27 | -d - Path to custom CCU2 firmware file
28 | -b - Build number (=version) of the CCU2-FW
29 |
30 | Commands:
31 | install - Create new lxc instance with actual ccu2 image.
32 | update - Updates lxc instance to the actual version.
33 | remove - Removes lxc instance.
34 | EOF
35 | exit 1
36 | }
37 |
38 | DATA_FILE=""
39 | BUILD=""
40 | PATCH_FILE=""
41 | PARAMETER="fvn:d:b:p:"
42 |
43 | # Include laden
44 | source /opt/YAHM/share/include.sh
45 |
46 | if [ "$DATA_FILE" != "" ] && [ "$BUILD" == "" ]
47 | then
48 | die "Please specify firmware file version number with -b flag (e.g. -b 2.17.16)"
49 | fi
50 |
51 | remove_lxc_container()
52 | {
53 | if [ `check_yahm_installed` -eq 0 ] && [ $IS_FORCE -ne 1 ]
54 | then
55 | die "ERROR: No container installed"
56 | fi
57 |
58 | if [ `check_yahm_name $LXCNAME` -eq 0 ] && [ $IS_FORCE -ne 1 ]
59 | then
60 | die "ERROR: Can not find $LXCNAME container"
61 | fi
62 |
63 | if [ $IS_FORCE -eq 1 ]
64 | then
65 | info "Entering force mode"
66 | fi
67 |
68 | installed_version=`get_yahm_version ${LXCNAME}`
69 |
70 | info "Deleting installed YAHM container: ${LXCNAME} version: ${installed_version} To cancel this operation type CTRL+C you have 5 seconds..."
71 | countdown
72 | info "... too late ;)"
73 |
74 | progress "Stopping LXC container"
75 | lxc-stop $QUIET -k -n $LXCNAME || info "Container can not be found or is not running"
76 |
77 | progress "Deleting LXC container"
78 | rm -rf ${LXC_ROOT}
79 |
80 | progress "Clean up"
81 | rm -rf ${YAHM_LIB}/*
82 | }
83 |
84 | create_lxc_container()
85 | {
86 | if [ `check_yahm_installed` -eq 1 ] && [ $IS_FORCE -ne 1 ]
87 | then
88 | die "ERROR: YAHM instance is already installed"
89 | fi
90 |
91 | if [ $IS_FORCE -eq 1 ] ; then
92 | progress "ATTENTION: FORCE-Switch is used, actual instance will be overwritten"
93 | fi
94 |
95 | if [ "${BUILD}" == "" ]
96 | then
97 | CCU2Version=`get_ccu2_actual_version`
98 | else
99 | CCU2Version=$BUILD
100 | fi
101 |
102 | # Compatibility Check
103 | if [ `yahm_compatibility $CCU2Version` -eq 1 ] && [ $IS_FORCE -ne 1 ]
104 | then
105 | die "ERROR: We dont have any patches for this version, please call 'yahm-ctl update' and try again"
106 | fi
107 |
108 | info "Creating new lxc container name: $LXCNAME, version $CCU2Version"
109 | # Verzeichnis anlegen
110 | mkdir -p $LXC_ROOT
111 | mkdir -p $YAHM_TMP
112 |
113 | if [ "$DATA_FILE" = "" ]
114 | then
115 | download_ccu2_fw $CCU2Version
116 | else
117 | if [ ! -f $DATA_FILE ]
118 | then
119 | die "ERROR: Restore file can not be found, please specify it with -d flag"
120 | fi
121 |
122 | EQ3_FW=$DATA_FILE
123 | fi
124 |
125 | # 100kb sind mehr als jede HTML5 Fehlerseite, aber kleiner als CCU2 FW
126 | if [ $(stat -c%s "${EQ3_FW}") -le 100000 ] && [ $IS_FORCE -ne 1 ]
127 | then
128 | die "ERROR: Firmware file size is to small, please take a look on ${EQ3_FW} file"
129 | fi
130 |
131 | progress "Extracting firmware"
132 | tar $VERBOSE -xzf $EQ3_FW -C $YAHM_TMP
133 |
134 | if [ $? -eq 1 ]
135 | then
136 | die "Something is wrong with downloaded archive, exit" # SRC Ordner fehlt
137 | fi
138 |
139 | progress "Extract ubi image"
140 | $YAHM_DIR/share/tools/ubi_reader/ubi_extract_files.py $QUIET -k -o $LXC_ROOT "${YAHM_TMP}/rootfs.ubi"
141 |
142 | # most lxc commands use rootfs folder and not the config option
143 | ln -s $LXC_ROOT_FS $LXC_ROOT/rootfs
144 |
145 | if [ "$DATA_FILE" != "" ]
146 | then
147 | info "Manually CCU2 image was selected, trying to detect installed version"
148 | CCU2Version=`get_yahm_version ${LXCNAME}`
149 |
150 | if [ ! -f ${YAHM_DIR}/share/firmware/patches/${CCU2Version}.patch ] && [ $IS_FORCE -ne 1 ]
151 | then
152 | die "ERROR: Detected Version: ${CCU2Version}, can not find patch file for this version use -f for patching with version ${$LastCCU2Version}"
153 | else
154 | CCU2Version=$LastCCU2Version
155 | fi
156 | fi
157 |
158 | # try last known configuration
159 | if [ `yahm_compatibility $CCU2Version` -eq 1 ] && [ $IS_FORCE -eq 1 ]
160 | then
161 | info "INFO: No patches for version ${CCU2Version} found, trying to use old patches from ${LastCCU2Version}"
162 | CCU2Version=$LastCCU2Version
163 | fi
164 |
165 | if [ $(ver ${CCU2Version}) -ge $(ver "2.17.15") ]
166 | then
167 | progress "Cleanup CCU2 source"
168 | cd $LXC_ROOT_FS
169 | find . -iname '*.ftl' | xargs dos2unix $QUIET
170 | find . -iname '*.cgi' | xargs dos2unix $QUIET
171 | fi
172 |
173 | progress "Applying patch"
174 | cd $LXC_ROOT_FS
175 | patch --no-backup-if-mismatch $QUIET -l --input "${YAHM_DIR}/share/firmware/patches/${CCU2Version}.patch" -p1
176 |
177 | progress "Applying scripts"
178 | cd $LXC_ROOT_FS
179 | sh "${YAHM_DIR}/share/firmware/scripts/${CCU2Version}.sh"
180 |
181 | progress "Creating SD card"
182 | mkdir -p ${YAHM_LIB}/SDcard/${LXCNAME}/sd-mmcblk0
183 | touch ${YAHM_LIB}/SDcard/${LXCNAME}/sd-mmcblk0/.initialised
184 |
185 | # clean up download sources
186 | progress "Clean Up"
187 | rm -rf $YAHM_TMP
188 |
189 | # create lxc config file
190 | create_lxc_config
191 |
192 | if [ "$ARCH" = "X86" ]
193 | then
194 | info "Found x86 CPU architecture, need to install QEMU"
195 | cp /usr/bin/qemu-arm-static ${LXC_ROOT_FS}/usr/bin/
196 | echo "lxc.arch = armhf" >> ${LXC_ROOT}/config
197 | fi
198 |
199 | CCU2current=`get_yahm_version ${LXCNAME}`
200 | info "Container version ${CCU2current} is created, please use 'yahm-ctl -n ${LXCNAME} start' to start and 'yahm-ctl -n ${LXCNAME} join' for console access"
201 | info "For network configuration see yahm-network script"
202 |
203 | echo $LXCNAME > ${YAHM_LIB}/container_name
204 | touch ${YAHM_LIB}/is_installed
205 | # set right name under defaults
206 | sed -i /etc/default/yahm -e "s/LXCNAME=.*$/LXCNAME='${LXCNAME}'/"
207 | }
208 |
209 | create_lxc_config()
210 | {
211 | # lxc config file
212 | progress "Creating lxc config file"
213 | cat > "${LXC_ROOT}/config" < lxc.start.auto=0
224 | lxc.start.auto = 1
225 |
226 | lxc.tty = 1
227 | lxc.pts = 1
228 |
229 | # cgroups
230 | lxc.cgroup.devices.allow = a
231 |
232 | # /dev/null and zero
233 | lxc.cgroup.devices.allow = c 1:3 rwm
234 | lxc.cgroup.devices.allow = c 1:5 rwm
235 |
236 | # consoles
237 | lxc.cgroup.devices.allow = c 5:1 rwm
238 | lxc.cgroup.devices.allow = c 5:0 rwm
239 | lxc.cgroup.devices.allow = c 4:0 rwm
240 | lxc.cgroup.devices.allow = c 4:1 rwm
241 |
242 | # hm-mod-rpi
243 | lxc.cgroup.devices.allow = c 204:64 rwm
244 |
245 | # hmip-rf
246 | lxc.cgroup.devices.allow = c 241:* rwm
247 | lxc.cgroup.devices.allow = c 242:* rwm
248 | lxc.cgroup.devices.allow = c 243:* rwm
249 | lxc.cgroup.devices.allow = c 244:* rwm
250 | lxc.cgroup.devices.allow = c 245:* rwm
251 | lxc.cgroup.devices.allow = c 246:* rwm
252 | lxc.cgroup.devices.allow = c 247:* rwm
253 |
254 | # /dev/{,u}random
255 | lxc.cgroup.devices.allow = c 1:9 rwm
256 | lxc.cgroup.devices.allow = c 1:8 rwm
257 |
258 | # /dev/pts/* - pts namespaces are "coming soon"
259 | lxc.cgroup.devices.allow = c 136:* rwm
260 | lxc.cgroup.devices.allow = c 5:2 rwm
261 | lxc.cgroup.devices.allow = c 10:200 rwm
262 |
263 | # includes
264 | lxc.include = ${LXC_ROOT}/config.network
265 |
266 | EOF
267 | if [ "$CODENAME" = "stretch" ] ;
268 | then
269 | echo "lxc.autodev = 0" >> ${LXC_ROOT}/config
270 | fi
271 |
272 | # blank config file
273 | touch ${LXC_ROOT}/config.network
274 | }
275 |
276 | update_lxc_container()
277 | {
278 |
279 | if [ `check_yahm_installed` -eq 0 ] && [ $IS_FORCE -ne 1 ]
280 | then
281 | die "ERROR: YAHM is not installed"
282 | fi
283 |
284 | if [ `check_yahm_name $LXCNAME` -eq 0 ] && [ $IS_FORCE -ne 1 ]
285 | then
286 | die "ERROR: Can not find $LXCNAME container"
287 | fi
288 |
289 | if [ $(lxc-info -n ${LXCNAME}|grep RUNNING |wc -l) -eq 0 ]
290 | then
291 | die "${LXCNAME} container is not running (needed for data backup)."
292 | fi
293 |
294 | if [ "${BUILD}" == "" ]
295 | then
296 | CCU2Version=`get_ccu2_actual_version`
297 | else
298 | CCU2Version=$BUILD
299 | fi
300 |
301 | installed_version=`get_yahm_version ${LXCNAME}`
302 | info "\nInstalled version: $installed_version"
303 | info "Available version: $CCU2Version\n"
304 |
305 | if [ $(ver $installed_version) -ge $(ver $CCU2Version) ] && [ $IS_FORCE -ne 1 ]
306 | then
307 | die "ERROR: Installed version $installed_version is greater than or equal to available version $CCU2Version"
308 | fi
309 |
310 | # Compatibility Check
311 | if [ `yahm_compatibility $CCU2Version` -eq 1 ] && [ $IS_FORCE -ne 1 ]
312 | then
313 | die "ERROR: Can not find any patches for ${CCU2Version}, please call 'yahm-ctl update' and try again"
314 | fi
315 |
316 | [ $IS_FORCE -eq 1 ] && force_switch="-f" || force_switch=""
317 |
318 | progress "Trying to create a config-backup from installed version ${installed_version}, calling: 'yahm-backup data_backup' script"
319 | if [ $IS_DEBUG -eq 1 ] ; then
320 | info "Calling: /opt/YAHM/bin/yahm-backup ${VERBOSE} ${force_switch} -n ${LXCNAME} data_backup"
321 | fi
322 | /opt/YAHM/bin/yahm-backup ${VERBOSE} ${force_switch} -n ${LXCNAME} data_backup
323 |
324 | rm -rf ${YAHM_TMP}_update/${LXCNAME}/
325 | mkdir -p ${YAHM_TMP}_update/${LXCNAME}/
326 | mv ${YAHM_TMP}/*.sbk ${YAHM_TMP}_update/${LXCNAME}/
327 |
328 | progress "Backup old LXC config"
329 | cp ${LXC_ROOT}/conf* ${YAHM_TMP}_update/${LXCNAME}/
330 | progress "Backup installed modules"
331 | cp -rf ${LXC_ROOT}/.modules ${YAHM_TMP}_update/${LXCNAME}/
332 |
333 | data_backup_file=$(ls ${YAHM_TMP}_update/${LXCNAME}/*.sbk)
334 | info "INFO: Config backup file location: ${data_backup_file}"
335 |
336 | progress "Creating full backup from installed version ${installed_version}, calling: 'yahm-backup full_backup' script"
337 | if [ $IS_DEBUG -eq 1 ] ; then
338 | info "Calling: /opt/YAHM/bin/yahm-backup ${VERBOSE} ${force_switch} -n ${LXCNAME} full_backup"
339 | fi
340 | /opt/YAHM/bin/yahm-backup ${VERBOSE} ${force_switch} -n ${LXCNAME} full_backup
341 |
342 | mv ${YAHM_TMP}/yahm_backup-${installed_version}.tgz ${YAHM_TMP}_update/${LXCNAME}/yahm_backup-${installed_version}_$(date +%Y%m%d).tgz
343 | full_backup_file=$(ls ${YAHM_TMP}_update/${LXCNAME}/yahm_backup-*.tgz)
344 | info "INFO: Full backup file location: ${full_backup_file}"
345 |
346 | progress "Delete old YAHM Container version: $installed_version"
347 | if [ $IS_DEBUG -eq 1 ] ; then
348 | info "Calling: remove_lxc_container"
349 | fi
350 |
351 | progress "Backup virtual SD-Card"
352 | if [ -d ${LXC_ROOT}/sd-mmcblk0 ]
353 | then
354 | mkdir -p ${YAHM_LIB}/SDcard/${LXCNAME}/sd-mmcblk0
355 | cp -rf ${LXC_ROOT}/sd-mmcblk0/* ${YAHM_LIB}/SDcard/${LXCNAME}/sd-mmcblk0/
356 | fi
357 |
358 | remove_lxc_container
359 |
360 | progress "Create new YAHM Container version: $CCU2Version"
361 | if [ $IS_DEBUG -eq 1 ] ; then
362 | info "Calling: create_lxc_container"
363 | fi
364 | create_lxc_container
365 |
366 | progress "Restoring old LXC config"
367 | cp ${YAHM_TMP}_update/${LXCNAME}/conf* ${LXC_ROOT}/
368 |
369 | # moving SDCard path
370 | if [ $( cat ${LXC_ROOT}/config | grep SDcard | wc -l ) -eq 0 ]
371 | then
372 | # removing old value
373 | sed -i ${LXC_ROOT}/config -e '/sd-mmcblk0/d'
374 | echo "lxc.mount.entry = /var/lib/yahm/SDcard/${LXCNAME}/sd-mmcblk0 media/sd-mmcblk0/ none defaults,bind 0 0" >> ${LXC_ROOT}/config
375 | fi
376 |
377 | progress "Trying to restore old CCU2 backup, calling 'yahm-backup data_restore'"
378 | if [ $IS_DEBUG -eq 1 ] ; then
379 | info "Calling: yahm-backup ${VERBOSE} ${force_switch} -n ${LXCNAME} -d ${data_backup_file} data_restore"
380 | fi
381 | /opt/YAHM/bin/yahm-backup ${VERBOSE} ${force_switch} -n ${LXCNAME} -d ${data_backup_file} data_restore
382 |
383 | if [ $IS_DEBUG -eq 1 ] ; then
384 | info "Calling: yahm-ctl -n ${LXCNAME} start"
385 | fi
386 | yahm-ctl -n ${LXCNAME} start
387 |
388 | progress "Restoring old installed modules"
389 | files=`ls ${YAHM_TMP}_update/${LXCNAME}/.modules`
390 |
391 | for file in $files
392 | do
393 | info "Restoring ${file} Module"
394 | if [ $IS_DEBUG -eq 1 ] ; then
395 | info "Calling: /opt/YAHM/bin/yahm-module -n ${LXCNAME} ${VERBOSE} -f -m $file enable"
396 | fi
397 | /opt/YAHM/bin/yahm-module -n ${LXCNAME} ${VERBOSE} -f -m $file enable
398 | done
399 |
400 | #rm -rf ${YAHM_TMP}_update/
401 | CCU2current=`get_yahm_version ${LXCNAME}`
402 | info "STATUS: Update was successfully new version is: ${CCU2current}"
403 | info "STATUS: Old config backup file: ${data_backup_file}"
404 | info "STATUS: Old full lxc backup file: ${full_backup_file}"
405 | }
406 |
407 | if [[ $# != 1 ]]; then
408 | show_help
409 | fi
410 |
411 | for key in "$@"; do
412 | case $key in
413 | install)
414 | shift
415 | create_lxc_container
416 | break;
417 | ;;
418 | update)
419 | update_lxc_container
420 | shift
421 | break;
422 | ;;
423 | remove)
424 | shift
425 | remove_lxc_container
426 | break;
427 | ;;
428 | *)
429 | show_help
430 | exit 0
431 | ;;
432 | esac
433 | done
434 |
--------------------------------------------------------------------------------
/bin/yahm-module:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Leonid Kogan
4 | # Yet Another Homematic Management
5 | #
6 | # Module management script, install or remove modules for CCU2 container
7 | #
8 |
9 | # Stop on Errors
10 | set -e
11 |
12 | MODULE=""
13 |
14 | # Hilfe Output
15 | show_help ()
16 | {
17 | cat << EOF
18 | YAHM modules management script
19 |
20 | Usage Example:
21 |
22 | ./yahm-module [FLAG] COMMAND
23 | ./yahm-module -n mycccu -m module_name enable
24 |
25 | Flags:
26 | -n - LXC container name.
27 | -f - Force operation (no halt on errors).
28 | -v - Verbose output
29 | -m - Module name
30 |
31 | Commands:
32 | enable - Enable module
33 | disable - Disable module
34 | available - Show available modules
35 | installed - Show installed modules
36 | EOF
37 | exit 1
38 | }
39 |
40 | PARAMETER="m:vfn:"
41 |
42 | # Include laden
43 | source /opt/YAHM/share/include.sh
44 |
45 | mkdir -p ${LXC_ROOT_MODULES}
46 |
47 | _module_installed()
48 | {
49 | if [ -e ${LXC_ROOT_MODULES}/${MODULE} ] ; then
50 | echo 1
51 | else
52 | echo 0
53 | fi
54 | }
55 |
56 | available_modules()
57 | {
58 | local description
59 | progress "Available modules:"
60 | files=`ls ${YAHM_DIR}/share/modules/`
61 | for file in $files
62 | do
63 | if [[ -f ${YAHM_DIR}/share/modules/${file} ]]; then
64 | description=`cat ${YAHM_DIR}/share/modules/${file} | grep description -m1 | cut -d'"' -f2`
65 | printf "\t%-20s%s\n" "$file" "$description"
66 | fi
67 | done
68 | }
69 |
70 | installed_modules()
71 | {
72 | local description
73 | progress "Installed modules:"
74 | files=`ls ${LXC_ROOT_MODULES}/`
75 | for file in $files
76 | do
77 | description=`cat ${YAHM_DIR}/share/modules/${file} | grep description -m1 | cut -d'"' -f2`
78 | printf "\t%-20s%s\n" "$file" "$description"
79 | done
80 | }
81 |
82 | enable_modules()
83 | {
84 | if [ "$MODULE" = "" ]
85 | then
86 | die "ERROR: Please specify module name with -m MODULE, show available modules with 'yahm-modules available'"
87 | fi
88 |
89 | if [ `check_yahm_name $LXCNAME` -eq 0 ] && [ $IS_FORCE -ne 1 ]
90 | then
91 | die "ERROR: Can not find $LXCNAME container"
92 | fi
93 |
94 | if [ `_module_installed` -eq 1 ] && [ $IS_FORCE -ne 1 ]
95 | then
96 | die "ERROR: Module ${MODULE} is already installed, use -f to overwrite it"
97 | fi
98 |
99 | progress "Executing ${MODULE} module_install()"
100 | source ${YAHM_DIR}/share/modules/${MODULE}
101 |
102 | _module_install
103 |
104 | info "STATUS: Module ${MODULE} was successfully installed"
105 |
106 | touch ${LXC_ROOT_MODULES}/${MODULE}
107 | }
108 |
109 | disable_modules()
110 | {
111 | if [ "$MODULE" = "" ]
112 | then
113 | die "ERROR: Please specify module name with -m MODULE, show available modules with 'yahm-modules available'"
114 | fi
115 |
116 | if [ `check_yahm_name $LXCNAME` -eq 0 ] && [ $IS_FORCE -ne 1 ]
117 | then
118 | die "ERROR: Can not find $LXCNAME container"
119 | fi
120 |
121 | if [ `_module_installed` -eq 0 ] && [ $IS_FORCE -ne 1 ]
122 | then
123 | die "ERROR: Module ${MODULE} is not installed, use -f force this operation"
124 | fi
125 |
126 | progress "Executing ${MODULE} module_remove()"
127 | source ${YAHM_DIR}/share/modules/${MODULE}
128 |
129 | _module_remove
130 |
131 | rm ${LXC_ROOT_MODULES}/${MODULE}
132 |
133 | info "STATUS: Module ${MODULE} was successfully removed"
134 | }
135 |
136 |
137 | if [[ $# != 1 ]]; then
138 | show_help
139 | fi
140 |
141 | for key in "$@"; do
142 | case $key in
143 | enable)
144 | enable_modules
145 | shift
146 | break;
147 | ;;
148 | disable)
149 | disable_modules
150 | shift
151 | break;
152 | ;;
153 | available)
154 | available_modules
155 | shift
156 | break;
157 | ;;
158 | installed)
159 | installed_modules
160 | shift
161 | break;
162 | ;;
163 | *)
164 | show_help
165 | exit 0
166 | ;;
167 | esac
168 | done
169 |
170 |
--------------------------------------------------------------------------------
/share/include.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Leonid Kogan
4 | # Yet Another Homematic Management
5 | #
6 | # Globale Funktionen
7 | #
8 |
9 | if [[ $EUID -ne 0 ]]; then
10 | echo "This script must be run as root!" 1>&2
11 | exit 1
12 | fi
13 |
14 | #echo ${0##*/}
15 | #exit;
16 |
17 |
18 | if [ ! -f /etc/default/yahm ]
19 | then
20 | cat > /etc/default/yahm < 1
42 | IS_DEBUG=0
43 | # always froce operations -> 1
44 | IS_FORCE=0
45 | # always show verbose output -> 1
46 | IS_VERBOSE=0
47 | # show update warning -> 1
48 | SHOW_YAHM_UPDATES=1
49 |
50 | EOF
51 |
52 | fi
53 |
54 | source /etc/default/yahm
55 |
56 |
57 |
58 | #######################################
59 | ## DO NOT CHANGE THE FOLLOWING LINES ##
60 | #######################################
61 |
62 | # Default options
63 | YAHM_VERSION=$(cat $YAHM_DIR/VERSION)
64 | OPTIND=1
65 | QUIET="--quiet"
66 | VERBOSE=""
67 | ARCH=""
68 |
69 | # Default behavior YAHM
70 | DRY_RUN=0
71 | RESTART=1
72 | LSB_RELEASE="/usr/bin/lsb_release"
73 | DIST_ID="$($LSB_RELEASE -is)"
74 | CODENAME="$($LSB_RELEASE -cs)"
75 |
76 | # Check if we can use colours in our output
77 | use_colour=0
78 | [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null && use_colour=1
79 |
80 | # Some useful functions
81 | progress()
82 | {
83 | [ $use_colour -eq 1 ] && echo -ne "\033[01;32m"
84 | echo -e "$@" 2>&1
85 | [ $use_colour -eq 1 ] && echo -ne "\033[00m"
86 | }
87 |
88 | info()
89 | {
90 | [ $use_colour -eq 1 ] && echo -ne "\033[01;34m"
91 | echo -e "$@" 2>&1
92 | [ $use_colour -eq 1 ] && echo -ne "\033[00m"
93 | }
94 |
95 | error()
96 | {
97 | [ $use_colour -eq 1 ] && echo -ne "\033[01;31m"
98 | echo -e "$@" >&2
99 | [ $use_colour -eq 1 ] && echo -ne "\033[00m"
100 | }
101 |
102 | die () {
103 | [ $use_colour -eq 1 ] && echo -ne "\033[01;31m"
104 | echo -e "$@" >&2
105 | [ $use_colour -eq 1 ] && echo -ne "\033[00m"
106 | exit 1
107 | }
108 |
109 | # Load system information
110 | if [ -f ${YAHM_LIB}/systeminfo ]
111 | then
112 | source ${YAHM_LIB}/systeminfo
113 | else
114 | mkdir -p ${YAHM_LIB}
115 | source ${YAHM_TOOLS}/arm-board-detect/armhwinfo.sh
116 | echo "BOARD_TYPE='$BOARD_TYPE'" >> ${YAHM_LIB}/systeminfo
117 | echo "ARCH='$ARCH'" >> ${YAHM_LIB}/systeminfo
118 | echo "BOARD_VERSION='$BOARD_VERSION'" >> ${YAHM_LIB}/systeminfo
119 | fi
120 |
121 | # check architecture
122 | #case `dpkg --print-architecture` in
123 | case $ARCH in
124 | armhf|armv6l|armv7l|arm64|aarch64)
125 | ARCH="ARM"
126 | ;;
127 | i386|amd64|x86_64|i686)
128 | ARCH="X86"
129 | ;;
130 | *)
131 | die "Unsupported CPU architecture, we support only ARM and x86"
132 | ;;
133 | esac
134 |
135 | while getopts "${PARAMETER}" OPTION
136 | do
137 | case $OPTION in
138 | f)
139 | IS_FORCE=1
140 | set +e
141 | ;;
142 | b)
143 | BUILD=$OPTARG
144 | BRIDGE=$OPTARG
145 | ;;
146 | i)
147 | INTERFACE=$OPTARG
148 | ;;
149 | w)
150 | WRITE=1
151 | ;;
152 | d)
153 | DRY_RUN=1
154 | DATA_FILE=$OPTARG
155 | ;;
156 | p)
157 | PATCH_FILE=$OPTARG
158 | if [ ! -f "${PATCH_FILE}" ]
159 | then
160 | die "Specified patch file can not be found"
161 | fi
162 | ;;
163 | m)
164 | MODULE=$OPTARG
165 | # Pruefen ob Modul existiert
166 | if [ ! -f "${YAHM_DIR}/share/modules/${MODULE}" ]
167 | then
168 | die "Specified module can not be found"
169 | fi
170 | ;;
171 | r)
172 | if [ $OPTARG == "false" ] || [ $OPTARG == "no" ] || [ $OPTARG == "0" ]
173 | then
174 | RESTART=0
175 | elif [ $OPTARG == "true" ] || [ $OPTARG == "yes" ] || [ $OPTARG == "1" ]
176 | then
177 | RESTART=1
178 | else
179 | die "Unsupported option"
180 | fi
181 | ;;
182 | v)
183 | IS_VERBOSE=1
184 | QUIET=""
185 | VERBOSE="-v"
186 | ;;
187 | n)
188 | LXCNAME=$OPTARG
189 | ;;
190 | h|\?)
191 | show_help
192 | ;;
193 | esac
194 | done
195 |
196 | shift $((OPTIND-1))
197 |
198 | [ "$1" = "--" ] && shift
199 |
200 | LXC_ROOT=/var/lib/lxc/$LXCNAME
201 | LXC_ROOT_FS=/var/lib/lxc/$LXCNAME/root
202 | LXC_ROOT_MODULES=/var/lib/lxc/$LXCNAME/.modules
203 |
204 | # Develop Branch warning
205 | cd ${YAHM_DIR}
206 | GIT_BRANCH=$(git branch | grep -e "^*" | cut -d' ' -f 2)
207 | if [ "$GIT_BRANCH" == "develop" ]
208 | then
209 | error "\n!!! You are using develop branch, this branch is unstable. Using at your own risk !!!!\n"
210 | fi
211 |
212 | get_ccu2_actual_version()
213 | {
214 | # aktuelle Version bestimmen
215 | checkVersion="http://update.homematic.com/firmware/download?cmd=js_check_version&serial=0&product=HM-CCU2"
216 | curVersion=$(wget $QUIET -qO- -T 3 -t 1 "$checkVersion" | cut -d"'" -f2)
217 | # Bei misserfolg letze bekannte Version ausgeben
218 | if [ "$curVersion" = "" ] || [ "$curVersion" = "n/a" ]
219 | then
220 | curVersion=$CCU2Version
221 | fi
222 | # Ausgabe
223 | echo $curVersion
224 | }
225 |
226 | download_ccu2_fw()
227 | {
228 | BUILD=$1
229 | aBUILD=`get_ccu2_actual_version`
230 |
231 | if [ "${BUILD}" == "" ]
232 | then
233 | BUILD=$aBUILD
234 | fi
235 |
236 | progress "Downloading CCU Firmware"
237 | # Falls wir aktuelle FW runterladen
238 | if [ $(ver ${BUILD}) -eq $(ver ${aBUILD}) ]
239 | then
240 | curFWdl="http://update.homematic.com/firmware/download?cmd=download&product=HM-CCU2&serial=0"
241 | # Falls Download nicht funktioniert aus dem GIT runterladen (archiv)
242 | wget $QUIET -T 3 -t 1 --spider "$curFWdl" || {
243 | if [ `check_ccu2_archive $BUILD` -eq 0 ] && [ $IS_FORCE -ne 1 ]
244 | then
245 | die "ERROR: Can not find specified file in repository"
246 | fi
247 | error "EQ3 site, seems to be down. Trying to download from GIT"
248 | curFWdl="https://github.com/leonsio/CCU2-FW/raw/master/HM-CCU2-${BUILD}.tgz"
249 | }
250 | fi
251 | # Falls die FW unter aktuellen liegt, aus dem GIT runterladen (archiv)
252 | if [ $(ver ${BUILD}) -lt $(ver ${aBUILD}) ]
253 | then
254 | if [ `check_ccu2_archive $BUILD` -eq 0 ] && [ $IS_FORCE -ne 1 ]
255 | then
256 | die "ERROR: Can not find specified version in repository"
257 | fi
258 | curFWdl="https://github.com/leonsio/CCU2-FW/raw/master/HM-CCU2-${BUILD}.tgz"
259 | fi
260 | # Sollte nicht vorkommen
261 | if [ $(ver ${BUILD}) -gt $(ver ${aBUILD}) ]
262 | then
263 | die "ERROR: Specified version is greater than actual version"
264 | fi
265 |
266 | EQ3_FW="${YAHM_TMP}/HM-CCU2-${BUILD}.tar.gz"
267 |
268 | wget $QUIET --tries=3 --retry-connrefused -O "$EQ3_FW" "$curFWdl" || info "Can not download file"
269 |
270 | if [ ! -f "$EQ3_FW" ] && [ $IS_FORCE -ne 1 ]
271 | then
272 | die "ERROR: Can not download firmware. Are you connected to the internet? Try to download the file manually and use -d flag"
273 | fi
274 | }
275 |
276 | check_ccu2_archive()
277 | {
278 | CCU2_VERSION=$1
279 | if [ ! -f ${YAHM_LIB}/fw.list ]
280 | then
281 | wget $QUIET -O ${YAHM_LIB}/fw.list -N https://raw.githubusercontent.com/leonsio/CCU2-FW/master/fw.list
282 | fi
283 | ALL_FW=$(cat ${YAHM_LIB}/fw.list | grep -Po '(?<=CCU2-)\d.\d\d?.\d\d?')
284 | [[ $ALL_FW =~ $CCU2_VERSION ]] && echo 1 || echo 0
285 | }
286 |
287 | # Gibt installierte Bridge zurück
288 | get_ccu2_bridge()
289 | {
290 | CCU2_BRIDGE=$(cat ${LXC_ROOT}/config.network | grep "lxc.network.link" | cut -d" " -f3)
291 | echo $CCU2_BRIDGE
292 | }
293 |
294 | # Achtung gibt nur das Erste Interface zurück, mehrere Interfaces werden nicht unterstützt
295 | get_bridge_interface()
296 | {
297 | BRIDGE_NAME=$1
298 | BRIDGE_INTERFACE=$(brctl show ${BRIDGE_NAME} | awk 'NF>1 && NR>1 {print $4}')
299 | echo $BRIDGE_INTERFACE
300 | }
301 |
302 | get_yahm_name()
303 | {
304 | if [ `check_yahm_installed` -eq 1 ]
305 | then
306 | local installed_name=`cat ${YAHM_LIB}/container_name`
307 | else
308 | echo 0
309 | fi
310 |
311 | }
312 |
313 | check_yahm_name()
314 | {
315 | if [ `check_yahm_installed` -eq 1 ] ; then
316 | local container_name=$1
317 | local installed_name=`cat ${YAHM_LIB}/container_name`
318 |
319 | if [ "$container_name" = "$installed_name" ] ; then
320 | echo 1
321 | return 1
322 | fi
323 | fi
324 | echo 0
325 | return 1
326 | }
327 |
328 | check_yahm_installed()
329 | {
330 | file="${YAHM_LIB}/is_installed"
331 | if [ -f "$file" ]
332 | then
333 | echo 1
334 | else
335 | echo 0
336 | fi
337 | }
338 |
339 | check_container_installed()
340 | {
341 | file="${LXC_ROOT}/config"
342 | if [ -f "$file" ]
343 | then
344 | echo 1
345 | else
346 | echo 0
347 | fi
348 | }
349 |
350 |
351 | get_yahm_version()
352 | {
353 | local container_name=$1
354 | local yahm_version=`cat /var/lib/lxc/${container_name}/root/boot/VERSION | cut -d'=' -f2`
355 | echo $yahm_version
356 | }
357 |
358 | yahm_compatibility()
359 | {
360 | local ccufw_version=$1
361 | if [ ! -f "${YAHM_DIR}/share/firmware/patches/${ccufw_version}.patch" ] ; then
362 | echo 1
363 | return 1
364 | fi
365 |
366 | if [ ! -f "${YAHM_DIR}/share/firmware/scripts/${ccufw_version}.sh" ] ; then
367 | echo 1
368 | return 1
369 | fi
370 |
371 | echo 0
372 | }
373 |
374 | ver()
375 | {
376 | printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' ' ')
377 | }
378 |
379 | countdown()
380 | {
381 | secs=$((5))
382 | while [ $secs -gt 0 ]; do
383 | echo -ne "$secs\033[0K\r"
384 | sleep 1
385 | : $((secs--))
386 | done
387 | }
388 |
389 | check_install_deb()
390 | {
391 | progress "Installing dependencies"
392 | packages=$1
393 | for P in $packages
394 | do
395 | dpkg -s "$P" >/dev/null 2>&1 && {
396 | info $P is installed
397 | } || {
398 | install_package "$P"
399 | }
400 | done
401 | }
402 |
403 | install_package() {
404 | package=$1
405 | info "install ${package}"
406 | apt-get -qq -y install $package 2>&1 > /dev/null
407 | return $?
408 | }
409 |
410 | ### Shared Network functionality
411 |
412 | show_bridges()
413 | {
414 | info "Available Bridges"
415 | brctl show
416 | }
417 |
418 | check_bridge_name()
419 | {
420 | local brname=$1
421 | local bridges=$(brctl show | awk 'NF>1 && NR>1 {print $1}')
422 | for bridge in $bridges
423 | do
424 | if [ "$brname" = "$bridge" ]
425 | then
426 | echo 1
427 | return 1
428 | fi
429 | done
430 | echo 0
431 | }
432 |
433 |
434 | check_interface_name()
435 | {
436 | # interface name
437 | local int_name=$1
438 |
439 | if [[ ! `ip -d link show ${int_name} 2>/dev/null ` ]]; then
440 | die "ERROR: Interface ${int_name} does not exists"
441 | elif [[ `ip -d link show ${int_name} | tail -n +2 | grep loopback` ]] ; then
442 | echo "local"
443 | elif [[ `ip -d link show ${int_name} | tail -n +2 | grep vlan` ]] ; then
444 | echo "vlan"
445 | elif [[ `ip -d link show ${int_name} | tail -n +2 | grep bridge` ]] ; then
446 | echo "bridge"
447 | else
448 | echo "physical"
449 | fi
450 | }
451 |
452 | check_git_update()
453 | {
454 | cd ${YAHM_DIR}
455 | git remote update >/dev/null
456 | LOCAL=$(git rev-parse @)
457 | REMOTE=$(git rev-parse @{u})
458 | BASE=$(git merge-base @ @{u})
459 |
460 | if [ $LOCAL = $REMOTE ]; then
461 | echo 0
462 | elif [ $LOCAL = $BASE ]; then
463 | echo 1
464 | fi
465 | }
466 |
467 | # Check if we have new YAHM or CCU version and inform use
468 | if [ -f ${YAHM_LIB}/version_status ]
469 | then
470 | CREATED_TIME=$(stat -c %Y ${YAHM_LIB}/version_status)
471 | source ${YAHM_LIB}/version_status
472 | else
473 | echo -e "NEW_CCU2_VERSION=\nNEW_YAHM_VERSION=" > ${YAHM_LIB}/version_status
474 | CREATED_TIME=123456789
475 | fi
476 |
477 | RUNNING_TIME=$(date +%s)
478 |
479 | if [ $((RUNNING_TIME-CREATED_TIME)) -gt 86400 ]
480 | then
481 | # get newest CCU version
482 | NEW_CCU2_VERSION=`get_ccu2_actual_version`
483 | sed -i ${YAHM_LIB}/version_status -e "s/NEW_CCU2_VERSION=.*$/NEW_CCU2_VERSION=${NEW_CCU2_VERSION}/"
484 | # get newest YAHM version
485 | NEW_YAHM_VERSION=$(wget $QUIET -O- -T 3 -t 1 https://raw.githubusercontent.com/leonsio/YAHM/master/VERSION)
486 | sed -i ${YAHM_LIB}/version_status -e "s/NEW_YAHM_VERSION=.*$/NEW_YAHM_VERSION=${NEW_YAHM_VERSION}/"
487 | fi
488 |
489 | if [ `check_yahm_installed` -eq 1 ]
490 | then
491 | CCU2current=`get_yahm_version ${LXCNAME}`
492 | if [ $(ver $NEW_CCU2_VERSION) -gt $(ver $CCU2current) ] && [ $SHOW_YAHM_UPDATES -eq 1 ]
493 | then
494 | progress "New CCU2 firmware: ${NEW_CCU2_VERSION} available, update with 'yahm-lxc update' possible"
495 | fi
496 | fi
497 |
498 | if [ $(ver ${NEW_YAHM_VERSION}) -gt $(ver ${YAHM_VERSION}) ] && [ $SHOW_YAHM_UPDATES -eq 1 ]
499 | then
500 | progress "New YAHM version: ${NEW_YAHM_VERSION} available, update with 'yahm-ctl update' possible"
501 | fi
--------------------------------------------------------------------------------
/share/tools/checks/check_interfaces.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Thomas Kluge
4 | #
5 | # InterfacesList.xml Config Check
6 | #
7 |
8 |
9 | _check_result=0
10 | _check_fail="Es wurde eine fehlerhafte InterfacesList.xml Datei in /usr/local/etc/config gefunden."
11 | _check_ok="Die InterfacesList.xml sieht ok aus."
12 |
13 | _check_proceed() {
14 | # Check Interfaces.xml
15 | if [ $(cat ${LXC_ROOT_FS}/usr/local/etc/config/InterfacesList.xml|grep "BidCos-RF"|wc -l) -eq 1 ];then
16 | _check_result=1
17 | fi
18 | echo $_check_result
19 | }
20 |
21 |
22 | _check_fix_issue() {
23 | progress "Not yet implemented"
24 | }
--------------------------------------------------------------------------------
/share/tools/checks/check_rfd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Thomas Kluge
4 | #
5 | # RFD Config Check
6 | #
7 |
8 |
9 | _check_result=0
10 | _check_ok="Die rfd.conf sieht ok aus."
11 | _check_fail="Es wurde das HM-MOD-RPI-PCB Modul installiert, aber eine Anpassung in der Konfigurationsdatei fehlt. Eventuell wurde diese ja durch ein eingespieltes Backup überschrieben. Bitte reinstalliere das YAHM Modul HM-MOD-RPI-PCB um dieses Problem zu lösen."
12 |
13 |
14 | _check_proceed() {
15 | # Check RFD.conf
16 | if [ -e ${LXC_ROOT_MODULES}/hm-mod-rpi-pcb ] ; then
17 | if [ $(cat ${LXC_ROOT_FS}/usr/local/etc/config/rfd.conf|grep "\Improved\ Coprocessor\ Initialization\ =\ true"|wc -l) -eq 1 ];then
18 | _check_result=1
19 | fi
20 | fi
21 | echo $_check_result
22 | }
23 |
24 |
25 | _check_fix_issue() {
26 | progress "Not yet implemented"
27 | }
--------------------------------------------------------------------------------
/share/tools/hmgw/Makefile:
--------------------------------------------------------------------------------
1 | #CC = gcc-4.6
2 | CC = gcc
3 |
4 | #CFLAGS = -O2 -Wall -Wno-deprecated
5 | #CFLAGS = -O2 -pipe -Wall
6 | CFLAGS = -Wall -O2 -pipe -march=armv6j -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard
7 |
8 | all: hmlangw
9 |
10 |
11 | hmlangw: hmlangw.o hmframe.o
12 | $(CC) -o hmlangw hmlangw.o hmframe.o -lpthread
13 |
14 | # $(CC) -o hmlangw hmlangw.o hmframe.o -lutil -lpthread -lrt -lm -lstdc++
15 |
16 | .cpp.o:
17 | $(CC) -c $(CFLAGS) $<
18 |
19 | .c.o:
20 | $(CC) -c $(CFLAGS) $<
21 |
22 |
23 | # DO NOT DELETE
24 |
25 | hmlangw.o: hmlangw.cpp hmframe.h
26 | hmframe.o: hmframe.cpp hmframe.h
27 |
28 |
--------------------------------------------------------------------------------
/share/tools/hmgw/README.md:
--------------------------------------------------------------------------------
1 | Für Support siehe: [Homematic-Forum](http://homematic-forum.de/forum/viewtopic.php?f=18&t=27705)
2 |
3 | Dokumentation bzgl. Benutzung innnerhalb von YAHM siehe: [Wiki](https://github.com/leonsio/YAHM/wiki/YAHM-Module:-HM-FAKE-LAN-GW)
4 |
--------------------------------------------------------------------------------
/share/tools/hmgw/eq3/bin/eq3configcmd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonsio/YAHM/949b748b22fe2da0f3aff5b5681147c18c06cb03/share/tools/hmgw/eq3/bin/eq3configcmd
--------------------------------------------------------------------------------
/share/tools/hmgw/eq3/firmware/fwmap:
--------------------------------------------------------------------------------
1 | #Type Filename Version
2 |
3 | #Coprozessor
4 | CCU2 coprocessor_update.eq3 1.4.1 #CoProzessor CCU2
5 |
6 |
--------------------------------------------------------------------------------
/share/tools/hmgw/eq3/lib/libLanDeviceUtils.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonsio/YAHM/949b748b22fe2da0f3aff5b5681147c18c06cb03/share/tools/hmgw/eq3/lib/libLanDeviceUtils.so
--------------------------------------------------------------------------------
/share/tools/hmgw/eq3/lib/libUnifiedLanComm.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonsio/YAHM/949b748b22fe2da0f3aff5b5681147c18c06cb03/share/tools/hmgw/eq3/lib/libUnifiedLanComm.so
--------------------------------------------------------------------------------
/share/tools/hmgw/eq3/lib/libelvutils.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonsio/YAHM/949b748b22fe2da0f3aff5b5681147c18c06cb03/share/tools/hmgw/eq3/lib/libelvutils.so
--------------------------------------------------------------------------------
/share/tools/hmgw/eq3/lib/libeq3config.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonsio/YAHM/949b748b22fe2da0f3aff5b5681147c18c06cb03/share/tools/hmgw/eq3/lib/libeq3config.so
--------------------------------------------------------------------------------
/share/tools/hmgw/hmframe.cpp:
--------------------------------------------------------------------------------
1 | /* HM-LGW emulation for HM-MOD-RPI
2 | *
3 | * Copyright (c) 2015 Oliver Kastl
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to
7 | * deal in the Software without restriction, including without limitation the
8 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 | * sell copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 | * IN THE SOFTWARE.
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #include "hmframe.h"
31 |
32 |
33 | int writeall( int fd, const void *buffer, int len )
34 | {
35 | int result = 0;
36 | while( len )
37 | {
38 | int r = write( fd, buffer, len );
39 | if( r == -1 )
40 | {
41 | result = r;
42 | break;
43 | }
44 | result += r;
45 | len -= r;
46 | }
47 | return result;
48 | }
49 |
50 | static const unsigned char enterBootloader[] =
51 | {
52 | 0xfd, 0x00, 0x03, 0x00, 0x00, 0x03, 0x18, 0x0a
53 | };
54 |
55 | static const unsigned char bootloaderReply[] =
56 | {
57 | 0xfd, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x5f, 0x43, 0x50, 0x55, 0x5f, 0x42, 0x4c, 0x72, 0x51
58 | };
59 |
60 | int sendEnterBootloader( int fd )
61 | {
62 | int result = -1;
63 | while( 1 )
64 | {
65 | char buffer[80];
66 | tcflush(fd, TCIOFLUSH);
67 | result =writeall( fd, enterBootloader, sizeof( enterBootloader ) );
68 | if( result <= 0 )
69 | {
70 | break;
71 | }
72 | result = readBidcosFrame( fd, buffer, sizeof( buffer ) );
73 | if( result <= 0 )
74 | {
75 | break;
76 | }
77 | if( isBootloaderReply( buffer, result ) )
78 | {
79 | break;
80 | }
81 | }
82 | return result;
83 | }
84 |
85 | int sendBootloaderReply( int fd )
86 | {
87 | return writeall( fd, bootloaderReply, sizeof( bootloaderReply ) );
88 | }
89 |
90 | bool isBootloaderReply( const void *buffer, int len )
91 | {
92 | if( len != sizeof(bootloaderReply) )
93 | return false;
94 |
95 | return (memcmp( buffer, bootloaderReply, len ) == 0);
96 | }
97 |
98 |
99 | int readBidcosFrame( int fd, char *buffer, int bufsize )
100 | {
101 | int result = 0;
102 | int msgLen = 0;
103 | int escaped = 0;
104 | int count = bufsize;
105 | unsigned char *buf = (unsigned char *)buffer;
106 | char escapeValue = 0x00;
107 | bool haveLength = false;
108 |
109 | while ( count )
110 | {
111 | int r = read( fd, buf, 1 );
112 | if( r <= 0 )
113 | {
114 | result = r;
115 | perror( "ERROR: readBidcosFrame" );
116 | break;
117 | }
118 | if( *buf == 0xFD ) // sync byte
119 | {
120 | result = 0;
121 | msgLen = 0;
122 | escaped = 0;
123 | count = bufsize;
124 | buf = (unsigned char *)buffer;
125 | escapeValue = 0x00;
126 | haveLength = false;
127 | // fprintf( stderr, "readBidcosFrame reset\n" );
128 | }
129 | else if( result == 0 )
130 | {
131 | fprintf( stderr, "ERROR: readBidcosFrame sync error %2.2x\n", *buf );
132 | // No sync at beginning? Not good...
133 | break;
134 | }
135 |
136 | result += r;
137 |
138 | if( *buf == 0xFC && result > 1 ) // escape byte
139 | {
140 | escaped++;
141 | escapeValue = 0x80;
142 | // fprintf( stderr, "ESCAPE msgLen set %d result %d\n", msgLen, result );
143 | }
144 | else
145 | {
146 | escapeValue = 0x00;
147 | }
148 |
149 | if( false == haveLength )
150 | {
151 | if( result == 2 + escaped )
152 | {
153 | msgLen = *buf; // MSB
154 | msgLen |= escapeValue;
155 | msgLen = msgLen<<8;
156 | }
157 | else if( result == 3 + escaped )
158 | {
159 | msgLen |= *buf; // LSB
160 | msgLen |= escapeValue;
161 | haveLength = true;
162 | // fprintf( stderr, "readBidcosFrame msgLen set %d result %d\n", msgLen, result );
163 | }
164 | }
165 | else if( result >= msgLen + escaped + 5 )
166 | {
167 | // fprintf( stderr, "readBidcosFrame done, msgLen %d result %d\n", msgLen, result );
168 | break;
169 | }
170 |
171 | count -= r;
172 | buf+=r;
173 | }
174 |
175 | return result;
176 | }
177 |
--------------------------------------------------------------------------------
/share/tools/hmgw/hmframe.h:
--------------------------------------------------------------------------------
1 | /* HM-LGW emulation for HM-MOD-RPI
2 | *
3 | * Copyright (c) 2015 Oliver Kastl
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to
7 | * deal in the Software without restriction, including without limitation the
8 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 | * sell copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 | * IN THE SOFTWARE.
22 | */
23 |
24 | int readBidcosFrame( int fd, char *buffer, int bufsize );
25 | int sendEnterBootloader( int fd );
26 | int sendBootloaderReply( int fd );
27 | int writeall( int fd, const void *buffer, int len );
28 | bool isBootloaderReply( const void *buffer, int len );
29 |
--------------------------------------------------------------------------------
/share/tools/hmgw/hmframe.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonsio/YAHM/949b748b22fe2da0f3aff5b5681147c18c06cb03/share/tools/hmgw/hmframe.o
--------------------------------------------------------------------------------
/share/tools/hmgw/hmlangw:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonsio/YAHM/949b748b22fe2da0f3aff5b5681147c18c06cb03/share/tools/hmgw/hmlangw
--------------------------------------------------------------------------------
/share/tools/hmgw/hmlangw.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonsio/YAHM/949b748b22fe2da0f3aff5b5681147c18c06cb03/share/tools/hmgw/hmlangw.o
--------------------------------------------------------------------------------
/share/tools/hmgw/kill-hmlan.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sudo killall -w hmlangw
3 |
--------------------------------------------------------------------------------
/share/tools/hmgw/run-hmlan.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #cd /root/hmgw
3 | cd /home/pi/hmgw
4 | sudo killall -w hmlangw
5 | sudo ./hmlangw -n auto 1> /dev/null 2> /dev/null &
6 |
7 |
--------------------------------------------------------------------------------
/share/tools/hmgw/start-hmlan.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sudo killall -w hmlangw
3 | sudo ./hmlangw -n auto -D
4 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/README.md:
--------------------------------------------------------------------------------
1 | # UBI Reader
2 |
3 |
4 | UBI Reader is a program capable of reading UBI and UBIFS images.
5 | It will provide various information about images, volumes, physical erase
6 | blocks, along with UBIFS superblock and master nodes. It is capable of walking
7 | the UBIFS index node, gathering associated directory entry, data and inode nodes,
8 | ordered by inode number. Also possible is extracting the directory tree with in
9 | with all associated files.
10 |
11 | ## Install:
12 |
13 | Python is required.
14 |
15 | python-lzo is the only non-standard module, possibly included in your disto repo, if not.
16 |
17 | $ sudo apt-get install liblzo2-dev
18 |
19 | If its available in your repos.
20 | $ sudo apt-get install python-lzo
21 |
22 | Else
23 | $ git clone https://github.com/jd-boyd/python-lzo.git
24 | $ cd python-lzo
25 | $ python setup.py install
26 |
27 |
28 | ## Usage:
29 | All scripts save output into the ubi_reader/output/ directory, depending on information
30 | available to the script, names can vary from input file name to volume names or what order
31 | the image was found.
32 |
33 | Run program with -h or --help for explanation of options.
34 |
35 | ### UBI Images:
36 |
37 | __ubi_extract.py__
38 |
39 | $ ubi_extract.py [options] /path/to/image.ubi
40 |
41 | Extract a UBI image from file. This is useful with a NAND dump or other such binary data.
42 | Will extract any images found, as long as they have different image_seq numbers.
43 | It is possible to specify keyword args start_offset and end\_offset in the ubi\_file() call.
44 |
45 |
46 | __ubi_extract_ubifs.py__
47 |
48 | $ ubi_extract_ubifs.py [options] /path/to/image.ubi
49 |
50 | Extract UBIFS image from file. Like ubi_extract.py, but provides the additional step of
51 | stripping out UBI information and saving the UBIFS image.
52 |
53 |
54 | __ubi\_extract\_files.py__
55 |
56 | $ ubi_extract_files.py [options] /path/to/image.ubi
57 |
58 | Extract contents of a UBI image, saving to output. If this is not run as root, depending
59 | on files and types of files being extracted and their permissions, not all actions may
60 | be taken, and you'll see a lot of warnings. To preserve all permissions and for things
61 | such as device files run as root. Internally this creates a virtual UBIFS image to read
62 | from. As such, it is faster to extract the UBIFS image, and use ubifs\_extract\_files.py
63 | but this will save a step, and doesn't take up file system space.
64 |
65 | __ubi_info.py__
66 |
67 | $ ubi_info.py [options] /path/to/image.ubi
68 |
69 | With no Physical Erase Block number provided, this will print all found information about
70 | the UBI images and volumes found in the file. If PEB Number is provided, it will print
71 | out the header contents of that PEB. If PEB Number not found, will print the first block.
72 |
73 |
74 | __create\_build\_script.py__
75 |
76 | $ create_build_script.py [options] /path/to/image.ubi
77 |
78 | Analyze provided image and creates the .ini configuration file and a shell script that accepts
79 | a path(s) to a folder(s) to build a similiar configured UBI image. If Image contains multiple
80 | volumes, script will accept multiple paths. Compare to .ini file for which path corrisponds
81 | to which input.
82 |
83 | __ubi\_utils\_info.py__
84 |
85 | $ ubi_utils_info.py [options] /path/to/image.ubi
86 |
87 | Analyze provided image, and print to console the names, option flags and values of any relevant
88 | information for use with programs such as mkfs.ubi, ubinize, ubimkvol, ubiformat, etc. Make
89 | sure to check with the relevant application, as some option flags are duplicates.
90 |
91 |
92 | ### UBIFS Images:
93 | __ubifs\_extract\_files.py__
94 |
95 | $ ubifs_extract_files.py [options] /path/to/image.ubifs
96 |
97 | Same as ubi\_extract\_files.py but works on UBIFS images.
98 |
99 | __ubifs\_info.py__
100 |
101 | $ ubifs_info.py [options] /path/to/image.ubifs
102 |
103 | Prints the Superblock node and Master node.
104 |
105 | ### Known Issues
106 |
107 | * Will not create a SOCK file type, instead just saves an empty text file with its name.
108 |
109 | * For NAND dumps and the like, this will not fix anything ECC would take care of, so some bad data
110 | may be extracted.
111 |
112 | * This does not replay the journal, so uncommited data will not be retrieved.
113 |
114 | * Assumes things are in good condition and where it thinks they should be...
115 |
116 | ### TODO
117 |
118 | * Organize, document, the usual.
119 |
120 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/create_build_script.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 | import sys
22 | import argparse
23 | import ConfigParser
24 |
25 | from ui.common import get_ubi_params, output_dir
26 | from ubi_io import ubi_file
27 | from ubi import ubi, get_peb_size
28 |
29 | def make_files(ubi, output_path):
30 | ubi_params = get_ubi_params(ubi)
31 |
32 | for img_params in ubi_params:
33 | config = ConfigParser.ConfigParser()
34 | output_img_path = os.path.join(output_path, 'img-%s' % img_params)
35 |
36 | if not os.path.exists(output_img_path):
37 | os.mkdir(output_img_path)
38 |
39 | ini_path = os.path.join(output_img_path, 'img-%s.ini' % img_params)
40 | ubi_file = os.path.join('img-%s.ubi' % img_params)
41 | script_path = os.path.join(output_img_path, 'create_ubi_img-%s.sh' % img_params)
42 | ubifs_files =[]
43 | buf = '#!/bin/sh\n'
44 | print 'Writing to: %s' % script_path
45 |
46 | with open(script_path, 'w') as fscr:
47 | with open(ini_path, 'w') as fini:
48 | print 'Writing to: %s' % ini_path
49 | vol_idx = 0
50 |
51 | for volume in ubi_params[img_params]:
52 | ubifs_files.append(os.path.join('img-%s_%s.ubifs' % (img_params, vol_idx)))
53 | ini_params = ubi_params[img_params][volume]['ini']
54 | ini_file = 'img-%s.ini' % img_params
55 | config.add_section(volume)
56 | config.set(volume, 'mode', 'ubi')
57 | config.set(volume, 'image', ubifs_files[vol_idx])
58 |
59 | for i in ini_params:
60 | config.set(volume, i, ini_params[i])
61 |
62 | ubi_flags = ubi_params[img_params][volume]['flags']
63 | ubi_args = ubi_params[img_params][volume]['args']
64 |
65 | leb = '%s %s' % (ubi_flags['leb_size'], ubi_args['leb_size'])
66 | peb = '%s %s' % (ubi_flags['peb_size'], ubi_args['peb_size'])
67 | min_io = '%s %s' % (ubi_flags['min_io_size'], ubi_args['min_io_size'])
68 | leb_cnt = '%s %s' % (ubi_flags['max_leb_cnt'], ubi_args['max_leb_cnt'])
69 | vid_hdr = '%s %s' % (ubi_flags['vid_hdr_offset'], ubi_args['vid_hdr_offset'])
70 | sub_page = '%s %s' % (ubi_flags['sub_page_size'], ubi_args['sub_page_size'])
71 |
72 | buf += '/usr/sbin/mkfs.ubifs %s %s %s -r $%s %s\n' % (min_io, leb, leb_cnt, (vol_idx+1), ubifs_files[vol_idx])
73 |
74 | vol_idx += 1
75 |
76 | config.write(fini)
77 |
78 | buf += '/usr/sbin/ubinize %s %s %s %s -o %s %s\n' % (peb, min_io, sub_page, vid_hdr, ubi_file, ini_file)
79 | fscr.write(buf)
80 | os.chmod(script_path, 0755)
81 |
82 | if __name__ == '__main__':
83 | description = """Gather information from the UBI image and create a
84 | ubi file along with a shell script to create a UBI image from a given path."""
85 | usage = 'ubi_utils_info.py [options] filepath'
86 | parser = argparse.ArgumentParser(usage=usage, description=description)
87 |
88 | parser.add_argument('-p', '--peb-size', type=int, dest='block_size',
89 | help='Specify PEB size of input image.')
90 |
91 | parser.add_argument('-o', '--output-dir', dest='output_path',
92 | help='Specify output directory path.')
93 |
94 | parser.add_argument('filepath', help='File to get info from.')
95 |
96 | if len(sys.argv) == 1:
97 | parser.print_help()
98 | sys.exit()
99 |
100 | args = parser.parse_args()
101 |
102 | if args.filepath:
103 | path = args.filepath
104 | if not os.path.exists(path):
105 | parser.error("filepath doesn't exist.")
106 |
107 | if args.output_path:
108 | output_path = args.output_path
109 | else:
110 | img_name = os.path.splitext(os.path.basename(path))[0]
111 | output_path = os.path.join(output_dir, img_name)
112 |
113 | if not os.path.exists(output_path):
114 | os.makedirs(output_path)
115 |
116 | # Determine block size if not provided
117 | if args.block_size:
118 | block_size = args.block_size
119 | else:
120 | block_size = get_peb_size(path)
121 |
122 | # Create file object
123 | ufile = ubi_file(path, block_size)
124 | # Create UBI object
125 | uubi = ubi(ufile)
126 | # Print info.
127 | make_files(uubi, output_path)
128 | sys.exit()
--------------------------------------------------------------------------------
/share/tools/ubi_reader/output/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import re
21 | from ubi.volume import get_volumes
22 | from ubi.block import sort, get_blocks_in_list, extract_blocks
23 | from ubi.defines import *
24 | from ubi import display
25 | from ubi.image import description as image
26 | from ubi.block import layout
27 |
28 |
29 | class ubi():
30 | """UBI object
31 |
32 | Arguments:
33 | Obj:image -- UBI image object
34 |
35 | Attributes:
36 | Int:leb_size -- Size of Logical Erase Blocks.
37 | Int:peb_size -- Size of Physical Erase Blocks.
38 | Int:first_peb_num -- Number of the first UBI PEB in file.
39 | Int:min_io -- Size of min I/O from vid_hdr_offset.
40 | List:images -- List of UBI image objects.
41 | List:data_blocks_list -- List of all data blocks in file.
42 | List:layout_blocks_list -- List of all layout blocks in file.
43 | List:int_vol_blocks_list -- List of internal volumes minus layout.
44 | List:unknown_blocks_list -- List of blocks with unknown types. *
45 | Dict:blocks -- Dict keyed by PEB number of all blocks.
46 | * More research into these is needed.
47 | """
48 | def __init__(self, ubi_file):
49 | self._file = ubi_file
50 | self._first_peb_num = 0
51 | self._blocks = extract_blocks(self)
52 | self._block_count = len(self.blocks)
53 |
54 | if self._block_count <= 0:
55 | raise Exception('No blocks found.')
56 |
57 | layout_list, data_list, int_vol_list, unknown_list = sort.by_type(self.blocks)
58 |
59 | self._layout_blocks_list = layout_list
60 | self._data_blocks_list = data_list
61 | self._int_vol_blocks_list = int_vol_list
62 | self._unknown_blocks_list = unknown_list
63 |
64 | arbitrary_block = self.blocks.itervalues().next()
65 | self._min_io_size = arbitrary_block.ec_hdr.vid_hdr_offset
66 | self._leb_size = self.file.block_size - arbitrary_block.ec_hdr.data_offset
67 |
68 | layout_pairs = layout.group_pairs(self.blocks, self.layout_blocks_list)
69 |
70 | # Plus 2 to adjust for layout blocks
71 | layout_infos = layout.associate_blocks(self.blocks, layout_pairs, self.first_peb_num)
72 |
73 | self._images = []
74 | for i in range(0, len(layout_infos)):
75 | self._images.append(image(self.blocks, layout_infos[i]))
76 |
77 | def _get_file(self):
78 | """UBI File object
79 |
80 | Returns:
81 | Obj -- UBI File object.
82 | """
83 | return self._file
84 | file = property(_get_file)
85 |
86 |
87 | def _get_images(self):
88 | """Get UBI images.
89 |
90 | Returns:
91 | List -- Of volume objects groupled by image.
92 | """
93 | return self._images
94 | images = property(_get_images)
95 |
96 |
97 | def _get_data_blocks_list(self):
98 | """Get all UBI blocks found in file that are data blocks.
99 |
100 | Returns:
101 | List -- List of block objects.
102 | """
103 | return self._data_blocks_list
104 | data_blocks_list = property(_get_data_blocks_list)
105 |
106 |
107 | def _get_layout_blocks_list(self):
108 | """Get all UBI blocks found in file that are layout volume blocks.
109 |
110 | Returns:
111 | List -- List of block objects.
112 | """
113 | return self._layout_blocks_list
114 | layout_blocks_list = property(_get_layout_blocks_list)
115 |
116 |
117 | def _get_int_vol_blocks_list(self):
118 | """Get all UBI blocks found in file that are internal volume blocks.
119 |
120 | Returns:
121 | List -- List of block objects.
122 |
123 | This does not include layout blocks.
124 | """
125 | return self._int_vol_blocks_list
126 | int_vol_blocks_list = property(_get_int_vol_blocks_list)
127 |
128 |
129 | def _get_unknown_blocks_list(self):
130 | """Get all UBI blocks found in file of unknown type..
131 |
132 | Returns:
133 | List -- List of block objects.
134 | """
135 | return self._unknown_blocks_list
136 | unknown_blocks_list = property(_get_unknown_blocks_list)
137 |
138 |
139 | def _get_block_count(self):
140 | """Total amount of UBI blocks in file.
141 |
142 | Returns:
143 | Int -- Number of blocks
144 | """
145 | return self._block_count
146 | block_count = property(_get_block_count)
147 |
148 |
149 | def _set_first_peb_num(self, i):
150 | self._first_peb_num = i
151 | def _get_first_peb_num(self):
152 | """First Physical Erase Block with UBI data
153 |
154 | Returns:
155 | Int -- Number of the first PEB.
156 | """
157 | return self._first_peb_num
158 | first_peb_num = property(_get_first_peb_num, _set_first_peb_num)
159 |
160 |
161 | def _get_leb_size(self):
162 | """LEB size of UBI blocks in file.
163 |
164 | Returns:
165 | Int -- LEB Size.
166 | """
167 | return self._leb_size
168 | leb_size = property(_get_leb_size)
169 |
170 |
171 | def _get_peb_size(self):
172 | """PEB size of UBI blocks in file.
173 |
174 | Returns:
175 | Int -- PEB Size.
176 | """
177 | return self.file.block_size
178 | peb_size = property(_get_peb_size)
179 |
180 |
181 | def _get_min_io_size(self):
182 | """Min I/O Size
183 |
184 | Returns:
185 | Int -- Min I/O Size.
186 | """
187 | return self._min_io_size
188 | min_io_size = property(_get_min_io_size)
189 |
190 |
191 | def _get_blocks(self):
192 | """Main Dict of UBI Blocks
193 |
194 | Passed around for lists of indexes to be made or to be returned
195 | filtered through a list. So there isn't multiple copies of blocks,
196 | as there can be thousands.
197 | """
198 | return self._blocks
199 | blocks = property(_get_blocks)
200 |
201 |
202 | def display(self, tab=''):
203 | """Print information about this object.
204 |
205 | Argument:
206 | Str:tab -- '\t' for spacing this object.
207 | """
208 | display.ubi(self, tab)
209 |
210 |
211 | def get_peb_size(path):
212 | """Determine the most likely block size
213 |
214 | Arguments:
215 | Str:path -- Path to file.
216 |
217 | Returns:
218 | Int -- PEB size.
219 |
220 | Searches file for Magic Number, picks most
221 | common length between them.
222 | """
223 | file_offset = 0
224 | offsets = []
225 | f = open(path, 'rb')
226 | f.seek(0,2)
227 | file_size = f.tell()+1
228 | f.seek(0)
229 |
230 | for i in range(0, file_size, FILE_CHUNK_SZ):
231 | buf = f.read(FILE_CHUNK_SZ)
232 | for m in re.finditer(UBI_EC_HDR_MAGIC, buf):
233 | start = m.start()
234 |
235 | if not file_offset:
236 | file_offset = start
237 | idx = start
238 | else:
239 | idx = start+file_offset
240 |
241 | offsets.append(idx)
242 |
243 | file_offset += FILE_CHUNK_SZ
244 | f.close()
245 |
246 | occurances = {}
247 | for i in range(0, len(offsets)):
248 | try:
249 | diff = offsets[i] - offsets[i-1]
250 | except:
251 | diff = offsets[i]
252 |
253 | if diff not in occurances:
254 | occurances[diff] = 0
255 |
256 | occurances[diff] += 1
257 |
258 | most_frequent = 0
259 | block_size = 0
260 |
261 | for offset in occurances:
262 | if occurances[offset] > most_frequent:
263 | most_frequent = occurances[offset]
264 | block_size = offset
265 |
266 | return block_size
267 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/block/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import re
21 | from ubi import display
22 | from ubi.defines import *
23 | from ubi.headers import *
24 |
25 | # build block object out of data
26 | # takes raw data divided up by ec magic number
27 | class description(object):
28 | """UBI Block description Object
29 |
30 | UBI Specifications:
31 | http://www.linux-mtd.infradead.org/ -- Home page
32 | /drivers/mtd/ubi/ubi-media.h -- Header structs
33 | and defines
34 |
35 | Attributes:
36 | Obj:ec_hdr -- Error Count Header
37 | Obj:vid_hdr -- Volume ID Header
38 | List:vtbl_recs -- (Optional) List of Volume Table Records.
39 | Bool:is_vtbl -- If contains volume records table.
40 | Bool:is_internal_vol -- If Vol ID is > UBI_INTERNAL_VOL_START
41 | Bool:is_valid -- If ec_hdr & vid_hdr are error free.
42 | Int:peb_num -- Physical Erase Block number.
43 | Int:leb_num -- Logical Erase Block number.
44 | Int:file_offset -- Address location in file of this block.
45 | Int:size -- Size of total block data or PEB size.
46 | Will print out all information when invoked as a string.
47 | """
48 |
49 | def __init__(self, block_buf):
50 |
51 | self.file_offset = -1
52 | self.peb_num = -1
53 | self.leb_num = -1
54 | self.size = -1
55 |
56 | self.vid_hdr = None
57 | self.is_internal_vol = False
58 | self.vtbl_recs = []
59 |
60 | # TODO better understanding of block types/errors
61 | self.ec_hdr = extract_ec_hdr(block_buf[0:UBI_EC_HDR_SZ])
62 |
63 | if not self.ec_hdr.errors:
64 | self.vid_hdr = extract_vid_hdr(block_buf[self.ec_hdr.vid_hdr_offset:self.ec_hdr.vid_hdr_offset+UBI_VID_HDR_SZ])
65 |
66 | self.is_internal_vol = self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START
67 |
68 | if self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START:
69 | self.vtbl_recs = extract_vtbl_rec(block_buf[self.ec_hdr.data_offset:])
70 |
71 | self.leb_num = self.vid_hdr.lnum
72 |
73 | self.is_vtbl = bool(self.vtbl_recs) or False
74 | self.is_valid = not self.ec_hdr.errors and not self.vid_hdr.errors
75 |
76 |
77 | def __repr__(self):
78 | return 'Block: PEB# %s: LEB# %s' % (self.peb_num, self.leb_num)
79 |
80 | def display(self, tab=''):
81 | display.block(self, tab)
82 |
83 |
84 | def get_blocks_in_list(blocks, idx_list):
85 | """Retrieve block objects in list of indexes
86 |
87 | Arguments:
88 | List:blocks -- List of block objects
89 | List:idx_list -- List of block indexes
90 |
91 | Returns:
92 | Dict:blocks -- List of block objects generated
93 | from provided list of indexes in
94 | order of idx_list.
95 | """
96 | return {i:blocks[i] for i in idx_list}
97 |
98 |
99 | def extract_blocks(ubi):
100 | """Get a list of UBI block objects from file
101 |
102 | Arguments:.
103 | Obj:ubi -- UBI object.
104 |
105 | Returns:
106 | Dict -- Of block objects keyed by PEB number.
107 | """
108 | blocks = {}
109 | start_peb = 0
110 | ubi.file.seek(ubi.file.start_offset)
111 | peb_count = 0
112 | cur_offset = 0
113 |
114 | for i in range(ubi.file.start_offset, ubi.file.end_offset, ubi.file.block_size):
115 | buf = ubi.file.read(ubi.file.block_size)
116 |
117 | if buf.startswith(UBI_EC_HDR_MAGIC):
118 | blk = description(buf)
119 | blk.file_offset = i
120 | blk.peb_num = ubi.first_peb_num + peb_count
121 | blk.size = ubi.file.block_size
122 | blocks[blk.peb_num] = blk
123 | peb_count += 1
124 | else:
125 | cur_offset += ubi.file.block_size
126 | ubi.first_peb_num = cur_offset/ubi.file.block_size
127 | ubi.file.start_offset = cur_offset
128 |
129 | return blocks
130 |
131 |
132 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/block/layout.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | from ubi.block import sort
21 |
22 |
23 | def group_pairs(blocks, layout_blocks_list):
24 | """Sort a list of layout blocks into pairs
25 |
26 | Arguments:
27 | List:blocks -- List of block objects
28 | List:layout_blocks -- List of layout block indexes
29 |
30 | Returns:
31 | List -- Layout block pair indexes grouped in a list
32 | """
33 | layouts_grouped = [[blocks[layout_blocks_list[0]].peb_num]]
34 |
35 | for l in layout_blocks_list[1:]:
36 | for lnd in layouts_grouped:
37 | if blocks[l].vtbl_recs[0].name == blocks[lnd[0]].vtbl_recs[0].name:
38 | lnd.append(blocks[l].peb_num)
39 | break
40 |
41 | else:
42 | layouts_grouped.append([blocks[l].peb_num])
43 |
44 | return layouts_grouped
45 |
46 |
47 | def associate_blocks(blocks, layout_pairs, start_peb_num):
48 | """Group block indexes with appropriate layout pairs
49 |
50 | Arguments:
51 | List:blocks -- List of block objects
52 | List:layout_pairs -- List of grouped layout blocks
53 | Int:start_peb_num -- Number of the PEB to start from.
54 |
55 | Returns:
56 | List -- Layout block pairs grouped with associated block ranges.
57 | """
58 | seq_blocks = []
59 | for layout_pair in layout_pairs:
60 | seq_blocks = sort.by_image_seq(blocks, blocks[layout_pair[0]].ec_hdr.image_seq)
61 |
62 | layout_pair.append(seq_blocks)
63 |
64 | return layout_pairs
65 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/block/sort.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | def list_by_list(blist, slist):
21 | """Sort list of block indexes, by another list.
22 |
23 | Argument:
24 | List:blist -- List of block indexes.
25 | List:slist -- Secondary list of blocks.
26 |
27 | Returns:
28 | List -- List of block indexes matching slist from blist.
29 | """
30 | slist_blocks = []
31 | for block in blist:
32 | if block in slist:
33 | slist_blocks.append(block)
34 |
35 | return slist_blocks
36 |
37 | def by_image_seq(blocks, image_seq):
38 | """Sort blocks by provided image_seq number.
39 |
40 | Argument:
41 | List:blocks -- List of block objects to sort.
42 | Int:image_seq -- image_seq number found in ec_hdr.
43 |
44 | Returns:
45 | List -- List of block indexes matching image_seq number.
46 | """
47 | seq_blocks = []
48 | for block in blocks:
49 | if blocks[block].ec_hdr.image_seq == image_seq:
50 | seq_blocks.append(block)
51 |
52 | return seq_blocks
53 |
54 |
55 | def by_range(blocks, block_range):
56 | """Sort blocks by Logical Erase Block number.
57 |
58 | Arguments:
59 | List:blocks -- List of block objects to sort.
60 | List:block_range -- range[0] = start number, range[1] = length
61 |
62 | Returns:
63 | List -- Indexes of blocks sorted by LEB.
64 | """
65 | peb_range = range(block_range[0],block_range[1])
66 | return [i for i in blocks if i in peb_range]
67 |
68 |
69 | def by_leb(blocks):
70 | """Sort blocks by Logical Erase Block number.
71 |
72 | Arguments:
73 | List:blocks -- List of block objects to sort.
74 |
75 | Returns:
76 | List -- Indexes of blocks sorted by LEB.
77 | """
78 | slist_len = len(blocks)
79 | slist = ['x'] * slist_len
80 |
81 | for block in blocks:
82 | if blocks[block].leb_num >= slist_len:
83 | add_elements = blocks[block].leb_num - slist_len + 1
84 | slist += (['x'] * add_elements)
85 | slist_len = len(slist)
86 |
87 | slist[blocks[block].leb_num] = block
88 | return slist
89 | return sorted(blocks.iterkeys(), key=lambda x: blocks[x].leb_num)
90 |
91 |
92 | def by_vol_id(blocks, slist=None):
93 | """Sort blocks by volume id
94 |
95 | Arguments:
96 | Obj:blocks -- List of block objects.
97 | List:slist -- (optional) List of block indexes.
98 |
99 | Return:
100 | Dict -- blocks grouped in lists with dict key as volume id.
101 | """
102 |
103 | vol_blocks = {}
104 |
105 | # sort block by volume
106 | # not reliable with multiple partitions (fifo)
107 |
108 | for i in blocks:
109 | if slist and i not in slist:
110 | continue
111 | elif not blocks[i].is_valid:
112 | continue
113 |
114 | if blocks[i].vid_hdr.vol_id not in vol_blocks:
115 | vol_blocks[blocks[i].vid_hdr.vol_id] = []
116 |
117 | vol_blocks[blocks[i].vid_hdr.vol_id].append(blocks[i].peb_num)
118 |
119 | return vol_blocks
120 |
121 |
122 | def clean_bad(blocks, slist=None):
123 | """Remove blocks from list with errors
124 |
125 | Arguments:
126 | Obj:blocks -- List of block objects.
127 | List:slist -- (optional) List of block indexes.
128 |
129 | Return:
130 | List -- Of error free block objects.
131 | """
132 |
133 | clean_blocks = []
134 |
135 | for i in range(0, len(blocks)):
136 | if slist and i not in slist:
137 | continue
138 |
139 | if blocks[i].is_valid:
140 | clean_blocks.append(i)
141 |
142 | return clean_blocks
143 |
144 |
145 | def by_type(blocks, slist=None):
146 | """Sort blocks into layout, internal volume, data or unknown
147 |
148 | Arguments:
149 | Obj:blocks -- List of block objects.
150 | List:slist -- (optional) List of block indexes.
151 |
152 | Returns:
153 | List:layout -- List of block indexes of blocks containing the
154 | volume table records.
155 | List:data -- List of block indexes containing filesystem data.
156 | List:int_vol -- List of block indexes containing volume ids
157 | greater than UBI_INTERNAL_VOL_START that are not
158 | layout volumes.
159 | List:unknown -- List of block indexes of blocks that failed validation
160 | of crc in ed_hdr or vid_hdr.
161 | """
162 |
163 | layout = []
164 | data = []
165 | int_vol = []
166 | unknown = []
167 |
168 | for i in blocks:
169 | if slist and i not in slist:
170 | continue
171 |
172 | if blocks[i].is_vtbl and blocks[i].is_valid:
173 | layout.append(i)
174 |
175 | elif blocks[i].is_internal_vol and blocks[i].is_valid:
176 | int_vol.append(i)
177 |
178 | elif blocks[i].is_valid:
179 | data.append(i)
180 |
181 | else:
182 | unknown.append(i)
183 |
184 | return layout, data, int_vol, unknown
185 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/defines.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | #############################################################
4 | # Adapted in part from linux-source-3.2/drivers/mtd/ubi/ubi-media.h
5 | # for use in Python.
6 | # Oct. 2013 by Jason Pruitt
7 | #
8 | # Original copyright notice.
9 | # --------------------------
10 | #
11 | # Copyright (c) International Business Machines Corp., 2006
12 | #
13 | # This program is free software; you can redistribute it and/or modify
14 | # it under the terms of the GNU General Public License as published by
15 | # the Free Software Foundation; either version 2 of the License, or
16 | # (at your option) any later version.
17 | #
18 | # This program is distributed in the hope that it will be useful,
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
21 | # the GNU General Public License for more details.
22 | #
23 | # You should have received a copy of the GNU General Public License
24 | # along with this program; if not, write to the Free Software
25 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 | #
27 | # Authors: Artem Bityutskiy (Битюцкий Артём)
28 | # Thomas Gleixner
29 | # Frank Haverkamp
30 | # Oliver Lohmann
31 | # Andreas Arnez
32 | #
33 | #############################################################
34 |
35 | import struct
36 | # Initial CRC32 checksum value.
37 | UBI_CRC32_INIT = 4294967295 #0xFFFFFFFF
38 |
39 | # Max number of volumes allowed.
40 | UBI_MAX_VOLUMES = 128
41 |
42 | # Internal Volume ID start.
43 | UBI_INTERNAL_VOL_START = 2147479551
44 |
45 | # Error Count header.
46 | UBI_EC_HDR_MAGIC = '\x55\x42\x49\x23' # UBI#
47 | EC_HDR_FORMAT = '>4sB3sQIII32sI'
48 | EC_HDR_FIELDS = ['magic', # Magic string UBI#
49 | 'version', # UBI version meant to accept this image.
50 | 'padding', # Reserved for future, zeros.
51 | 'ec', # Erase counter
52 | 'vid_hdr_offset', # Where the VID header starts.
53 | 'data_offset', # Where user data starts.
54 | 'image_seq', # Image sequence number
55 | 'padding2', # Reserved for future, zeros.
56 | 'hdr_crc'] # EC header crc32 checksum.
57 |
58 |
59 | UBI_EC_HDR_SZ = struct.calcsize(EC_HDR_FORMAT) # 64
60 |
61 | # Volume ID header.
62 | UBI_VID_HDR_MAGIC ='\x55\x42\x49\x21' # UBI!
63 | VID_HDR_FORMAT = '>4sBBBBII4sIIII4sQ12sI'
64 | VID_HDR_FIELDS = ['magic', # Magic string UBI!
65 | 'version', # UBI version meant to accept this image.
66 | 'vol_type', # Volume type, Dynamic/Static
67 | 'copy_flag', # If this is a copied PEB b/c of wear leveling.
68 | 'compat', # Compatibility of this volume UBI_COMPAT_*
69 | 'vol_id', # ID of this volume.
70 | 'lnum', # LEB number.
71 | 'padding', # Reserved for future, zeros.
72 | 'data_size', # How many bytes of data this contains.
73 | # Used for static types only.
74 | 'used_ebs', # Total num of used LEBs in this volume.
75 | 'data_pad', # How many bytes at end of LEB are not used.
76 | 'data_crc', # CRC32 checksum of data, static type only.
77 | 'padding2', # Reserved for future, zeros.
78 | 'sqnum', # Sequence number.
79 | 'padding3', # Reserved for future, zeros.
80 | 'hdr_crc'] # VID header CRC32 checksum.
81 |
82 |
83 | UBI_VID_HDR_SZ = struct.calcsize(VID_HDR_FORMAT) # 64
84 |
85 | # Volume table records.
86 | VTBL_REC_FORMAT = '>IIIBBH128sB23sI'
87 | VTBL_REC_FIELDS = ['reserved_pebs', # How many PEBs reserved for this volume.
88 | 'alignment', # Volume alignment.
89 | 'data_pad', # Number of unused bytes at end of PEB.
90 | 'vol_type', # Volume type, static/dynamic.
91 | 'upd_marker', # If vol update started but not finished.
92 | 'name_len', # Length of name.
93 | 'name', # Volume name.
94 | 'flags', # Volume flags
95 | 'padding', # Reserved for future, zeros.
96 | 'crc'] # Vol record CRC32 checksum.
97 |
98 |
99 | UBI_VTBL_REC_SZ = struct.calcsize(VTBL_REC_FORMAT) # 172
100 |
101 | # Volume Identifier Header
102 | UBI_VID_DYNAMIC = 1 # Volume can be resized.
103 | UBI_VID_STATIC = 2 # Volume can not be resized.
104 | PRINT_VOL_TYPE_LIST = [0, 'dynamic', 'static']
105 |
106 | # Volume table record
107 | UBI_VTBL_AUTORESIZE_FLG = 1
108 |
109 | UBI_COMPAT_DELETE = 1 # Delete this internal volume before anything written.
110 | UBI_COMPAT_RO = 2 # Attach this device in read-only mode.
111 | UBI_COMPAT_PRESERVE = 4 # Preserve this internal volume - touch nothing.
112 | UBI_COMPAT_REJECT = 5 # Reject this UBI image
113 | PRINT_COMPAT_LIST = [0, 'Delete', 'Read Only', 0, 'Preserve', 'Reject']
114 |
115 | # File chunk size for reads.
116 | FILE_CHUNK_SZ = 5 * 1024 * 1024
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/display.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | from ubi.defines import PRINT_COMPAT_LIST, PRINT_VOL_TYPE_LIST, UBI_VTBL_AUTORESIZE_FLG
21 |
22 | def ubi(ubi, tab=''):
23 | print '%sUBI File' % (tab)
24 | print '%s---------------------' % (tab)
25 | print '\t%sMin I/O: %s' % (tab, ubi.min_io_size)
26 | print '\t%sLEB Size: %s' % (tab, ubi.leb_size)
27 | print '\t%sPEB Size: %s' % (tab, ubi.peb_size)
28 | print '\t%sTotal Block Count: %s' % (tab, ubi.block_count)
29 | print '\t%sData Block Count: %s' % (tab, len(ubi.data_blocks_list))
30 | print '\t%sLayout Block Count: %s' % (tab, len(ubi.layout_blocks_list))
31 | print '\t%sInternal Volume Block Count: %s' % (tab, len(ubi.int_vol_blocks_list))
32 | print '\t%sUnknown Block Count: %s' % (tab, len(ubi.unknown_blocks_list))
33 | print '\t%sFirst UBI PEB Number: %s' % (tab, ubi.first_peb_num)
34 |
35 |
36 | def image(image, tab=''):
37 | print '%s%s' % (tab, image)
38 | print '%s---------------------' % (tab)
39 | print '\t%sImage Sequence Num: %s' % (tab, image.image_seq)
40 | for volume in image.volumes:
41 | print '\t%sVolume Name:%s' % (tab, volume)
42 | print '\t%sPEB Range: %s - %s' % (tab, image.peb_range[0], image.peb_range[1])
43 |
44 |
45 | def volume(volume, tab=''):
46 | print '%s%s' % (tab, volume)
47 | print '%s---------------------' % (tab)
48 | print '\t%sVol ID: %s' % (tab, volume.vol_id)
49 | print '\t%sName: %s' % (tab, volume.name)
50 | print '\t%sBlock Count: %s' % (tab, volume.block_count)
51 |
52 | print '\n'
53 | print '\t%sVolume Record' % (tab)
54 | print '\t%s---------------------' % (tab)
55 | vol_rec(volume.vol_rec, '\t\t%s' % tab)
56 |
57 | print '\n'
58 |
59 |
60 | def block(block, tab='\t'):
61 | print '%s%s' % (tab, block)
62 | print '%s---------------------' % (tab)
63 | print '\t%sFile Offset: %s' % (tab, block.file_offset)
64 | print '\t%sPEB #: %s' % (tab, block.peb_num)
65 | print '\t%sLEB #: %s' % (tab, block.leb_num)
66 | print '\t%sBlock Size: %s' % (tab, block.size)
67 | print '\t%sInternal Volume: %s' % (tab, block.is_internal_vol)
68 | print '\t%sIs Volume Table: %s' % (tab, block.is_vtbl)
69 | print '\t%sIs Valid: %s' % (tab, block.is_valid)
70 |
71 | if not block.ec_hdr.errors:
72 | print '\n'
73 | print '\t%sErase Count Header' % (tab)
74 | print '\t%s---------------------' % (tab)
75 | ec_hdr(block.ec_hdr, '\t\t%s' % tab)
76 |
77 | if block.vid_hdr and not block.vid_hdr.errors:
78 | print '\n'
79 | print '\t%sVID Header Header' % (tab)
80 | print '\t%s---------------------' % (tab)
81 | vid_hdr(block.vid_hdr, '\t\t%s' % tab)
82 |
83 | if block.vtbl_recs:
84 | print '\n'
85 | print '\t%sVolume Records' % (tab)
86 | print '\t%s---------------------' % (tab)
87 | for vol in block.vtbl_recs:
88 | vol_rec(vol, '\t\t%s' % tab)
89 |
90 | print '\n'
91 |
92 |
93 | def ec_hdr(ec_hdr, tab=''):
94 | for key, value in ec_hdr:
95 | if key == 'errors':
96 | value = ','.join(value)
97 |
98 | print '%s%s: %r' % (tab, key, value)
99 |
100 |
101 | def vid_hdr(vid_hdr, tab=''):
102 | for key, value in vid_hdr:
103 | if key == 'errors':
104 | value = ','.join(value)
105 |
106 | elif key == 'compat':
107 | if value in PRINT_COMPAT_LIST:
108 | value = PRINT_COMPAT_LIST[value]
109 | else:
110 | value = -1
111 |
112 | elif key == 'vol_type':
113 | if value < len(PRINT_VOL_TYPE_LIST):
114 | value = PRINT_VOL_TYPE_LIST[value]
115 | else:
116 | value = -1
117 |
118 | print '%s%s: %s' % (tab, key, value)
119 |
120 |
121 | def vol_rec(vol_rec, tab=''):
122 | for key, value in vol_rec:
123 | if key == 'errors':
124 | value = ','.join(value)
125 | elif key == 'vol_type':
126 | if value < len(PRINT_VOL_TYPE_LIST):
127 | value = PRINT_VOL_TYPE_LIST[value]
128 | else:
129 | value = -1
130 | elif key == 'flags' and value == UBI_VTBL_AUTORESIZE_FLG:
131 | value = 'autoresize'
132 | elif key == 'name':
133 | value = value.strip('\x00')
134 |
135 | print '%s%s: %s' % (tab, key, value)
136 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/headers/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import struct
21 | from ubi.defines import *
22 | from ubi.headers import errors
23 |
24 | class ec_hdr(object):
25 | def __init__(self, buf):
26 | fields = dict(zip(EC_HDR_FIELDS, struct.unpack(EC_HDR_FORMAT,buf)))
27 | for key in fields:
28 | setattr(self, key, fields[key])
29 | setattr(self, 'errors', [])
30 |
31 | def __repr__(self):
32 | return 'Error Count Header'
33 |
34 | def __iter__(self):
35 | for key in dir(self):
36 | if not key.startswith('_'):
37 | yield key, getattr(self, key)
38 |
39 |
40 | class vid_hdr(object):
41 | def __init__(self, buf):
42 | fields = dict(zip(VID_HDR_FIELDS, struct.unpack(VID_HDR_FORMAT,buf)))
43 | for key in fields:
44 | setattr(self, key, fields[key])
45 | setattr(self, 'errors', [])
46 |
47 | def __iter__(self):
48 | for key in dir(self):
49 | if not key.startswith('_'):
50 | yield key, getattr(self, key)
51 |
52 | def __repr__(self):
53 | return 'VID Header'
54 |
55 |
56 | class vtbl_rec(object):
57 | def __init__(self, buf):
58 | fields = dict(zip(VTBL_REC_FIELDS, struct.unpack(VTBL_REC_FORMAT,buf)))
59 | for key in fields:
60 | setattr(self, key, fields[key])
61 | setattr(self, 'errors', [])
62 | setattr(self, 'rec_index', -1)
63 |
64 | def __repr__(self):
65 | return 'Volume Table Record: %s' % getattr(self, 'name')
66 |
67 | def __iter__(self):
68 | for key in dir(self):
69 | if not key.startswith('_'):
70 | yield key, getattr(self, key)
71 |
72 |
73 | def extract_ec_hdr(buf):
74 | ec_hdr_buf = buf
75 | ec_hdr_ret = ec_hdr(ec_hdr_buf)
76 |
77 | errors.ec_hdr(ec_hdr_ret, ec_hdr_buf)
78 | return ec_hdr_ret
79 |
80 |
81 | def extract_vid_hdr(buf):
82 | vid_hdr_buf = buf
83 | vid_hdr_ret = vid_hdr(vid_hdr_buf)
84 |
85 | errors.vid_hdr(vid_hdr_ret, vid_hdr_buf)
86 |
87 | return vid_hdr_ret
88 |
89 |
90 | def extract_vtbl_rec(buf):
91 | data_buf = buf
92 | vtbl_recs = []
93 | vtbl_rec_ret = ''
94 |
95 | for i in range(0, UBI_MAX_VOLUMES):
96 | offset = i*UBI_VTBL_REC_SZ
97 | vtbl_rec_buf = data_buf[offset:offset+UBI_VTBL_REC_SZ]
98 |
99 | if len(vtbl_rec_buf) == UBI_VTBL_REC_SZ:
100 | vtbl_rec_ret = vtbl_rec(vtbl_rec_buf)
101 | errors.vtbl_rec(vtbl_rec_ret, vtbl_rec_buf)
102 |
103 | if len(vtbl_rec_ret.errors) == 0:
104 | vtbl_rec_ret.rec_index = i
105 | vtbl_recs.append(vtbl_rec_ret)
106 |
107 | return vtbl_recs
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/headers/errors.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 | from zlib import crc32
20 | from ubi.defines import *
21 |
22 | def ec_hdr(ec_hdr, buf):
23 | if ec_hdr.hdr_crc != (~crc32(buf[:-4]) & 0xFFFFFFFF):
24 | ec_hdr.errors.append('crc')
25 |
26 | return ec_hdr
27 |
28 | def vid_hdr(vid_hdr, buf):
29 | vid_hdr.errors = []
30 |
31 | if vid_hdr.hdr_crc != (~crc32(buf[:-4]) & 0xFFFFFFFF):
32 | vid_hdr.errors.append('crc')
33 |
34 | return vid_hdr
35 |
36 | def vtbl_rec(vtbl_rec, buf):
37 | likely_vtbl = True
38 |
39 | if vtbl_rec.name_len != len(vtbl_rec.name.strip('\x00')):
40 | likely_vtbl = False
41 |
42 | elif vtbl_rec.vol_type not in [1,2]:
43 | likely_vtbl = False
44 |
45 | if vtbl_rec.crc != (~crc32(buf[:-4]) & 0xFFFFFFFF):
46 | vtbl_rec.errors.append('crc')
47 |
48 | if not likely_vtbl:
49 | vtbl_rec.errors = ['False']
50 |
51 | return vtbl_rec
52 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/image.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 | from ubi import display
20 | from ubi.volume import get_volumes
21 | from ubi.block import get_blocks_in_list
22 |
23 | class description(object):
24 | def __init__(self, blocks, layout_info):
25 | self._image_seq = blocks[layout_info[0]].ec_hdr.image_seq
26 | self.vid_hdr_offset = blocks[layout_info[0]].ec_hdr.vid_hdr_offset
27 | self.version = blocks[layout_info[0]].ec_hdr.version
28 | self._start_peb = min(layout_info[2])
29 | self._end_peb = max(layout_info[2])
30 | self._volumes = get_volumes(blocks, layout_info)
31 |
32 |
33 | def __repr__(self):
34 | return 'Image: %s' % (self.image_seq)
35 |
36 |
37 | def get_blocks(self, blocks):
38 | return get_blocks_in_list(blocks, range(self._start_peb, self._end_peb+1))
39 |
40 |
41 | def _get_peb_range(self):
42 | return [self._start_peb, self._end_peb]
43 | peb_range = property(_get_peb_range)
44 |
45 |
46 |
47 | def _get_image_seq(self):
48 | return self._image_seq
49 | image_seq = property(_get_image_seq)
50 |
51 |
52 | def _get_volumes(self):
53 | return self._volumes
54 | volumes = property(_get_volumes)
55 |
56 |
57 | def display(self, tab=''):
58 | display.image(self, tab)
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi/volume/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | from ubi import display
21 | from ubi.block import sort, get_blocks_in_list
22 |
23 | class description(object):
24 | """UBI Volume object
25 |
26 | Attributes:
27 | Int:vol_id -- Volume ID
28 | Str:vol_name -- Name of volume.
29 | Obj:vol_rec -- Volume record object
30 | Int:block_count -- Number of block associated with volume.
31 |
32 | Methods:
33 | display(tab) -- Print Volume information
34 | Str:tab -- (optional) '\t' to preface lines with.
35 |
36 | get_blocks(blocks) -- Returns list of block objects tied to this volume
37 |
38 | Volume object is basically a list of block indexes and some metadata
39 | describing a volume found in a UBI image.
40 | """
41 | def __init__(self, vol_id, vol_rec, block_list):
42 | self._vol_id = vol_id
43 | self._vol_rec = vol_rec
44 | self._name = self._vol_rec.name
45 | self._block_list = block_list
46 |
47 | def __repr__(self):
48 | return 'Volume: %s' % (self.name)
49 |
50 |
51 | def _get_name(self):
52 | return self._name
53 | name = property(_get_name)
54 |
55 |
56 | def _get_vol_id(self):
57 | return self._vol_id
58 | vol_id = property(_get_vol_id)
59 |
60 |
61 | def _get_block_count(self):
62 | return len(self._block_list)
63 | block_count = property(_get_block_count)
64 |
65 |
66 | def _get_vol_rec(self):
67 | return self._vol_rec
68 | vol_rec = property(_get_vol_rec)
69 |
70 |
71 | def _get_block_list(self):
72 | return self._block_list
73 | block_list = property(_get_block_list)
74 |
75 |
76 | def get_blocks(self, blocks):
77 | return get_blocks_in_list(blocks, self._block_list)
78 |
79 |
80 | def display(self, tab=''):
81 | display.volume(self, tab)
82 |
83 | def reader(self, ubi):
84 | last_leb = 0
85 | for block in sort.by_leb(self.get_blocks(ubi.blocks)):
86 | if block == 'x':
87 | #while 0 != (ubi.blocks[block].leb_num - last_leb):
88 | last_leb += 1
89 | yield '\xff'*ubi.leb_size
90 | else:
91 | last_leb += 1
92 | yield ubi.file.read_block_data(ubi.blocks[block])
93 |
94 |
95 | def get_volumes(blocks, layout_info):
96 | """Get a list of UBI volume objects from list of blocks
97 |
98 | Arguments:
99 | List:blocks -- List of layout block objects
100 | List:layout_info -- Layout info (indexes of layout blocks and
101 | associated data blocks.)
102 |
103 | Returns:
104 | Dict -- Of Volume objects by volume name, including any
105 | relevant blocks.
106 | """
107 | volumes = {}
108 |
109 | vol_blocks_lists = sort.by_vol_id(blocks, layout_info[2])
110 |
111 | for vol_rec in blocks[layout_info[0]].vtbl_recs:
112 | vol_name = vol_rec.name.strip('\x00')
113 | if vol_rec.rec_index not in vol_blocks_lists:
114 | vol_blocks_lists[vol_rec.rec_index] = []
115 | volumes[vol_name] = description(vol_rec.rec_index, vol_rec, vol_blocks_lists[vol_rec.rec_index])
116 |
117 | return volumes
118 |
119 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi_extract.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 | import sys
22 | import argparse
23 |
24 | from ui.common import output_dir
25 | from ubi import ubi, get_peb_size
26 | from ubi_io import ubi_file
27 |
28 |
29 | def extract_ubi(ubi, out_path):
30 | for image in ubi.images:
31 | img_path = os.path.join(out_path, 'img-%s.ubi' % image.image_seq)
32 | if os.path.exists(img_path):
33 | print 'File exists skipping: %s' % img_path
34 | else:
35 | print 'Writing to: %s' % img_path
36 | f = open(img_path, 'wb')
37 | # iterate through image blocks
38 | for block in image.get_blocks(ubi.blocks):
39 | if ubi.blocks[block].is_valid:
40 | # Write whole block to file
41 | f.write(ubi.file.read_block(ubi.blocks[block]))
42 |
43 |
44 | if __name__ == '__main__':
45 | description = 'Extract UBI image from file. Works with binary dumps containing multiple images if image_seq is not the same.'
46 | usage = 'ubi_extract.py [options] filepath'
47 | parser = argparse.ArgumentParser(usage=usage, description=description)
48 |
49 | parser.add_argument('-p', '--peb-size', type=int, dest='block_size',
50 | help='Specify PEB size.')
51 |
52 | parser.add_argument('-o', '--output-dir', dest='output_path',
53 | help='Specify output directory path.')
54 |
55 | parser.add_argument('filepath', help='File to extract UBI contents of.')
56 |
57 | if len(sys.argv) == 1:
58 | parser.print_help()
59 | sys.exit()
60 |
61 | args = parser.parse_args()
62 |
63 | if args.filepath:
64 | path = args.filepath
65 | if not os.path.exists(path):
66 | parser.error("filepath doesn't exist.")
67 |
68 | if args.output_path:
69 | output_path = args.output_path
70 | else:
71 | img_name = os.path.splitext(os.path.basename(path))[0]
72 | output_path = os.path.join(output_dir, img_name)
73 |
74 | # Determine block size if not provided
75 | if args.block_size:
76 | block_size = args.block_size
77 | else:
78 | block_size = get_peb_size(path)
79 |
80 | if not os.path.exists(output_path):
81 | os.makedirs(output_path)
82 |
83 |
84 | # Create file object.
85 | ufile = ubi_file(path, block_size)
86 | # Create UBI object
87 | uubi = ubi(ufile)
88 | # Run extract UBI.
89 | extract_ubi(uubi, output_path)
90 | sys.exit()
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi_extract_files.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 | import os
20 | import sys
21 | import argparse
22 |
23 | from ubi import ubi, get_peb_size
24 | from ubifs import ubifs
25 | from ubi_io import ubi_file, leb_virtual_file
26 | from ui.common import extract_files, output_dir
27 |
28 | if __name__ == '__main__':
29 | description = 'Extract contents of UBI image.'
30 | usage = 'ubi_extract_files.py [options] filepath'
31 | parser = argparse.ArgumentParser(usage=usage, description=description)
32 |
33 | parser.add_argument('-l', '--log-file', dest='logpath',
34 | help='Log output to file output/LOGPATH. (default: ubifs_output.log)')
35 |
36 | parser.add_argument('-k', '--keep-permissions', action='store_true', dest='permissions',
37 | help='Maintain file permissions, requires running as root. (default: False)')
38 |
39 | parser.add_argument('-q', '--quiet', action='store_true', dest='quiet',
40 | help='Suppress warnings and non-fatal errors. (default: False)')
41 |
42 | parser.add_argument('-p', '--peb-size', type=int, dest='block_size',
43 | help='Specify PEB size.')
44 |
45 | parser.add_argument('-o', '--output-dir', dest='output_path',
46 | help='Specify output directory path.')
47 |
48 | parser.add_argument('filepath', help='File to extract contents of.')
49 |
50 | if len(sys.argv) == 1:
51 | parser.print_help()
52 | sys.exit()
53 |
54 | args = parser.parse_args()
55 |
56 | if args.filepath:
57 | path = args.filepath
58 | if not os.path.exists(path):
59 | parser.error("File path doesn't exist.")
60 |
61 | if args.output_path:
62 | output_path = args.output_path
63 | else:
64 | img_name = os.path.splitext(os.path.basename(path))[0]
65 | output_path = os.path.join(output_dir, img_name)
66 |
67 | if args.logpath:
68 | log_to_file = True
69 | log_file = args.logpath
70 | else:
71 | log_to_file = None
72 | log_file = None
73 |
74 | # Determine block size if not provided
75 | if args.block_size:
76 | block_size = args.block_size
77 | else:
78 | block_size = get_peb_size(path)
79 |
80 | perms = args.permissions
81 | quiet = args.quiet
82 |
83 | if not os.path.exists(output_path):
84 | os.makedirs(output_path)
85 |
86 | # Create file object.
87 | ufile = ubi_file(path, block_size)
88 | # Create UBI object
89 | uubi = ubi(ufile)
90 |
91 | # Traverse items found extracting files.
92 | for image in uubi.images:
93 | for volume in image.volumes:
94 | vol_out_path = os.path.join(output_path, volume)
95 |
96 | if not os.path.exists(vol_out_path):
97 | os.makedirs(vol_out_path)
98 | elif os.listdir(vol_out_path):
99 | parser.error('Volume output directory is not empty. %s' % vol_out_path)
100 |
101 | # Create file object backed by UBI blocks.
102 | ufsfile = leb_virtual_file(uubi, image.volumes[volume])
103 | # Create UBIFS object
104 | uubifs = ubifs(ufsfile)
105 | # Set up logging.
106 | uubifs.log.log_file = log_file
107 | uubifs.log.log_to_file = log_to_file
108 | uubifs.log.quiet = quiet
109 | # Run extract all files.
110 | print 'Writing to: %s' % vol_out_path
111 | extract_files(uubifs, vol_out_path, perms)
112 |
113 | sys.exit(0)
114 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi_extract_ubifs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 | import sys
22 | import argparse
23 |
24 | from ubi import ubi, get_peb_size
25 | from ubi_io import ubi_file
26 | from ui.common import output_dir
27 |
28 |
29 | def extract_ubifs(ubi, output_path):
30 | for image in ubi.images:
31 | for volume in image.volumes:
32 | vol_path = os.path.join(output_path, 'img-%s_vol-%s.ubifs' % (image.image_seq, volume))
33 | if os.path.exists(vol_path):
34 | print 'File exists skipping: %s' % vol_path
35 | else:
36 | print 'Writing to: %s' % vol_path
37 | f = open(vol_path, 'wb')
38 | # Get UBIFS image from volume.
39 | for block in image.volumes[volume].reader(ubi):
40 | f.write(block)
41 |
42 | if __name__ == '__main__':
43 | description = """Extract UBIFS image from UBI image.
44 | Works with binary dumps containing multiple images if image_seq is not the same."""
45 | usage = 'ubi_extract_ubifs.py [options] filepath'
46 | parser = argparse.ArgumentParser(usage=usage, description=description)
47 |
48 | parser.add_argument('-p', '--peb-size', type=int, dest='block_size',
49 | help='Specify PEB size.')
50 |
51 | parser.add_argument('-o', '--output-dir', dest='output_path',
52 | help='Specify output directory path.')
53 |
54 | parser.add_argument('filepath', help='File to extract UBIFS contents of.')
55 |
56 | if len(sys.argv) == 1:
57 | parser.print_help()
58 | sys.exit()
59 |
60 | args = parser.parse_args()
61 |
62 | if args.filepath:
63 | path = args.filepath
64 | if not os.path.exists(path):
65 | parser.error("File path doesn't exist.")
66 |
67 | if args.output_path:
68 | output_path = args.output_path
69 | else:
70 | output_path = output_dir
71 |
72 | # Determine block size if not provided
73 | if args.block_size:
74 | block_size = args.block_size
75 | else:
76 | block_size = get_peb_size(path)
77 |
78 | if not os.path.exists(output_path):
79 | os.makedirs(output_path)
80 |
81 | # Create file object
82 | ufile = ubi_file(path, block_size)
83 | # Create UBI object
84 | uubi = ubi(ufile)
85 | # Run extract UBIFS
86 | extract_ubifs(uubi, output_path)
87 | sys.exit(0)
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi_info.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 | import sys
22 | import argparse
23 |
24 | from ubi_io import ubi_file
25 | from ubi import ubi, get_peb_size
26 |
27 | def print_info(ubi, num=None):
28 | # Roll through all Objects pretty contained information
29 | if num is None:
30 | # Print main UBI Object attributes
31 | ubi.display()
32 | print '\n'
33 | # Loop through images found
34 | for image in ubi.images:
35 | # Print image Object attributes
36 | image.display('\t')
37 | print '\n'
38 | # Loop through volumes in image.
39 | for volume in image.volumes:
40 | # Print volume attribtures and UBI headers
41 | image.volumes[volume].display('\t\t')
42 |
43 | else:
44 | try:
45 | # Print Block Object with PEB #
46 | # If not in index, show first PEB of UBI data
47 | ubi.blocks[num].display()
48 |
49 | except Exception, e:
50 | print e
51 |
52 | print 'Block out of range, printing first UBI block'
53 | ubi.blocks[ubi.first_peb_num].display()
54 | return
55 |
56 |
57 | if __name__ == '__main__':
58 | description = 'Show info about provided UBI image.'
59 | usage = 'ubi_info.py [options] filepath'
60 | parser = argparse.ArgumentParser(usage=usage, description=description)
61 |
62 | parser.add_argument('-b', '--block-num', type=int, dest="block_num",
63 | help='Block Number: Show information about this PEB. Shows first one if doesn\'t exist')
64 |
65 | parser.add_argument('-p', '--peb-size', type=int, dest='block_size',
66 | help='Specify PEB size.')
67 |
68 | parser.add_argument('filepath', help='File to get info from.')
69 |
70 | if len(sys.argv) == 1:
71 | parser.print_help()
72 | sys.exit()
73 |
74 | args = parser.parse_args()
75 |
76 | if args.filepath:
77 | path = args.filepath
78 | if not os.path.exists(path):
79 | parser.error("filepath doesn't exist.")
80 |
81 | block_num = args.block_num
82 |
83 | # Determine block size if not provided
84 | if args.block_size:
85 | block_size = args.block_size
86 | else:
87 | block_size = get_peb_size(path)
88 |
89 | # Create file object
90 | ufile = ubi_file(path, block_size)
91 | # Create UBI object
92 | uubi = ubi(ufile)
93 | # Print info
94 | print_info(uubi, block_num)
95 | sys.exit()
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi_io/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubi_io
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | from ubi.block import sort
21 |
22 | class ubi_file(object):
23 | """UBI image file object
24 |
25 | Arguments:
26 | Str:path -- Path to file to parse
27 | Int:block_size -- Erase block size of NAND in bytes.
28 | Int:start_offset -- (optional) Where to start looking in the file for
29 | UBI data.
30 | Int:end_offset -- (optional) Where to stop looking in the file.
31 |
32 | Methods:
33 | seek -- Put file head to specified byte offset.
34 | Int:offset
35 | read -- Read specified bytes from file handle.
36 | Int:size
37 | tell -- Returns byte offset of current file location.
38 | read_block -- Returns complete PEB data of provided block
39 | description.
40 | Obj:block
41 | read_block_data -- Returns LEB data only from provided block.
42 | Obj:block
43 | reader -- Generator that returns data from file.
44 | reset -- Reset file position to start_offset
45 |
46 | Handles all the actual file interactions, read, seek,
47 | extract blocks, etc.
48 | """
49 |
50 | def __init__(self, path, block_size, start_offset=0, end_offset=None):
51 | self._fhandle = open(path, 'rb')
52 | self._start_offset = start_offset
53 |
54 | if end_offset:
55 | self._end_offset = end_offset
56 | else:
57 | self._fhandle.seek(0,2)
58 | self._end_offset = self.tell()
59 |
60 | self._block_size = block_size
61 |
62 | if start_offset >= self._end_offset:
63 | raise Exception('Start offset larger than file size!')
64 |
65 | self._fhandle.seek(self._start_offset)
66 |
67 |
68 | def _set_start(self, i):
69 | self._start_offset = i
70 | def _get_start(self):
71 | return self._start_offset
72 | start_offset = property(_get_start, _set_start)
73 |
74 |
75 | def _get_end(self):
76 | return self._end_offset
77 | end_offset = property(_get_end)
78 |
79 |
80 | def _get_block_size(self):
81 | return self._block_size
82 | block_size = property(_get_block_size)
83 |
84 |
85 | def seek(self, offset):
86 | self._fhandle.seek(offset)
87 |
88 |
89 | def read(self, size):
90 | return self._fhandle.read(size)
91 |
92 |
93 | def tell(self):
94 | return self._fhandle.tell()
95 |
96 |
97 | def reset(self):
98 | self._fhandle.seek(self.start_offset)
99 |
100 |
101 | def reader(self):
102 | self.reset()
103 | while True:
104 | cur_loc = self._fhandle.tell()
105 | if self.end_offset and cur_loc > self.end_offset:
106 | break
107 | elif self.end_offset and self.end_offset - cur_loc < self.block_size:
108 | chunk_size = self.end_offset - cur_loc
109 | else:
110 | chunk_size = self.block_size
111 |
112 | buf = self.read(chunk_size)
113 |
114 | if not buf:
115 | break
116 | yield buf
117 |
118 |
119 | def read_block(self, block):
120 | """Read complete PEB data from file.
121 |
122 | Argument:
123 | Obj:block -- Block data is desired for.
124 | """
125 | self.seek(block.file_offset)
126 | return self._fhandle.read(block.size)
127 |
128 |
129 | def read_block_data(self, block):
130 | """Read LEB data from file
131 |
132 | Argument:
133 | Obj:block -- Block data is desired for.
134 | """
135 | self.seek(block.file_offset + block.ec_hdr.data_offset)
136 | buf = self._fhandle.read(block.size - block.ec_hdr.data_offset - block.vid_hdr.data_pad)
137 | return buf
138 |
139 |
140 | class leb_virtual_file():
141 | def __init__(self, ubi, volume):
142 | self._ubi = ubi
143 | self._volume = volume
144 | self._blocks = sort.by_leb(self._volume.get_blocks(self._ubi.blocks))
145 | self._seek = 0
146 | self.leb_data_size = len(self._blocks) * self._ubi.leb_size
147 | self._last_leb = -1
148 | self._last_buf = ''
149 |
150 |
151 | def read(self, i):
152 | buf = ''
153 | leb = int(self.tell() / self._ubi.leb_size)
154 | offset = self.tell() % self._ubi.leb_size
155 |
156 | if leb == self._last_leb:
157 | self.seek(self.tell() + i)
158 | return self._last_buf[offset:offset+i]
159 | else:
160 | buf = self._ubi.file.read_block_data(self._ubi.blocks[self._blocks[leb]])
161 | self._last_buf = buf
162 | self._last_leb = leb
163 | self.seek(self.tell() + i)
164 | return buf[offset:offset+i]
165 |
166 |
167 | def reset(self):
168 | self.seek(0)
169 |
170 |
171 | def seek(self, offset):
172 | self._seek = offset
173 |
174 |
175 | def tell(self):
176 | return self._seek
177 |
178 |
179 | def reader(self):
180 | last_leb = 0
181 | for block in self._blocks:
182 | while 0 != (self._ubi.blocks[block].leb_num - last_leb):
183 | last_leb += 1
184 | yield '\xff'*self._ubi.leb_size
185 |
186 | last_leb += 1
187 | yield self._ubi.file.read_block_data(self._ubi.blocks[block])
188 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubi_utils_info.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 | import sys
22 | import argparse
23 |
24 | from ui.common import get_ubi_params
25 | from ubi_io import ubi_file
26 | from ubi import ubi, get_peb_size
27 |
28 | def print_ubi_params(ubi):
29 | ubi_params = get_ubi_params(ubi)
30 | for img_params in ubi_params:
31 | for volume in ubi_params[img_params]:
32 | ubi_flags = ubi_params[img_params][volume]['flags']
33 | ubi_args = ubi_params[img_params][volume]['args']
34 | ini_params = ubi_params[img_params][volume]['ini']
35 | sorted_keys = sorted(ubi_params[img_params][volume]['args'])
36 |
37 | print '\nVolume %s' % volume
38 | for key in sorted_keys:
39 | if len(key)< 8:
40 | name = '%s\t' % key
41 | else:
42 | name = key
43 | print '\t%s\t%s %s' % (name, ubi_flags[key], ubi_args[key])
44 |
45 | print '\n\t#ubinize.ini#'
46 | print '\t[%s]' % ini_params['vol_name']
47 | for key in ini_params:
48 | if key != 'name':
49 | print '\t%s=%s' % (key, ini_params[key])
50 | if __name__ == '__main__':
51 | description = """Gather information from the UBI image useful for using mkfs.ubi, ubinize, ubiformat, etc. and print to screen.
52 | Some may be duplicates, be sure to check which ones apply."""
53 | usage = 'ubi_utils_info.py [options] filepath'
54 | parser = argparse.ArgumentParser(usage=usage, description=description)
55 |
56 | parser.add_argument('-p', '--peb-size', type=int, dest='block_size',
57 | help='Specify PEB size.')
58 |
59 | parser.add_argument('filepath', help='File to get info from.')
60 |
61 | if len(sys.argv) == 1:
62 | parser.print_help()
63 | sys.exit()
64 |
65 | args = parser.parse_args()
66 |
67 | if args.filepath:
68 | path = args.filepath
69 | if not os.path.exists(path):
70 | parser.error("filepath doesn't exist.")
71 |
72 | # Determine block size if not provided
73 | if args.block_size:
74 | block_size = args.block_size
75 | else:
76 | block_size = get_peb_size(path)
77 |
78 | # Create file object
79 | ufile = ubi_file(path, block_size)
80 | # Create UBI object
81 | uubi = ubi(ufile)
82 | # Print info.
83 | print_ubi_params(uubi)
84 | sys.exit()
85 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubifs/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubifs
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 | import re
20 | import struct
21 |
22 | from ubifs.defines import *
23 | from ubifs import nodes
24 | from ubifs.nodes import extract
25 | from ubifs.log import log
26 |
27 | class ubifs():
28 | """UBIFS object
29 |
30 | Arguments:
31 | Str:path -- File path to UBIFS image.
32 |
33 | Attributes:
34 | Int:leb_size -- Size of Logical Erase Blocks.
35 | Int:min_io -- Size of min I/O from vid_hdr_offset.
36 | Obj:sb_node -- Superblock node of UBIFS image LEB0
37 | Obj:mst_node -- Master Node of UBIFS image LEB1
38 | Obj:log -- Log object for errors.
39 |
40 | Methods:
41 | key_search -- Search nodes for matching key.
42 | Str:key -- Hex string representation of key.
43 | """
44 | def __init__(self, ubifs_file):
45 | self.log = log()
46 | self._file = ubifs_file
47 | self._sb_node = extract.sb_node(self, UBIFS_COMMON_HDR_SZ)
48 | self._min_io_size = self._sb_node.min_io_size
49 | self._leb_size = self._sb_node.leb_size
50 | self._mst_node = extract.mst_node(self, 1, UBIFS_COMMON_HDR_SZ)
51 | self._mst_node = extract.mst_node(self, 2, UBIFS_COMMON_HDR_SZ)
52 |
53 |
54 | def _get_file(self):
55 | return self._file
56 | file = property(_get_file)
57 |
58 |
59 | def _get_superblock(self):
60 | """ Superblock Node Object
61 |
62 | Returns:
63 | Obj:Superblock Node
64 | """
65 | return self._sb_node
66 | superblock_node = property(_get_superblock)
67 |
68 |
69 | def _get_master_node(self):
70 | """Master Node Object
71 |
72 | Returns:
73 | Obj:Master Node
74 | """
75 | return self._mst_node
76 | master_node = property(_get_master_node)
77 |
78 |
79 | def _get_master_node2(self):
80 | """Master Node Object 2
81 |
82 | Returns:
83 | Obj:Master Node
84 | """
85 | return self._mst_node
86 | master_node2 = property(_get_master_node2)
87 |
88 |
89 | def _get_leb_size(self):
90 | """LEB size of UBI blocks in file.
91 |
92 | Returns:
93 | Int -- LEB Size.
94 | """
95 | return self._leb_size
96 | leb_size = property(_get_leb_size)
97 |
98 |
99 | def _get_min_io_size(self):
100 | """Min I/O Size
101 |
102 | Returns:
103 | Int -- Min I/O Size.
104 | """
105 | return self._min_io_size
106 | min_io_size = property(_get_min_io_size)
107 |
108 |
109 | def get_leb_size(path):
110 | """Get LEB size from superblock
111 |
112 | Arguments:
113 | Str:path -- Path to file.
114 |
115 | Returns:
116 | Int -- LEB size.
117 |
118 | Searches file superblock and retrieves leb size.
119 | """
120 |
121 | f = open(path, 'rb')
122 | f.seek(0,2)
123 | file_size = f.tell()+1
124 | f.seek(0)
125 | block_size = 0
126 |
127 | for i in range(0, file_size, FILE_CHUNK_SZ):
128 | buf = f.read(FILE_CHUNK_SZ)
129 |
130 | for m in re.finditer(UBIFS_NODE_MAGIC, buf):
131 | start = m.start()
132 | chdr = nodes.common_hdr(buf[start:start+UBIFS_COMMON_HDR_SZ])
133 |
134 | if chdr and chdr.node_type == UBIFS_SB_NODE:
135 | sb_start = start + UBIFS_COMMON_HDR_SZ
136 | sb_end = sb_start + UBIFS_SB_NODE_SZ
137 |
138 | if chdr.len != len(buf[sb_start:sb_end]):
139 | f.seek(sb_start)
140 | buf = f.read(UBIFS_SB_NODE_SZ)
141 | else:
142 | buf = buf[sb_start:sb_end]
143 |
144 | sbn = nodes.sb_node(buf)
145 | block_size = sbn.leb_size
146 | f.close()
147 | return block_size
148 |
149 | f.close()
150 | return block_size
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubifs/log.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubifs
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 | import sys
22 |
23 | import ui
24 |
25 | class log():
26 | def __init__(self):
27 | self.log_to_file = False
28 | self.log_file = 'ubifs_output.log'
29 | self.exit_on_except = False
30 | self.quiet = False
31 |
32 | def _out(self, s):
33 | if not self.quiet:
34 | if self.log_to_file:
35 | with open(os.path.join(ui.common.output_dir, self.log_file), 'a') as f:
36 | f.write('%s\n' % s)
37 | f.close()
38 | else:
39 | print '%s' % s
40 |
41 | if self.exit_on_except:
42 | sys.exit()
43 |
44 | def write(self, s):
45 | self._out(s)
46 |
47 | def write_node(self, n):
48 | buf = '%s\n' % n
49 | for key, value in n:
50 | buf += '\t%s: %s\n' % (key, value)
51 | self._out(buf)
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubifs/misc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubifs
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 | import lzo
20 | import struct
21 | import zlib
22 | from ubifs.defines import *
23 |
24 | # For happy printing
25 | ino_types = ['file', 'dir','lnk','blk','chr','fifo','sock']
26 | node_types = ['ino','data','dent','xent','trun','pad','sb','mst','ref','idx','cs','orph']
27 | key_types = ['ino','data','dent','xent']
28 |
29 |
30 | def parse_key(key):
31 | """Parse node key
32 |
33 | Arguments:
34 | Str:key -- Hex string literal of node key.
35 |
36 | Returns:
37 | Int:key_type -- Type of key, data, ino, dent, etc.
38 | Int:ino_num -- Inode number.
39 | Int:khash -- Key hash.
40 | """
41 | hkey, lkey = struct.unpack('> UBIFS_S_KEY_BLOCK_BITS
44 | khash = lkey
45 |
46 | #if key_type < UBIFS_KEY_TYPES_CNT:
47 | return {'type':key_type, 'ino_num':ino_num, 'khash': khash}
48 |
49 |
50 | def decompress(ctype, unc_len, data):
51 | """Decompress data.
52 |
53 | Arguments:
54 | Int:ctype -- Compression type LZO, ZLIB (*currently unused*).
55 | Int:unc_len -- Uncompressed data lenth.
56 | Str:data -- Data to be uncompessed.
57 |
58 | Returns:
59 | Uncompressed Data.
60 | """
61 | if ctype == UBIFS_COMPR_LZO:
62 | return lzo.decompress(''.join(('\xf0', struct.pack('>I', unc_len), data)))
63 | elif ctype == UBIFS_COMPR_ZLIB:
64 | return zlib.decompress(data, -11)
65 | else:
66 | return data
67 |
68 |
69 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubifs/nodes/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubifs
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import struct
21 | from ubifs.defines import *
22 | from ubifs.misc import parse_key
23 |
24 | class common_hdr(object):
25 | def __init__(self, buf):
26 | fields = dict(zip(UBIFS_COMMON_HDR_FIELDS, struct.unpack(UBIFS_COMMON_HDR_FORMAT,buf)))
27 | for key in fields:
28 | setattr(self, key, fields[key])
29 | setattr(self, 'errors', [])
30 |
31 | def __repr__(self):
32 | return 'UBIFS Common Header'
33 |
34 | def __iter__(self):
35 | for key in dir(self):
36 | if not key.startswith('_'):
37 | yield key, getattr(self, key)
38 |
39 |
40 | class sb_node(object):
41 | def __init__(self, buf):
42 | fields = dict(zip(UBIFS_SB_NODE_FIELDS, struct.unpack(UBIFS_SB_NODE_FORMAT,buf)))
43 | for key in fields:
44 | setattr(self, key, fields[key])
45 |
46 | def __repr__(self):
47 | return 'UBIFS Super Block Node'
48 |
49 | def __iter__(self):
50 | for key in dir(self):
51 | if not key.startswith('_'):
52 | yield key, getattr(self, key)
53 |
54 |
55 | class mst_node(object):
56 | def __init__(self, buf):
57 | fields = dict(zip(UBIFS_MST_NODE_FIELDS, struct.unpack(UBIFS_MST_NODE_FORMAT,buf)))
58 | for key in fields:
59 | setattr(self, key, fields[key])
60 |
61 | def __repr__(self):
62 | return 'UBIFS Master Block Node'
63 |
64 | def __iter__(self):
65 | for key in dir(self):
66 | if not key.startswith('_'):
67 | yield key, getattr(self, key)
68 |
69 |
70 | class dent_node(object):
71 | def __init__(self, buf):
72 | fields = dict(zip(UBIFS_DENT_NODE_FIELDS, struct.unpack(UBIFS_DENT_NODE_FORMAT,buf)))
73 | for key in fields:
74 | if key == 'key':
75 | setattr(self, key, parse_key(fields[key]))
76 | else:
77 | setattr(self, key, fields[key])
78 | setattr(self, 'name', '')
79 |
80 | def __repr__(self):
81 | return 'UBIFS Directory Entry Node'
82 |
83 | def __iter__(self):
84 | for key in dir(self):
85 | if not key.startswith('_'):
86 | yield key, getattr(self, key)
87 |
88 |
89 | class data_node(object):
90 | def __init__(self, buf):
91 | fields = dict(zip(UBIFS_DATA_NODE_FIELDS, struct.unpack(UBIFS_DATA_NODE_FORMAT,buf)))
92 | for key in fields:
93 | if key == 'key':
94 | setattr(self, key, parse_key(fields[key]))
95 | else:
96 | setattr(self, key, fields[key])
97 | setattr(self, 'offset', 0)
98 | setattr(self, 'compr_len', 0)
99 |
100 | def __repr__(self):
101 | return 'UBIFS Data Node'
102 |
103 | def __iter__(self):
104 | for key in dir(self):
105 | if not key.startswith('_'):
106 | yield key, getattr(self, key)
107 |
108 |
109 | class idx_node(object):
110 | def __init__(self, buf):
111 | fields = dict(zip(UBIFS_IDX_NODE_FIELDS, struct.unpack(UBIFS_IDX_NODE_FORMAT,buf)))
112 | for key in fields:
113 | setattr(self, key, fields[key])
114 | setattr(self, 'branches', [])
115 | def __repr__(self):
116 | return 'UBIFS Index Node'
117 |
118 | def __iter__(self):
119 | for key in dir(self):
120 | if not key.startswith('_'):
121 | yield key, getattr(self, key)
122 |
123 |
124 | class ino_node(object):
125 | def __init__(self, buf):
126 | fields = dict(zip(UBIFS_INO_NODE_FIELDS, struct.unpack(UBIFS_INO_NODE_FORMAT,buf)))
127 | for key in fields:
128 | if key == 'key':
129 | setattr(self, key, parse_key(fields[key]))
130 | else:
131 | setattr(self, key, fields[key])
132 | setattr(self, 'data', '')
133 |
134 | def __repr__(self):
135 | return 'UBIFS Ino Node'
136 |
137 | def __iter__(self):
138 | for key in dir(self):
139 | if not key.startswith('_'):
140 | yield key, getattr(self, key)
141 |
142 |
143 | class branch(object):
144 | def __init__(self, buf):
145 | fields = dict(zip(UBIFS_BRANCH_FIELDS, struct.unpack(UBIFS_BRANCH_FORMAT,buf)))
146 | for key in fields:
147 | setattr(self, key, fields[key])
148 |
149 | def __repr__(self):
150 | return 'UBIFS Branch'
151 |
152 | def __iter__(self):
153 | for key in dir(self):
154 | if not key.startswith('_'):
155 | yield key, getattr(self, key)
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubifs/nodes/extract.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubifs
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | from ubifs import nodes
21 | from ubifs.defines import *
22 |
23 |
24 | def common_hdr(ubifs, lnum, offset=0):
25 | """Get common header at given LEB number + offset.
26 |
27 | Arguments:
28 | Obj:ubifs -- UBIFS object.
29 | Int:lnum -- LEB number common header is in.
30 | Int:offset -- Offset in LEB of common header.
31 |
32 | Returns:
33 | Obj:common_hdr -- Common header found at lnum/offset.
34 | """
35 | ubifs.file.seek((ubifs.leb_size * lnum) + offset)
36 | # crc checks here
37 | return nodes.common_hdr(ubifs.file.read(UBIFS_COMMON_HDR_SZ))
38 |
39 |
40 | def ino_node(ubifs, lnum, offset=0):
41 | """Get inode node at given LEB number + offset.
42 |
43 | Arguments:
44 | Obj:ubifs -- UBIFS object.
45 | Int:lnum -- LEB number inode node is in.
46 | Int:offset -- Offset in LEB of inode node.
47 |
48 | Returns:
49 | Obj:ino_node -- Inode node found at lnum/offset.
50 | """
51 | ubifs.file.seek((ubifs.leb_size * lnum) + offset)
52 | inon = nodes.ino_node(ubifs.file.read(UBIFS_INO_NODE_SZ))
53 | inon.data = ubifs.file.read(inon.data_len)
54 | return inon
55 |
56 |
57 | def mst_node(ubifs, lnum, offset=0):
58 | """Get master node at given LEB number + offset.
59 |
60 | Arguments:
61 | Obj:ubifs -- UBIFS object.
62 | Int:lnum -- LEB number master node is in.
63 | Int:offset -- Offset in LEB of master node.
64 |
65 | Returns:
66 | Obj:mst_node -- Master node found at lnum/offset.
67 | """
68 | ubifs.file.seek((ubifs.leb_size * lnum) + offset)
69 | return nodes.mst_node(ubifs.file.read(UBIFS_MST_NODE_SZ))
70 |
71 |
72 | def sb_node(ubifs, offset=0):
73 | """Get superblock node at given LEB number + offset.
74 |
75 | Arguments:
76 | Obj:ubifs -- UBIFS object.
77 | Int:offset -- Offset in LEB of superblock node.
78 |
79 | Returns:
80 | Obj:sb_node -- Superblock node found at lnum/offset.
81 | """
82 | ubifs.file.seek(offset)
83 | return nodes.sb_node(ubifs.file.read(UBIFS_SB_NODE_SZ))
84 |
85 |
86 | def dent_node(ubifs, lnum, offset=0):
87 | """Get dir entry node at given LEB number + offset.
88 |
89 | Arguments:
90 | Obj:ubifs -- UBIFS object.
91 | Int:lnum -- LEB number dir entry node is in.
92 | Int:offset -- Offset in LEB of dir entry node.
93 |
94 | Returns:
95 | Obj:dent_node -- Dir entry node found at lnum/offset.
96 | """
97 | ubifs.file.seek((ubifs.leb_size * lnum) + offset)
98 | den = nodes.dent_node(ubifs.file.read(UBIFS_DENT_NODE_SZ))
99 | den.name = '%s' % ubifs.file.read(den.nlen)
100 | return den
101 |
102 |
103 | def data_node(ubifs, lnum, offset=0, node_len=0):
104 | """Get data node at given LEB number + offset.
105 |
106 | Arguments:
107 | Obj:ubifs -- UBIFS object.
108 | Int:lnum -- LEB number data node is in.
109 | Int:offset -- Offset in LEB of data node.
110 |
111 | Returns:
112 | Obj:data_node -- Data node found at lnum/offset.
113 | """
114 | ubifs.file.seek((ubifs.leb_size * lnum) + offset)
115 | datn = nodes.data_node(ubifs.file.read(UBIFS_DATA_NODE_SZ))
116 | datn.offset = (ubifs.leb_size * lnum) + offset + UBIFS_DATA_NODE_SZ
117 | datn.compr_len = node_len - UBIFS_COMMON_HDR_SZ - UBIFS_DATA_NODE_SZ
118 | return datn
119 |
120 |
121 | def idx_node(ubifs, lnum, offset=0):
122 | """Get index node at given LEB number + offset.
123 |
124 | Arguments:
125 | Obj:ubifs -- UBIFS object.
126 | Int:lnum -- LEB number index node is in.
127 | Int:offset -- Offset in LEB of index node.
128 |
129 | Returns:
130 | Obj:idx_node -- Index node found at lnum/offset.
131 | """
132 | ubifs.file.seek((ubifs.leb_size * lnum) + offset)
133 | idxn = nodes.idx_node(ubifs.file.read(UBIFS_IDX_NODE_SZ))
134 |
135 | for i in range(0, idxn.child_cnt):
136 | idxn.branches.append(nodes.branch(ubifs.file.read(UBIFS_BRANCH_SZ)))
137 |
138 | return idxn
139 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubifs/output.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubifs
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 | import struct
22 |
23 | from ubifs.defines import *
24 | from ubifs.misc import decompress
25 |
26 | def dents(ubifs, inodes, dent_node, path='', perms=False):
27 | inode = inodes[dent_node.inum]
28 | dent_path = os.path.join(path, dent_node.name)
29 |
30 | if dent_node.type == UBIFS_ITYPE_DIR:
31 | try:
32 | if not os.path.exists(dent_path):
33 | os.mkdir(dent_path)
34 | if perms:
35 | set_file_perms(dent_path, inode)
36 | except Exception, e:
37 | ubifs.log.write('DIR Fail: %s' % e)
38 |
39 | if 'dent' in inode:
40 | for dnode in inode['dent']:
41 | dents(ubifs, inodes, dnode, dent_path, perms)
42 |
43 | elif dent_node.type == UBIFS_ITYPE_REG:
44 | try:
45 | if inode['ino'].nlink > 1:
46 | if 'hlink' not in inode:
47 | inode['hlink'] = dent_path
48 | buf = process_reg_file(ubifs, inode, dent_path)
49 | write_reg_file(dent_path, buf)
50 | else:
51 | os.link(inode['hlink'] ,dent_path)
52 | else:
53 | buf = process_reg_file(ubifs, inode, dent_path)
54 | write_reg_file(dent_path, buf)
55 |
56 | if perms:
57 | set_file_perms(dent_path, inode)
58 |
59 | except Exception, e:
60 | ubifs.log.write('FILE Fail: %s' % e)
61 |
62 | elif dent_node.type == UBIFS_ITYPE_LNK:
63 | try:
64 | # probably will need to decompress ino data if > UBIFS_MIN_COMPR_LEN
65 | os.symlink('%s' % inode['ino'].data, dent_path)
66 | except Exception, e:
67 | ubifs.log.write('SYMLINK Fail: %s : %s' % (inode['ino'].data, dent_path))
68 |
69 | elif dent_node.type in [UBIFS_ITYPE_BLK, UBIFS_ITYPE_CHR]:
70 | try:
71 | dev = struct.unpack(' len(buf):
143 | buf += '\x00' * (inode['ino'].size - len(buf))
144 |
145 | return buf
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubifs/walk.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader/ubifs
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | from ubifs import extract
21 | from ubifs.defines import *
22 |
23 | def index(ubifs, lnum, offset, inodes={}):
24 | """Walk the index gathering Inode, Dir Entry, and File nodes.
25 |
26 | Arguments:
27 | Obj:ubifs -- UBIFS object.
28 | Int:lnum -- Logical erase block number.
29 | Int:offset -- Offset in logical erase block.
30 | Dict:inodes -- Dict of ino/dent/file nodes keyed to inode number.
31 |
32 | Returns:
33 | Dict:inodes -- Dict of ino/dent/file nodes keyed to inode number.
34 | 'ino' -- Inode node.
35 | 'data' -- List of data nodes if present.
36 | 'dent' -- List of directory entry nodes if present.
37 | """
38 | chdr = extract.common_hdr(ubifs, lnum, offset)
39 |
40 | if chdr.node_type == UBIFS_IDX_NODE:
41 | idxn = extract.idx_node(ubifs, lnum, offset+UBIFS_COMMON_HDR_SZ)
42 |
43 | for branch in idxn.branches:
44 | index(ubifs, branch.lnum, branch.offs, inodes)
45 |
46 | elif chdr.node_type == UBIFS_INO_NODE:
47 | inon = extract.ino_node(ubifs, lnum, offset+UBIFS_COMMON_HDR_SZ)
48 | ino_num = inon.key['ino_num']
49 |
50 | if not ino_num in inodes:
51 | inodes[ino_num] = {}
52 |
53 | inodes[ino_num]['ino'] = inon
54 |
55 | elif chdr.node_type == UBIFS_DATA_NODE:
56 | datn = extract.data_node(ubifs, lnum, offset+UBIFS_COMMON_HDR_SZ, chdr.len)
57 | ino_num = datn.key['ino_num']
58 |
59 | if not ino_num in inodes:
60 | inodes[ino_num] = {}
61 |
62 | if not 'data' in inodes[ino_num]:
63 | inodes[ino_num]['data']= []
64 |
65 | inodes[ino_num]['data'].append(datn)
66 |
67 | elif chdr.node_type == UBIFS_DENT_NODE:
68 | dn = extract.dent_node(ubifs, lnum, offset+UBIFS_COMMON_HDR_SZ)
69 | ino_num = dn.key['ino_num']
70 |
71 | if not ino_num in inodes:
72 | inodes[ino_num] = {}
73 |
74 | if not 'dent' in inodes[ino_num]:
75 | inodes[ino_num]['dent']= []
76 |
77 | inodes[ino_num]['dent'].append(dn)
78 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubifs_extract_files.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 | import sys
22 | import argparse
23 |
24 | from ubi_io import ubi_file
25 | from ubifs import ubifs, get_leb_size
26 | from ui.common import extract_files, output_dir
27 |
28 | if __name__ == '__main__':
29 | description = """Extract file contents of UBIFS image."""
30 | usage = 'ubifs_extract_files.py [options] filepath'
31 | parser = argparse.ArgumentParser(usage=usage, description=description)
32 | parser.add_argument('-l', '--log-file', dest='logpath',
33 | help='Log output to file output/LOGPATH. (default: ubifs_output.log)')
34 |
35 | parser.add_argument('-k', '--keep-permissions', action='store_true', dest='permissions',
36 | help='Maintain file permissions, requires running as root. (default: False)')
37 |
38 |
39 | parser.add_argument('-q', '--quiet', action='store_true', dest='quiet',
40 | help='Suppress warnings and non-fatal errors. (default: False)')
41 |
42 | parser.add_argument('-e', '--leb-size', type=int, dest='block_size',
43 | help='Specify LEB size.')
44 |
45 | parser.add_argument('-o', '--output-dir', dest='output_path',
46 | help='Specify output directory path.')
47 |
48 | parser.add_argument('filepath', help='File to extract file contents of.')
49 |
50 | if len(sys.argv) == 1:
51 | parser.print_help()
52 | sys.exit()
53 |
54 |
55 | args = parser.parse_args()
56 |
57 | if args.filepath:
58 | path = args.filepath
59 | if not os.path.exists(path):
60 | parser.error("File path doesn't exist.")
61 |
62 | if args.output_path:
63 | output_path = args.output_path
64 | else:
65 | img_name = os.path.splitext(os.path.basename(path))[0]
66 | output_path = os.path.join(output_dir, img_name)
67 |
68 | if args.logpath:
69 | log_to_file = True
70 | log_file = args.logpath
71 | else:
72 | log_to_file = None
73 | log_file = None
74 |
75 | # Determine block size if not provided
76 | if args.block_size:
77 | block_size = args.block_size
78 | else:
79 | block_size = get_leb_size(path)
80 |
81 | if not os.path.exists(output_path):
82 | os.makedirs(output_path)
83 |
84 | perms = args.permissions
85 | quiet = args.quiet
86 |
87 | # Create file object
88 | ufsfile = ubi_file(path, block_size)
89 | # Create UBIFS object
90 | uubifs = ubifs(ufsfile)
91 | # Set up logging
92 | uubifs.log.log_file = log_file
93 | uubifs.log.log_to_file = log_to_file
94 | uubifs.quiet = quiet
95 |
96 | if not os.path.exists(output_path):
97 | os.makedirs(output_path)
98 | elif os.listdir(output_path):
99 | parser.error('Volume output directory is not empty. %s' % output_path)
100 |
101 | # Run extract all files
102 | print 'Writing to: %s' % output_path
103 | extract_files(uubifs, output_path, perms)
104 | sys.exit()
105 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ubifs_info.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 | import sys
22 | import argparse
23 |
24 | from ubi_io import ubi_file
25 | from ubifs import ubifs, get_leb_size
26 |
27 |
28 | if __name__ == '__main__':
29 |
30 | description = """Print superblock and master node information."""
31 | usage = 'ubifs_info.py [options] filepath'
32 | parser = argparse.ArgumentParser(usage=usage, description=description)
33 |
34 | parser.add_argument('-e', '--leb-size', type=int, dest='block_size',
35 | help='Specify LEB size.')
36 |
37 | parser.add_argument('filepath', help='File to get info from.')
38 |
39 | if len(sys.argv) == 1:
40 | parser.print_help()
41 | sys.exit()
42 |
43 | args = parser.parse_args()
44 |
45 | if args.filepath:
46 | path = args.filepath
47 | if not os.path.exists(path):
48 | parser.error("filepath doesn't exist.")
49 |
50 | # Determine block size if not provided
51 | if args.block_size:
52 | block_size = args.block_size
53 | else:
54 | block_size = get_leb_size(path)
55 |
56 | # Create file object.
57 | ufile = ubi_file(path, block_size)
58 | # Create UBIFS Object.
59 | uubifs = ubifs(ufile)
60 | # Write super block node info
61 | uubifs.log.write_node(uubifs.superblock_node)
62 | # Write first master node.
63 | uubifs.log.write_node(uubifs.master_node)
64 | uubifs.log.write_node(uubifs.master_node2)
65 | sys.exit()
66 |
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonsio/YAHM/949b748b22fe2da0f3aff5b5681147c18c06cb03/share/tools/ubi_reader/ui/__init__.py
--------------------------------------------------------------------------------
/share/tools/ubi_reader/ui/common.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #############################################################
3 | # ubi_reader
4 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 |
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #############################################################
19 |
20 | import os
21 |
22 | from ubi_io import leb_virtual_file
23 | from ubifs import ubifs, walk, output
24 | from ubifs.defines import PRINT_UBIFS_KEY_HASH, PRINT_UBIFS_COMPR
25 | from ubi.defines import PRINT_VOL_TYPE_LIST, UBI_VTBL_AUTORESIZE_FLG
26 |
27 | output_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'output')
28 |
29 |
30 | def extract_files(ubifs, out_path, perms=False):
31 | """Extract UBIFS contents to_path/
32 |
33 | Arguments:
34 | Obj:ubifs -- UBIFS object.
35 | Str:out_path -- Path to extract contents to.
36 | """
37 | try:
38 | inodes = {}
39 | walk.index(ubifs, ubifs.master_node.root_lnum, ubifs.master_node.root_offs, inodes)
40 |
41 | for dent in inodes[1]['dent']:
42 | output.dents(ubifs, inodes, dent, out_path, perms)
43 |
44 | except Exception, e:
45 | import traceback
46 | ubifs.log.write('%s' % e)
47 | traceback.print_exc()
48 |
49 |
50 | def get_ubi_params(ubi):
51 | """Get UBI utils params
52 |
53 | Arguments:
54 | Obj:ubi -- UBI object.
55 |
56 | Returns:
57 | Dict -- Dict keyed to volume with Dict of args and flags.
58 | """
59 | ubi_flags = {'min_io_size':'-m',
60 | 'max_bud_bytes':'-j',
61 | 'leb_size':'-e',
62 | 'default_compr':'-x',
63 | 'sub_page_size':'-s',
64 | 'fanout':'-f',
65 | 'key_hash':'-k',
66 | 'orph_lebs':'-p',
67 | 'log_lebs':'-l',
68 | 'max_leb_cnt': '-c',
69 | 'peb_size':'-p',
70 | 'sub_page_size':'-s',
71 | 'vid_hdr_offset':'-O',
72 | 'version':'-x',
73 | 'image_seq':'-Q',
74 | 'alignment':'-a',
75 | 'vol_id':'-n',
76 | 'name':'-N'}
77 |
78 | ubi_params = {}
79 | ubi_args = {}
80 | ini_params = {}
81 | for image in ubi.images:
82 | img_seq = image.image_seq
83 | ubi_params[img_seq] = {}
84 | ubi_args[img_seq] = {}
85 | ini_params[img_seq] = {}
86 | for volume in image.volumes:
87 | ubi_args[img_seq][volume] = {}
88 | ini_params[img_seq][volume] = {}
89 |
90 | # Get ubinize.ini settings
91 | ini_params[img_seq][volume]['vol_type'] = PRINT_VOL_TYPE_LIST[image.volumes[volume].vol_rec.vol_type]
92 |
93 | if image.volumes[volume].vol_rec.flags == UBI_VTBL_AUTORESIZE_FLG:
94 | ini_params[img_seq][volume]['vol_flags'] = 'autoresize'
95 | else:
96 | ini_params[img_seq][volume]['vol_flags'] = image.volumes[volume].vol_rec.flags
97 |
98 | ini_params[img_seq][volume]['vol_id'] = image.volumes[volume].vol_id
99 | ini_params[img_seq][volume]['vol_name'] = image.volumes[volume].name.rstrip('\x00')
100 | ini_params[img_seq][volume]['vol_alignment'] = image.volumes[volume].vol_rec.alignment
101 |
102 | ini_params[img_seq][volume]['vol_size'] = image.volumes[volume].vol_rec.reserved_pebs * ubi.leb_size
103 |
104 | # Create file object backed by UBI blocks.
105 | ufsfile = leb_virtual_file(ubi, image.volumes[volume])
106 | # Create UBIFS object
107 | uubifs = ubifs(ufsfile)
108 | for key, value in uubifs.superblock_node:
109 | if key == 'key_hash':
110 | value = PRINT_UBIFS_KEY_HASH[value]
111 | elif key == 'default_compr':
112 | value = PRINT_UBIFS_COMPR[value]
113 |
114 | if key in ubi_flags:
115 | ubi_args[img_seq][volume][key] = value
116 |
117 | for key, value in image.volumes[volume].vol_rec:
118 | if key == 'name':
119 | value = value.rstrip('\x00')
120 |
121 | if key in ubi_flags:
122 | ubi_args[img_seq][volume][key] = value
123 |
124 | ubi_args[img_seq][volume]['version'] = image.version
125 | ubi_args[img_seq][volume]['vid_hdr_offset'] = image.vid_hdr_offset
126 | ubi_args[img_seq][volume]['sub_page_size'] = ubi_args[img_seq][volume]['vid_hdr_offset']
127 | ubi_args[img_seq][volume]['sub_page_size'] = ubi_args[img_seq][volume]['vid_hdr_offset']
128 | ubi_args[img_seq][volume]['image_seq'] = image.image_seq
129 | ubi_args[img_seq][volume]['peb_size'] = ubi.peb_size
130 | ubi_args[img_seq][volume]['vol_id'] = image.volumes[volume].vol_id
131 |
132 | ubi_params[img_seq][volume] = {'flags':ubi_flags, 'args':ubi_args[img_seq][volume], 'ini':ini_params[img_seq][volume]}
133 |
134 | return ubi_params
--------------------------------------------------------------------------------
/share/yahm_completion:
--------------------------------------------------------------------------------
1 | shopt -s progcomp
2 |
3 | # @todo Wildcard Handling überarbeiten
4 | # @todo GLOBAL_FLAGS wirklich global machen (-n -f -v) und in Funktion mit lokalen mergen
5 | # @todo YAHM/share/include.sh verwenden (Problem mit Meldung bzgl. Dev branch)
6 |
7 | #check_interface_name()
8 | #{
9 | # # interface name
10 | # local int_name=$1
11 | #
12 | # if [[ ! `ip -d link show ${int_name} 2>/dev/null ` ]]; then
13 | # echo -e "ERROR: Interface ${int_name} does not exists"
14 | # elif [[ `ip -d link show ${int_name} | tail -n +2 | grep loopback` ]] ; then
15 | # echo "local"
16 | # elif [[ `ip -d link show ${int_name} | tail -n +2 | grep vlan` ]] ; then
17 | # echo "vlan"
18 | # elif [[ `ip -d link show ${int_name} | tail -n +2 | grep bridge` ]] ; then
19 | # echo "bridge"
20 | # else
21 | # echo "physical"
22 | # fi
23 | #}
24 |
25 | _backup()
26 | {
27 | local cur prev complete_words complete_options
28 |
29 | # Don't break words at : and =, see [1] and [2]
30 | COMP_WORDBREAKS=${COMP_WORDBREAKS//[:=]}
31 |
32 | cur=${COMP_WORDS[COMP_CWORD]}
33 | prev=${COMP_WORDS[COMP_CWORD-1]}
34 |
35 | GLOBAL_COMMANDS="\
36 | data_backup\
37 | data_restore\
38 | full_backup\
39 | full_restore"
40 |
41 | GLOBAL_FLAGS="\
42 | -n\
43 | -f\
44 | -v\
45 | -d"
46 |
47 | case "${prev}" in
48 | -n)
49 | YAHM_DIR="/var/lib/lxc/"
50 | YAHM_NAMES=$(cd ${YAHM_DIR} && set -- */; printf "%s\n" "${@%/}")
51 | COMPREPLY=( $(compgen -W "${YAHM_NAMES}" -- $cur) )
52 | return 0
53 | ;;
54 | -d)
55 | # Unescape space
56 | cur=${cur//\\ / }
57 | # Expand tilder to $HOME
58 | [[ ${cur} == "~/"* ]] && cur=${cur/\~/$HOME}
59 | # Show completion if path exist (and escape spaces)
60 | compopt -o filenames
61 | local files=("${cur}"*)
62 | [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]// /\ }" )
63 | return 0
64 | ;;
65 | data_backup|data_restore|full_backup|full_restore)
66 | return 0
67 | ;;
68 | *)
69 | complete_words="$GLOBAL_COMMANDS"
70 | complete_options="$GLOBAL_FLAGS"
71 | ;;
72 | esac
73 |
74 | # Either display words or options, depending on the user input
75 | if [[ $cur == -* ]]; then
76 | COMPREPLY=( $( compgen -W "$complete_options" -- $cur ))
77 |
78 | else
79 | COMPREPLY=( $( compgen -W "$complete_words" -- $cur ))
80 | fi
81 |
82 | return 0
83 | }
84 |
85 | _ctl()
86 | {
87 | local cur prev complete_words complete_options
88 |
89 | # Don't break words at : and =, see [1] and [2]
90 | COMP_WORDBREAKS=${COMP_WORDBREAKS//[:=]}
91 |
92 | cur=${COMP_WORDS[COMP_CWORD]}
93 | prev=${COMP_WORDS[COMP_CWORD-1]}
94 |
95 | GLOBAL_COMMANDS="\
96 | start\
97 | stop\
98 | join\
99 | info\
100 | fw_update\
101 | update"
102 |
103 | GLOBAL_FLAGS="\
104 | -n\
105 | -f\
106 | -v"
107 |
108 | case "${prev}" in
109 | -n)
110 | YAHM_DIR="/var/lib/lxc/"
111 | YAHM_NAMES=$(cd ${YAHM_DIR} && set -- */; printf "%s\n" "${@%/}")
112 | COMPREPLY=( $(compgen -W "${YAHM_NAMES}" -- $cur) )
113 | return 0
114 | ;;
115 | start|stop|info|join|update)
116 | return 0
117 | ;;
118 | *)
119 | complete_words="$GLOBAL_COMMANDS"
120 | complete_options="$GLOBAL_FLAGS"
121 | ;;
122 | esac
123 |
124 | # Either display words or options, depending on the user input
125 | if [[ $cur == -* ]]; then
126 | COMPREPLY=( $( compgen -W "$complete_options" -- $cur ))
127 |
128 | else
129 | COMPREPLY=( $( compgen -W "$complete_words" -- $cur ))
130 | fi
131 |
132 | return 0
133 | }
134 |
135 | _lxc()
136 | {
137 | # todo ggf um Beschreibung erweitern: http://stackoverflow.com/questions/7267185/bash-autocompletion-add-description-for-possible-completions
138 | local cur prev complete_words complete_options
139 |
140 | # Don't break words at : and =, see [1] and [2]
141 | COMP_WORDBREAKS=${COMP_WORDBREAKS//[:=]}
142 |
143 | cur=${COMP_WORDS[COMP_CWORD]}
144 | prev=${COMP_WORDS[COMP_CWORD-1]}
145 |
146 | GLOBAL_COMMANDS="\
147 | install\
148 | remove\
149 | update"
150 |
151 | GLOBAL_FLAGS="\
152 | -n\
153 | -f\
154 | -b\
155 | -p\
156 | -v\
157 | -d"
158 |
159 | #echo -e "\nprev = $prev, cur = $cur, firstword = $firstword, lastword = $lastword\n"
160 |
161 | case "${prev}" in
162 | -n)
163 | #compopt -o nospace
164 | YAHM_DIR="/var/lib/lxc/"
165 | YAHM_NAMES=$(cd ${YAHM_DIR} && set -- */; printf "%s\n" "${@%/}")
166 | COMPREPLY=( $(compgen -W "${YAHM_NAMES}" -- $cur) )
167 | return 0
168 | ;;
169 | -d)
170 | # Unescape space
171 | cur=${cur//\\ / }
172 | # Expand tilder to $HOME
173 | [[ ${cur} == "~/"* ]] && cur=${cur/\~/$HOME}
174 | # Show completion if path exist (and escape spaces)
175 | compopt -o filenames
176 | local files=("${cur}"*)
177 | [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]// /\ }" )
178 | return 0
179 | ;;
180 | -b)
181 | if [ ! -f /var/lib/yahm/fw.list ]
182 | then
183 | cd /var/lib/yahm/
184 | wget -q -N https://raw.githubusercontent.com/leonsio/CCU2-FW/master/fw.list
185 | fi
186 | ALL_FW=$(cat /var/lib/yahm/fw.list | grep -Po '(?<=CCU2-)\d.\d\d?.\d\d?')
187 | COMPREPLY=( $(compgen -W "${ALL_FW}" -- $cur) )
188 | return 0
189 | ;;
190 | install|update|remove)
191 | return 0
192 | ;;
193 | *)
194 | complete_words="$GLOBAL_COMMANDS"
195 | complete_options="$GLOBAL_FLAGS"
196 | ;;
197 | esac
198 |
199 | # Either display words or options, depending on the user input
200 | if [[ $cur == -* ]]; then
201 | COMPREPLY=( $( compgen -W "$complete_options" -- $cur ))
202 |
203 | else
204 | COMPREPLY=( $( compgen -W "$complete_words" -- $cur ))
205 | fi
206 |
207 | return 0
208 | }
209 |
210 | _module()
211 | {
212 | local cur prev complete_words complete_options
213 |
214 | # Don't break words at : and =, see [1] and [2]
215 | COMP_WORDBREAKS=${COMP_WORDBREAKS//[:=]}
216 |
217 | cur=${COMP_WORDS[COMP_CWORD]}
218 | prev=${COMP_WORDS[COMP_CWORD-1]}
219 |
220 | GLOBAL_COMMANDS="\
221 | enable\
222 | disable\
223 | available\
224 | installed"
225 |
226 | GLOBAL_FLAGS="\
227 | -n\
228 | -f\
229 | -v\
230 | -m"
231 |
232 | case "${prev}" in
233 | -n)
234 | YAHM_DIR="/var/lib/lxc/"
235 | YAHM_NAMES=$(cd ${YAHM_DIR} && set -- */; printf "%s\n" "${@%/}")
236 | COMPREPLY=( $(compgen -W "${YAHM_NAMES}" -- $cur) )
237 | return 0
238 | ;;
239 | -m)
240 | YAHM_DIR="/opt/YAHM/share/modules/"
241 | YAHM_MODULES=$(find ${YAHM_DIR} -maxdepth 1 -type f -printf '%f\n')
242 | COMPREPLY=( $(compgen -W "${YAHM_MODULES}" -- $cur) )
243 | return 0
244 | ;;
245 | enable|disable|available|installed)
246 | return 0
247 | ;;
248 | *)
249 | complete_words="$GLOBAL_COMMANDS"
250 | complete_options="$GLOBAL_FLAGS"
251 | ;;
252 | esac
253 |
254 | # Either display words or options, depending on the user input
255 | if [[ $cur == -* ]]; then
256 | COMPREPLY=( $( compgen -W "$complete_options" -- $cur ))
257 |
258 | else
259 | COMPREPLY=( $( compgen -W "$complete_words" -- $cur ))
260 | fi
261 |
262 | return 0
263 | }
264 |
265 | _network()
266 | {
267 | # todo ggf um Beschreibung erweitern: http://stackoverflow.com/questions/7267185/bash-autocompletion-add-description-for-possible-completions
268 | local cur prev complete_words complete_options
269 |
270 | # Don't break words at : and =, see [1] and [2]
271 | COMP_WORDBREAKS=${COMP_WORDBREAKS//[:=]}
272 |
273 | cur=${COMP_WORDS[COMP_CWORD]}
274 | prev=${COMP_WORDS[COMP_CWORD-1]}
275 |
276 | GLOBAL_COMMANDS="\
277 | create_bridge\
278 | delete_bridge\
279 | attach_bridge\
280 | dettach_bridge\
281 | show_bridge"
282 |
283 | GLOBAL_FLAGS="\
284 | -n\
285 | -f\
286 | -v\
287 | -b\
288 | -i\
289 | -d\
290 | -w"
291 |
292 | case "${prev}" in
293 | -n)
294 | YAHM_DIR="/var/lib/lxc/"
295 | YAHM_NAMES=$(cd ${YAHM_DIR} && set -- */; printf "%s\n" "${@%/}")
296 | COMPREPLY=( $(compgen -W "${YAHM_NAMES}" -- $cur) )
297 | return 0
298 | ;;
299 | -i)
300 | # INTERFACES=$(find /sys/class/net/ -maxdepth 1 -type l -printf '%f\n')
301 | # unset PHYS_VLAN
302 | # for i in $INTERFACES
303 | # do
304 | # if [ `check_interface_name $i` == "physical" ] || [ `check_interface_name $i` == "vlan" ]
305 | # then
306 | # PHYS_VLAN+=($i)
307 | # fi
308 | # done
309 | # #echo ${PHYS_VLAN[*]}
310 | # COMPREPLY=( $(compgen -W "${PHYS_VLAN[@]}" -- $cur) )
311 |
312 | # @todo geht bestimmt besser
313 | INTERFACES=$(systemctl -a | grep net-devices | grep -v "/sys/subsystem" | awk '{print $1}' | cut -d"-" -f5 | cut -d"." -f1)
314 | COMPREPLY=( $(compgen -W "${INTERFACES}" -- $cur) )
315 | return 0
316 | ;;
317 | -b)
318 | BRIDGES=$(brctl show | awk 'NF>1 && NR>1 {print $1}')
319 | COMPREPLY=( $(compgen -W "${BRIDGES}" -- $cur) )
320 | return 0
321 | ;;
322 | create_bridge|delete_bridge|attach_bridge|dettach_bridge|show_bridge)
323 | return 0
324 | ;;
325 | *)
326 | complete_words="$GLOBAL_COMMANDS"
327 | complete_options="$GLOBAL_FLAGS"
328 | ;;
329 | esac
330 |
331 | # Either display words or options, depending on the user input
332 | if [[ $cur == -* ]]; then
333 | COMPREPLY=( $( compgen -W "$complete_options" -- $cur ))
334 |
335 | else
336 | COMPREPLY=( $( compgen -W "$complete_words" -- $cur ))
337 | fi
338 |
339 | return 0
340 | }
341 |
342 | complete -F _backup yahm-backup
343 | complete -F _ctl yahm-ctl
344 | complete -F _lxc yahm-lxc
345 | complete -F _network yahm-network
346 | complete -F _module yahm-module
--------------------------------------------------------------------------------
/yahm-init:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # @todo Nach jedem Skript Fehler abfangen
4 | #
5 | #
6 |
7 | set -e
8 |
9 | LSB_RELEASE="/usr/bin/lsb_release"
10 | ERROR=1
11 |
12 | # Check if we can use colours in our output
13 | use_colour=0
14 | [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null && use_colour=1
15 |
16 | # Some useful functions
17 | progress() {
18 | [ $use_colour -eq 1 ] && echo -ne "\033[01;32m"
19 | echo -e "$@" >&2
20 | [ $use_colour -eq 1 ] && echo -ne "\033[00m"
21 | }
22 |
23 | info() {
24 | [ $use_colour -eq 1 ] && echo -ne "\033[01;34m"
25 | echo -e "$@" >&2
26 | [ $use_colour -eq 1 ] && echo -ne "\033[00m"
27 | }
28 |
29 | die () {
30 | [ $use_colour -eq 1 ] && echo -ne "\033[01;31m"
31 | echo -e "$@" >&2
32 | [ $use_colour -eq 1 ] && echo -ne "\033[00m"
33 | exit 1
34 | }
35 |
36 | if [ "$1" = "quickinstall" ]
37 | then
38 | exit_error()
39 | {
40 | if [ $ERROR -eq 1 ]
41 | then
42 | die "An error occurred while processing quickinstall mode. Pleasy try manually installation"
43 | fi
44 | }
45 | trap exit_error EXIT SIGINT SIGTERM
46 | fi
47 |
48 | check_install_deb()
49 | {
50 | progress "Installing dependencies.."
51 | packages=$1
52 | for P in $packages
53 | do
54 | dpkg -s "$P" >/dev/null 2>&1 && {
55 | info $P is installed
56 | } || {
57 | install_package "$P"
58 | }
59 | done
60 | info "\t..done"
61 | }
62 |
63 | install_package() {
64 | package=$1
65 | info "install ${package}"
66 | apt-get -qq -y install $package 2>&1 > /dev/null
67 | return $?
68 | }
69 |
70 | [ "x$(id -un)" == "xroot" ] || die "Sorry, this script must be run as root."
71 |
72 | [ -x $LSB_RELEASE ] || install_package "lsb-release"
73 |
74 | # Creating needed folders
75 | mkdir -p /var/log/yahm
76 | mkdir -p /var/lib/yahm
77 |
78 | # check architecture
79 | case `dpkg --print-architecture` in
80 | armhf|arm64)
81 | info "Found ARM based distribution"
82 | ;;
83 | i386|amd64|i686|x86_64)
84 | info "X86 CPU found, need to install QEMU"
85 | check_install_deb "qemu-user-static binfmt-support"
86 | ;;
87 | *)
88 | die "Unsupported CPU architecture, we support only ARM and x86"
89 | ;;
90 | esac
91 |
92 | DIST_ID="$($LSB_RELEASE -is)"
93 | CODENAME="$($LSB_RELEASE -cs)"
94 | INTERFACE="eth0"
95 | DIST=""
96 | IS_VERBOSE=0
97 |
98 | # Check the distribution is in the supported list
99 | case "$DIST_ID:$CODENAME" in
100 | Raspbian:jessie) DIST="debian";;
101 | Raspbian:stretch) DIST="debian";;
102 | Debian:jessie) DIST="debian";;
103 | Debian:stretch) DIST="debian";;
104 | Ubuntu:xenial) DIST="ubuntu";;
105 | *) die "Sorry, this script does not support your distribution/release ($DIST_ID $CODENAME)." ;;
106 | esac
107 |
108 | progress "Updating sources (can take some time).."
109 | apt-get -q=2 update
110 | info "\t..done"
111 |
112 | check_install_deb "bash-completion wget dos2unix python git lxc liblzo2-dev bridge-utils python-lzo patch gzip openssl"
113 |
114 | progress "Clean up YAHM directory (removing old versions).."
115 | rm -rf /opt/YAHM
116 | info "\t...done"
117 |
118 | # checkout all files
119 | progress "Downloading actual version from git repository.."
120 | mkdir -p /opt
121 | cd /opt
122 |
123 | #####################################
124 | #### REMOVE --branch IN MASTER !!!!!#
125 | #####################################
126 | git clone --recursive https://github.com/leonsio/YAHM.git 2>>/var/log/yahm/git.log >>/var/log/yahm/git.log
127 | cd /opt/YAHM
128 | # update modules
129 | git submodule foreach git pull origin master 2>>/var/log/yahm/git.log >>/var/log/yahm/git.log
130 | # update second level submodule
131 | git submodule foreach git submodule update --init --recursive 2>>/var/log/yahm/git.log >>/var/log/yahm/git.log
132 | info "\t..done"
133 |
134 | progress "Including YAHM into PATH.."
135 | chmod +x /opt/YAHM/bin/*
136 | ln -sf /opt/YAHM/bin/* /usr/sbin/
137 | info "\t..done"
138 |
139 | progress "Installing bash command completion.."
140 | ln -sf /opt/YAHM/share/yahm_completion /etc/bash_completion.d/yahm_completion
141 | info "\tdone"
142 |
143 | if [ "$1" = "ui" ] && [ "$DIST" != "ubuntu" ]
144 | then
145 | info "\n\tEnter UI mode\n"
146 | /opt/YAHM/bin/yahm-ui
147 | info "\n\tuse 'yahm-ui' to launch the UI again\n"
148 | fi
149 |
150 | if [ "$1" = "quickinstall" ] && [ "$DIST" != "ubuntu" ]
151 | then
152 | info "\n\tEnter quick install mode\n"
153 |
154 | if [ "$DIST_ID" = "Raspbian" ] ;
155 | then
156 |
157 | if [ $(cat /etc/dhcpcd.conf | grep -v "^#" | grep "interface " | wc -l) -gt 0 ] ;
158 | then
159 | die "Custom network configuration is not supported, please use manual installation"
160 | fi
161 |
162 | info "Disable new dhcpcd on Raspbian"
163 | systemctl disable dhcpcd.service
164 | systemctl stop dhcpcd.service
165 |
166 | if [ "$CODENAME" = "jessie" ] ;
167 | then
168 | sed -i /etc/network/interfaces -e "s/iface eth0 inet manual/auto eth0\niface eth0 inet dhcp/"
169 | fi
170 |
171 | if [ "$CODENAME" = "stretch" ] ;
172 | then
173 | # INTERFACE=`ls /sys/class/net | grep enx`
174 | cat >> "/etc/network/interfaces" <>/var/log/yahm/network_create.log >>/var/log/yahm/network_create.log
191 | info "\tBridge yahmbr0 with interface eth0 was created\n"
192 |
193 | progress "\tAttaching network configuration to LXC container"
194 | /opt/YAHM/bin/yahm-network attach_bridge 2>>/var/log/yahm/network_attach.log >>/var/log/yahm/network_attach.log
195 | info "\tyahmbr0 was attached to YAHM LXC container\n"
196 |
197 | #progress "\n\tStarting LXC container (timeout 20 seconds )\n"
198 | #lxc-start -n yahm -d 2>>/var/log/yahm/ccu_start.log >>/var/log/yahm/ccu_start.log
199 | #sleep 20
200 | #info "\tYAHM started\n"
201 |
202 | source /opt/YAHM/share/tools/arm-board-detect/armhwinfo.sh
203 |
204 | if [ "$BOARD_TYPE" = "Raspberry Pi" ] || [ "$BOARD_TYPE" = "ASUS" ]
205 | then
206 | info "\tFound ${BOARD_TYPE} hardware, installing pivccu-driver\n"
207 | /opt/YAHM/bin/yahm-module -m pivccu-driver enable
208 | else
209 | info "Automatic module installation currently only supported on raspberry pi or asus tinker board"
210 | info "To disable homematic-ip warnings, please run 'yahm-module -f -m homematic-ip disable'"
211 | fi
212 |
213 | info "ATTENTION: Please verify your network configuration (/etc/network/interfaces)"
214 | info "WARNING: You may became new IP-address after reboot"
215 | info "YAHM was successfully installed, please restart your system, to activate new networking configuration"
216 | # Disable Error handling
217 | ERROR=0
218 | else
219 | # Info
220 | info "Please see 'yahm-lxc' for creating new container, 'yahm-network' for network configuration and 'yahm-modules' for additional modules"
221 | ERROR=0
222 | fi
223 |
--------------------------------------------------------------------------------