├── .gitignore ├── COPYING ├── Makefile.am ├── README.md ├── configure.ac ├── m4 ├── ax_pthread.m4 └── ax_python_devel.m4 ├── po ├── Makefile.am ├── ar.po ├── bg.po ├── de.po ├── el.po ├── et.po ├── fi.po ├── fr.po ├── it.po ├── lt.po ├── nl.po ├── open-multiboot.pot ├── pl.po ├── pt.po ├── ru.po ├── tr.po └── updateallpo.sh └── src ├── BoxConfig.py ├── Makefile.am ├── OMBConfig.py ├── OMBList.py ├── OMBManager.py ├── OMBManagerAbout.py ├── OMBManagerCommon.py ├── OMBManagerInstall.py ├── OMBManagerList.py ├── OMBManagerLocale.py ├── __init__.py ├── elftools ├── Makefile.am ├── __init__.py ├── common │ ├── Makefile.am │ ├── __init__.py │ ├── construct_utils.py │ ├── exceptions.py │ ├── py3compat.py │ └── utils.py ├── construct │ ├── LICENSE │ ├── Makefile.am │ ├── README │ ├── __init__.py │ ├── adapters.py │ ├── bdb.py │ ├── core.py │ ├── debug.py │ ├── lib │ │ ├── Makefile.am │ │ ├── __init__.py │ │ ├── binary.py │ │ ├── bitstream.py │ │ ├── container.py │ │ ├── hex.py │ │ └── py3compat.py │ ├── macros.py │ └── pdb.py ├── dwarf │ ├── Makefile.am │ ├── __init__.py │ ├── abbrevtable.py │ ├── aranges.py │ ├── callframe.py │ ├── compileunit.py │ ├── constants.py │ ├── descriptions.py │ ├── die.py │ ├── dwarf_expr.py │ ├── dwarfinfo.py │ ├── enums.py │ ├── lineprogram.py │ ├── locationlists.py │ ├── namelut.py │ ├── ranges.py │ └── structs.py ├── ehabi │ ├── Makefile.am │ ├── __init__.py │ ├── constants.py │ ├── decoder.py │ ├── ehabiinfo.py │ └── structs.py └── elf │ ├── Makefile.am │ ├── __init__.py │ ├── constants.py │ ├── descriptions.py │ ├── dynamic.py │ ├── elffile.py │ ├── enums.py │ ├── gnuversions.py │ ├── hash.py │ ├── notes.py │ ├── relocation.py │ ├── sections.py │ ├── segments.py │ └── structs.py ├── open-multiboot-branding-helper.py ├── open-multiboot-menu-helper.py ├── plugin.png ├── plugin.py └── ubi_reader ├── Makefile.am ├── ubi ├── Makefile.am ├── __init__.py ├── block │ ├── Makefile.am │ ├── __init__.py │ ├── layout.py │ └── sort.py ├── defines.py ├── display.py ├── headers │ ├── Makefile.am │ ├── __init__.py │ └── errors.py ├── image.py └── volume │ ├── Makefile.am │ └── __init__.py ├── ubi_extract_files.py ├── ubi_io ├── Makefile.am └── __init__.py ├── ubifs ├── Makefile.am ├── __init__.py ├── defines.py ├── log.py ├── lzo.so ├── misc.py ├── nodes │ ├── Makefile.am │ ├── __init__.py │ └── extract.py ├── output.py └── walk.py └── ui ├── Makefile.am ├── __init__.py └── common.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | SUBDIRS = po src 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenMultiBoot - 1.0 2014/10/03# 2 | 3 | - OpenMultiBoot will be donated to OE-Alliance by GigaBlue. 4 | - OpenMultiBoot can be modified or adapted to work with stb's from other vendors as long naming "openMultiBoot" is not changed and logos of openMultiBoot persists. 5 | - OpenMultiBoot uses boxbranding and informations from oe-alliance bitbake recipes. Due to that - ipk's are specific for each stb! Do not try to use OpenMultiBoot from stb A on stb B. 6 | - **GigaBlue takes no responsibility for any potential damage openMultiBoot might cause on stb's from other vendors.** 7 | - OpenMultiBoot requires some kernel-modules to work. They will be installed on installation of OpenMultiBoot. 8 | - **ubifs** - **kernel-module-nandsim** 9 | - **jffs2** - **kernel-module-nandsim kernel-module-block2mtd** 10 | 11 | (c) 2014 Impex-Sat GmbH & Co. KG - http://www.gigablue.de 12 | 13 | # This branch have some improvements to the original OMB: 14 | - Supports py2 and py3 images. 15 | - Supports enigma.info. 16 | - Supports moving of the exteran between different boxes. Just jump to flash image before disconnecting. Omb will show you on the menu just the image for current box. 17 | - Menu load faster by calling external binary (boxbranding helper ) just one time for each image. 18 | - New bootmenu helper that produce a json. @devs, You can use this new helper to preview the image list output. 19 | 20 | ## Notes: ## 21 | - < device > has to be formated in ext4 22 | - < device > should be a fast usb-stick or ssd - not recommended to use a normal hdd as hdd would almost never stop spinning 23 | - Upload any zipped image to < device >/open-multiboot-upload or /omb/open-multiboot-upload 24 | - Zipped image needs regular folderstructure like flashing from usb-device 25 | - It is not recommended to re-use existing settings - do not blame us if problems occur 26 | - Check your recording path configuration and existing timers if you attach a new device 27 | - Do not use Flash-Online if you have not booted your regularly flashed image - use delete/install in OpenMultiBoot of regularly flashed image 28 | - Special thx goes to skaman, kajgan, captain, arn354 and all testers! 29 | 30 | 31 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(plugins,1.0) 2 | AM_INIT_AUTOMAKE(plugins,1.0) 3 | 4 | AC_PATH_PROG(MSGFMT, msgfmt, AC_MSG_ERROR(Could not find msgfmt)) 5 | 6 | AM_PATH_PYTHON 7 | AC_PYTHON_DEVEL 8 | 9 | AC_PROG_CXX 10 | 11 | CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS" 12 | LDFLAGS="$LDFLAGS $PYTHON_LDFLAGS" 13 | 14 | AC_ARG_WITH(po, 15 | AS_HELP_STRING([--with-po],[enable updating of po files]), 16 | [with_po="$withval"],[with_po="no"]) 17 | if test "$with_po" = "yes"; then 18 | AC_PATH_PROG(MSGINIT, msginit) 19 | AC_PATH_PROG(MSGMERGE, msgmerge) 20 | AC_PATH_PROG(MSGUNIQ, msguniq) 21 | AC_PATH_PROG(XGETTEXT, xgettext) 22 | if test -z "$MSGINIT" -o -z "$MSGMERGE" -o -z "$MSGUNIQ" -o -z "$XGETTEXT"; then 23 | AC_MSG_ERROR([Could not find required gettext tools]) 24 | fi 25 | fi 26 | AM_CONDITIONAL(UPDATE_PO, test "$with_po" = "yes") 27 | 28 | AC_ARG_WITH(arch, 29 | [ --with-arch=NAME box arch [[none,ah4,mipsel...]]], 30 | [ARCH="$withval"],[ARCH="mipsel"]) 31 | AC_SUBST(ARCH) 32 | AC_DEFINE_UNQUOTED(ARCH,"$ARCH",[box arch]) 33 | 34 | AM_CONDITIONAL(SH4, test `echo "$ARCH" | cut -b 1-3` == "sh4") 35 | AM_CONDITIONAL(MIPSEL, test `echo "$ARCH" | cut -b 1-6` == "mipsel") 36 | AM_CONDITIONAL(ARM, test `echo "$ARCH" | cut -b 1-3` == "arm") 37 | 38 | AC_OUTPUT([ 39 | Makefile 40 | po/Makefile 41 | src/Makefile 42 | src/ubi_reader/Makefile 43 | src/ubi_reader/ubi/Makefile 44 | src/ubi_reader/ubi/block/Makefile 45 | src/ubi_reader/ubi/headers/Makefile 46 | src/ubi_reader/ubi/volume/Makefile 47 | src/ubi_reader/ubi_io/Makefile 48 | src/ubi_reader/ubifs/Makefile 49 | src/ubi_reader/ubifs/nodes/Makefile 50 | src/ubi_reader/ui/Makefile 51 | src/elftools/construct/Makefile 52 | src/elftools/construct/lib/Makefile 53 | src/elftools/ehabi/Makefile 54 | src/elftools/Makefile 55 | src/elftools/common/Makefile 56 | src/elftools/elf/Makefile 57 | src/elftools/dwarf/Makefile 58 | ]) 59 | -------------------------------------------------------------------------------- /po/Makefile.am: -------------------------------------------------------------------------------- 1 | LANGS = ar bg de el et fi fr it lt nl pl pt ru tr 2 | LANGMO = $(LANGS:=.mo) 3 | LANGPO = $(LANGS:=.po) 4 | 5 | EXTRA_DIST = $(LANGPO) 6 | 7 | if UPDATE_PO 8 | # the TRANSLATORS: allows putting translation comments before the to-be-translated line. 9 | open-multiboot-py.pot: $(top_srcdir)/src/*.py 10 | $(XGETTEXT) --no-wrap -L Python --from-code=UTF-8 -kpgettext:1c,2 --add-comments="TRANSLATORS:" -d @PACKAGE_NAME@ -s -o $@ $^ 11 | 12 | open-multiboot.pot: open-multiboot-py.pot 13 | sed --in-place open-multiboot-py.pot --expression=s/CHARSET/UTF-8/ 14 | $(MSGUNIQ) --no-wrap --no-location $^ -o $@ 15 | 16 | %.po: open-multiboot.pot 17 | if [ -f $@ ]; then \ 18 | $(MSGMERGE) --backup=none --no-wrap --no-location -s -N -U $@ $< && touch $@; \ 19 | else \ 20 | $(MSGINIT) -l $@ -o $@ -i $< --no-translator; \ 21 | fi 22 | endif 23 | 24 | .po.mo: 25 | $(MSGFMT) -o $@ $< 26 | 27 | BUILT_SOURCES = $(LANGMO) 28 | CLEANFILES = $(LANGMO) open-multiboot-py.pot open-multiboot.pot 29 | 30 | dist-hook: $(LANGPO) 31 | 32 | install-data-local: $(LANGMO) 33 | for lang in $(LANGS); do \ 34 | $(mkinstalldirs) $(DESTDIR)$(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/locale/$$lang/LC_MESSAGES; \ 35 | $(INSTALL_DATA) $$lang.mo $(DESTDIR)$(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/locale/$$lang/LC_MESSAGES/OpenMultiboot.mo; \ 36 | $(INSTALL_DATA) $$lang.po $(DESTDIR)$(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/locale/$$lang.po; \ 37 | done 38 | 39 | uninstall-local: 40 | for lang in $(LANGS); do \ 41 | $(RM) $(DESTDIR)$(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/locale/$$lang/LC_MESSAGES/OpenMultiboot.mo; \ 42 | $(RM) $(DESTDIR)$(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/locale/$$lang.po; \ 43 | done 44 | -------------------------------------------------------------------------------- /po/ar.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: OpenMultiboot\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2022-11-30 13:12+0000\n" 6 | "PO-Revision-Date: 2018-12-02 13:33+0300\n" 7 | "Last-Translator: mosad - مساعد الجعيد \n" 8 | "Language-Team: mosad - مساعد الجعيد\n" 9 | "Language: ar\n" 10 | "MIME-Version: 1.0\n" 11 | "Content-Type: text/plain; charset=UTF-8\n" 12 | "Content-Transfer-Encoding: 8bit\n" 13 | "X-Generator: Poedit 2.2\n" 14 | "Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n" 15 | 16 | #: ../src/OMBManager.py:145 17 | msgid "" 18 | " to use openMultiboot\n" 19 | "Do you want install it?" 20 | msgstr "" 21 | " لا تستخدم الملتيبوت المفتوح\n" 22 | "هل تريد تثبيته؟" 23 | 24 | #: ../src/OMBManagerList.py:263 25 | msgid "About" 26 | msgstr "حول" 27 | 28 | #: ../src/OMBManager.py:50 29 | msgid "Cancel" 30 | msgstr "إلغاء" 31 | 32 | #: ../src/OMBManager.py:78 33 | msgid "Cannot create data folder" 34 | msgstr "لا يمكن إنشاء مجلد بيانات" 35 | 36 | #: ../src/OMBManagerInstall.py:229 ../src/OMBManagerInstall.py:240 37 | #, python-format 38 | msgid "Cannot create folder %s" 39 | msgstr "لا يمكن إنشاء المجلد %s" 40 | 41 | #: ../src/OMBManagerInstall.py:219 42 | #, python-format 43 | msgid "Cannot create kernel folder %s" 44 | msgstr "لا يمكن إنشاء مجلد نواة %s" 45 | 46 | #: ../src/OMBManagerInstall.py:212 47 | #, python-format 48 | msgid "Cannot create main folder %s" 49 | msgstr "لا يمكن إنشاء المجلد الرئيسي %s" 50 | 51 | #: ../src/OMBManagerInstall.py:382 52 | msgid "Cannot create virtual MTD device" 53 | msgstr "لا يمكن إنشاء الجهاز الظاهري" 54 | 55 | #: ../src/OMBManagerInstall.py:244 56 | msgid "Cannot deflate image" 57 | msgstr "لا يمكن إفراغ الصورة" 58 | 59 | #: ../src/OMBManagerInstall.py:250 60 | msgid "Cannot extract nfi image" 61 | msgstr "لا يمكن استخراج صورة nfi" 62 | 63 | #: ../src/OMBManager.py:104 64 | msgid "Cannot format the device" 65 | msgstr "لا يمكن تهيئه الجهاز" 66 | 67 | #: ../src/OMBManager.py:164 68 | msgid "Cannot install " 69 | msgstr "لا يمكن التثبيت" 70 | 71 | #: ../src/OMBManager.py:107 72 | msgid "Cannot remount the device" 73 | msgstr "لا يمكن أعاده ربط الجهاز" 74 | 75 | #: ../src/OMBManager.py:101 76 | msgid "Cannot umount the device" 77 | msgstr "لا يمكن ربط الجهاز" 78 | 79 | #: ../src/OMBManagerInstall.py:152 80 | msgid "Choose the image to install" 81 | msgstr "اختر الصورة التي سيتم تثبيتها" 82 | 83 | #: ../src/OMBManagerList.py:178 84 | msgid "Current Running Image:" 85 | msgstr "تعمل الصورة الحالية:" 86 | 87 | #: ../src/OMBManagerList.py:238 88 | msgid "Delete" 89 | msgstr "حذف" 90 | 91 | #: ../src/OMBManagerList.py:319 92 | #, python-format 93 | msgid "Do you want to delete %s?" 94 | msgstr "هل تريد حذف %s ؟" 95 | 96 | #: ../src/OMBManagerList.py:256 97 | msgid "Do you want to reboot now ?" 98 | msgstr "هل تريد أعاده التشغيل الآن ؟" 99 | 100 | #: ../src/OMBManagerList.py:370 101 | msgid "Enable Boot Menu" 102 | msgstr "تمكين قائمة الإقلاع" 103 | 104 | #: ../src/OMBManagerInstall.py:286 ../src/OMBManagerInstall.py:316 105 | #: ../src/OMBManagerInstall.py:332 ../src/OMBManagerInstall.py:397 106 | msgid "Error copying kernel" 107 | msgstr "خطاء نسخ النواة" 108 | 109 | #: ../src/OMBManagerInstall.py:313 ../src/OMBManagerInstall.py:329 110 | #: ../src/OMBManagerInstall.py:394 111 | msgid "Error copying unpacked rootfs" 112 | msgstr "حدث خطاء أثناء نسخ الجذر الذي تم فك حزمته" 113 | 114 | #: ../src/OMBManagerInstall.py:281 ../src/OMBManagerInstall.py:308 115 | msgid "Error unpacking rootfs" 116 | msgstr "خطا في إستخراج الجذر" 117 | 118 | #: ../src/OMBManager.py:133 119 | msgid "" 120 | "Filesystem not supported\n" 121 | "Do you want format your drive?" 122 | msgstr "" 123 | "نظام الملفات غير معتمد\n" 124 | "هل تريد تهئية محرك الاقراص الخاص بك ؟" 125 | 126 | #: ../src/OMBManagerInstall.py:335 ../src/OMBManagerInstall.py:400 127 | #, fuzzy 128 | msgid "Generic error in unpack process" 129 | msgstr "خطاء عام في عملية فتح الملف المضغوط" 130 | 131 | #: ../src/OMBManagerList.py:189 132 | msgid "Install" 133 | msgstr "تثبيت" 134 | 135 | #: ../src/OMBManagerList.py:187 136 | msgid "Menu" 137 | msgstr "قائمة" 138 | 139 | #: ../src/OMBManager.py:55 140 | msgid "No suitable devices found" 141 | msgstr "لم يتم العثور علي أجهزه مناسبة" 142 | 143 | #: ../src/OMBManagerList.py:264 144 | msgid "Open MultiBoot Menu" 145 | msgstr "قائمة الملتيبوت المفتوح" 146 | 147 | #: ../src/plugin.py:34 148 | msgid "OpenMultiboot Manager" 149 | msgstr "إدارة الملتيبوت المفتوح" 150 | 151 | #: ../src/OMBManagerList.py:280 152 | msgid "Please enter new name:" 153 | msgstr "الرجاء إدخال اسم جديد:" 154 | 155 | #: ../src/OMBManagerList.py:338 156 | #, python-format 157 | msgid "Please upload an image inside %s" 158 | msgstr "من فضلك أرفع صورة في الداخل %s" 159 | 160 | #: ../src/OMBManagerList.py:298 161 | msgid "Please wait while delete is in progress." 162 | msgstr "الرجاء الانتظار أثناء الحذف قيد التقدم." 163 | 164 | #: ../src/OMBManager.py:92 165 | msgid "Please wait while format is in progress." 166 | msgstr "الرجاء الانتظار بينما تكون التهئية قيد التقدم." 167 | 168 | #: ../src/OMBManager.py:155 169 | msgid "Please wait while installation is in progress." 170 | msgstr "الرجاء الانتظار أثناء التثبيت قيد التقدم." 171 | 172 | #: ../src/OMBManagerInstall.py:168 173 | msgid "" 174 | "Please wait while installation is in progress.\n" 175 | "This operation may take a while." 176 | msgstr "" 177 | "الرجاء الانتظار أثناء التثبيت قيد التقدم.\n" 178 | "قد تستغرق هذه العملية بعض الوقت." 179 | 180 | #: ../src/OMBManagerList.py:263 181 | msgid "Preferences" 182 | msgstr "الإعدادات" 183 | 184 | #: ../src/OMBManagerList.py:185 185 | msgid "Rename" 186 | msgstr "إعادة تسمية" 187 | 188 | #: ../src/OMBManagerList.py:358 189 | msgid "Save" 190 | msgstr "حفظ" 191 | 192 | #: ../src/OMBManagerList.py:245 193 | #, python-format 194 | msgid "Set next boot to %s ?" 195 | msgstr "هل تريد تعيين الإقلاع التالي %s ?" 196 | 197 | #: ../src/OMBManagerInstall.py:223 198 | #, python-format 199 | msgid "The folder %s already exist" 200 | msgstr "المجلد %s موجود بالفعل" 201 | 202 | #: ../src/OMBManager.py:43 203 | msgid "Where do you want to install openMultiboot?" 204 | msgstr "أين تريد تثبيت نظام الملتيبوت المفتوح؟" 205 | 206 | #: ../src/OMBManager.py:145 207 | msgid "You need the module " 208 | msgstr "أنت في حاجه إلى الوحدة" 209 | 210 | #: ../src/OMBManagerInstall.py:272 211 | msgid "Your STB doesn't seem supported" 212 | msgstr "لا يبدو أن جهاز الإستقبال الخاص بك معتمد" 213 | 214 | #: ../src/OMBManagerAbout.py:47 215 | msgid "openMultiboot About" 216 | msgstr "حول الملتيبوت المفتوح" 217 | 218 | #: ../src/OMBManagerInstall.py:143 219 | msgid "openMultiboot Install" 220 | msgstr "تثبيت الملتيبوت المفتوح" 221 | 222 | #: ../src/OMBManagerList.py:167 223 | msgid "openMultiboot Manager" 224 | msgstr "إدارة الملتيبوت المفتوح" 225 | -------------------------------------------------------------------------------- /po/et.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: \n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2022-11-30 13:12+0000\n" 11 | "PO-Revision-Date: 2018-12-02 10:59+0200\n" 12 | "Last-Translator: rimas \n" 13 | "Language-Team: \n" 14 | "Language: et_EE\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "X-Generator: Poedit 2.2\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: ../src/OMBManager.py:145 22 | msgid "" 23 | " to use openMultiboot\n" 24 | "Do you want install it?" 25 | msgstr "" 26 | " on vajalik openMultiboot kasutamiseks\n" 27 | "Kas paigaldada see?" 28 | 29 | #: ../src/OMBManagerList.py:263 30 | msgid "About" 31 | msgstr "" 32 | 33 | #: ../src/OMBManager.py:50 34 | msgid "Cancel" 35 | msgstr "Tühista" 36 | 37 | #: ../src/OMBManager.py:78 38 | msgid "Cannot create data folder" 39 | msgstr "Andmekataloogi loomine nurjus" 40 | 41 | #: ../src/OMBManagerInstall.py:229 ../src/OMBManagerInstall.py:240 42 | #, python-format 43 | msgid "Cannot create folder %s" 44 | msgstr "Kataloogi %s loomine nurjus" 45 | 46 | #: ../src/OMBManagerInstall.py:219 47 | #, python-format 48 | msgid "Cannot create kernel folder %s" 49 | msgstr "Kerneli kataloogi %s loomine nurjus" 50 | 51 | #: ../src/OMBManagerInstall.py:212 52 | #, python-format 53 | msgid "Cannot create main folder %s" 54 | msgstr "Põhikataloogi %s loomine nurjus" 55 | 56 | #: ../src/OMBManagerInstall.py:382 57 | msgid "Cannot create virtual MTD device" 58 | msgstr "Virtuaalse MTD seadme loomine nurjus" 59 | 60 | #: ../src/OMBManagerInstall.py:244 61 | msgid "Cannot deflate image" 62 | msgstr "Püsivara lahtipakkimine nurjus" 63 | 64 | #: ../src/OMBManagerInstall.py:250 65 | msgid "Cannot extract nfi image" 66 | msgstr "NFI tõmmise paigaldamine pole võimalik" 67 | 68 | #: ../src/OMBManager.py:104 69 | msgid "Cannot format the device" 70 | msgstr "Andmekandjat ei saa vormindada" 71 | 72 | #: ../src/OMBManager.py:164 73 | msgid "Cannot install " 74 | msgstr "Paigaldamine nurjus " 75 | 76 | #: ../src/OMBManager.py:107 77 | msgid "Cannot remount the device" 78 | msgstr "Andmekandja taashaakimine nurjus" 79 | 80 | #: ../src/OMBManager.py:101 81 | msgid "Cannot umount the device" 82 | msgstr "Andmekandja lahtihaakimine nurjus" 83 | 84 | #: ../src/OMBManagerInstall.py:152 85 | msgid "Choose the image to install" 86 | msgstr "Vali paigaldatav püsivara" 87 | 88 | #: ../src/OMBManagerList.py:178 89 | msgid "Current Running Image:" 90 | msgstr "Aktiivne püsivara:" 91 | 92 | #: ../src/OMBManagerList.py:238 93 | msgid "Delete" 94 | msgstr "Kustuta" 95 | 96 | #: ../src/OMBManagerList.py:319 97 | #, python-format 98 | msgid "Do you want to delete %s?" 99 | msgstr "Kas kustutada %s?" 100 | 101 | #: ../src/OMBManagerList.py:256 102 | msgid "Do you want to reboot now ?" 103 | msgstr "Kas taaskäivitada kohe?" 104 | 105 | #: ../src/OMBManagerList.py:370 106 | msgid "Enable Boot Menu" 107 | msgstr "Luba buudimenüü" 108 | 109 | #: ../src/OMBManagerInstall.py:286 ../src/OMBManagerInstall.py:316 110 | #: ../src/OMBManagerInstall.py:332 ../src/OMBManagerInstall.py:397 111 | msgid "Error copying kernel" 112 | msgstr "Viga kerneli kopeerimisel!" 113 | 114 | #: ../src/OMBManagerInstall.py:313 ../src/OMBManagerInstall.py:329 115 | #: ../src/OMBManagerInstall.py:394 116 | msgid "Error copying unpacked rootfs" 117 | msgstr "Viga rootfs kopeerimisel!" 118 | 119 | #: ../src/OMBManagerInstall.py:281 ../src/OMBManagerInstall.py:308 120 | msgid "Error unpacking rootfs" 121 | msgstr "Viga rootfs lahtipakkimisel!" 122 | 123 | #: ../src/OMBManager.py:133 124 | msgid "" 125 | "Filesystem not supported\n" 126 | "Do you want format your drive?" 127 | msgstr "" 128 | "Failisüsteem ei ole toetatud\n" 129 | "Kas vormindada andmekandja?" 130 | 131 | #: ../src/OMBManagerInstall.py:335 ../src/OMBManagerInstall.py:400 132 | msgid "Generic error in unpack process" 133 | msgstr "Üldine tõrge lahtipakkimisel" 134 | 135 | #: ../src/OMBManagerList.py:189 136 | msgid "Install" 137 | msgstr "Paigalda" 138 | 139 | #: ../src/OMBManagerList.py:187 140 | msgid "Menu" 141 | msgstr "Menüü" 142 | 143 | #: ../src/OMBManager.py:55 144 | msgid "No suitable devices found" 145 | msgstr "Sobivat andmekandjat ei leitud" 146 | 147 | #: ../src/OMBManagerList.py:264 148 | msgid "Open MultiBoot Menu" 149 | msgstr "OpenMultiBoot menüü" 150 | 151 | #: ../src/plugin.py:34 152 | msgid "OpenMultiboot Manager" 153 | msgstr "OpenMultiboot haldur" 154 | 155 | #: ../src/OMBManagerList.py:280 156 | msgid "Please enter new name:" 157 | msgstr "Sisesta uus nimi:" 158 | 159 | #: ../src/OMBManagerList.py:338 160 | #, python-format 161 | msgid "Please upload an image inside %s" 162 | msgstr "Saada tõmmis kataloogi %s" 163 | 164 | #: ../src/OMBManagerList.py:298 165 | msgid "Please wait while delete is in progress." 166 | msgstr "Toimub kustutamine." 167 | 168 | #: ../src/OMBManager.py:92 169 | msgid "Please wait while format is in progress." 170 | msgstr "Toimub vormindamine." 171 | 172 | #: ../src/OMBManager.py:155 173 | msgid "Please wait while installation is in progress." 174 | msgstr "Toimub paigaldamine." 175 | 176 | #: ../src/OMBManagerInstall.py:168 177 | msgid "" 178 | "Please wait while installation is in progress.\n" 179 | "This operation may take a while." 180 | msgstr "" 181 | "Toimub paigaldamine.\n" 182 | "See võib kesta mõnda aega." 183 | 184 | #: ../src/OMBManagerList.py:263 185 | msgid "Preferences" 186 | msgstr "" 187 | 188 | #: ../src/OMBManagerList.py:185 189 | msgid "Rename" 190 | msgstr "Nimeta ümber" 191 | 192 | #: ../src/OMBManagerList.py:358 193 | msgid "Save" 194 | msgstr "Salvesta" 195 | 196 | #: ../src/OMBManagerList.py:245 197 | #, python-format 198 | msgid "Set next boot to %s ?" 199 | msgstr "Kas järgmisel buutimisel laadida %s?" 200 | 201 | #: ../src/OMBManagerInstall.py:223 202 | #, python-format 203 | msgid "The folder %s already exist" 204 | msgstr "Kaust %s on juba olemas" 205 | 206 | #: ../src/OMBManager.py:43 207 | msgid "Where do you want to install openMultiboot?" 208 | msgstr "Kuhu openMultiboot paigaldada?" 209 | 210 | #: ../src/OMBManager.py:145 211 | msgid "You need the module " 212 | msgstr "Moodul " 213 | 214 | #: ../src/OMBManagerInstall.py:272 215 | msgid "Your STB doesn't seem supported" 216 | msgstr "Vastuvõtja pole toetatud" 217 | 218 | #: ../src/OMBManagerAbout.py:47 219 | msgid "openMultiboot About" 220 | msgstr "Programmist" 221 | 222 | #: ../src/OMBManagerInstall.py:143 223 | msgid "openMultiboot Install" 224 | msgstr "openMultiboot - paigaldamine" 225 | 226 | #: ../src/OMBManagerList.py:167 227 | msgid "openMultiboot Manager" 228 | msgstr "openMultiboot haldur" 229 | -------------------------------------------------------------------------------- /po/it.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # Sandro Cavazzoni , 2014. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: \n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2022-11-30 13:12+0000\n" 12 | "PO-Revision-Date: 2016-05-08 13:20+0200\n" 13 | "Last-Translator: neoatomic \n" 14 | "Language-Team: Italiano \n" 15 | "Language: it\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | "X-Generator: Poedit 1.8.7\n" 21 | "X-Poedit-Basepath: ..\n" 22 | "X-Poedit-SearchPath-0: .\n" 23 | 24 | #: ../src/OMBManager.py:145 25 | msgid "" 26 | " to use openMultiboot\n" 27 | "Do you want install it?" 28 | msgstr "" 29 | 30 | #: ../src/OMBManagerList.py:263 31 | msgid "About" 32 | msgstr "" 33 | 34 | #: ../src/OMBManager.py:50 35 | msgid "Cancel" 36 | msgstr "" 37 | 38 | #: ../src/OMBManager.py:78 39 | msgid "Cannot create data folder" 40 | msgstr "Impossibile creare la cartella dei dati" 41 | 42 | #: ../src/OMBManagerInstall.py:229 ../src/OMBManagerInstall.py:240 43 | #, python-format 44 | msgid "Cannot create folder %s" 45 | msgstr "Impossibile creare la cartella %s" 46 | 47 | #: ../src/OMBManagerInstall.py:219 48 | #, python-format 49 | msgid "Cannot create kernel folder %s" 50 | msgstr "Impossibile creare la cartella del kernel %s" 51 | 52 | #: ../src/OMBManagerInstall.py:212 53 | #, python-format 54 | msgid "Cannot create main folder %s" 55 | msgstr "" 56 | 57 | #: ../src/OMBManagerInstall.py:382 58 | msgid "Cannot create virtual MTD device" 59 | msgstr "Impossibile creare il dispositivo MTD virtuale" 60 | 61 | #: ../src/OMBManagerInstall.py:244 62 | msgid "Cannot deflate image" 63 | msgstr "Impossibile decomprimere l'immagine" 64 | 65 | #: ../src/OMBManagerInstall.py:250 66 | msgid "Cannot extract nfi image" 67 | msgstr "" 68 | 69 | #: ../src/OMBManager.py:104 70 | msgid "Cannot format the device" 71 | msgstr "Impossibile formattare il dispositivo" 72 | 73 | #: ../src/OMBManager.py:164 74 | msgid "Cannot install " 75 | msgstr "" 76 | 77 | #: ../src/OMBManager.py:107 78 | msgid "Cannot remount the device" 79 | msgstr "Impossibile riconnettere il dispositivo" 80 | 81 | #: ../src/OMBManager.py:101 82 | msgid "Cannot umount the device" 83 | msgstr "Impossibile sconnettere il dispositivo" 84 | 85 | #: ../src/OMBManagerInstall.py:152 86 | msgid "Choose the image to install" 87 | msgstr "Scegli l'immagine da installare" 88 | 89 | #: ../src/OMBManagerList.py:178 90 | msgid "Current Running Image:" 91 | msgstr "" 92 | 93 | #: ../src/OMBManagerList.py:238 94 | msgid "Delete" 95 | msgstr "Elimina" 96 | 97 | #: ../src/OMBManagerList.py:319 98 | #, python-format 99 | msgid "Do you want to delete %s?" 100 | msgstr "Vuoi eliminare %s?" 101 | 102 | #: ../src/OMBManagerList.py:256 103 | msgid "Do you want to reboot now ?" 104 | msgstr "" 105 | 106 | #: ../src/OMBManagerList.py:370 107 | msgid "Enable Boot Menu" 108 | msgstr "" 109 | 110 | #: ../src/OMBManagerInstall.py:286 ../src/OMBManagerInstall.py:316 111 | #: ../src/OMBManagerInstall.py:332 ../src/OMBManagerInstall.py:397 112 | msgid "Error copying kernel" 113 | msgstr "" 114 | 115 | #: ../src/OMBManagerInstall.py:313 ../src/OMBManagerInstall.py:329 116 | #: ../src/OMBManagerInstall.py:394 117 | msgid "Error copying unpacked rootfs" 118 | msgstr "" 119 | 120 | #: ../src/OMBManagerInstall.py:281 ../src/OMBManagerInstall.py:308 121 | msgid "Error unpacking rootfs" 122 | msgstr "" 123 | 124 | #: ../src/OMBManager.py:133 125 | msgid "" 126 | "Filesystem not supported\n" 127 | "Do you want format your drive?" 128 | msgstr "" 129 | "Filesystem non supportato\n" 130 | "Vuoi formattare il tuo disco?" 131 | 132 | #: ../src/OMBManagerInstall.py:335 ../src/OMBManagerInstall.py:400 133 | msgid "Generic error in unpack process" 134 | msgstr "" 135 | 136 | #: ../src/OMBManagerList.py:189 137 | msgid "Install" 138 | msgstr "Installa" 139 | 140 | #: ../src/OMBManagerList.py:187 141 | msgid "Menu" 142 | msgstr "" 143 | 144 | #: ../src/OMBManager.py:55 145 | msgid "No suitable devices found" 146 | msgstr "Nessun dispositivo supportato trovato" 147 | 148 | #: ../src/OMBManagerList.py:264 149 | msgid "Open MultiBoot Menu" 150 | msgstr "" 151 | 152 | #: ../src/plugin.py:34 153 | msgid "OpenMultiboot Manager" 154 | msgstr "" 155 | 156 | #: ../src/OMBManagerList.py:280 157 | msgid "Please enter new name:" 158 | msgstr "" 159 | 160 | #: ../src/OMBManagerList.py:338 161 | #, python-format 162 | msgid "Please upload an image inside %s" 163 | msgstr "Per favore carica un'immagine dentro %s" 164 | 165 | #: ../src/OMBManagerList.py:298 166 | msgid "Please wait while delete is in progress." 167 | msgstr "Attendere, eliminazione in corso." 168 | 169 | #: ../src/OMBManager.py:92 170 | msgid "Please wait while format is in progress." 171 | msgstr "Attendere, formattazione in corso." 172 | 173 | #: ../src/OMBManager.py:155 174 | msgid "Please wait while installation is in progress." 175 | msgstr "Attendere, installazione in corso." 176 | 177 | #: ../src/OMBManagerInstall.py:168 178 | msgid "" 179 | "Please wait while installation is in progress.\n" 180 | "This operation may take a while." 181 | msgstr "" 182 | "Attendere, installazione in corso.\n" 183 | "L'operazione potrebbe richiedere molto tempo." 184 | 185 | #: ../src/OMBManagerList.py:263 186 | msgid "Preferences" 187 | msgstr "" 188 | 189 | #: ../src/OMBManagerList.py:185 190 | msgid "Rename" 191 | msgstr "Rinomina" 192 | 193 | #: ../src/OMBManagerList.py:358 194 | msgid "Save" 195 | msgstr "" 196 | 197 | #: ../src/OMBManagerList.py:245 198 | #, python-format 199 | msgid "Set next boot to %s ?" 200 | msgstr "" 201 | 202 | #: ../src/OMBManagerInstall.py:223 203 | #, python-format 204 | msgid "The folder %s already exist" 205 | msgstr "La cartella %s è già esistente" 206 | 207 | #: ../src/OMBManager.py:43 208 | msgid "Where do you want to install openMultiboot?" 209 | msgstr "Dove vuoi installare openMultiboot?" 210 | 211 | #: ../src/OMBManager.py:145 212 | msgid "You need the module " 213 | msgstr "" 214 | 215 | #: ../src/OMBManagerInstall.py:272 216 | msgid "Your STB doesn't seem supported" 217 | msgstr "Il tuo decoder non sembra essere supportato" 218 | 219 | #: ../src/OMBManagerAbout.py:47 220 | msgid "openMultiboot About" 221 | msgstr "openMultiboot About" 222 | 223 | #: ../src/OMBManagerInstall.py:143 224 | msgid "openMultiboot Install" 225 | msgstr "openMultiboot Install" 226 | 227 | #: ../src/OMBManagerList.py:167 228 | msgid "openMultiboot Manager" 229 | msgstr "openMultiboot Manager" 230 | -------------------------------------------------------------------------------- /po/lt.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: openMultiboot\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2022-11-30 13:12+0000\n" 6 | "PO-Revision-Date: 2017-06-18 08:48+0300\n" 7 | "Last-Translator: Vytenis P. \n" 8 | "Language-Team: Vytenis P. \n" 9 | "Language: lt\n" 10 | "MIME-Version: 1.0\n" 11 | "Content-Type: text/plain; charset=UTF-8\n" 12 | "Content-Transfer-Encoding: 8bit\n" 13 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" 14 | "X-Generator: Poedit 2.0.2\n" 15 | "X-Poedit-SourceCharset: UTF-8\n" 16 | 17 | #: ../src/OMBManager.py:145 18 | msgid "" 19 | " to use openMultiboot\n" 20 | "Do you want install it?" 21 | msgstr "" 22 | " kad naudoti OpenMultiboot\n" 23 | "Norite jį įdiegti?" 24 | 25 | #: ../src/OMBManagerList.py:263 26 | msgid "About" 27 | msgstr "" 28 | 29 | #: ../src/OMBManager.py:50 30 | msgid "Cancel" 31 | msgstr "Atšaukti" 32 | 33 | #: ../src/OMBManager.py:78 34 | msgid "Cannot create data folder" 35 | msgstr "Nepavyko sukurti duomenų katalogo" 36 | 37 | #: ../src/OMBManagerInstall.py:229 ../src/OMBManagerInstall.py:240 38 | #, python-format 39 | msgid "Cannot create folder %s" 40 | msgstr "Nepavyko sukurti katalogo %s" 41 | 42 | #: ../src/OMBManagerInstall.py:219 43 | #, python-format 44 | msgid "Cannot create kernel folder %s" 45 | msgstr "Nepavyko sukurti branduolio katalogo %s" 46 | 47 | #: ../src/OMBManagerInstall.py:212 48 | #, python-format 49 | msgid "Cannot create main folder %s" 50 | msgstr "Nepavyko sukurti pirminio katalogo %s" 51 | 52 | #: ../src/OMBManagerInstall.py:382 53 | msgid "Cannot create virtual MTD device" 54 | msgstr "Nepavyko sukurti virtualaus MTD prietaiso" 55 | 56 | #: ../src/OMBManagerInstall.py:244 57 | msgid "Cannot deflate image" 58 | msgstr "Nepavyko išskleisti atvaizdo" 59 | 60 | #: ../src/OMBManagerInstall.py:250 61 | msgid "Cannot extract nfi image" 62 | msgstr "Nepavyko išskleisti NFI atvaizdo" 63 | 64 | #: ../src/OMBManager.py:104 65 | msgid "Cannot format the device" 66 | msgstr "Šio įrenginio formatuoti nepavyko" 67 | 68 | #: ../src/OMBManager.py:164 69 | msgid "Cannot install " 70 | msgstr "Nepavyko įdiegti " 71 | 72 | #: ../src/OMBManager.py:107 73 | msgid "Cannot remount the device" 74 | msgstr "Nepavyko persieti šio įrenginio" 75 | 76 | #: ../src/OMBManager.py:101 77 | msgid "Cannot umount the device" 78 | msgstr "Nepavyko atjungti šio įrenginio" 79 | 80 | #: ../src/OMBManagerInstall.py:152 81 | msgid "Choose the image to install" 82 | msgstr "Pasirinkite atvaizdą įdiegimui" 83 | 84 | #: ../src/OMBManagerList.py:178 85 | msgid "Current Running Image:" 86 | msgstr "Dabartinis atvaizdas:" 87 | 88 | #: ../src/OMBManagerList.py:238 89 | msgid "Delete" 90 | msgstr "Pašalinti" 91 | 92 | #: ../src/OMBManagerList.py:319 93 | #, python-format 94 | msgid "Do you want to delete %s?" 95 | msgstr "Ar tikrai norite šalinti %s?" 96 | 97 | #: ../src/OMBManagerList.py:256 98 | msgid "Do you want to reboot now ?" 99 | msgstr "Ar norite paleisti iš naujo?" 100 | 101 | #: ../src/OMBManagerList.py:370 102 | msgid "Enable Boot Menu" 103 | msgstr "Įjungti paleisties meniu" 104 | 105 | #: ../src/OMBManagerInstall.py:286 ../src/OMBManagerInstall.py:316 106 | #: ../src/OMBManagerInstall.py:332 ../src/OMBManagerInstall.py:397 107 | msgid "Error copying kernel" 108 | msgstr "" 109 | 110 | #: ../src/OMBManagerInstall.py:313 ../src/OMBManagerInstall.py:329 111 | #: ../src/OMBManagerInstall.py:394 112 | msgid "Error copying unpacked rootfs" 113 | msgstr "" 114 | 115 | #: ../src/OMBManagerInstall.py:281 ../src/OMBManagerInstall.py:308 116 | msgid "Error unpacking rootfs" 117 | msgstr "" 118 | 119 | #: ../src/OMBManager.py:133 120 | msgid "" 121 | "Filesystem not supported\n" 122 | "Do you want format your drive?" 123 | msgstr "" 124 | "Nepalaikoma failų sistema\n" 125 | "Ar norite formatuoti laikmeną?" 126 | 127 | #: ../src/OMBManagerInstall.py:335 ../src/OMBManagerInstall.py:400 128 | msgid "Generic error in unpack process" 129 | msgstr "" 130 | 131 | #: ../src/OMBManagerList.py:189 132 | msgid "Install" 133 | msgstr "Įdiegti" 134 | 135 | #: ../src/OMBManagerList.py:187 136 | msgid "Menu" 137 | msgstr "Meniu" 138 | 139 | #: ../src/OMBManager.py:55 140 | msgid "No suitable devices found" 141 | msgstr "Tinkamų įrenginių nerasta" 142 | 143 | #: ../src/OMBManagerList.py:264 144 | msgid "Open MultiBoot Menu" 145 | msgstr "Atverti MultiBoot meniu" 146 | 147 | #: ../src/plugin.py:34 148 | msgid "OpenMultiboot Manager" 149 | msgstr "OpenMultiboot - pasirinktinės įkrovos valdymas" 150 | 151 | #: ../src/OMBManagerList.py:280 152 | msgid "Please enter new name:" 153 | msgstr "Įrašykite naują pavadinimą:" 154 | 155 | #: ../src/OMBManagerList.py:338 156 | #, python-format 157 | msgid "Please upload an image inside %s" 158 | msgstr "Įkelkite atvaizdą į %s" 159 | 160 | #: ../src/OMBManagerList.py:298 161 | msgid "Please wait while delete is in progress." 162 | msgstr "Palaukite, kol vyksta šalinimas." 163 | 164 | #: ../src/OMBManager.py:92 165 | msgid "Please wait while format is in progress." 166 | msgstr "Palaukite, kol vyksta formatavimas." 167 | 168 | #: ../src/OMBManager.py:155 169 | msgid "Please wait while installation is in progress." 170 | msgstr "Palaukite, kol vyksta diegimas." 171 | 172 | #: ../src/OMBManagerInstall.py:168 173 | msgid "" 174 | "Please wait while installation is in progress.\n" 175 | "This operation may take a while." 176 | msgstr "" 177 | "Palaukite, kol vyksta diegimas.\n" 178 | "Ši operacija gali šiek tiek užtrukti." 179 | 180 | #: ../src/OMBManagerList.py:263 181 | msgid "Preferences" 182 | msgstr "" 183 | 184 | #: ../src/OMBManagerList.py:185 185 | msgid "Rename" 186 | msgstr "Pervadinti" 187 | 188 | #: ../src/OMBManagerList.py:358 189 | msgid "Save" 190 | msgstr "Išsaugoti" 191 | 192 | #: ../src/OMBManagerList.py:245 193 | #, python-format 194 | msgid "Set next boot to %s ?" 195 | msgstr "Kitam paleidimui pasirinkti %s ?" 196 | 197 | #: ../src/OMBManagerInstall.py:223 198 | #, python-format 199 | msgid "The folder %s already exist" 200 | msgstr "Aplankas %s jau yra" 201 | 202 | #: ../src/OMBManager.py:43 203 | msgid "Where do you want to install openMultiboot?" 204 | msgstr "Kur norite įdiegti OpenMultiboot?" 205 | 206 | #: ../src/OMBManager.py:145 207 | msgid "You need the module " 208 | msgstr "Jums reikia modulio " 209 | 210 | #: ../src/OMBManagerInstall.py:272 211 | msgid "Your STB doesn't seem supported" 212 | msgstr "Jūsų imtuvas to nepalaiko" 213 | 214 | #: ../src/OMBManagerAbout.py:47 215 | msgid "openMultiboot About" 216 | msgstr "Apie OpenMultiboot" 217 | 218 | #: ../src/OMBManagerInstall.py:143 219 | msgid "openMultiboot Install" 220 | msgstr "Įdiegti OpenMultiboot" 221 | 222 | #: ../src/OMBManagerList.py:167 223 | msgid "openMultiboot Manager" 224 | msgstr "OpenMultiboot valdymas" 225 | -------------------------------------------------------------------------------- /po/open-multiboot.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2022-11-30 13:12+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: ../src/OMBManager.py:145 21 | msgid "" 22 | " to use openMultiboot\n" 23 | "Do you want install it?" 24 | msgstr "" 25 | 26 | #: ../src/OMBManagerList.py:263 27 | msgid "About" 28 | msgstr "" 29 | 30 | #: ../src/OMBManager.py:50 31 | msgid "Cancel" 32 | msgstr "" 33 | 34 | #: ../src/OMBManager.py:78 35 | msgid "Cannot create data folder" 36 | msgstr "" 37 | 38 | #: ../src/OMBManagerInstall.py:229 ../src/OMBManagerInstall.py:240 39 | #, python-format 40 | msgid "Cannot create folder %s" 41 | msgstr "" 42 | 43 | #: ../src/OMBManagerInstall.py:219 44 | #, python-format 45 | msgid "Cannot create kernel folder %s" 46 | msgstr "" 47 | 48 | #: ../src/OMBManagerInstall.py:212 49 | #, python-format 50 | msgid "Cannot create main folder %s" 51 | msgstr "" 52 | 53 | #: ../src/OMBManagerInstall.py:382 54 | msgid "Cannot create virtual MTD device" 55 | msgstr "" 56 | 57 | #: ../src/OMBManagerInstall.py:244 58 | msgid "Cannot deflate image" 59 | msgstr "" 60 | 61 | #: ../src/OMBManagerInstall.py:250 62 | msgid "Cannot extract nfi image" 63 | msgstr "" 64 | 65 | #: ../src/OMBManager.py:104 66 | msgid "Cannot format the device" 67 | msgstr "" 68 | 69 | #: ../src/OMBManager.py:164 70 | msgid "Cannot install " 71 | msgstr "" 72 | 73 | #: ../src/OMBManager.py:107 74 | msgid "Cannot remount the device" 75 | msgstr "" 76 | 77 | #: ../src/OMBManager.py:101 78 | msgid "Cannot umount the device" 79 | msgstr "" 80 | 81 | #: ../src/OMBManagerInstall.py:152 82 | msgid "Choose the image to install" 83 | msgstr "" 84 | 85 | #: ../src/OMBManagerList.py:178 86 | msgid "Current Running Image:" 87 | msgstr "" 88 | 89 | #: ../src/OMBManagerList.py:238 90 | msgid "Delete" 91 | msgstr "" 92 | 93 | #: ../src/OMBManagerList.py:319 94 | #, python-format 95 | msgid "Do you want to delete %s?" 96 | msgstr "" 97 | 98 | #: ../src/OMBManagerList.py:256 99 | msgid "Do you want to reboot now ?" 100 | msgstr "" 101 | 102 | #: ../src/OMBManagerList.py:370 103 | msgid "Enable Boot Menu" 104 | msgstr "" 105 | 106 | #: ../src/OMBManagerInstall.py:286 ../src/OMBManagerInstall.py:316 107 | #: ../src/OMBManagerInstall.py:332 ../src/OMBManagerInstall.py:397 108 | msgid "Error copying kernel" 109 | msgstr "" 110 | 111 | #: ../src/OMBManagerInstall.py:313 ../src/OMBManagerInstall.py:329 112 | #: ../src/OMBManagerInstall.py:394 113 | msgid "Error copying unpacked rootfs" 114 | msgstr "" 115 | 116 | #: ../src/OMBManagerInstall.py:281 ../src/OMBManagerInstall.py:308 117 | msgid "Error unpacking rootfs" 118 | msgstr "" 119 | 120 | #: ../src/OMBManager.py:133 121 | msgid "" 122 | "Filesystem not supported\n" 123 | "Do you want format your drive?" 124 | msgstr "" 125 | 126 | #: ../src/OMBManagerInstall.py:335 ../src/OMBManagerInstall.py:400 127 | msgid "Generic error in unpack process" 128 | msgstr "" 129 | 130 | #: ../src/OMBManagerList.py:189 131 | msgid "Install" 132 | msgstr "" 133 | 134 | #: ../src/OMBManagerList.py:187 135 | msgid "Menu" 136 | msgstr "" 137 | 138 | #: ../src/OMBManager.py:55 139 | msgid "No suitable devices found" 140 | msgstr "" 141 | 142 | #: ../src/OMBManagerList.py:264 143 | msgid "Open MultiBoot Menu" 144 | msgstr "" 145 | 146 | #: ../src/plugin.py:34 147 | msgid "OpenMultiboot Manager" 148 | msgstr "" 149 | 150 | #: ../src/OMBManagerList.py:280 151 | msgid "Please enter new name:" 152 | msgstr "" 153 | 154 | #: ../src/OMBManagerList.py:338 155 | #, python-format 156 | msgid "Please upload an image inside %s" 157 | msgstr "" 158 | 159 | #: ../src/OMBManagerList.py:298 160 | msgid "Please wait while delete is in progress." 161 | msgstr "" 162 | 163 | #: ../src/OMBManager.py:92 164 | msgid "Please wait while format is in progress." 165 | msgstr "" 166 | 167 | #: ../src/OMBManager.py:155 168 | msgid "Please wait while installation is in progress." 169 | msgstr "" 170 | 171 | #: ../src/OMBManagerInstall.py:168 172 | msgid "" 173 | "Please wait while installation is in progress.\n" 174 | "This operation may take a while." 175 | msgstr "" 176 | 177 | #: ../src/OMBManagerList.py:263 178 | msgid "Preferences" 179 | msgstr "" 180 | 181 | #: ../src/OMBManagerList.py:185 182 | msgid "Rename" 183 | msgstr "" 184 | 185 | #: ../src/OMBManagerList.py:358 186 | msgid "Save" 187 | msgstr "" 188 | 189 | #: ../src/OMBManagerList.py:245 190 | #, python-format 191 | msgid "Set next boot to %s ?" 192 | msgstr "" 193 | 194 | #: ../src/OMBManagerInstall.py:223 195 | #, python-format 196 | msgid "The folder %s already exist" 197 | msgstr "" 198 | 199 | #: ../src/OMBManager.py:43 200 | msgid "Where do you want to install openMultiboot?" 201 | msgstr "" 202 | 203 | #: ../src/OMBManager.py:145 204 | msgid "You need the module " 205 | msgstr "" 206 | 207 | #: ../src/OMBManagerInstall.py:272 208 | msgid "Your STB doesn't seem supported" 209 | msgstr "" 210 | 211 | #: ../src/OMBManagerAbout.py:47 212 | msgid "openMultiboot About" 213 | msgstr "" 214 | 215 | #: ../src/OMBManagerInstall.py:143 216 | msgid "openMultiboot Install" 217 | msgstr "" 218 | 219 | #: ../src/OMBManagerList.py:167 220 | msgid "openMultiboot Manager" 221 | msgstr "" 222 | -------------------------------------------------------------------------------- /po/tr.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # Sandro Cavazzoni , 2014. 6 | # 7 | #, fuzzy 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: OpenMultiBoot\n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2022-11-30 13:12+0000\n" 13 | "PO-Revision-Date: 2016-12-07 15:59+0300\n" 14 | "Last-Translator: Hasan Kiran \n" 15 | "Language-Team: Turkish \n" 16 | "Language: tr\n" 17 | "MIME-Version: 1.0\n" 18 | "Content-Type: text/plain; charset=UTF-8\n" 19 | "Content-Transfer-Encoding: 8bit\n" 20 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 21 | "X-Generator: Poedit 1.8.4\n" 22 | 23 | #: ../src/OMBManager.py:145 24 | msgid "" 25 | " to use openMultiboot\n" 26 | "Do you want install it?" 27 | msgstr "" 28 | 29 | #: ../src/OMBManagerList.py:263 30 | msgid "About" 31 | msgstr "" 32 | 33 | #: ../src/OMBManager.py:50 34 | msgid "Cancel" 35 | msgstr "İptal" 36 | 37 | #: ../src/OMBManager.py:78 38 | msgid "Cannot create data folder" 39 | msgstr "" 40 | 41 | #: ../src/OMBManagerInstall.py:229 ../src/OMBManagerInstall.py:240 42 | #, python-format 43 | msgid "Cannot create folder %s" 44 | msgstr "" 45 | 46 | #: ../src/OMBManagerInstall.py:219 47 | #, python-format 48 | msgid "Cannot create kernel folder %s" 49 | msgstr "" 50 | 51 | #: ../src/OMBManagerInstall.py:212 52 | #, python-format 53 | msgid "Cannot create main folder %s" 54 | msgstr "" 55 | 56 | #: ../src/OMBManagerInstall.py:382 57 | msgid "Cannot create virtual MTD device" 58 | msgstr "" 59 | 60 | #: ../src/OMBManagerInstall.py:244 61 | msgid "Cannot deflate image" 62 | msgstr "" 63 | 64 | #: ../src/OMBManagerInstall.py:250 65 | msgid "Cannot extract nfi image" 66 | msgstr "" 67 | 68 | #: ../src/OMBManager.py:104 69 | msgid "Cannot format the device" 70 | msgstr "" 71 | 72 | #: ../src/OMBManager.py:164 73 | msgid "Cannot install " 74 | msgstr "" 75 | 76 | #: ../src/OMBManager.py:107 77 | msgid "Cannot remount the device" 78 | msgstr "" 79 | 80 | #: ../src/OMBManager.py:101 81 | msgid "Cannot umount the device" 82 | msgstr "" 83 | 84 | #: ../src/OMBManagerInstall.py:152 85 | msgid "Choose the image to install" 86 | msgstr "" 87 | 88 | #: ../src/OMBManagerList.py:178 89 | msgid "Current Running Image:" 90 | msgstr "" 91 | 92 | #: ../src/OMBManagerList.py:238 93 | msgid "Delete" 94 | msgstr "Sil" 95 | 96 | #: ../src/OMBManagerList.py:319 97 | #, python-format 98 | msgid "Do you want to delete %s?" 99 | msgstr "" 100 | 101 | #: ../src/OMBManagerList.py:256 102 | msgid "Do you want to reboot now ?" 103 | msgstr "" 104 | 105 | #: ../src/OMBManagerList.py:370 106 | msgid "Enable Boot Menu" 107 | msgstr "" 108 | 109 | #: ../src/OMBManagerInstall.py:286 ../src/OMBManagerInstall.py:316 110 | #: ../src/OMBManagerInstall.py:332 ../src/OMBManagerInstall.py:397 111 | msgid "Error copying kernel" 112 | msgstr "" 113 | 114 | #: ../src/OMBManagerInstall.py:313 ../src/OMBManagerInstall.py:329 115 | #: ../src/OMBManagerInstall.py:394 116 | msgid "Error copying unpacked rootfs" 117 | msgstr "" 118 | 119 | #: ../src/OMBManagerInstall.py:281 ../src/OMBManagerInstall.py:308 120 | msgid "Error unpacking rootfs" 121 | msgstr "" 122 | 123 | #: ../src/OMBManager.py:133 124 | msgid "" 125 | "Filesystem not supported\n" 126 | "Do you want format your drive?" 127 | msgstr "" 128 | 129 | #: ../src/OMBManagerInstall.py:335 ../src/OMBManagerInstall.py:400 130 | msgid "Generic error in unpack process" 131 | msgstr "" 132 | 133 | #: ../src/OMBManagerList.py:189 134 | msgid "Install" 135 | msgstr "" 136 | 137 | #: ../src/OMBManagerList.py:187 138 | msgid "Menu" 139 | msgstr "Menü" 140 | 141 | #: ../src/OMBManager.py:55 142 | msgid "No suitable devices found" 143 | msgstr "" 144 | 145 | #: ../src/OMBManagerList.py:264 146 | msgid "Open MultiBoot Menu" 147 | msgstr "" 148 | 149 | #: ../src/plugin.py:34 150 | msgid "OpenMultiboot Manager" 151 | msgstr "" 152 | 153 | #: ../src/OMBManagerList.py:280 154 | msgid "Please enter new name:" 155 | msgstr "" 156 | 157 | #: ../src/OMBManagerList.py:338 158 | #, python-format 159 | msgid "Please upload an image inside %s" 160 | msgstr "" 161 | 162 | #: ../src/OMBManagerList.py:298 163 | msgid "Please wait while delete is in progress." 164 | msgstr "" 165 | 166 | #: ../src/OMBManager.py:92 167 | msgid "Please wait while format is in progress." 168 | msgstr "" 169 | 170 | #: ../src/OMBManager.py:155 171 | msgid "Please wait while installation is in progress." 172 | msgstr "" 173 | 174 | #: ../src/OMBManagerInstall.py:168 175 | msgid "" 176 | "Please wait while installation is in progress.\n" 177 | "This operation may take a while." 178 | msgstr "" 179 | 180 | #: ../src/OMBManagerList.py:263 181 | msgid "Preferences" 182 | msgstr "" 183 | 184 | #: ../src/OMBManagerList.py:185 185 | msgid "Rename" 186 | msgstr "" 187 | 188 | #: ../src/OMBManagerList.py:358 189 | msgid "Save" 190 | msgstr "" 191 | 192 | #: ../src/OMBManagerList.py:245 193 | #, python-format 194 | msgid "Set next boot to %s ?" 195 | msgstr "" 196 | 197 | #: ../src/OMBManagerInstall.py:223 198 | #, python-format 199 | msgid "The folder %s already exist" 200 | msgstr "" 201 | 202 | #: ../src/OMBManager.py:43 203 | msgid "Where do you want to install openMultiboot?" 204 | msgstr "" 205 | 206 | #: ../src/OMBManager.py:145 207 | msgid "You need the module " 208 | msgstr "" 209 | 210 | #: ../src/OMBManagerInstall.py:272 211 | msgid "Your STB doesn't seem supported" 212 | msgstr "" 213 | 214 | #: ../src/OMBManagerAbout.py:47 215 | msgid "openMultiboot About" 216 | msgstr "" 217 | 218 | #: ../src/OMBManagerInstall.py:143 219 | msgid "openMultiboot Install" 220 | msgstr "" 221 | 222 | #: ../src/OMBManagerList.py:167 223 | msgid "openMultiboot Manager" 224 | msgstr "" 225 | -------------------------------------------------------------------------------- /po/updateallpo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to generate po files outside of the normal build process 3 | # 4 | # Pre-requisite: 5 | # The following tools must be installed on your system and accessible from path 6 | # gawk, find, xgettext, $localgsed, python, msguniq, msgmerge, msgattrib, msgfmt, msginit 7 | # 8 | # Run this script from within the po folder. 9 | # 10 | # Author: Pr2 11 | # Version: 1.3 12 | PluginName=open-multiboot 13 | printf "Po files update/creation from script starting.\n" 14 | # 15 | # Retrieve languages from Makefile.am LANGS variable for backward compatibility 16 | # 17 | # languages=($(gawk ' BEGIN { FS=" " } 18 | # /^LANGS/ { 19 | # for (i=3; i<=NF; i++) 20 | # printf "%s ", $i 21 | # } ' Makefile.am )) 22 | # 23 | # To use the existing files as reference for languages 24 | # 25 | localgsed="sed" 26 | gsed --version 2> /dev/null | grep -q "GNU" 27 | if [ $? -eq 0 ]; then 28 | localgsed="gsed" 29 | else 30 | "$localgsed" --version | grep -q "GNU" 31 | if [ $? -eq 0 ]; then 32 | printf "GNU sed found: [%s]\n" $localgsed 33 | fi 34 | fi 35 | 36 | languages=($(ls *.po | $localgsed 's/\.po//')) 37 | 38 | # If you want to define the language locally in this script uncomment and defined languages 39 | #languages=("ar" "bg" "ca" "cs" "da" "de" "el" "en" "es" "et" "fa" "fi" "fr" "fy" "he" "hk" "hr" "hu" "id" "is" "it" "ku" "lt" "lv" "nl" "nb" "nn" "pl" "pt" "pt_BR" "ro" "ru" "sk" "sl" "sr" "sv" "th" "tr" "uk" "zh") 40 | 41 | # 42 | # Arguments to generate the pot and po files are not retrieved from the Makefile. 43 | # So if parameters are changed in Makefile please report the same changes in this script. 44 | # 45 | 46 | printf "Creating temporary file $PluginName-py.pot\n" 47 | find .. -name "*.py" -exec xgettext --no-wrap -L Python --from-code=UTF-8 -kpgettext:1c,2 --add-comments="TRANSLATORS:" -d $PluginName -s -o $PluginName-py.pot {} \+ 48 | $localgsed --in-place $PluginName-py.pot --expression=s/CHARSET/UTF-8/ 49 | printf "Creating temporary file $PluginName-xml.pot\n" 50 | find .. -name "*.xml" -exec python xml2po.py {} \+ > $PluginName-xml.pot 51 | printf "Merging pot files to create: $PluginName.pot\n" 52 | cat $PluginName-py.pot $PluginName-xml.pot | msguniq --no-wrap -o $PluginName.pot - 53 | OLDIFS=$IFS 54 | IFS=" " 55 | for lang in "${languages[@]}" ; do 56 | if [ -f $lang.po ]; then 57 | printf "Updating existing translation file %s.po\n" $lang 58 | msgmerge --backup=none --no-wrap -s -U $lang.po $PluginName.pot && touch $lang.po 59 | msgattrib --no-wrap --no-obsolete $lang.po -o $lang.po 60 | msgfmt -o $lang.mo $lang.po 61 | else \ 62 | printf "New file created: %s.po, please add it to github before commit\n" $lang 63 | msginit -l $lang.po -o $lang.po -i $PluginName.pot --no-translator 64 | msgfmt -o $lang.mo $lang.po 65 | fi 66 | done 67 | rm $PluginName-py.pot $PluginName-xml.pot 68 | IFS=$OLDIFS 69 | printf "Po files update/creation from script finished!\n" 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = ubi_reader elftools 2 | 3 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot 4 | install_PYTHON = *.py 5 | dist_install_DATA = plugin.png -------------------------------------------------------------------------------- /src/OMBConfig.py: -------------------------------------------------------------------------------- 1 | omb_legacy=True 2 | -------------------------------------------------------------------------------- /src/OMBList.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from __future__ import absolute_import 3 | 4 | import os 5 | import json 6 | 7 | from .BoxConfig import BoxConfig 8 | 9 | from .OMBManagerCommon import OMB_DATA_DIR, OMB_UPLOAD_DIR 10 | from .OMBConfig import omb_legacy 11 | 12 | class OMBList(): 13 | def __init__(self, mount_point, debug = True): 14 | mount_point = mount_point.rstrip("/") 15 | self.mount_point = mount_point 16 | self.data_dir = mount_point + '/' + OMB_DATA_DIR 17 | self.debug = debug 18 | self.debug_boxconfig = [] 19 | self.images_list = [] 20 | self.images_entries = [] 21 | 22 | flashroot = "/" 23 | f = open("/proc/mounts", "r") 24 | for line in f: 25 | if line.find(self.data_dir + "/flash") > -1: 26 | flashroot = self.data_dir + "/flash" 27 | self.flashroot = flashroot 28 | self.boxinfo = BoxConfig(debug=self.debug, root = flashroot) 29 | 30 | def getBoxInfo(self): 31 | return self.boxinfo 32 | 33 | def imageTitleFromLabel(self, file_entry): 34 | f = open(self.data_dir + '/' + file_entry) 35 | label = f.readline().strip() 36 | f.close() 37 | return label 38 | 39 | def currentImage(self): 40 | selected = 'Flash' 41 | try: 42 | selected = open(omb_legacy and self.data_dir + '/.selected' or '%s/.%s-selected' % (self.data_dir, self.boxinfo.getItem("model"))).read() 43 | except: 44 | pass 45 | return selected 46 | 47 | def guessImageTitle(self, boxinfo, identifier): 48 | # for i in boxinfo.getItemsList(): 49 | # print ("DEBUG:", i,boxinfo.getItem(i)) 50 | 51 | try: 52 | # print (boxinfo.getItem("distro")) 53 | # print (boxinfo.getItem("imageversion")) 54 | return boxinfo.getItem("distro") + " " + str(boxinfo.getItem("imageversion")) 55 | except Exception as e: 56 | print ("OMB: ERROR %s" % e) 57 | return identifier 58 | 59 | def populateImagesList(self): 60 | 61 | self.debug_boxconfig.append(self.boxinfo.getItemsDict()) 62 | 63 | file_entry = "flash" 64 | if os.path.exists(self.data_dir + '/.label_' + file_entry): 65 | title = self.imageTitleFromLabel('.label_' + file_entry) 66 | else: 67 | title = self.guessImageTitle(self.boxinfo, file_entry) 68 | 69 | self.images_entries.append({ 70 | 'label': title + ' (Flash)', 71 | 'identifier': omb_legacy and 'flash' or '%s-flash' % self.boxinfo.getItem("model"), 72 | 'path': self.flashroot, 73 | 'background': '/usr/share/bootlogo.mvi' 74 | }) 75 | self.images_list.append(self.images_entries[0]['label']) 76 | 77 | if os.path.exists(self.data_dir): 78 | for file_entry in os.listdir(self.data_dir): 79 | if not os.path.isdir(self.data_dir + '/' + file_entry): 80 | continue 81 | 82 | if file_entry[0] == '.': 83 | continue 84 | 85 | if file_entry == "flash" or file_entry == '%s-flash' % self.boxinfo.getItem("model"): 86 | continue 87 | 88 | TargetBoxInfo = BoxConfig(root = self.data_dir + '/' + file_entry, debug=self.debug) 89 | 90 | self.debug_boxconfig.append(TargetBoxInfo.getItemsDict()) 91 | 92 | # with following check you can switch back to your image in flash and move your stick between different boxes. 93 | # print ("OMB: Compare flash model with target model %s %s" % (self.boxinfo.getItem("model"), TargetBoxInfo.getItem("model"))) 94 | if self.boxinfo.getItem("model") != TargetBoxInfo.getItem("model"): 95 | continue 96 | 97 | if os.path.exists(self.data_dir + '/.label_' + file_entry): 98 | title = self.imageTitleFromLabel('.label_' + file_entry) 99 | else: 100 | title = self.guessImageTitle(TargetBoxInfo, file_entry) 101 | 102 | background = "/usr/share/bootlogo.mvi" 103 | if not os.path.exists(self.data_dir + '/' + file_entry + '/usr/share/bootlogo.mvi'): 104 | background = '/usr/share/' + self.boxinfo.getItem("brand") + '-bootlogo/bootlogo.mvi' 105 | 106 | self.images_entries.append({ 107 | 'label': title, 108 | 'identifier': file_entry, 109 | 'path': self.data_dir + '/' + file_entry, 110 | 'labelfile': self.data_dir + '/' + '.label_' + file_entry, 111 | 'kernelbin': self.data_dir + '/' + '.kernels' + '/' + file_entry + '.bin', 112 | 'background': background 113 | }) 114 | self.images_list.append(title) 115 | 116 | def getImagesList(self): 117 | return self.images_list 118 | 119 | def getImagesEntries(self): 120 | return self.images_entries 121 | 122 | def getJson(self, debug = None): 123 | parsed = { 'currentimage': self.currentImage(), 'images_entries': self.images_entries} 124 | if debug: 125 | parsed['debug_boxconfig'] = self.debug_boxconfig 126 | return json.dumps(parsed, indent=4) 127 | -------------------------------------------------------------------------------- /src/OMBManagerAbout.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | ############################################################################# 3 | # 4 | # Copyright (C) 2014 Impex-Sat Gmbh & Co.KG 5 | # Written by Sandro Cavazzoni 6 | # All Rights Reserved. 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License along 19 | # with this program; if not, write to the Free Software Foundation, Inc., 20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | # 22 | ############################################################################# 23 | 24 | from Screens.Screen import Screen 25 | from Screens.MessageBox import MessageBox 26 | 27 | from Components.ActionMap import ActionMap 28 | from Components.Label import Label 29 | 30 | from .OMBManagerCommon import OMB_DATA_DIR, OMB_UPLOAD_DIR, OMB_TMP_DIR, OMB_MANAGER_VERION 31 | from .OMBManagerLocale import _ 32 | 33 | 34 | class OMBManagerAbout(Screen): 35 | skin = """ 36 | 37 | 42 | """ 43 | 44 | def __init__(self, session): 45 | Screen.__init__(self, session) 46 | 47 | self.setTitle(_('openMultiboot About')) 48 | 49 | about = "openMultiboot Manager " + OMB_MANAGER_VERION + "\n" 50 | about += "(c) 2014 Impex-Sat Gmbh & Co.KG\n\n" 51 | about += "Written by Sandro Cavazzoni " 52 | 53 | self['about'] = Label(about) 54 | self["actions"] = ActionMap(["SetupActions"], 55 | { 56 | "cancel": self.keyCancel 57 | }) 58 | 59 | def keyCancel(self): 60 | self.close() 61 | -------------------------------------------------------------------------------- /src/OMBManagerCommon.py: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # 3 | # Copyright (C) 2014 Impex-Sat Gmbh & Co.KG 4 | # Written by Sandro Cavazzoni 5 | # All Rights Reserved. 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | ############################################################################# 22 | 23 | OMB_MAIN_DIR = '/omb' 24 | OMB_DATA_DIR = 'open-multiboot' 25 | OMB_UPLOAD_DIR = 'open-multiboot-upload' 26 | OMB_TMP_DIR = 'open-multiboot-tmp' 27 | OMB_MANAGER_VERION = '1.3' 28 | -------------------------------------------------------------------------------- /src/OMBManagerLocale.py: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # 3 | # Copyright (C) 2014 Impex-Sat Gmbh & Co.KG 4 | # Written by Sandro Cavazzoni 5 | # All Rights Reserved. 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | ############################################################################# 22 | 23 | from Components.Language import language 24 | from Tools.Directories import resolveFilename, SCOPE_PLUGINS 25 | 26 | import gettext 27 | import os 28 | 29 | PluginLanguageDomain = "OpenMultiboot" 30 | PluginLanguagePath = "Extensions/OpenMultiboot/locale" 31 | 32 | 33 | def localeInit(): 34 | lang = language.getLanguage()[:2] 35 | os.environ["LANGUAGE"] = lang 36 | gettext.bindtextdomain(PluginLanguageDomain, resolveFilename(SCOPE_PLUGINS, PluginLanguagePath)) 37 | 38 | 39 | def _(txt): 40 | t = gettext.dgettext(PluginLanguageDomain, txt) 41 | if t == txt: 42 | t = gettext.gettext(txt) 43 | return t 44 | 45 | 46 | localeInit() 47 | language.addCallback(localeInit) 48 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oe-alliance/openmultibootmanager/e4d532e693d98d7c82e922973be18ab93cc8e681/src/__init__.py -------------------------------------------------------------------------------- /src/elftools/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/elftools 2 | 3 | SUBDIRS = common construct dwarf ehabi elf 4 | 5 | install_PYTHON = \ 6 | __init__.py 7 | -------------------------------------------------------------------------------- /src/elftools/__init__.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools 3 | # 4 | # Eli Bendersky (eliben@gmail.com) 5 | # This code is in the public domain 6 | #------------------------------------------------------------------------------- 7 | __version__ = '0.27' 8 | -------------------------------------------------------------------------------- /src/elftools/common/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/elftools/common 2 | 3 | install_PYTHON = \ 4 | construct_utils.py exceptions.py __init__.py py3compat.py utils.py 5 | -------------------------------------------------------------------------------- /src/elftools/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oe-alliance/openmultibootmanager/e4d532e693d98d7c82e922973be18ab93cc8e681/src/elftools/common/__init__.py -------------------------------------------------------------------------------- /src/elftools/common/construct_utils.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: common/construct_utils.py 3 | # 4 | # Some complementary construct utilities 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | from ..construct import ( 10 | Subconstruct, ConstructError, ArrayError, Adapter, Field, RepeatUntil, 11 | Rename, SizeofError 12 | ) 13 | 14 | 15 | class RepeatUntilExcluding(Subconstruct): 16 | """ A version of construct's RepeatUntil that doesn't include the last 17 | element (which casued the repeat to exit) in the return value. 18 | 19 | Only parsing is currently implemented. 20 | 21 | P.S. removed some code duplication 22 | """ 23 | __slots__ = ["predicate"] 24 | def __init__(self, predicate, subcon): 25 | Subconstruct.__init__(self, subcon) 26 | self.predicate = predicate 27 | self._clear_flag(self.FLAG_COPY_CONTEXT) 28 | self._set_flag(self.FLAG_DYNAMIC) 29 | def _parse(self, stream, context): 30 | obj = [] 31 | try: 32 | context_for_subcon = context 33 | if self.subcon.conflags & self.FLAG_COPY_CONTEXT: 34 | context_for_subcon = context.__copy__() 35 | 36 | while True: 37 | subobj = self.subcon._parse(stream, context_for_subcon) 38 | if self.predicate(subobj, context): 39 | break 40 | obj.append(subobj) 41 | except ConstructError as ex: 42 | raise ArrayError("missing terminator", ex) 43 | return obj 44 | def _build(self, obj, stream, context): 45 | raise NotImplementedError('no building') 46 | def _sizeof(self, context): 47 | raise SizeofError("can't calculate size") 48 | 49 | 50 | def _LEB128_reader(): 51 | """ Read LEB128 variable-length data from the stream. The data is terminated 52 | by a byte with 0 in its highest bit. 53 | """ 54 | return RepeatUntil( 55 | lambda obj, ctx: ord(obj) < 0x80, 56 | Field(None, 1)) 57 | 58 | 59 | class _ULEB128Adapter(Adapter): 60 | """ An adapter for ULEB128, given a sequence of bytes in a sub-construct. 61 | """ 62 | def _decode(self, obj, context): 63 | value = 0 64 | for b in reversed(obj): 65 | value = (value << 7) + (ord(b) & 0x7F) 66 | return value 67 | 68 | 69 | class _SLEB128Adapter(Adapter): 70 | """ An adapter for SLEB128, given a sequence of bytes in a sub-construct. 71 | """ 72 | def _decode(self, obj, context): 73 | value = 0 74 | for b in reversed(obj): 75 | value = (value << 7) + (ord(b) & 0x7F) 76 | if ord(obj[-1]) & 0x40: 77 | # negative -> sign extend 78 | value |= - (1 << (7 * len(obj))) 79 | return value 80 | 81 | 82 | def ULEB128(name): 83 | """ A construct creator for ULEB128 encoding. 84 | """ 85 | return Rename(name, _ULEB128Adapter(_LEB128_reader())) 86 | 87 | 88 | def SLEB128(name): 89 | """ A construct creator for SLEB128 encoding. 90 | """ 91 | return Rename(name, _SLEB128Adapter(_LEB128_reader())) 92 | -------------------------------------------------------------------------------- /src/elftools/common/exceptions.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: common/exceptions.py 3 | # 4 | # Exception classes for elftools 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | class ELFError(Exception): 10 | pass 11 | 12 | class ELFRelocationError(ELFError): 13 | pass 14 | 15 | class ELFParseError(ELFError): 16 | pass 17 | 18 | class ELFCompressionError(ELFError): 19 | pass 20 | 21 | class DWARFError(Exception): 22 | pass 23 | -------------------------------------------------------------------------------- /src/elftools/common/py3compat.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: common/py3compat.py 3 | # 4 | # Python 2/3 compatibility code 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | import sys 10 | PY3 = sys.version_info[0] == 3 11 | 12 | 13 | if PY3: 14 | import io 15 | StringIO = io.StringIO 16 | BytesIO = io.BytesIO 17 | 18 | # Functions for acting on bytestrings and strings. In Python 2 and 3, 19 | # strings and bytes are the same and chr/ord can be used to convert between 20 | # numeric byte values and their string pepresentations. In Python 3, bytes 21 | # and strings are different types and bytes hold numeric values when 22 | # iterated over. 23 | 24 | def bytes2str(b): return b.decode('latin-1') 25 | def str2bytes(s): return s.encode('latin-1') 26 | def int2byte(i): return bytes((i,)) 27 | def byte2int(b): return b 28 | 29 | def iterbytes(b): 30 | """Return an iterator over the elements of a bytes object. 31 | 32 | For example, for b'abc' yields b'a', b'b' and then b'c'. 33 | """ 34 | for i in range(len(b)): 35 | yield b[i:i+1] 36 | 37 | ifilter = filter 38 | 39 | maxint = sys.maxsize 40 | else: 41 | import cStringIO 42 | StringIO = BytesIO = cStringIO.StringIO 43 | 44 | def bytes2str(b): return b 45 | def str2bytes(s): return s 46 | int2byte = chr 47 | byte2int = ord 48 | def iterbytes(b): 49 | return iter(b) 50 | 51 | from itertools import ifilter 52 | 53 | maxint = sys.maxint 54 | 55 | 56 | def iterkeys(d): 57 | """Return an iterator over the keys of a dictionary.""" 58 | return getattr(d, 'keys' if PY3 else 'iterkeys')() 59 | 60 | def itervalues(d): 61 | """Return an iterator over the values of a dictionary.""" 62 | return getattr(d, 'values' if PY3 else 'itervalues')() 63 | 64 | def iteritems(d): 65 | """Return an iterator over the items of a dictionary.""" 66 | return getattr(d, 'items' if PY3 else 'iteritems')() 67 | 68 | try: 69 | from collections.abc import Mapping # python >= 3.3 70 | except ImportError: 71 | from collections import Mapping # python < 3.3 72 | -------------------------------------------------------------------------------- /src/elftools/common/utils.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: common/utils.py 3 | # 4 | # Miscellaneous utilities for elftools 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | from contextlib import contextmanager 10 | from .exceptions import ELFParseError, ELFError, DWARFError 11 | from .py3compat import int2byte 12 | from ..construct import ConstructError, ULInt8 13 | 14 | 15 | def merge_dicts(*dicts): 16 | "Given any number of dicts, merges them into a new one.""" 17 | result = {} 18 | for d in dicts: 19 | result.update(d) 20 | return result 21 | 22 | 23 | def bytelist2string(bytelist): 24 | """ Convert a list of byte values (e.g. [0x10 0x20 0x00]) to a bytes object 25 | (e.g. b'\x10\x20\x00'). 26 | """ 27 | return b''.join(int2byte(b) for b in bytelist) 28 | 29 | 30 | def struct_parse(struct, stream, stream_pos=None): 31 | """ Convenience function for using the given struct to parse a stream. 32 | If stream_pos is provided, the stream is seeked to this position before 33 | the parsing is done. Otherwise, the current position of the stream is 34 | used. 35 | Wraps the error thrown by construct with ELFParseError. 36 | """ 37 | try: 38 | if stream_pos is not None: 39 | stream.seek(stream_pos) 40 | return struct.parse_stream(stream) 41 | except ConstructError as e: 42 | raise ELFParseError(str(e)) 43 | 44 | 45 | def parse_cstring_from_stream(stream, stream_pos=None): 46 | """ Parse a C-string from the given stream. The string is returned without 47 | the terminating \x00 byte. If the terminating byte wasn't found, None 48 | is returned (the stream is exhausted). 49 | If stream_pos is provided, the stream is seeked to this position before 50 | the parsing is done. Otherwise, the current position of the stream is 51 | used. 52 | Note: a bytes object is returned here, because this is what's read from 53 | the binary file. 54 | """ 55 | if stream_pos is not None: 56 | stream.seek(stream_pos) 57 | CHUNKSIZE = 64 58 | chunks = [] 59 | found = False 60 | while True: 61 | chunk = stream.read(CHUNKSIZE) 62 | end_index = chunk.find(b'\x00') 63 | if end_index >= 0: 64 | chunks.append(chunk[:end_index]) 65 | found = True 66 | break 67 | else: 68 | chunks.append(chunk) 69 | if len(chunk) < CHUNKSIZE: 70 | break 71 | return b''.join(chunks) if found else None 72 | 73 | 74 | def elf_assert(cond, msg=''): 75 | """ Assert that cond is True, otherwise raise ELFError(msg) 76 | """ 77 | _assert_with_exception(cond, msg, ELFError) 78 | 79 | 80 | def dwarf_assert(cond, msg=''): 81 | """ Assert that cond is True, otherwise raise DWARFError(msg) 82 | """ 83 | _assert_with_exception(cond, msg, DWARFError) 84 | 85 | 86 | @contextmanager 87 | def preserve_stream_pos(stream): 88 | """ Usage: 89 | # stream has some position FOO (return value of stream.tell()) 90 | with preserve_stream_pos(stream): 91 | # do stuff that manipulates the stream 92 | # stream still has position FOO 93 | """ 94 | saved_pos = stream.tell() 95 | yield 96 | stream.seek(saved_pos) 97 | 98 | 99 | def roundup(num, bits): 100 | """ Round up a number to nearest multiple of 2^bits. The result is a number 101 | where the least significant bits passed in bits are 0. 102 | """ 103 | return (num - 1 | (1 << bits) - 1) + 1 104 | 105 | def read_blob(stream, length): 106 | """Read length bytes from stream, return a list of ints 107 | """ 108 | return [struct_parse(ULInt8(''), stream) for i in range(length)] 109 | 110 | #------------------------- PRIVATE ------------------------- 111 | 112 | def _assert_with_exception(cond, msg, exception_type): 113 | if not cond: 114 | raise exception_type(msg) 115 | -------------------------------------------------------------------------------- /src/elftools/construct/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2009 Tomer Filiba, 2010-2011 Corbin Simpson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/elftools/construct/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/elftools/construct 2 | 3 | SUBDIRS = lib 4 | 5 | install_PYTHON = \ 6 | adapters.py core.py debug.py __init__.py macros.py pdb.py bdb.py 7 | -------------------------------------------------------------------------------- /src/elftools/construct/README: -------------------------------------------------------------------------------- 1 | construct is a Python library for declarative parsing and building of binary 2 | data. This is my fork of construct 2, with some modifications for Python 3 3 | and bug fixes. The construct website is http://construct.readthedocs.org 4 | 5 | pyelftools carries construct around because construct has been abandoned for 6 | a long time and didn't get bugfixes; it also didn't work with Python 3. 7 | 8 | These days (Feb 2018) construct is maintained again, but its APIs have 9 | underwent extensive changes that would require rewriting all of the 10 | construct-facing code in pyelftools. I'm still evaluating the pros/cons of 11 | this effort. See https://github.com/eliben/pyelftools/issues/180 for details. 12 | 13 | LICENSE is the original license. 14 | -------------------------------------------------------------------------------- /src/elftools/construct/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | #### #### 3 | ## #### ## ## #### ###### ##### ## ## #### ###### ## ## 4 | ## ## ## ### ## ## ## ## ## ## ## ## ## #### ## 5 | ## ## ## ###### ### ## ##### ## ## ## ## ## 6 | ## ## ## ## ### ## ## ## ## ## ## ## ## ## 7 | #### #### ## ## #### ## ## ## ##### #### ## ###### 8 | 9 | Parsing made even more fun (and faster too) 10 | 11 | Homepage: 12 | http://construct.wikispaces.com (including online tutorial) 13 | 14 | Typical usage: 15 | >>> from construct import * 16 | 17 | Hands-on example: 18 | >>> from construct import * 19 | >>> s = Struct("foo", 20 | ... UBInt8("a"), 21 | ... UBInt16("b"), 22 | ... ) 23 | >>> s.parse("\\x01\\x02\\x03") 24 | Container(a = 1, b = 515) 25 | >>> print s.parse("\\x01\\x02\\x03") 26 | Container: 27 | a = 1 28 | b = 515 29 | >>> s.build(Container(a = 1, b = 0x0203)) 30 | "\\x01\\x02\\x03" 31 | """ 32 | 33 | from .core import * 34 | from .adapters import * 35 | from .macros import * 36 | from .debug import Probe, Debugger 37 | 38 | 39 | #=============================================================================== 40 | # Metadata 41 | #=============================================================================== 42 | __author__ = "tomer filiba (tomerfiliba [at] gmail.com)" 43 | __maintainer__ = "Corbin Simpson " 44 | __version__ = "2.06" 45 | 46 | #=============================================================================== 47 | # Shorthand expressions 48 | #=============================================================================== 49 | Bits = BitField 50 | Byte = UBInt8 51 | Bytes = Field 52 | Const = ConstAdapter 53 | Tunnel = TunnelAdapter 54 | Embed = Embedded 55 | 56 | #=============================================================================== 57 | # Deprecated names 58 | # Next scheduled name cleanout: 2.1 59 | #=============================================================================== 60 | import functools, warnings 61 | 62 | def deprecated(f): 63 | @functools.wraps(f) 64 | def wrapper(*args, **kwargs): 65 | warnings.warn( 66 | "This name is deprecated, use %s instead" % f.__name__, 67 | DeprecationWarning, stacklevel=2) 68 | return f(*args, **kwargs) 69 | return wrapper 70 | 71 | MetaBytes = deprecated(MetaField) 72 | GreedyRepeater = deprecated(GreedyRange) 73 | OptionalGreedyRepeater = deprecated(OptionalGreedyRange) 74 | Repeater = deprecated(Range) 75 | StrictRepeater = deprecated(Array) 76 | MetaRepeater = deprecated(Array) 77 | OneOfValidator = deprecated(OneOf) 78 | NoneOfValidator = deprecated(NoneOf) 79 | 80 | #=============================================================================== 81 | # exposed names 82 | #=============================================================================== 83 | __all__ = [ 84 | 'AdaptationError', 'Adapter', 'Alias', 'Aligned', 'AlignedStruct', 85 | 'Anchor', 'Array', 'ArrayError', 'BFloat32', 'BFloat64', 'Bit', 'BitField', 86 | 'BitIntegerAdapter', 'BitIntegerError', 'BitStruct', 'Bits', 'Bitwise', 87 | 'Buffered', 'Byte', 'Bytes', 'CString', 'CStringAdapter', 'Const', 88 | 'ConstAdapter', 'ConstError', 'Construct', 'ConstructError', 'Container', 89 | 'Debugger', 'Embed', 'Embedded', 'EmbeddedBitStruct', 'Enum', 'ExprAdapter', 90 | 'Field', 'FieldError', 'Flag', 'FlagsAdapter', 'FlagsContainer', 91 | 'FlagsEnum', 'FormatField', 'GreedyRange', 'GreedyRepeater', 92 | 'HexDumpAdapter', 'If', 'IfThenElse', 'IndexingAdapter', 'LFloat32', 93 | 'LFloat64', 'LazyBound', 'LengthValueAdapter', 'ListContainer', 94 | 'MappingAdapter', 'MappingError', 'MetaArray', 'MetaBytes', 'MetaField', 95 | 'MetaRepeater', 'NFloat32', 'NFloat64', 'Nibble', 'NoneOf', 96 | 'NoneOfValidator', 'Octet', 'OnDemand', 'OnDemandPointer', 'OneOf', 97 | 'OneOfValidator', 'OpenRange', 'Optional', 'OptionalGreedyRange', 98 | 'OptionalGreedyRepeater', 'PaddedStringAdapter', 'Padding', 99 | 'PaddingAdapter', 'PaddingError', 'PascalString', 'Pass', 'Peek', 100 | 'Pointer', 'PrefixedArray', 'Probe', 'Range', 'RangeError', 'Reconfig', 101 | 'Rename', 'RepeatUntil', 'Repeater', 'Restream', 'SBInt16', 'SBInt32', 102 | 'SBInt64', 'SBInt8', 'SLInt16', 'SLInt32', 'SLInt64', 'SLInt8', 'SNInt16', 103 | 'SNInt32', 'SNInt64', 'SNInt8', 'Select', 'SelectError', 'Sequence', 104 | 'SizeofError', 'SlicingAdapter', 'StaticField', 'StrictRepeater', 'String', 105 | 'StringAdapter', 'Struct', 'Subconstruct', 'Switch', 'SwitchError', 106 | 'SymmetricMapping', 'Terminator', 'TerminatorError', 'Tunnel', 107 | 'TunnelAdapter', 'UBInt16', 'UBInt32', 'UBInt64', 'UBInt8', 'ULInt16', 108 | 'ULInt32', 'ULInt64', 'ULInt8', 'UNInt16', 'UNInt32', 'UNInt64', 'UNInt8', 109 | 'Union', 'ValidationError', 'Validator', 'Value', "Magic", 110 | ] 111 | -------------------------------------------------------------------------------- /src/elftools/construct/debug.py: -------------------------------------------------------------------------------- 1 | """ 2 | Debugging utilities for constructs 3 | """ 4 | from __future__ import print_function 5 | import sys 6 | import traceback 7 | import pdb 8 | import inspect 9 | from .core import Construct, Subconstruct 10 | from .lib import HexString, Container, ListContainer 11 | 12 | 13 | class Probe(Construct): 14 | """ 15 | A probe: dumps the context, stack frames, and stream content to the screen 16 | to aid the debugging process. 17 | See also Debugger. 18 | 19 | Parameters: 20 | * name - the display name 21 | * show_stream - whether or not to show stream contents. default is True. 22 | the stream must be seekable. 23 | * show_context - whether or not to show the context. default is True. 24 | * show_stack - whether or not to show the upper stack frames. default 25 | is True. 26 | * stream_lookahead - the number of bytes to dump when show_stack is set. 27 | default is 100. 28 | 29 | Example: 30 | Struct("foo", 31 | UBInt8("a"), 32 | Probe("between a and b"), 33 | UBInt8("b"), 34 | ) 35 | """ 36 | __slots__ = [ 37 | "printname", "show_stream", "show_context", "show_stack", 38 | "stream_lookahead" 39 | ] 40 | counter = 0 41 | 42 | def __init__(self, name = None, show_stream = True, 43 | show_context = True, show_stack = True, 44 | stream_lookahead = 100): 45 | Construct.__init__(self, None) 46 | if name is None: 47 | Probe.counter += 1 48 | name = "" % (Probe.counter,) 49 | self.printname = name 50 | self.show_stream = show_stream 51 | self.show_context = show_context 52 | self.show_stack = show_stack 53 | self.stream_lookahead = stream_lookahead 54 | def __repr__(self): 55 | return "%s(%r)" % (self.__class__.__name__, self.printname) 56 | def _parse(self, stream, context): 57 | self.printout(stream, context) 58 | def _build(self, obj, stream, context): 59 | self.printout(stream, context) 60 | def _sizeof(self, context): 61 | return 0 62 | 63 | def printout(self, stream, context): 64 | obj = Container() 65 | if self.show_stream: 66 | obj.stream_position = stream.tell() 67 | follows = stream.read(self.stream_lookahead) 68 | if not follows: 69 | obj.following_stream_data = "EOF reached" 70 | else: 71 | stream.seek(-len(follows), 1) 72 | obj.following_stream_data = HexString(follows) 73 | print 74 | 75 | if self.show_context: 76 | obj.context = context 77 | 78 | if self.show_stack: 79 | obj.stack = ListContainer() 80 | frames = [s[0] for s in inspect.stack()][1:-1] 81 | frames.reverse() 82 | for f in frames: 83 | a = Container() 84 | a.__update__(f.f_locals) 85 | obj.stack.append(a) 86 | 87 | print("=" * 80) 88 | print("Probe", self.printname) 89 | print(obj) 90 | print("=" * 80) 91 | 92 | class Debugger(Subconstruct): 93 | """ 94 | A pdb-based debugger. When an exception occurs in the subcon, a debugger 95 | will appear and allow you to debug the error (and even fix on-the-fly). 96 | 97 | Parameters: 98 | * subcon - the subcon to debug 99 | 100 | Example: 101 | Debugger( 102 | Enum(UBInt8("foo"), 103 | a = 1, 104 | b = 2, 105 | c = 3 106 | ) 107 | ) 108 | """ 109 | __slots__ = ["retval"] 110 | def _parse(self, stream, context): 111 | try: 112 | return self.subcon._parse(stream, context) 113 | except Exception: 114 | self.retval = NotImplemented 115 | self.handle_exc("(you can set the value of 'self.retval', " 116 | "which will be returned)") 117 | if self.retval is NotImplemented: 118 | raise 119 | else: 120 | return self.retval 121 | def _build(self, obj, stream, context): 122 | try: 123 | self.subcon._build(obj, stream, context) 124 | except Exception: 125 | self.handle_exc() 126 | def handle_exc(self, msg = None): 127 | print("=" * 80) 128 | print("Debugging exception of %s:" % (self.subcon,)) 129 | print("".join(traceback.format_exception(*sys.exc_info())[1:])) 130 | if msg: 131 | print(msg) 132 | pdb.post_mortem(sys.exc_info()[2]) 133 | print("=" * 80) 134 | -------------------------------------------------------------------------------- /src/elftools/construct/lib/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/elftools/construct/lib 2 | 3 | install_PYTHON = \ 4 | binary.py bitstream.py container.py hex.py __init__.py py3compat.py -------------------------------------------------------------------------------- /src/elftools/construct/lib/__init__.py: -------------------------------------------------------------------------------- 1 | from .binary import ( 2 | int_to_bin, bin_to_int, swap_bytes, encode_bin, decode_bin) 3 | from .bitstream import BitStreamReader, BitStreamWriter 4 | from .container import (Container, FlagsContainer, ListContainer, 5 | LazyContainer) 6 | from .hex import HexString, hexdump 7 | 8 | -------------------------------------------------------------------------------- /src/elftools/construct/lib/binary.py: -------------------------------------------------------------------------------- 1 | from .py3compat import int2byte 2 | 3 | 4 | def int_to_bin(number, width=32): 5 | r""" 6 | Convert an integer into its binary representation in a bytes object. 7 | Width is the amount of bits to generate. If width is larger than the actual 8 | amount of bits required to represent number in binary, sign-extension is 9 | used. If it's smaller, the representation is trimmed to width bits. 10 | Each "bit" is either '\x00' or '\x01'. The MSBit is first. 11 | 12 | Examples: 13 | 14 | >>> int_to_bin(19, 5) 15 | b'\x01\x00\x00\x01\x01' 16 | >>> int_to_bin(19, 8) 17 | b'\x00\x00\x00\x01\x00\x00\x01\x01' 18 | """ 19 | if number < 0: 20 | number += 1 << width 21 | i = width - 1 22 | bits = bytearray(width) 23 | while number and i >= 0: 24 | bits[i] = number & 1 25 | number >>= 1 26 | i -= 1 27 | return bytes(bits) 28 | 29 | 30 | _bit_values = { 31 | 0: 0, 32 | 1: 1, 33 | 48: 0, # '0' 34 | 49: 1, # '1' 35 | 36 | # The following are for Python 2, in which iteration over a bytes object 37 | # yields single-character bytes and not integers. 38 | '\x00': 0, 39 | '\x01': 1, 40 | '0': 0, 41 | '1': 1, 42 | } 43 | 44 | def bin_to_int(bits, signed=False): 45 | r""" 46 | Logical opposite of int_to_bin. Both '0' and '\x00' are considered zero, 47 | and both '1' and '\x01' are considered one. Set sign to True to interpret 48 | the number as a 2-s complement signed integer. 49 | """ 50 | number = 0 51 | bias = 0 52 | ptr = 0 53 | if signed and _bit_values[bits[0]] == 1: 54 | bits = bits[1:] 55 | bias = 1 << len(bits) 56 | for b in bits: 57 | number <<= 1 58 | number |= _bit_values[b] 59 | return number - bias 60 | 61 | 62 | def swap_bytes(bits, bytesize=8): 63 | r""" 64 | Bits is a b'' object containing a binary representation. Assuming each 65 | bytesize bits constitute a bytes, perform a endianness byte swap. Example: 66 | 67 | >>> swap_bytes(b'00011011', 2) 68 | b'11100100' 69 | """ 70 | i = 0 71 | l = len(bits) 72 | output = [b""] * ((l // bytesize) + 1) 73 | j = len(output) - 1 74 | while i < l: 75 | output[j] = bits[i : i + bytesize] 76 | i += bytesize 77 | j -= 1 78 | return b"".join(output) 79 | 80 | 81 | _char_to_bin = {} 82 | _bin_to_char = {} 83 | for i in range(256): 84 | ch = int2byte(i) 85 | bin = int_to_bin(i, 8) 86 | # Populate with for both keys i and ch, to support Python 2 & 3 87 | _char_to_bin[ch] = bin 88 | _char_to_bin[i] = bin 89 | _bin_to_char[bin] = ch 90 | 91 | 92 | def encode_bin(data): 93 | """ 94 | Create a binary representation of the given b'' object. Assume 8-bit 95 | ASCII. Example: 96 | 97 | >>> encode_bin('ab') 98 | b"\x00\x01\x01\x00\x00\x00\x00\x01\x00\x01\x01\x00\x00\x00\x01\x00" 99 | """ 100 | return b"".join(_char_to_bin[ch] for ch in data) 101 | 102 | 103 | def decode_bin(data): 104 | """ 105 | Locical opposite of decode_bin. 106 | """ 107 | if len(data) & 7: 108 | raise ValueError("Data length must be a multiple of 8") 109 | i = 0 110 | j = 0 111 | l = len(data) // 8 112 | chars = [b""] * l 113 | while j < l: 114 | chars[j] = _bin_to_char[data[i:i+8]] 115 | i += 8 116 | j += 1 117 | return b"".join(chars) 118 | -------------------------------------------------------------------------------- /src/elftools/construct/lib/bitstream.py: -------------------------------------------------------------------------------- 1 | from .binary import encode_bin, decode_bin 2 | 3 | class BitStreamReader(object): 4 | 5 | __slots__ = ["substream", "buffer", "total_size"] 6 | 7 | def __init__(self, substream): 8 | self.substream = substream 9 | self.total_size = 0 10 | self.buffer = "" 11 | 12 | def close(self): 13 | if self.total_size % 8 != 0: 14 | raise ValueError("total size of read data must be a multiple of 8", 15 | self.total_size) 16 | 17 | def tell(self): 18 | return self.substream.tell() 19 | 20 | def seek(self, pos, whence = 0): 21 | self.buffer = "" 22 | self.total_size = 0 23 | self.substream.seek(pos, whence) 24 | 25 | def read(self, count): 26 | if count < 0: 27 | raise ValueError("count cannot be negative") 28 | 29 | l = len(self.buffer) 30 | if count == 0: 31 | data = "" 32 | elif count <= l: 33 | data = self.buffer[:count] 34 | self.buffer = self.buffer[count:] 35 | else: 36 | data = self.buffer 37 | count -= l 38 | bytes = count // 8 39 | if count & 7: 40 | bytes += 1 41 | buf = encode_bin(self.substream.read(bytes)) 42 | data += buf[:count] 43 | self.buffer = buf[count:] 44 | self.total_size += len(data) 45 | return data 46 | 47 | class BitStreamWriter(object): 48 | 49 | __slots__ = ["substream", "buffer", "pos"] 50 | 51 | def __init__(self, substream): 52 | self.substream = substream 53 | self.buffer = [] 54 | self.pos = 0 55 | 56 | def close(self): 57 | self.flush() 58 | 59 | def flush(self): 60 | bytes = decode_bin("".join(self.buffer)) 61 | self.substream.write(bytes) 62 | self.buffer = [] 63 | self.pos = 0 64 | 65 | def tell(self): 66 | return self.substream.tell() + self.pos // 8 67 | 68 | def seek(self, pos, whence = 0): 69 | self.flush() 70 | self.substream.seek(pos, whence) 71 | 72 | def write(self, data): 73 | if not data: 74 | return 75 | if type(data) is not str: 76 | raise TypeError("data must be a string, not %r" % (type(data),)) 77 | self.buffer.append(data) 78 | -------------------------------------------------------------------------------- /src/elftools/construct/lib/container.py: -------------------------------------------------------------------------------- 1 | """ 2 | Various containers. 3 | """ 4 | 5 | from pprint import pformat 6 | from .py3compat import MutableMapping 7 | 8 | def recursion_lock(retval, lock_name = "__recursion_lock__"): 9 | def decorator(func): 10 | def wrapper(self, *args, **kw): 11 | if getattr(self, lock_name, False): 12 | return retval 13 | setattr(self, lock_name, True) 14 | try: 15 | return func(self, *args, **kw) 16 | finally: 17 | setattr(self, lock_name, False) 18 | wrapper.__name__ = func.__name__ 19 | return wrapper 20 | return decorator 21 | 22 | class Container(MutableMapping): 23 | """ 24 | A generic container of attributes. 25 | 26 | Containers are the common way to express parsed data. 27 | """ 28 | 29 | def __init__(self, **kw): 30 | self.__dict__ = kw 31 | 32 | # The core dictionary interface. 33 | 34 | def __getitem__(self, name): 35 | return self.__dict__[name] 36 | 37 | def __delitem__(self, name): 38 | del self.__dict__[name] 39 | 40 | def __setitem__(self, name, value): 41 | self.__dict__[name] = value 42 | 43 | def keys(self): 44 | return self.__dict__.keys() 45 | 46 | def __len__(self): 47 | return len(self.__dict__.keys()) 48 | 49 | # Extended dictionary interface. 50 | 51 | def update(self, other): 52 | self.__dict__.update(other) 53 | 54 | __update__ = update 55 | 56 | def __contains__(self, value): 57 | return value in self.__dict__ 58 | 59 | # Rich comparisons. 60 | 61 | def __eq__(self, other): 62 | try: 63 | return self.__dict__ == other.__dict__ 64 | except AttributeError: 65 | return False 66 | 67 | def __ne__(self, other): 68 | return not self == other 69 | 70 | # Copy interface. 71 | 72 | def copy(self): 73 | return self.__class__(**self.__dict__) 74 | 75 | __copy__ = copy 76 | 77 | # Iterator interface. 78 | 79 | def __iter__(self): 80 | return iter(self.__dict__) 81 | 82 | def __repr__(self): 83 | return "%s(%s)" % (self.__class__.__name__, repr(self.__dict__)) 84 | 85 | def __str__(self): 86 | return "%s(%s)" % (self.__class__.__name__, str(self.__dict__)) 87 | 88 | class FlagsContainer(Container): 89 | """ 90 | A container providing pretty-printing for flags. 91 | 92 | Only set flags are displayed. 93 | """ 94 | 95 | @recursion_lock("<...>") 96 | def __str__(self): 97 | d = dict((k, self[k]) for k in self 98 | if self[k] and not k.startswith("_")) 99 | return "%s(%s)" % (self.__class__.__name__, pformat(d)) 100 | 101 | class ListContainer(list): 102 | """ 103 | A container for lists. 104 | """ 105 | 106 | __slots__ = ["__recursion_lock__"] 107 | 108 | @recursion_lock("[...]") 109 | def __str__(self): 110 | return pformat(self) 111 | 112 | class LazyContainer(object): 113 | 114 | __slots__ = ["subcon", "stream", "pos", "context", "_value"] 115 | 116 | def __init__(self, subcon, stream, pos, context): 117 | self.subcon = subcon 118 | self.stream = stream 119 | self.pos = pos 120 | self.context = context 121 | self._value = NotImplemented 122 | 123 | def __eq__(self, other): 124 | try: 125 | return self._value == other._value 126 | except AttributeError: 127 | return False 128 | 129 | def __ne__(self, other): 130 | return not (self == other) 131 | 132 | def __str__(self): 133 | return self.__pretty_str__() 134 | 135 | def __pretty_str__(self, nesting = 1, indentation = " "): 136 | if self._value is NotImplemented: 137 | text = "" 138 | elif hasattr(self._value, "__pretty_str__"): 139 | text = self._value.__pretty_str__(nesting, indentation) 140 | else: 141 | text = str(self._value) 142 | return "%s: %s" % (self.__class__.__name__, text) 143 | 144 | def read(self): 145 | self.stream.seek(self.pos) 146 | return self.subcon._parse(self.stream, self.context) 147 | 148 | def dispose(self): 149 | self.subcon = None 150 | self.stream = None 151 | self.context = None 152 | self.pos = None 153 | 154 | def _get_value(self): 155 | if self._value is NotImplemented: 156 | self._value = self.read() 157 | return self._value 158 | 159 | value = property(_get_value) 160 | 161 | has_value = property(lambda self: self._value is not NotImplemented) 162 | -------------------------------------------------------------------------------- /src/elftools/construct/lib/hex.py: -------------------------------------------------------------------------------- 1 | from .py3compat import byte2int, int2byte, bytes2str 2 | 3 | 4 | # Map an integer in the inclusive range 0-255 to its string byte representation 5 | _printable = dict((i, ".") for i in range(256)) 6 | _printable.update((i, bytes2str(int2byte(i))) for i in range(32, 128)) 7 | 8 | 9 | def hexdump(data, linesize): 10 | """ 11 | data is a bytes object. The returned result is a string. 12 | """ 13 | prettylines = [] 14 | if len(data) < 65536: 15 | fmt = "%%04X %%-%ds %%s" 16 | else: 17 | fmt = "%%08X %%-%ds %%s" 18 | fmt = fmt % (3 * linesize - 1,) 19 | for i in range(0, len(data), linesize): 20 | line = data[i : i + linesize] 21 | hextext = " ".join('%02x' % byte2int(b) for b in line) 22 | rawtext = "".join(_printable[byte2int(b)] for b in line) 23 | prettylines.append(fmt % (i, str(hextext), str(rawtext))) 24 | return prettylines 25 | 26 | 27 | class HexString(bytes): 28 | """ 29 | Represents bytes that will be hex-dumped to a string when its string 30 | representation is requested. 31 | """ 32 | def __init__(self, data, linesize = 16): 33 | self.linesize = linesize 34 | 35 | def __new__(cls, data, *args, **kwargs): 36 | return bytes.__new__(cls, data) 37 | 38 | def __str__(self): 39 | if not self: 40 | return "''" 41 | sep = "\n" 42 | return sep + sep.join( 43 | hexdump(self, self.linesize)) 44 | -------------------------------------------------------------------------------- /src/elftools/construct/lib/py3compat.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # py3compat.py 3 | # 4 | # Some Python2&3 compatibility code 5 | #------------------------------------------------------------------------------- 6 | import sys 7 | PY3 = sys.version_info[0] == 3 8 | 9 | try: 10 | from collections.abc import MutableMapping # python >= 3.3 11 | except ImportError: 12 | from collections import MutableMapping # python < 3.3 13 | 14 | 15 | if PY3: 16 | import io 17 | StringIO = io.StringIO 18 | BytesIO = io.BytesIO 19 | 20 | def bchr(i): 21 | """ When iterating over b'...' in Python 2 you get single b'_' chars 22 | and in Python 3 you get integers. Call bchr to always turn this 23 | to single b'_' chars. 24 | """ 25 | return bytes((i,)) 26 | 27 | def u(s): 28 | return s 29 | 30 | def int2byte(i): 31 | return bytes((i,)) 32 | 33 | def byte2int(b): 34 | return b 35 | 36 | def str2bytes(s): 37 | return s.encode("latin-1") 38 | 39 | def str2unicode(s): 40 | return s 41 | 42 | def bytes2str(b): 43 | return b.decode('latin-1') 44 | 45 | def decodebytes(b, encoding): 46 | return bytes(b, encoding) 47 | 48 | advance_iterator = next 49 | 50 | else: 51 | import cStringIO 52 | StringIO = BytesIO = cStringIO.StringIO 53 | 54 | int2byte = chr 55 | byte2int = ord 56 | bchr = lambda i: i 57 | 58 | def u(s): 59 | return unicode(s, "unicode_escape") 60 | 61 | def str2bytes(s): 62 | return s 63 | 64 | def str2unicode(s): 65 | return unicode(s, "unicode_escape") 66 | 67 | def bytes2str(b): 68 | return b 69 | 70 | def decodebytes(b, encoding): 71 | return b.decode(encoding) 72 | 73 | def advance_iterator(it): 74 | return it.next() 75 | -------------------------------------------------------------------------------- /src/elftools/dwarf/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/elftools/dwarf 2 | 3 | install_PYTHON = \ 4 | abbrevtable.py aranges.py callframe.py compileunit.py constants.py descriptions.py die.py dwarf_expr.py dwarfinfo.py enums.py __init__.py lineprogram.py locationlists.py namelut.py ranges.py structs.py 5 | -------------------------------------------------------------------------------- /src/elftools/dwarf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oe-alliance/openmultibootmanager/e4d532e693d98d7c82e922973be18ab93cc8e681/src/elftools/dwarf/__init__.py -------------------------------------------------------------------------------- /src/elftools/dwarf/abbrevtable.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: dwarf/abbrevtable.py 3 | # 4 | # DWARF abbreviation table 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | from ..common.utils import struct_parse, dwarf_assert 10 | 11 | 12 | class AbbrevTable(object): 13 | """ Represents a DWARF abbreviation table. 14 | """ 15 | def __init__(self, structs, stream, offset): 16 | """ Create new abbreviation table. Parses the actual table from the 17 | stream and stores it internally. 18 | 19 | structs: 20 | A DWARFStructs instance for parsing the data 21 | 22 | stream, offset: 23 | The stream and offset into the stream where this abbreviation 24 | table lives. 25 | """ 26 | self.structs = structs 27 | self.stream = stream 28 | self.offset = offset 29 | 30 | self._abbrev_map = self._parse_abbrev_table() 31 | 32 | def get_abbrev(self, code): 33 | """ Get the AbbrevDecl for a given code. Raise KeyError if no 34 | declaration for this code exists. 35 | """ 36 | return self._abbrev_map[code] 37 | 38 | def _parse_abbrev_table(self): 39 | """ Parse the abbrev table from the stream 40 | """ 41 | map = {} 42 | self.stream.seek(self.offset) 43 | while True: 44 | decl_code = struct_parse( 45 | struct=self.structs.Dwarf_uleb128(''), 46 | stream=self.stream) 47 | if decl_code == 0: 48 | break 49 | declaration = struct_parse( 50 | struct=self.structs.Dwarf_abbrev_declaration, 51 | stream=self.stream) 52 | map[decl_code] = AbbrevDecl(decl_code, declaration) 53 | return map 54 | 55 | 56 | class AbbrevDecl(object): 57 | """ Wraps a parsed abbreviation declaration, exposing its fields with 58 | dict-like access, and adding some convenience methods. 59 | 60 | The abbreviation declaration represents an "entry" that points to it. 61 | """ 62 | def __init__(self, code, decl): 63 | self.code = code 64 | self.decl = decl 65 | 66 | def has_children(self): 67 | """ Does the entry have children? 68 | """ 69 | return self['children_flag'] == 'DW_CHILDREN_yes' 70 | 71 | def iter_attr_specs(self): 72 | """ Iterate over the attribute specifications for the entry. Yield 73 | (name, form) pairs. 74 | """ 75 | for attr_spec in self['attr_spec']: 76 | yield attr_spec.name, attr_spec.form 77 | 78 | def __getitem__(self, entry): 79 | return self.decl[entry] 80 | -------------------------------------------------------------------------------- /src/elftools/dwarf/aranges.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: dwarf/aranges.py 3 | # 4 | # DWARF aranges section decoding (.debug_aranges) 5 | # 6 | # Dorothy Chen (dorothchen@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | import os 10 | from collections import namedtuple 11 | from ..common.utils import struct_parse 12 | from bisect import bisect_right 13 | import math 14 | 15 | # An entry in the aranges table; 16 | # begin_addr: The beginning address in the CU 17 | # length: The length of the address range in this entry 18 | # info_offset: The CU's offset into .debug_info 19 | # see 6.1.2 in DWARF4 docs for explanation of the remaining fields 20 | ARangeEntry = namedtuple('ARangeEntry', 21 | 'begin_addr length info_offset unit_length version address_size segment_size') 22 | 23 | class ARanges(object): 24 | """ ARanges table in DWARF 25 | 26 | stream, size: 27 | A stream holding the .debug_aranges section, and its size 28 | 29 | structs: 30 | A DWARFStructs instance for parsing the data 31 | """ 32 | def __init__(self, stream, size, structs): 33 | self.stream = stream 34 | self.size = size 35 | self.structs = structs 36 | 37 | # Get entries of aranges table in the form of ARangeEntry tuples 38 | self.entries = self._get_entries() 39 | 40 | # Sort entries by the beginning address 41 | self.entries.sort(key=lambda entry: entry.begin_addr) 42 | 43 | # Create list of keys (first addresses) for better searching 44 | self.keys = [entry.begin_addr for entry in self.entries] 45 | 46 | 47 | def cu_offset_at_addr(self, addr): 48 | """ Given an address, get the offset of the CU it belongs to, where 49 | 'offset' refers to the offset in the .debug_info section. 50 | """ 51 | tup = self.entries[bisect_right(self.keys, addr) - 1] 52 | if tup.begin_addr <= addr < tup.begin_addr + tup.length: 53 | return tup.info_offset 54 | else: 55 | return None 56 | 57 | 58 | #------ PRIVATE ------# 59 | def _get_entries(self): 60 | """ Populate self.entries with ARangeEntry tuples for each range of addresses 61 | """ 62 | self.stream.seek(0) 63 | entries = [] 64 | offset = 0 65 | 66 | # one loop == one "set" == one CU 67 | while offset < self.size : 68 | aranges_header = struct_parse(self.structs.Dwarf_aranges_header, 69 | self.stream, offset) 70 | addr_size = self._get_addr_size_struct(aranges_header["address_size"]) 71 | 72 | # No segmentation 73 | if aranges_header["segment_size"] == 0: 74 | # pad to nearest multiple of tuple size 75 | tuple_size = aranges_header["address_size"] * 2 76 | fp = self.stream.tell() 77 | seek_to = int(math.ceil(fp/float(tuple_size)) * tuple_size) 78 | self.stream.seek(seek_to) 79 | 80 | # entries in this set/CU 81 | addr = struct_parse(addr_size('addr'), self.stream) 82 | length = struct_parse(addr_size('length'), self.stream) 83 | while addr != 0 or length != 0: 84 | # 'begin_addr length info_offset version address_size segment_size' 85 | entries.append( 86 | ARangeEntry(begin_addr=addr, 87 | length=length, 88 | info_offset=aranges_header["debug_info_offset"], 89 | unit_length=aranges_header["unit_length"], 90 | version=aranges_header["version"], 91 | address_size=aranges_header["address_size"], 92 | segment_size=aranges_header["segment_size"])) 93 | addr = struct_parse(addr_size('addr'), self.stream) 94 | length = struct_parse(addr_size('length'), self.stream) 95 | # Segmentation exists in executable 96 | elif aranges_header["segment_size"] != 0: 97 | raise NotImplementedError("Segmentation not implemented") 98 | 99 | offset = (offset 100 | + aranges_header.unit_length 101 | + self.structs.initial_length_field_size()) 102 | 103 | return entries 104 | 105 | def _get_addr_size_struct(self, addr_header_value): 106 | """ Given this set's header value (int) for the address size, 107 | get the Construct representation of that size 108 | """ 109 | if addr_header_value == 4: 110 | return self.structs.Dwarf_uint32 111 | else: 112 | assert addr_header_value == 8 113 | return self.structs.Dwarf_uint64 114 | -------------------------------------------------------------------------------- /src/elftools/dwarf/constants.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: dwarf/constants.py 3 | # 4 | # Constants and flags 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | 10 | # Inline codes 11 | # 12 | DW_INL_not_inlined = 0 13 | DW_INL_inlined = 1 14 | DW_INL_declared_not_inlined = 2 15 | DW_INL_declared_inlined = 3 16 | 17 | 18 | # Source languages 19 | # 20 | DW_LANG_C89 = 0x0001 21 | DW_LANG_C = 0x0002 22 | DW_LANG_Ada83 = 0x0003 23 | DW_LANG_C_plus_plus = 0x0004 24 | DW_LANG_Cobol74 = 0x0005 25 | DW_LANG_Cobol85 = 0x0006 26 | DW_LANG_Fortran77 = 0x0007 27 | DW_LANG_Fortran90 = 0x0008 28 | DW_LANG_Pascal83 = 0x0009 29 | DW_LANG_Modula2 = 0x000a 30 | DW_LANG_Java = 0x000b 31 | DW_LANG_C99 = 0x000c 32 | DW_LANG_Ada95 = 0x000d 33 | DW_LANG_Fortran95 = 0x000e 34 | DW_LANG_PLI = 0x000f 35 | DW_LANG_ObjC = 0x0010 36 | DW_LANG_ObjC_plus_plus = 0x0011 37 | DW_LANG_UPC = 0x0012 38 | DW_LANG_D = 0x0013 39 | DW_LANG_Python = 0x0014 40 | DW_LANG_OpenCL = 0x0015 41 | DW_LANG_Go = 0x0016 42 | DW_LANG_Modula3 = 0x0017 43 | DW_LANG_Haskell = 0x0018 44 | DW_LANG_C_plus_plus_03 = 0x0019 45 | DW_LANG_C_plus_plus_11 = 0x001a 46 | DW_LANG_OCaml = 0x001b 47 | DW_LANG_Rust = 0x001c 48 | DW_LANG_C11 = 0x001d 49 | DW_LANG_Swift = 0x001e 50 | DW_LANG_Julia = 0x001f 51 | DW_LANG_Dylan = 0x0020 52 | DW_LANG_C_plus_plus_14 = 0x0021 53 | DW_LANG_Fortran03 = 0x0022 54 | DW_LANG_Fortran08 = 0x0023 55 | DW_LANG_RenderScript = 0x0024 56 | DW_LANG_BLISS = 0x0025 57 | DW_LANG_Mips_Assembler = 0x8001 58 | DW_LANG_Upc = 0x8765 59 | DW_LANG_HP_Bliss = 0x8003 60 | DW_LANG_HP_Basic91 = 0x8004 61 | DW_LANG_HP_Pascal91 = 0x8005 62 | DW_LANG_HP_IMacro = 0x8006 63 | DW_LANG_HP_Assembler = 0x8007 64 | DW_LANG_GOOGLE_RenderScript = 0x8e57 65 | DW_LANG_BORLAND_Delphi = 0xb000 66 | 67 | 68 | # Encoding 69 | # 70 | DW_ATE_void = 0x0 71 | DW_ATE_address = 0x1 72 | DW_ATE_boolean = 0x2 73 | DW_ATE_complex_float = 0x3 74 | DW_ATE_float = 0x4 75 | DW_ATE_signed = 0x5 76 | DW_ATE_signed_char = 0x6 77 | DW_ATE_unsigned = 0x7 78 | DW_ATE_unsigned_char = 0x8 79 | DW_ATE_imaginary_float = 0x9 80 | DW_ATE_packed_decimal = 0xa 81 | DW_ATE_numeric_string = 0xb 82 | DW_ATE_edited = 0xc 83 | DW_ATE_signed_fixed = 0xd 84 | DW_ATE_unsigned_fixed = 0xe 85 | DW_ATE_decimal_float = 0xf 86 | DW_ATE_UTF = 0x10 87 | DW_ATE_UCS = 0x11 88 | DW_ATE_ASCII = 0x12 89 | DW_ATE_lo_user = 0x80 90 | DW_ATE_hi_user = 0xff 91 | DW_ATE_HP_float80 = 0x80 92 | DW_ATE_HP_complex_float80 = 0x81 93 | DW_ATE_HP_float128 = 0x82 94 | DW_ATE_HP_complex_float128 = 0x83 95 | DW_ATE_HP_floathpintel = 0x84 96 | DW_ATE_HP_imaginary_float80 = 0x85 97 | DW_ATE_HP_imaginary_float128 = 0x86 98 | 99 | 100 | # Access 101 | # 102 | DW_ACCESS_public = 1 103 | DW_ACCESS_protected = 2 104 | DW_ACCESS_private = 3 105 | 106 | 107 | # Visibility 108 | # 109 | DW_VIS_local = 1 110 | DW_VIS_exported = 2 111 | DW_VIS_qualified = 3 112 | 113 | 114 | # Virtuality 115 | # 116 | DW_VIRTUALITY_none = 0 117 | DW_VIRTUALITY_virtual = 1 118 | DW_VIRTUALITY_pure_virtual = 2 119 | 120 | 121 | # ID case 122 | # 123 | DW_ID_case_sensitive = 0 124 | DW_ID_up_case = 1 125 | DW_ID_down_case = 2 126 | DW_ID_case_insensitive = 3 127 | 128 | 129 | # Calling convention 130 | # 131 | DW_CC_normal = 0x1 132 | DW_CC_program = 0x2 133 | DW_CC_nocall = 0x3 134 | 135 | 136 | # Ordering 137 | # 138 | DW_ORD_row_major = 0 139 | DW_ORD_col_major = 1 140 | 141 | 142 | # Line program opcodes 143 | # 144 | DW_LNS_copy = 0x01 145 | DW_LNS_advance_pc = 0x02 146 | DW_LNS_advance_line = 0x03 147 | DW_LNS_set_file = 0x04 148 | DW_LNS_set_column = 0x05 149 | DW_LNS_negate_stmt = 0x06 150 | DW_LNS_set_basic_block = 0x07 151 | DW_LNS_const_add_pc = 0x08 152 | DW_LNS_fixed_advance_pc = 0x09 153 | DW_LNS_set_prologue_end = 0x0a 154 | DW_LNS_set_epilogue_begin = 0x0b 155 | DW_LNS_set_isa = 0x0c 156 | DW_LNE_end_sequence = 0x01 157 | DW_LNE_set_address = 0x02 158 | DW_LNE_define_file = 0x03 159 | DW_LNE_set_discriminator = 0x04 160 | DW_LNE_lo_user = 0x80 161 | DW_LNE_hi_user = 0xff 162 | 163 | # Line program header content types 164 | # 165 | DW_LNCT_path = 0x01 166 | DW_LNCT_directory_index = 0x02 167 | DW_LNCT_timestamp = 0x03 168 | DW_LNCT_size = 0x04 169 | DW_LNCT_MD5 = 0x05 170 | DW_LNCT_lo_user = 0x2000 171 | DW_LNCT_hi_user = 0x3fff 172 | 173 | # Call frame instructions 174 | # 175 | # Note that the first 3 instructions have the so-called "primary opcode" 176 | # (as described in DWARFv3 7.23), so only their highest 2 bits take part 177 | # in the opcode decoding. They are kept as constants with the low bits masked 178 | # out, and the callframe module knows how to handle this. 179 | # The other instructions use an "extended opcode" encoded just in the low 6 180 | # bits, with the high 2 bits, so these constants are exactly as they would 181 | # appear in an actual file. 182 | # 183 | DW_CFA_advance_loc = 0b01000000 184 | DW_CFA_offset = 0b10000000 185 | DW_CFA_restore = 0b11000000 186 | DW_CFA_nop = 0x00 187 | DW_CFA_set_loc = 0x01 188 | DW_CFA_advance_loc1 = 0x02 189 | DW_CFA_advance_loc2 = 0x03 190 | DW_CFA_advance_loc4 = 0x04 191 | DW_CFA_offset_extended = 0x05 192 | DW_CFA_restore_extended = 0x06 193 | DW_CFA_undefined = 0x07 194 | DW_CFA_same_value = 0x08 195 | DW_CFA_register = 0x09 196 | DW_CFA_remember_state = 0x0a 197 | DW_CFA_restore_state = 0x0b 198 | DW_CFA_def_cfa = 0x0c 199 | DW_CFA_def_cfa_register = 0x0d 200 | DW_CFA_def_cfa_offset = 0x0e 201 | DW_CFA_def_cfa_expression = 0x0f 202 | DW_CFA_expression = 0x10 203 | DW_CFA_offset_extended_sf = 0x11 204 | DW_CFA_def_cfa_sf = 0x12 205 | DW_CFA_def_cfa_offset_sf = 0x13 206 | DW_CFA_val_offset = 0x14 207 | DW_CFA_val_offset_sf = 0x15 208 | DW_CFA_val_expression = 0x16 209 | DW_CFA_GNU_args_size = 0x2e 210 | 211 | 212 | # Compilation unit types 213 | # 214 | # DWARFv5 introduces the "unit_type" field to each CU header, allowing 215 | # individual CUs to indicate whether they're complete, partial, and so forth. 216 | # See DWARFv5 3.1 ("Unit Entries") and 7.5.1 ("Unit Headers"). 217 | DW_UT_compile = 0x01 218 | DW_UT_type = 0x02 219 | DW_UT_partial = 0x03 220 | DW_UT_skeleton = 0x04 221 | DW_UT_split_compile = 0x05 222 | DW_UT_split_type = 0x06 223 | DW_UT_lo_user = 0x80 224 | DW_UT_hi_user = 0xff 225 | -------------------------------------------------------------------------------- /src/elftools/dwarf/locationlists.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: dwarf/locationlists.py 3 | # 4 | # DWARF location lists section decoding (.debug_loc) 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | import os 10 | from collections import namedtuple 11 | 12 | from ..common.utils import struct_parse 13 | 14 | LocationExpr = namedtuple('LocationExpr', 'loc_expr') 15 | LocationEntry = namedtuple('LocationEntry', 'entry_offset begin_offset end_offset loc_expr') 16 | BaseAddressEntry = namedtuple('BaseAddressEntry', 'entry_offset base_address') 17 | 18 | class LocationLists(object): 19 | """ A single location list is a Python list consisting of LocationEntry or 20 | BaseAddressEntry objects. 21 | """ 22 | def __init__(self, stream, structs): 23 | self.stream = stream 24 | self.structs = structs 25 | self._max_addr = 2 ** (self.structs.address_size * 8) - 1 26 | 27 | def get_location_list_at_offset(self, offset): 28 | """ Get a location list at the given offset in the section. 29 | """ 30 | self.stream.seek(offset, os.SEEK_SET) 31 | return self._parse_location_list_from_stream() 32 | 33 | def iter_location_lists(self): 34 | """ Yield all location lists found in the section. 35 | """ 36 | # Just call _parse_location_list_from_stream until the stream ends 37 | self.stream.seek(0, os.SEEK_END) 38 | endpos = self.stream.tell() 39 | 40 | self.stream.seek(0, os.SEEK_SET) 41 | while self.stream.tell() < endpos: 42 | yield self._parse_location_list_from_stream() 43 | 44 | #------ PRIVATE ------# 45 | 46 | def _parse_location_list_from_stream(self): 47 | lst = [] 48 | while True: 49 | entry_offset = self.stream.tell() 50 | begin_offset = struct_parse( 51 | self.structs.Dwarf_target_addr(''), self.stream) 52 | end_offset = struct_parse( 53 | self.structs.Dwarf_target_addr(''), self.stream) 54 | if begin_offset == 0 and end_offset == 0: 55 | # End of list - we're done. 56 | break 57 | elif begin_offset == self._max_addr: 58 | # Base address selection entry 59 | lst.append(BaseAddressEntry(entry_offset=entry_offset, base_address=end_offset)) 60 | else: 61 | # Location list entry 62 | expr_len = struct_parse( 63 | self.structs.Dwarf_uint16(''), self.stream) 64 | loc_expr = [struct_parse(self.structs.Dwarf_uint8(''), 65 | self.stream) 66 | for i in range(expr_len)] 67 | lst.append(LocationEntry( 68 | entry_offset=entry_offset, 69 | begin_offset=begin_offset, 70 | end_offset=end_offset, 71 | loc_expr=loc_expr)) 72 | return lst 73 | 74 | class LocationParser(object): 75 | """ A parser for location information in DIEs. 76 | Handles both location information contained within the attribute 77 | itself (represented as a LocationExpr object) and references to 78 | location lists in the .debug_loc section (represented as a 79 | list). 80 | """ 81 | def __init__(self, location_lists): 82 | self.location_lists = location_lists 83 | 84 | @staticmethod 85 | def attribute_has_location(attr, dwarf_version): 86 | """ Checks if a DIE attribute contains location information. 87 | """ 88 | return (LocationParser._attribute_is_loclistptr_class(attr) and 89 | (LocationParser._attribute_has_loc_expr(attr, dwarf_version) or 90 | LocationParser._attribute_has_loc_list(attr, dwarf_version))) 91 | 92 | def parse_from_attribute(self, attr, dwarf_version): 93 | """ Parses a DIE attribute and returns either a LocationExpr or 94 | a list. 95 | """ 96 | if self.attribute_has_location(attr, dwarf_version): 97 | if self._attribute_has_loc_expr(attr, dwarf_version): 98 | return LocationExpr(attr.value) 99 | elif self._attribute_has_loc_list(attr, dwarf_version): 100 | return self.location_lists.get_location_list_at_offset( 101 | attr.value) 102 | else: 103 | raise ValueError("Attribute does not have location information") 104 | 105 | #------ PRIVATE ------# 106 | 107 | @staticmethod 108 | def _attribute_has_loc_expr(attr, dwarf_version): 109 | return ((dwarf_version < 4 and attr.form.startswith('DW_FORM_block') and 110 | not attr.name == 'DW_AT_const_value') or 111 | attr.form == 'DW_FORM_exprloc') 112 | 113 | @staticmethod 114 | def _attribute_has_loc_list(attr, dwarf_version): 115 | return ((dwarf_version < 4 and 116 | attr.form in ('DW_FORM_data4', 'DW_FORM_data8') and 117 | not attr.name == 'DW_AT_const_value') or 118 | attr.form == 'DW_FORM_sec_offset') 119 | 120 | @staticmethod 121 | def _attribute_is_loclistptr_class(attr): 122 | return (attr.name in ( 'DW_AT_location', 'DW_AT_string_length', 123 | 'DW_AT_const_value', 'DW_AT_return_addr', 124 | 'DW_AT_data_member_location', 125 | 'DW_AT_frame_base', 'DW_AT_segment', 126 | 'DW_AT_static_link', 'DW_AT_use_location', 127 | 'DW_AT_vtable_elem_location', 128 | 'DW_AT_GNU_call_site_value', 129 | 'DW_AT_GNU_call_site_target', 130 | 'DW_AT_GNU_call_site_data_value')) 131 | -------------------------------------------------------------------------------- /src/elftools/dwarf/ranges.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: dwarf/ranges.py 3 | # 4 | # DWARF ranges section decoding (.debug_ranges) 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | import os 10 | from collections import namedtuple 11 | 12 | from ..common.utils import struct_parse 13 | 14 | 15 | RangeEntry = namedtuple('RangeEntry', 'begin_offset end_offset') 16 | BaseAddressEntry = namedtuple('BaseAddressEntry', 'base_address') 17 | 18 | 19 | class RangeLists(object): 20 | """ A single range list is a Python list consisting of RangeEntry or 21 | BaseAddressEntry objects. 22 | """ 23 | def __init__(self, stream, structs): 24 | self.stream = stream 25 | self.structs = structs 26 | self._max_addr = 2 ** (self.structs.address_size * 8) - 1 27 | 28 | def get_range_list_at_offset(self, offset): 29 | """ Get a range list at the given offset in the section. 30 | """ 31 | self.stream.seek(offset, os.SEEK_SET) 32 | return self._parse_range_list_from_stream() 33 | 34 | def iter_range_lists(self): 35 | """ Yield all range lists found in the section. 36 | """ 37 | # Just call _parse_range_list_from_stream until the stream ends 38 | self.stream.seek(0, os.SEEK_END) 39 | endpos = self.stream.tell() 40 | 41 | self.stream.seek(0, os.SEEK_SET) 42 | while self.stream.tell() < endpos: 43 | yield self._parse_range_list_from_stream() 44 | 45 | #------ PRIVATE ------# 46 | 47 | def _parse_range_list_from_stream(self): 48 | lst = [] 49 | while True: 50 | begin_offset = struct_parse( 51 | self.structs.Dwarf_target_addr(''), self.stream) 52 | end_offset = struct_parse( 53 | self.structs.Dwarf_target_addr(''), self.stream) 54 | if begin_offset == 0 and end_offset == 0: 55 | # End of list - we're done. 56 | break 57 | elif begin_offset == self._max_addr: 58 | # Base address selection entry 59 | lst.append(BaseAddressEntry(base_address=end_offset)) 60 | else: 61 | # Range entry 62 | lst.append(RangeEntry( 63 | begin_offset=begin_offset, 64 | end_offset=end_offset)) 65 | return lst 66 | -------------------------------------------------------------------------------- /src/elftools/ehabi/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/elftools/ehabi 2 | 3 | install_PYTHON = \ 4 | constants.py decoder.py ehabiinfo.py __init__.py structs.py 5 | -------------------------------------------------------------------------------- /src/elftools/ehabi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oe-alliance/openmultibootmanager/e4d532e693d98d7c82e922973be18ab93cc8e681/src/elftools/ehabi/__init__.py -------------------------------------------------------------------------------- /src/elftools/ehabi/constants.py: -------------------------------------------------------------------------------- 1 | EHABI_INDEX_ENTRY_SIZE = 8 2 | -------------------------------------------------------------------------------- /src/elftools/ehabi/structs.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------- 2 | # elftools: ehabi/structs.py 3 | # 4 | # Encapsulation of Construct structs for parsing an EHABI, adjusted for 5 | # correct endianness and word-size. 6 | # 7 | # LeadroyaL (leadroyal@qq.com) 8 | # This code is in the public domain 9 | # ------------------------------------------------------------------------------- 10 | 11 | from ..construct import UBInt32, ULInt32, Struct 12 | 13 | 14 | class EHABIStructs(object): 15 | """ Accessible attributes: 16 | 17 | EH_index_struct: 18 | Struct of item in section .ARM.exidx. 19 | 20 | EH_table_struct: 21 | Struct of item in section .ARM.extab. 22 | """ 23 | 24 | def __init__(self, little_endian): 25 | self._little_endian = little_endian 26 | self._create_structs() 27 | 28 | def _create_structs(self): 29 | if self._little_endian: 30 | self.EHABI_uint32 = ULInt32 31 | else: 32 | self.EHABI_uint32 = UBInt32 33 | self._create_exception_handler_index() 34 | self._create_exception_handler_table() 35 | 36 | def _create_exception_handler_index(self): 37 | self.EH_index_struct = Struct( 38 | 'EH_index', 39 | self.EHABI_uint32('word0'), 40 | self.EHABI_uint32('word1') 41 | ) 42 | 43 | def _create_exception_handler_table(self): 44 | self.EH_table_struct = Struct( 45 | 'EH_table', 46 | self.EHABI_uint32('word0'), 47 | ) 48 | -------------------------------------------------------------------------------- /src/elftools/elf/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/elftools/elf 2 | 3 | install_PYTHON = \ 4 | constants.py descriptions.py dynamic.py elffile.py enums.py gnuversions.py hash.py __init__.py notes.py relocation.py sections.py segments.py structs.py 5 | -------------------------------------------------------------------------------- /src/elftools/elf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oe-alliance/openmultibootmanager/e4d532e693d98d7c82e922973be18ab93cc8e681/src/elftools/elf/__init__.py -------------------------------------------------------------------------------- /src/elftools/elf/constants.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: elf/constants.py 3 | # 4 | # Constants and flags, placed into classes for namespacing 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | 10 | class E_FLAGS(object): 11 | """ Flag values for the e_flags field of the ELF header 12 | """ 13 | EF_ARM_EABIMASK=0xFF000000 14 | EF_ARM_EABI_VER1=0x01000000 15 | EF_ARM_EABI_VER2=0x02000000 16 | EF_ARM_EABI_VER3=0x03000000 17 | EF_ARM_EABI_VER4=0x04000000 18 | EF_ARM_EABI_VER5=0x05000000 19 | EF_ARM_GCCMASK=0x00400FFF 20 | EF_ARM_RELEXEC=0x01 21 | EF_ARM_HASENTRY=0x02 22 | EF_ARM_SYMSARESORTED=0x04 23 | EF_ARM_DYNSYMSUSESEGIDX=0x8 24 | EF_ARM_MAPSYMSFIRST=0x10 25 | EF_ARM_LE8=0x00400000 26 | EF_ARM_BE8=0x00800000 27 | EF_ARM_ABI_FLOAT_SOFT=0x00000200 28 | EF_ARM_ABI_FLOAT_HARD=0x00000400 29 | 30 | EF_PPC64_ABI_V0=0 31 | EF_PPC64_ABI_V1=1 32 | EF_PPC64_ABI_V2=2 33 | 34 | EF_MIPS_NOREORDER=1 35 | EF_MIPS_PIC=2 36 | EF_MIPS_CPIC=4 37 | EF_MIPS_XGOT=8 38 | EF_MIPS_64BIT_WHIRL=16 39 | EF_MIPS_ABI2=32 40 | EF_MIPS_ABI_ON32=64 41 | EF_MIPS_32BITMODE = 256 42 | EF_MIPS_NAN2008=1024 43 | EF_MIPS_ARCH=0xf0000000 44 | EF_MIPS_ARCH_1=0x00000000 45 | EF_MIPS_ARCH_2=0x10000000 46 | EF_MIPS_ARCH_3=0x20000000 47 | EF_MIPS_ARCH_4=0x30000000 48 | EF_MIPS_ARCH_5=0x40000000 49 | EF_MIPS_ARCH_32=0x50000000 50 | EF_MIPS_ARCH_64=0x60000000 51 | EF_MIPS_ARCH_32R2=0x70000000 52 | EF_MIPS_ARCH_64R2=0x80000000 53 | 54 | 55 | class E_FLAGS_MASKS(object): 56 | """Masks to be used for convenience when working with E_FLAGS 57 | 58 | This is a simplified approach that is also used by GNU binutils 59 | readelf 60 | """ 61 | EFM_MIPS_ABI = 0x0000F000 62 | EFM_MIPS_ABI_O32 = 0x00001000 63 | EFM_MIPS_ABI_O64 = 0x00002000 64 | EFM_MIPS_ABI_EABI32 = 0x00003000 65 | EFM_MIPS_ABI_EABI64 = 0x00004000 66 | 67 | 68 | class SHN_INDICES(object): 69 | """ Special section indices 70 | """ 71 | SHN_UNDEF=0 72 | SHN_LORESERVE=0xff00 73 | SHN_LOPROC=0xff00 74 | SHN_HIPROC=0xff1f 75 | SHN_ABS=0xfff1 76 | SHN_COMMON=0xfff2 77 | SHN_HIRESERVE=0xffff 78 | SHN_XINDEX=0xffff 79 | 80 | 81 | class SH_FLAGS(object): 82 | """ Flag values for the sh_flags field of section headers 83 | """ 84 | SHF_WRITE=0x1 85 | SHF_ALLOC=0x2 86 | SHF_EXECINSTR=0x4 87 | SHF_MERGE=0x10 88 | SHF_STRINGS=0x20 89 | SHF_INFO_LINK=0x40 90 | SHF_LINK_ORDER=0x80 91 | SHF_OS_NONCONFORMING=0x100 92 | SHF_GROUP=0x200 93 | SHF_TLS=0x400 94 | SHF_COMPRESSED=0x800 95 | SHF_MASKOS=0x0ff00000 96 | SHF_EXCLUDE=0x80000000 97 | SHF_MASKPROC=0xf0000000 98 | 99 | 100 | class RH_FLAGS(object): 101 | """ Flag values for the DT_MIPS_FLAGS dynamic table entries 102 | """ 103 | RHF_NONE=0x00000000 104 | RHF_QUICKSTART=0x00000001 105 | RHF_NOTPOT=0x00000002 106 | RHF_NO_LIBRARY_REPLACEMENT=0x00000004 107 | RHF_NO_MOVE=0x00000008 108 | RHF_SGI_ONLY=0x00000010 109 | RHF_GUARANTEE_INIT=0x00000020 110 | RHF_DELTA_C_PLUS_PLUS=0x00000040 111 | RHF_GUARANTEE_START_INIT=0x00000080 112 | RHF_PIXIE=0x00000100 113 | RHF_DEFAULT_DELAY_LOAD=0x00000200 114 | RHF_REQUICKSTART=0x00000400 115 | RHF_REQUICKSTARTED=0x00000800 116 | RHF_CORD=0x00001000 117 | RHF_NO_UNRES_UNDEF=0x00002000 118 | RHF_RLD_ORDER_SAFE=0x00004000 119 | 120 | 121 | class P_FLAGS(object): 122 | """ Flag values for the p_flags field of program headers 123 | """ 124 | PF_X=0x1 125 | PF_W=0x2 126 | PF_R=0x4 127 | PF_MASKOS=0x00FF0000 128 | PF_MASKPROC=0xFF000000 129 | 130 | 131 | # symbol info flags for entries 132 | # in the .SUNW_syminfo section 133 | class SUNW_SYMINFO_FLAGS(object): 134 | """ Flags for the si_flags field of entries 135 | in the .SUNW_syminfo section 136 | """ 137 | SYMINFO_FLG_DIRECT=0x1 138 | SYMINFO_FLG_FILTER=0x2 139 | SYMINFO_FLG_COPY=0x4 140 | SYMINFO_FLG_LAZYLOAD=0x8 141 | SYMINFO_FLG_DIRECTBIND=0x10 142 | SYMINFO_FLG_NOEXTDIRECT=0x20 143 | SYMINFO_FLG_AUXILIARY=0x40 144 | SYMINFO_FLG_INTERPOSE=0x80 145 | SYMINFO_FLG_CAP=0x100 146 | SYMINFO_FLG_DEFERRED=0x200 147 | 148 | class VER_FLAGS(object): 149 | VER_FLG_BASE=0x1 150 | VER_FLG_WEAK=0x2 151 | VER_FLG_INFO=0x4 152 | -------------------------------------------------------------------------------- /src/elftools/elf/notes.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: elf/notes.py 3 | # 4 | # ELF notes 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | from ..common.py3compat import bytes2str 10 | from ..common.utils import struct_parse, roundup 11 | from ..construct import CString 12 | 13 | 14 | def iter_notes(elffile, offset, size): 15 | """ Yield all the notes in a section or segment. 16 | """ 17 | end = offset + size 18 | while offset < end: 19 | note = struct_parse( 20 | elffile.structs.Elf_Nhdr, 21 | elffile.stream, 22 | stream_pos=offset) 23 | note['n_offset'] = offset 24 | offset += elffile.structs.Elf_Nhdr.sizeof() 25 | elffile.stream.seek(offset) 26 | # n_namesz is 4-byte aligned. 27 | disk_namesz = roundup(note['n_namesz'], 2) 28 | note['n_name'] = bytes2str( 29 | CString('').parse(elffile.stream.read(disk_namesz))) 30 | offset += disk_namesz 31 | 32 | desc_data = bytes2str(elffile.stream.read(note['n_descsz'])) 33 | note['n_descdata'] = desc_data 34 | if note['n_type'] == 'NT_GNU_ABI_TAG': 35 | note['n_desc'] = struct_parse(elffile.structs.Elf_abi, 36 | elffile.stream, 37 | offset) 38 | elif note['n_type'] == 'NT_GNU_BUILD_ID': 39 | note['n_desc'] = ''.join('%.2x' % ord(b) for b in desc_data) 40 | elif note['n_type'] == 'NT_PRPSINFO': 41 | note['n_desc'] = struct_parse(elffile.structs.Elf_Prpsinfo, 42 | elffile.stream, 43 | offset) 44 | elif note['n_type'] == 'NT_FILE': 45 | note['n_desc'] = struct_parse(elffile.structs.Elf_Nt_File, 46 | elffile.stream, 47 | offset) 48 | else: 49 | note['n_desc'] = desc_data 50 | offset += roundup(note['n_descsz'], 2) 51 | note['n_size'] = offset - note['n_offset'] 52 | yield note 53 | -------------------------------------------------------------------------------- /src/elftools/elf/segments.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # elftools: elf/segments.py 3 | # 4 | # ELF segments 5 | # 6 | # Eli Bendersky (eliben@gmail.com) 7 | # This code is in the public domain 8 | #------------------------------------------------------------------------------- 9 | from ..construct import CString 10 | from ..common.utils import struct_parse 11 | from .constants import SH_FLAGS 12 | from .notes import iter_notes 13 | 14 | 15 | class Segment(object): 16 | def __init__(self, header, stream): 17 | self.header = header 18 | self.stream = stream 19 | 20 | def data(self): 21 | """ The segment data from the file. 22 | """ 23 | self.stream.seek(self['p_offset']) 24 | return self.stream.read(self['p_filesz']) 25 | 26 | def __getitem__(self, name): 27 | """ Implement dict-like access to header entries 28 | """ 29 | return self.header[name] 30 | 31 | def section_in_segment(self, section): 32 | """ Is the given section contained in this segment? 33 | 34 | Note: this tries to reproduce the intricate rules of the 35 | ELF_SECTION_IN_SEGMENT_STRICT macro of the header 36 | elf/include/internal.h in the source of binutils. 37 | """ 38 | # Only the 'strict' checks from ELF_SECTION_IN_SEGMENT_1 are included 39 | segtype = self['p_type'] 40 | sectype = section['sh_type'] 41 | secflags = section['sh_flags'] 42 | 43 | # Only PT_LOAD, PT_GNU_RELRO and PT_TLS segments can contain SHF_TLS 44 | # sections 45 | if ( secflags & SH_FLAGS.SHF_TLS and 46 | segtype in ('PT_TLS', 'PT_GNU_RELRO', 'PT_LOAD')): 47 | pass 48 | # PT_TLS segment contains only SHF_TLS sections, PT_PHDR no sections 49 | # at all 50 | elif ( (secflags & SH_FLAGS.SHF_TLS) == 0 and 51 | segtype not in ('PT_TLS', 'PT_PHDR')): 52 | pass 53 | else: 54 | return False 55 | 56 | # PT_LOAD and similar segments only have SHF_ALLOC sections. 57 | if ( (secflags & SH_FLAGS.SHF_ALLOC) == 0 and 58 | segtype in ('PT_LOAD', 'PT_DYNAMIC', 'PT_GNU_EH_FRAME', 59 | 'PT_GNU_RELRO', 'PT_GNU_STACK')): 60 | return False 61 | 62 | # In ELF_SECTION_IN_SEGMENT_STRICT the flag check_vma is on, so if 63 | # this is an alloc section, check whether its VMA is in bounds. 64 | if secflags & SH_FLAGS.SHF_ALLOC: 65 | secaddr = section['sh_addr'] 66 | vaddr = self['p_vaddr'] 67 | 68 | # This checks that the section is wholly contained in the segment. 69 | # The third condition is the 'strict' one - an empty section will 70 | # not match at the very end of the segment (unless the segment is 71 | # also zero size, which is handled by the second condition). 72 | if not (secaddr >= vaddr and 73 | secaddr - vaddr + section['sh_size'] <= self['p_memsz'] and 74 | secaddr - vaddr <= self['p_memsz'] - 1): 75 | return False 76 | 77 | # If we've come this far and it's a NOBITS section, it's in the segment 78 | if sectype == 'SHT_NOBITS': 79 | return True 80 | 81 | secoffset = section['sh_offset'] 82 | poffset = self['p_offset'] 83 | 84 | # Same logic as with secaddr vs. vaddr checks above, just on offsets in 85 | # the file 86 | return (secoffset >= poffset and 87 | secoffset - poffset + section['sh_size'] <= self['p_filesz'] and 88 | secoffset - poffset <= self['p_filesz'] - 1) 89 | 90 | 91 | class InterpSegment(Segment): 92 | """ INTERP segment. Knows how to obtain the path to the interpreter used 93 | for this ELF file. 94 | """ 95 | def __init__(self, header, stream): 96 | super(InterpSegment, self).__init__(header, stream) 97 | 98 | def get_interp_name(self): 99 | """ Obtain the interpreter path used for this ELF file. 100 | """ 101 | path_offset = self['p_offset'] 102 | return struct_parse( 103 | CString('', encoding='utf-8'), 104 | self.stream, 105 | stream_pos=path_offset) 106 | 107 | 108 | class NoteSegment(Segment): 109 | """ NOTE segment. Knows how to parse notes. 110 | """ 111 | def __init__(self, header, stream, elffile): 112 | super(NoteSegment, self).__init__(header, stream) 113 | self.elffile = elffile 114 | 115 | def iter_notes(self): 116 | 117 | """ Yield all the notes in the segment. Each result is a dictionary- 118 | like object with "n_name", "n_type", and "n_desc" fields, amongst 119 | others. 120 | """ 121 | return iter_notes(self.elffile, self['p_offset'], self['p_filesz']) 122 | -------------------------------------------------------------------------------- /src/open-multiboot-branding-helper.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | ############################################################################# 3 | # 4 | # Copyright (C) 2014 Impex-Sat Gmbh & Co.KG 5 | # Written by Sandro Cavazzoni 6 | # All Rights Reserved. 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License along 19 | # with this program; if not, write to the Free Software Foundation, Inc., 20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | # 22 | ############################################################################# 23 | 24 | import sys 25 | 26 | KEYS_FNC_MAP = { 27 | 'model': 'boxbranding.getMachineBuild()', 28 | 'displaybrand': 'boxbranding.getMachineBrand()', 29 | 'displaymodel': 'boxbranding.getMachineName()', 30 | 'mtdkernel': 'boxbranding.getMachineMtdKernel()', 31 | 'kernelfile': 'boxbranding.getMachineKernelFile()', 32 | 'mtdrootfs': 'boxbranding.getMachineMtdRoot()', 33 | 'rootfile': 'boxbranding.getMachineRootFile()', 34 | 'mkubifs': 'boxbranding.getMachineMKUBIFS()', 35 | 'ubinize': 'boxbranding.getMachineUBINIZE()', 36 | 'brand': 'boxbranding.getBrandOEM()', 37 | 'oe': 'boxbranding.getOEVersion()', 38 | 'imageversion': 'boxbranding.getImageVersion()', 39 | 'imagebuild': 'boxbranding.getImageBuild()', 40 | 'distro': 'boxbranding.getImageDistro()', 41 | 'imagedir': 'boxbranding.getImageFolder()', 42 | 'imagefs': 'boxbranding.getImageFileSystem()' 43 | #unsupported by boxconfig 44 | # 'model': 'boxbranding.getBoxType()', 45 | # 'driver_date': 'boxbranding.getDriverDate()', 46 | # 'machine_proc_model': 'boxbranding.getMachineProcModel()', 47 | } 48 | 49 | 50 | def print_help(): 51 | print('Syntax:') 52 | print(sys.argv[0] + ' enigma2_dir key') 53 | print('') 54 | print('Valid keys:') 55 | for key in KEYS_FNC_MAP.keys(): 56 | print(' * ' + key) 57 | print(' * all') 58 | 59 | 60 | if len(sys.argv) != 3: 61 | print_help() 62 | else: 63 | sys.path.insert(0, sys.argv[1]) 64 | try: 65 | import boxbranding 66 | except Exception as e: 67 | print ("OMBHELPER: Error:",e) 68 | if not sys.argv[2] in KEYS_FNC_MAP and sys.argv[2] != 'all': 69 | print_help() 70 | else: 71 | if sys.argv[2] == 'all': 72 | for key in KEYS_FNC_MAP.keys(): 73 | print(key + ' = ' + eval(KEYS_FNC_MAP[key])) 74 | else: 75 | print(eval(KEYS_FNC_MAP[sys.argv[2]])) 76 | -------------------------------------------------------------------------------- /src/open-multiboot-menu-helper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | import sys 5 | 6 | sys.path.insert(0, '/usr/lib/enigma2/python/Plugins/Extensions/') 7 | from OpenMultiboot import OMBList 8 | 9 | if __name__ == "__main__": 10 | 11 | debug = None 12 | ombdir = "/omb" 13 | 14 | if len(sys.argv) >= 2: 15 | ombdir = sys.argv[1] 16 | 17 | if len(sys.argv) == 3 and sys.argv[2].upper() == "DEBUG": 18 | debug = True 19 | 20 | ombList = OMBList.OMBList(ombdir, debug = debug) 21 | 22 | ombList.populateImagesList() 23 | print (ombList.getJson(debug = debug)) 24 | 25 | -------------------------------------------------------------------------------- /src/plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oe-alliance/openmultibootmanager/e4d532e693d98d7c82e922973be18ab93cc8e681/src/plugin.png -------------------------------------------------------------------------------- /src/plugin.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | ############################################################################# 3 | # 4 | # Copyright (C) 2014 Impex-Sat Gmbh & Co.KG 5 | # Written by Sandro Cavazzoni 6 | # All Rights Reserved. 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License along 19 | # with this program; if not, write to the Free Software Foundation, Inc., 20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | # 22 | ############################################################################# 23 | 24 | from Plugins.Plugin import PluginDescriptor 25 | 26 | from .OMBManager import OMBManager 27 | from .OMBManagerLocale import _ 28 | 29 | 30 | def Plugins(**kwargs): 31 | return [ 32 | PluginDescriptor( 33 | name="OpenMultiboot", 34 | description=_("OpenMultiboot Manager"), 35 | icon='plugin.png', 36 | where=[PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU], 37 | fnc=OMBManager 38 | ) 39 | ] 40 | -------------------------------------------------------------------------------- /src/ubi_reader/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/ubi_reader 2 | 3 | SUBDIRS = ubi ubi_io ubifs ui 4 | 5 | install_PYTHON = \ 6 | ubi_extract_files.py -------------------------------------------------------------------------------- /src/ubi_reader/ubi/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/ubi_reader/ubi 2 | 3 | SUBDIRS = block headers volume 4 | 5 | install_PYTHON = \ 6 | __init__.py defines.py display.py image.py -------------------------------------------------------------------------------- /src/ubi_reader/ubi/block/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/ubi_reader/ubi/block 2 | 3 | install_PYTHON = \ 4 | __init__.py layout.py sort.py -------------------------------------------------------------------------------- /src/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 | 28 | 29 | class description(object): 30 | """UBI Block description Object 31 | 32 | UBI Specifications: 33 | http://www.linux-mtd.infradead.org/ -- Home page 34 | /drivers/mtd/ubi/ubi-media.h -- Header structs 35 | and defines 36 | 37 | Attributes: 38 | Obj:ec_hdr -- Error Count Header 39 | Obj:vid_hdr -- Volume ID Header 40 | List:vtbl_recs -- (Optional) List of Volume Table Records. 41 | Bool:is_vtbl -- If contains volume records table. 42 | Bool:is_internal_vol -- If Vol ID is > UBI_INTERNAL_VOL_START 43 | Bool:is_valid -- If ec_hdr & vid_hdr are error free. 44 | Int:peb_num -- Physical Erase Block number. 45 | Int:leb_num -- Logical Erase Block number. 46 | Int:file_offset -- Address location in file of this block. 47 | Int:size -- Size of total block data or PEB size. 48 | Will print out all information when invoked as a string. 49 | """ 50 | 51 | def __init__(self, block_buf): 52 | 53 | self.file_offset = -1 54 | self.peb_num = -1 55 | self.leb_num = -1 56 | self.size = -1 57 | 58 | self.vid_hdr = None 59 | self.is_internal_vol = False 60 | self.vtbl_recs = [] 61 | 62 | # TODO better understanding of block types/errors 63 | self.ec_hdr = extract_ec_hdr(block_buf[0:UBI_EC_HDR_SZ]) 64 | 65 | if not self.ec_hdr.errors: 66 | self.vid_hdr = extract_vid_hdr(block_buf[self.ec_hdr.vid_hdr_offset:self.ec_hdr.vid_hdr_offset + UBI_VID_HDR_SZ]) 67 | 68 | self.is_internal_vol = self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START 69 | 70 | if self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START: 71 | self.vtbl_recs = extract_vtbl_rec(block_buf[self.ec_hdr.data_offset:]) 72 | 73 | self.leb_num = self.vid_hdr.lnum 74 | 75 | self.is_vtbl = bool(self.vtbl_recs) or False 76 | self.is_valid = not self.ec_hdr.errors and not self.vid_hdr.errors 77 | 78 | def __repr__(self): 79 | return 'Block: PEB# %s: LEB# %s' % (self.peb_num, self.leb_num) 80 | 81 | def display(self, tab=''): 82 | display.block(self, tab) 83 | 84 | 85 | def get_blocks_in_list(blocks, idx_list): 86 | """Retrieve block objects in list of indexes 87 | 88 | Arguments: 89 | List:blocks -- List of block objects 90 | List:idx_list -- List of block indexes 91 | 92 | Returns: 93 | Dict:blocks -- List of block objects generated 94 | from provided list of indexes in 95 | order of idx_list. 96 | """ 97 | return {i: blocks[i] for i in idx_list} 98 | 99 | 100 | def extract_blocks(ubi): 101 | """Get a list of UBI block objects from file 102 | 103 | Arguments:. 104 | Obj:ubi -- UBI object. 105 | 106 | Returns: 107 | Dict -- Of block objects keyed by PEB number. 108 | """ 109 | blocks = {} 110 | start_peb = 0 111 | ubi.file.seek(ubi.file.start_offset) 112 | peb_count = 0 113 | cur_offset = 0 114 | 115 | for i in range(ubi.file.start_offset, ubi.file.end_offset, ubi.file.block_size): 116 | buf = ubi.file.read(ubi.file.block_size) 117 | 118 | if buf.startswith(UBI_EC_HDR_MAGIC): 119 | blk = description(buf) 120 | blk.file_offset = i 121 | blk.peb_num = ubi.first_peb_num + peb_count 122 | blk.size = ubi.file.block_size 123 | blocks[blk.peb_num] = blk 124 | peb_count += 1 125 | else: 126 | cur_offset += ubi.file.block_size 127 | ubi.first_peb_num = cur_offset / ubi.file.block_size 128 | ubi.file.start_offset = cur_offset 129 | 130 | return blocks 131 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /src/ubi_reader/ubi/block/sort.py: -------------------------------------------------------------------------------- 1 | import six 2 | 3 | 4 | #!/usr/bin/env python 5 | ############################################################# 6 | # ubi_reader/ubi 7 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com) 8 | # 9 | # This program is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation, either version 3 of the License, or 12 | # (at your option) any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | ############################################################# 22 | 23 | def list_by_list(blist, slist): 24 | """Sort list of block indexes, by another list. 25 | 26 | Argument: 27 | List:blist -- List of block indexes. 28 | List:slist -- Secondary list of blocks. 29 | 30 | Returns: 31 | List -- List of block indexes matching slist from blist. 32 | """ 33 | slist_blocks = [] 34 | for block in blist: 35 | if block in slist: 36 | slist_blocks.append(block) 37 | 38 | return slist_blocks 39 | 40 | 41 | def by_image_seq(blocks, image_seq): 42 | """Sort blocks by provided image_seq number. 43 | 44 | Argument: 45 | List:blocks -- List of block objects to sort. 46 | Int:image_seq -- image_seq number found in ec_hdr. 47 | 48 | Returns: 49 | List -- List of block indexes matching image_seq number. 50 | """ 51 | seq_blocks = [] 52 | for block in blocks: 53 | if blocks[block].ec_hdr.image_seq == image_seq: 54 | seq_blocks.append(block) 55 | 56 | return seq_blocks 57 | 58 | 59 | def by_range(blocks, block_range): 60 | """Sort blocks by Logical Erase Block number. 61 | 62 | Arguments: 63 | List:blocks -- List of block objects to sort. 64 | List:block_range -- range[0] = start number, range[1] = length 65 | 66 | Returns: 67 | List -- Indexes of blocks sorted by LEB. 68 | """ 69 | peb_range = range(block_range[0], block_range[1]) 70 | return [i for i in blocks if i in peb_range] 71 | 72 | 73 | def by_leb(blocks): 74 | """Sort blocks by Logical Erase Block number. 75 | 76 | Arguments: 77 | List:blocks -- List of block objects to sort. 78 | 79 | Returns: 80 | List -- Indexes of blocks sorted by LEB. 81 | """ 82 | slist_len = len(blocks) 83 | slist = ['x'] * slist_len 84 | 85 | for block in blocks: 86 | if blocks[block].leb_num >= slist_len: 87 | add_elements = blocks[block].leb_num - slist_len + 1 88 | slist += (['x'] * add_elements) 89 | slist_len = len(slist) 90 | 91 | slist[blocks[block].leb_num] = block 92 | return slist 93 | return sorted(six.iterkeys(blocks), key=lambda x: blocks[x].leb_num) 94 | 95 | 96 | def by_vol_id(blocks, slist=None): 97 | """Sort blocks by volume id 98 | 99 | Arguments: 100 | Obj:blocks -- List of block objects. 101 | List:slist -- (optional) List of block indexes. 102 | 103 | Return: 104 | Dict -- blocks grouped in lists with dict key as volume id. 105 | """ 106 | 107 | vol_blocks = {} 108 | 109 | # sort block by volume 110 | # not reliable with multiple partitions (fifo) 111 | 112 | for i in blocks: 113 | if slist and i not in slist: 114 | continue 115 | elif not blocks[i].is_valid: 116 | continue 117 | 118 | if blocks[i].vid_hdr.vol_id not in vol_blocks: 119 | vol_blocks[blocks[i].vid_hdr.vol_id] = [] 120 | 121 | vol_blocks[blocks[i].vid_hdr.vol_id].append(blocks[i].peb_num) 122 | 123 | return vol_blocks 124 | 125 | 126 | def clean_bad(blocks, slist=None): 127 | """Remove blocks from list with errors 128 | 129 | Arguments: 130 | Obj:blocks -- List of block objects. 131 | List:slist -- (optional) List of block indexes. 132 | 133 | Return: 134 | List -- Of error free block objects. 135 | """ 136 | 137 | clean_blocks = [] 138 | 139 | for i in range(0, len(blocks)): 140 | if slist and i not in slist: 141 | continue 142 | 143 | if blocks[i].is_valid: 144 | clean_blocks.append(i) 145 | 146 | return clean_blocks 147 | 148 | 149 | def by_type(blocks, slist=None): 150 | """Sort blocks into layout, internal volume, data or unknown 151 | 152 | Arguments: 153 | Obj:blocks -- List of block objects. 154 | List:slist -- (optional) List of block indexes. 155 | 156 | Returns: 157 | List:layout -- List of block indexes of blocks containing the 158 | volume table records. 159 | List:data -- List of block indexes containing filesystem data. 160 | List:int_vol -- List of block indexes containing volume ids 161 | greater than UBI_INTERNAL_VOL_START that are not 162 | layout volumes. 163 | List:unknown -- List of block indexes of blocks that failed validation 164 | of crc in ed_hdr or vid_hdr. 165 | """ 166 | 167 | layout = [] 168 | data = [] 169 | int_vol = [] 170 | unknown = [] 171 | 172 | for i in blocks: 173 | if slist and i not in slist: 174 | continue 175 | 176 | if blocks[i].is_vtbl and blocks[i].is_valid: 177 | layout.append(i) 178 | 179 | elif blocks[i].is_internal_vol and blocks[i].is_valid: 180 | int_vol.append(i) 181 | 182 | elif blocks[i].is_valid: 183 | data.append(i) 184 | 185 | else: 186 | unknown.append(i) 187 | 188 | return layout, data, int_vol, unknown 189 | -------------------------------------------------------------------------------- /src/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 117 | -------------------------------------------------------------------------------- /src/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 __future__ import print_function 21 | from ubi.defines import PRINT_COMPAT_LIST, PRINT_VOL_TYPE_LIST, UBI_VTBL_AUTORESIZE_FLG 22 | 23 | 24 | def ubi(ubi, tab=''): 25 | print('%sUBI File' % (tab)) 26 | print('%s---------------------' % (tab)) 27 | print('\t%sMin I/O: %s' % (tab, ubi.min_io_size)) 28 | print('\t%sLEB Size: %s' % (tab, ubi.leb_size)) 29 | print('\t%sPEB Size: %s' % (tab, ubi.peb_size)) 30 | print('\t%sTotal Block Count: %s' % (tab, ubi.block_count)) 31 | print('\t%sData Block Count: %s' % (tab, len(ubi.data_blocks_list))) 32 | print('\t%sLayout Block Count: %s' % (tab, len(ubi.layout_blocks_list))) 33 | print('\t%sInternal Volume Block Count: %s' % (tab, len(ubi.int_vol_blocks_list))) 34 | print('\t%sUnknown Block Count: %s' % (tab, len(ubi.unknown_blocks_list))) 35 | print('\t%sFirst UBI PEB Number: %s' % (tab, ubi.first_peb_num)) 36 | 37 | 38 | def image(image, tab=''): 39 | print('%s%s' % (tab, image)) 40 | print('%s---------------------' % (tab)) 41 | print('\t%sImage Sequence Num: %s' % (tab, image.image_seq)) 42 | for volume in image.volumes: 43 | print('\t%sVolume Name:%s' % (tab, volume)) 44 | print('\t%sPEB Range: %s - %s' % (tab, image.peb_range[0], image.peb_range[1])) 45 | 46 | 47 | def volume(volume, tab=''): 48 | print('%s%s' % (tab, volume)) 49 | print('%s---------------------' % (tab)) 50 | print('\t%sVol ID: %s' % (tab, volume.vol_id)) 51 | print('\t%sName: %s' % (tab, volume.name)) 52 | print('\t%sBlock Count: %s' % (tab, volume.block_count)) 53 | 54 | print('\n') 55 | print('\t%sVolume Record' % (tab)) 56 | print('\t%s---------------------' % (tab)) 57 | vol_rec(volume.vol_rec, '\t\t%s' % tab) 58 | 59 | print('\n') 60 | 61 | 62 | def block(block, tab='\t'): 63 | print('%s%s' % (tab, block)) 64 | print('%s---------------------' % (tab)) 65 | print('\t%sFile Offset: %s' % (tab, block.file_offset)) 66 | print('\t%sPEB #: %s' % (tab, block.peb_num)) 67 | print('\t%sLEB #: %s' % (tab, block.leb_num)) 68 | print('\t%sBlock Size: %s' % (tab, block.size)) 69 | print('\t%sInternal Volume: %s' % (tab, block.is_internal_vol)) 70 | print('\t%sIs Volume Table: %s' % (tab, block.is_vtbl)) 71 | print('\t%sIs Valid: %s' % (tab, block.is_valid)) 72 | 73 | if not block.ec_hdr.errors: 74 | print('\n') 75 | print('\t%sErase Count Header' % (tab)) 76 | print('\t%s---------------------' % (tab)) 77 | ec_hdr(block.ec_hdr, '\t\t%s' % tab) 78 | 79 | if block.vid_hdr and not block.vid_hdr.errors: 80 | print('\n') 81 | print('\t%sVID Header Header' % (tab)) 82 | print('\t%s---------------------' % (tab)) 83 | vid_hdr(block.vid_hdr, '\t\t%s' % tab) 84 | 85 | if block.vtbl_recs: 86 | print('\n') 87 | print('\t%sVolume Records' % (tab)) 88 | print('\t%s---------------------' % (tab)) 89 | for vol in block.vtbl_recs: 90 | vol_rec(vol, '\t\t%s' % tab) 91 | 92 | print('\n') 93 | 94 | 95 | def ec_hdr(ec_hdr, tab=''): 96 | for key, value in ec_hdr: 97 | if key == 'errors': 98 | value = ','.join(value) 99 | 100 | print('%s%s: %r' % (tab, key, value)) 101 | 102 | 103 | def vid_hdr(vid_hdr, tab=''): 104 | for key, value in vid_hdr: 105 | if key == 'errors': 106 | value = ','.join(value) 107 | 108 | elif key == 'compat': 109 | if value in PRINT_COMPAT_LIST: 110 | value = PRINT_COMPAT_LIST[value] 111 | else: 112 | value = -1 113 | 114 | elif key == 'vol_type': 115 | if value < len(PRINT_VOL_TYPE_LIST): 116 | value = PRINT_VOL_TYPE_LIST[value] 117 | else: 118 | value = -1 119 | 120 | print('%s%s: %s' % (tab, key, value)) 121 | 122 | 123 | def vol_rec(vol_rec, tab=''): 124 | for key, value in vol_rec: 125 | if key == 'errors': 126 | value = ','.join(value) 127 | elif key == 'vol_type': 128 | if value < len(PRINT_VOL_TYPE_LIST): 129 | value = PRINT_VOL_TYPE_LIST[value] 130 | else: 131 | value = -1 132 | elif key == 'flags' and value == UBI_VTBL_AUTORESIZE_FLG: 133 | value = 'autoresize' 134 | elif key == 'name': 135 | value = value.strip('\x00') 136 | 137 | print('%s%s: %s' % (tab, key, value)) 138 | -------------------------------------------------------------------------------- /src/ubi_reader/ubi/headers/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/ubi_reader/ubi/headers 2 | 3 | install_PYTHON = \ 4 | __init__.py errors.py -------------------------------------------------------------------------------- /src/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 | 25 | class ec_hdr(object): 26 | def __init__(self, buf): 27 | fields = dict(zip(EC_HDR_FIELDS, struct.unpack(EC_HDR_FORMAT, buf))) 28 | for key in fields: 29 | setattr(self, key, fields[key]) 30 | setattr(self, 'errors', []) 31 | 32 | def __repr__(self): 33 | return 'Error Count Header' 34 | 35 | def __iter__(self): 36 | for key in dir(self): 37 | if not key.startswith('_'): 38 | yield key, getattr(self, key) 39 | 40 | 41 | class vid_hdr(object): 42 | def __init__(self, buf): 43 | fields = dict(zip(VID_HDR_FIELDS, struct.unpack(VID_HDR_FORMAT, buf))) 44 | for key in fields: 45 | setattr(self, key, fields[key]) 46 | setattr(self, 'errors', []) 47 | 48 | def __iter__(self): 49 | for key in dir(self): 50 | if not key.startswith('_'): 51 | yield key, getattr(self, key) 52 | 53 | def __repr__(self): 54 | return 'VID Header' 55 | 56 | 57 | class vtbl_rec(object): 58 | def __init__(self, buf): 59 | fields = dict(zip(VTBL_REC_FIELDS, struct.unpack(VTBL_REC_FORMAT, buf))) 60 | for key in fields: 61 | setattr(self, key, fields[key]) 62 | setattr(self, 'errors', []) 63 | setattr(self, 'rec_index', -1) 64 | 65 | def __repr__(self): 66 | return 'Volume Table Record: %s' % getattr(self, 'name') 67 | 68 | def __iter__(self): 69 | for key in dir(self): 70 | if not key.startswith('_'): 71 | yield key, getattr(self, key) 72 | 73 | 74 | def extract_ec_hdr(buf): 75 | ec_hdr_buf = buf 76 | ec_hdr_ret = ec_hdr(ec_hdr_buf) 77 | 78 | errors.ec_hdr(ec_hdr_ret, ec_hdr_buf) 79 | return ec_hdr_ret 80 | 81 | 82 | def extract_vid_hdr(buf): 83 | vid_hdr_buf = buf 84 | vid_hdr_ret = vid_hdr(vid_hdr_buf) 85 | 86 | errors.vid_hdr(vid_hdr_ret, vid_hdr_buf) 87 | 88 | return vid_hdr_ret 89 | 90 | 91 | def extract_vtbl_rec(buf): 92 | data_buf = buf 93 | vtbl_recs = [] 94 | vtbl_rec_ret = '' 95 | 96 | for i in range(0, UBI_MAX_VOLUMES): 97 | offset = i * UBI_VTBL_REC_SZ 98 | vtbl_rec_buf = data_buf[offset:offset + UBI_VTBL_REC_SZ] 99 | 100 | if len(vtbl_rec_buf) == UBI_VTBL_REC_SZ: 101 | vtbl_rec_ret = vtbl_rec(vtbl_rec_buf) 102 | errors.vtbl_rec(vtbl_rec_ret, vtbl_rec_buf) 103 | 104 | if len(vtbl_rec_ret.errors) == 0: 105 | vtbl_rec_ret.rec_index = i 106 | vtbl_recs.append(vtbl_rec_ret) 107 | 108 | return vtbl_recs 109 | -------------------------------------------------------------------------------- /src/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 | 23 | def ec_hdr(ec_hdr, buf): 24 | if ec_hdr.hdr_crc != (~crc32(buf[:-4]) & 0xFFFFFFFF): 25 | ec_hdr.errors.append('crc') 26 | 27 | return ec_hdr 28 | 29 | 30 | def vid_hdr(vid_hdr, buf): 31 | vid_hdr.errors = [] 32 | 33 | if vid_hdr.hdr_crc != (~crc32(buf[:-4]) & 0xFFFFFFFF): 34 | vid_hdr.errors.append('crc') 35 | 36 | return vid_hdr 37 | 38 | 39 | def vtbl_rec(vtbl_rec, buf): 40 | likely_vtbl = True 41 | 42 | if vtbl_rec.name_len != len(vtbl_rec.name.strip('\x00')): 43 | likely_vtbl = False 44 | 45 | elif vtbl_rec.vol_type not in [1, 2]: 46 | likely_vtbl = False 47 | 48 | if vtbl_rec.crc != (~crc32(buf[:-4]) & 0xFFFFFFFF): 49 | vtbl_rec.errors.append('crc') 50 | 51 | if not likely_vtbl: 52 | vtbl_rec.errors = ['False'] 53 | 54 | return vtbl_rec 55 | -------------------------------------------------------------------------------- /src/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 | 24 | class description(object): 25 | def __init__(self, blocks, layout_info): 26 | self._image_seq = blocks[layout_info[0]].ec_hdr.image_seq 27 | self.vid_hdr_offset = blocks[layout_info[0]].ec_hdr.vid_hdr_offset 28 | self.version = blocks[layout_info[0]].ec_hdr.version 29 | self._start_peb = min(layout_info[2]) 30 | self._end_peb = max(layout_info[2]) 31 | self._volumes = get_volumes(blocks, layout_info) 32 | 33 | def __repr__(self): 34 | return 'Image: %s' % (self.image_seq) 35 | 36 | def get_blocks(self, blocks): 37 | return get_blocks_in_list(blocks, range(self._start_peb, self._end_peb + 1)) 38 | 39 | def _get_peb_range(self): 40 | return [self._start_peb, self._end_peb] 41 | peb_range = property(_get_peb_range) 42 | 43 | def _get_image_seq(self): 44 | return self._image_seq 45 | image_seq = property(_get_image_seq) 46 | 47 | def _get_volumes(self): 48 | return self._volumes 49 | volumes = property(_get_volumes) 50 | 51 | def display(self, tab=''): 52 | display.image(self, tab) 53 | -------------------------------------------------------------------------------- /src/ubi_reader/ubi/volume/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/ubi_reader/ubi/volume 2 | 3 | install_PYTHON = \ 4 | __init__.py -------------------------------------------------------------------------------- /src/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 | 24 | class description(object): 25 | """UBI Volume object 26 | 27 | Attributes: 28 | Int:vol_id -- Volume ID 29 | Str:vol_name -- Name of volume. 30 | Obj:vol_rec -- Volume record object 31 | Int:block_count -- Number of block associated with volume. 32 | 33 | Methods: 34 | display(tab) -- Print Volume information 35 | Str:tab -- (optional) '\t' to preface lines with. 36 | 37 | get_blocks(blocks) -- Returns list of block objects tied to this volume 38 | 39 | Volume object is basically a list of block indexes and some metadata 40 | describing a volume found in a UBI image. 41 | """ 42 | 43 | def __init__(self, vol_id, vol_rec, block_list): 44 | self._vol_id = vol_id 45 | self._vol_rec = vol_rec 46 | self._name = self._vol_rec.name 47 | self._block_list = block_list 48 | 49 | def __repr__(self): 50 | return 'Volume: %s' % (self.name) 51 | 52 | def _get_name(self): 53 | return self._name 54 | name = property(_get_name) 55 | 56 | def _get_vol_id(self): 57 | return self._vol_id 58 | vol_id = property(_get_vol_id) 59 | 60 | def _get_block_count(self): 61 | return len(self._block_list) 62 | block_count = property(_get_block_count) 63 | 64 | def _get_vol_rec(self): 65 | return self._vol_rec 66 | vol_rec = property(_get_vol_rec) 67 | 68 | def _get_block_list(self): 69 | return self._block_list 70 | block_list = property(_get_block_list) 71 | 72 | def get_blocks(self, blocks): 73 | return get_blocks_in_list(blocks, self._block_list) 74 | 75 | def display(self, tab=''): 76 | display.volume(self, tab) 77 | 78 | def reader(self, ubi): 79 | last_leb = 0 80 | for block in sort.by_leb(self.get_blocks(ubi.blocks)): 81 | if block == 'x': 82 | #while 0 != (ubi.blocks[block].leb_num - last_leb): 83 | last_leb += 1 84 | yield '\xff' * ubi.leb_size 85 | else: 86 | last_leb += 1 87 | yield ubi.file.read_block_data(ubi.blocks[block]) 88 | 89 | 90 | def get_volumes(blocks, layout_info): 91 | """Get a list of UBI volume objects from list of blocks 92 | 93 | Arguments: 94 | List:blocks -- List of layout block objects 95 | List:layout_info -- Layout info (indexes of layout blocks and 96 | associated data blocks.) 97 | 98 | Returns: 99 | Dict -- Of Volume objects by volume name, including any 100 | relevant blocks. 101 | """ 102 | volumes = {} 103 | 104 | vol_blocks_lists = sort.by_vol_id(blocks, layout_info[2]) 105 | 106 | for vol_rec in blocks[layout_info[0]].vtbl_recs: 107 | vol_name = vol_rec.name.strip('\x00') 108 | if vol_rec.rec_index not in vol_blocks_lists: 109 | vol_blocks_lists[vol_rec.rec_index] = [] 110 | volumes[vol_name] = description(vol_rec.rec_index, vol_rec, vol_blocks_lists[vol_rec.rec_index]) 111 | 112 | return volumes 113 | -------------------------------------------------------------------------------- /src/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 | from __future__ import print_function 20 | import os 21 | import sys 22 | import argparse 23 | 24 | from ubi import ubi, get_peb_size 25 | from ubifs import ubifs 26 | from ubi_io import ubi_file, leb_virtual_file 27 | from ui.common import extract_files, output_dir 28 | 29 | if __name__ == '__main__': 30 | description = 'Extract contents of UBI image.' 31 | usage = 'ubi_extract_files.py [options] filepath' 32 | parser = argparse.ArgumentParser(usage=usage, description=description) 33 | 34 | parser.add_argument('-l', '--log-file', dest='logpath', 35 | help='Log output to file output/LOGPATH. (default: ubifs_output.log)') 36 | 37 | parser.add_argument('-k', '--keep-permissions', action='store_true', dest='permissions', 38 | help='Maintain file permissions, requires running as root. (default: False)') 39 | 40 | parser.add_argument('-q', '--quiet', action='store_true', dest='quiet', 41 | help='Suppress warnings and non-fatal errors. (default: False)') 42 | 43 | parser.add_argument('-p', '--peb-size', type=int, dest='block_size', 44 | help='Specify PEB size.') 45 | 46 | parser.add_argument('-o', '--output-dir', dest='output_path', 47 | help='Specify output directory path.') 48 | 49 | parser.add_argument('filepath', help='File to extract contents of.') 50 | 51 | if len(sys.argv) == 1: 52 | parser.print_help() 53 | sys.exit() 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_peb_size(path) 80 | 81 | perms = args.permissions 82 | quiet = args.quiet 83 | 84 | if not os.path.exists(output_path): 85 | os.makedirs(output_path) 86 | 87 | # Create file object. 88 | ufile = ubi_file(path, block_size) 89 | # Create UBI object 90 | uubi = ubi(ufile) 91 | 92 | # Traverse items found extracting files. 93 | for image in uubi.images: 94 | for volume in image.volumes: 95 | vol_out_path = os.path.join(output_path, volume) 96 | 97 | if not os.path.exists(vol_out_path): 98 | os.makedirs(vol_out_path) 99 | elif os.listdir(vol_out_path): 100 | parser.error('Volume output directory is not empty. %s' % vol_out_path) 101 | 102 | # Create file object backed by UBI blocks. 103 | ufsfile = leb_virtual_file(uubi, image.volumes[volume]) 104 | # Create UBIFS object 105 | uubifs = ubifs(ufsfile) 106 | # Set up logging. 107 | uubifs.log.log_file = log_file 108 | uubifs.log.log_to_file = log_to_file 109 | uubifs.log.quiet = quiet 110 | # Run extract all files. 111 | print('Writing to: %s' % vol_out_path) 112 | extract_files(uubifs, vol_out_path, perms) 113 | 114 | sys.exit(0) 115 | -------------------------------------------------------------------------------- /src/ubi_reader/ubi_io/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/ubi_reader/ubi_io 2 | 3 | install_PYTHON = \ 4 | __init__.py -------------------------------------------------------------------------------- /src/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 | 23 | class ubi_file(object): 24 | """UBI image file object 25 | 26 | Arguments: 27 | Str:path -- Path to file to parse 28 | Int:block_size -- Erase block size of NAND in bytes. 29 | Int:start_offset -- (optional) Where to start looking in the file for 30 | UBI data. 31 | Int:end_offset -- (optional) Where to stop looking in the file. 32 | 33 | Methods: 34 | seek -- Put file head to specified byte offset. 35 | Int:offset 36 | read -- Read specified bytes from file handle. 37 | Int:size 38 | tell -- Returns byte offset of current file location. 39 | read_block -- Returns complete PEB data of provided block 40 | description. 41 | Obj:block 42 | read_block_data -- Returns LEB data only from provided block. 43 | Obj:block 44 | reader -- Generator that returns data from file. 45 | reset -- Reset file position to start_offset 46 | 47 | Handles all the actual file interactions, read, seek, 48 | extract blocks, etc. 49 | """ 50 | 51 | def __init__(self, path, block_size, start_offset=0, end_offset=None): 52 | self._fhandle = open(path, 'rb') 53 | self._start_offset = start_offset 54 | 55 | if end_offset: 56 | self._end_offset = end_offset 57 | else: 58 | self._fhandle.seek(0, 2) 59 | self._end_offset = self.tell() 60 | 61 | self._block_size = block_size 62 | 63 | if start_offset >= self._end_offset: 64 | raise Exception('Start offset larger than file size!') 65 | 66 | self._fhandle.seek(self._start_offset) 67 | 68 | def _set_start(self, i): 69 | self._start_offset = i 70 | 71 | def _get_start(self): 72 | return self._start_offset 73 | start_offset = property(_get_start, _set_start) 74 | 75 | def _get_end(self): 76 | return self._end_offset 77 | end_offset = property(_get_end) 78 | 79 | def _get_block_size(self): 80 | return self._block_size 81 | block_size = property(_get_block_size) 82 | 83 | def seek(self, offset): 84 | self._fhandle.seek(offset) 85 | 86 | def read(self, size): 87 | return self._fhandle.read(size) 88 | 89 | def tell(self): 90 | return self._fhandle.tell() 91 | 92 | def reset(self): 93 | self._fhandle.seek(self.start_offset) 94 | 95 | def reader(self): 96 | self.reset() 97 | while True: 98 | cur_loc = self._fhandle.tell() 99 | if self.end_offset and cur_loc > self.end_offset: 100 | break 101 | elif self.end_offset and self.end_offset - cur_loc < self.block_size: 102 | chunk_size = self.end_offset - cur_loc 103 | else: 104 | chunk_size = self.block_size 105 | 106 | buf = self.read(chunk_size) 107 | 108 | if not buf: 109 | break 110 | yield buf 111 | 112 | def read_block(self, block): 113 | """Read complete PEB data from file. 114 | 115 | Argument: 116 | Obj:block -- Block data is desired for. 117 | """ 118 | self.seek(block.file_offset) 119 | return self._fhandle.read(block.size) 120 | 121 | def read_block_data(self, block): 122 | """Read LEB data from file 123 | 124 | Argument: 125 | Obj:block -- Block data is desired for. 126 | """ 127 | self.seek(block.file_offset + block.ec_hdr.data_offset) 128 | buf = self._fhandle.read(block.size - block.ec_hdr.data_offset - block.vid_hdr.data_pad) 129 | return buf 130 | 131 | 132 | class leb_virtual_file(): 133 | def __init__(self, ubi, volume): 134 | self._ubi = ubi 135 | self._volume = volume 136 | self._blocks = sort.by_leb(self._volume.get_blocks(self._ubi.blocks)) 137 | self._seek = 0 138 | self.leb_data_size = len(self._blocks) * self._ubi.leb_size 139 | self._last_leb = -1 140 | self._last_buf = '' 141 | 142 | def read(self, i): 143 | buf = '' 144 | leb = int(self.tell() / self._ubi.leb_size) 145 | offset = self.tell() % self._ubi.leb_size 146 | 147 | if leb == self._last_leb: 148 | self.seek(self.tell() + i) 149 | return self._last_buf[offset:offset + i] 150 | else: 151 | buf = self._ubi.file.read_block_data(self._ubi.blocks[self._blocks[leb]]) 152 | self._last_buf = buf 153 | self._last_leb = leb 154 | self.seek(self.tell() + i) 155 | return buf[offset:offset + i] 156 | 157 | def reset(self): 158 | self.seek(0) 159 | 160 | def seek(self, offset): 161 | self._seek = offset 162 | 163 | def tell(self): 164 | return self._seek 165 | 166 | def reader(self): 167 | last_leb = 0 168 | for block in self._blocks: 169 | while 0 != (self._ubi.blocks[block].leb_num - last_leb): 170 | last_leb += 1 171 | yield '\xff' * self._ubi.leb_size 172 | 173 | last_leb += 1 174 | yield self._ubi.file.read_block_data(self._ubi.blocks[block]) 175 | -------------------------------------------------------------------------------- /src/ubi_reader/ubifs/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/ubi_reader/ubifs 2 | 3 | SUBDIRS = nodes 4 | 5 | install_PYTHON = \ 6 | __init__.py defines.py log.py misc.py output.py walk.py 7 | 8 | if MIPSEL 9 | install_DATA = \ 10 | lzo.so 11 | endif -------------------------------------------------------------------------------- /src/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 | 28 | class ubifs(): 29 | """UBIFS object 30 | 31 | Arguments: 32 | Str:path -- File path to UBIFS image. 33 | 34 | Attributes: 35 | Int:leb_size -- Size of Logical Erase Blocks. 36 | Int:min_io -- Size of min I/O from vid_hdr_offset. 37 | Obj:sb_node -- Superblock node of UBIFS image LEB0 38 | Obj:mst_node -- Master Node of UBIFS image LEB1 39 | Obj:log -- Log object for errors. 40 | 41 | Methods: 42 | key_search -- Search nodes for matching key. 43 | Str:key -- Hex string representation of key. 44 | """ 45 | 46 | def __init__(self, ubifs_file): 47 | self.log = log() 48 | self._file = ubifs_file 49 | self._sb_node = extract.sb_node(self, UBIFS_COMMON_HDR_SZ) 50 | self._min_io_size = self._sb_node.min_io_size 51 | self._leb_size = self._sb_node.leb_size 52 | self._mst_node = extract.mst_node(self, 1, UBIFS_COMMON_HDR_SZ) 53 | self._mst_node = extract.mst_node(self, 2, UBIFS_COMMON_HDR_SZ) 54 | 55 | def _get_file(self): 56 | return self._file 57 | file = property(_get_file) 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 | def _get_master_node(self): 69 | """Master Node Object 70 | 71 | Returns: 72 | Obj:Master Node 73 | """ 74 | return self._mst_node 75 | master_node = property(_get_master_node) 76 | 77 | def _get_master_node2(self): 78 | """Master Node Object 2 79 | 80 | Returns: 81 | Obj:Master Node 82 | """ 83 | return self._mst_node 84 | master_node2 = property(_get_master_node2) 85 | 86 | def _get_leb_size(self): 87 | """LEB size of UBI blocks in file. 88 | 89 | Returns: 90 | Int -- LEB Size. 91 | """ 92 | return self._leb_size 93 | leb_size = property(_get_leb_size) 94 | 95 | def _get_min_io_size(self): 96 | """Min I/O Size 97 | 98 | Returns: 99 | Int -- Min I/O Size. 100 | """ 101 | return self._min_io_size 102 | min_io_size = property(_get_min_io_size) 103 | 104 | 105 | def get_leb_size(path): 106 | """Get LEB size from superblock 107 | 108 | Arguments: 109 | Str:path -- Path to file. 110 | 111 | Returns: 112 | Int -- LEB size. 113 | 114 | Searches file superblock and retrieves leb size. 115 | """ 116 | 117 | f = open(path, 'rb') 118 | f.seek(0, 2) 119 | file_size = f.tell() + 1 120 | f.seek(0) 121 | block_size = 0 122 | 123 | for i in range(0, file_size, FILE_CHUNK_SZ): 124 | buf = f.read(FILE_CHUNK_SZ) 125 | 126 | for m in re.finditer(UBIFS_NODE_MAGIC, buf): 127 | start = m.start() 128 | chdr = nodes.common_hdr(buf[start:start + UBIFS_COMMON_HDR_SZ]) 129 | 130 | if chdr and chdr.node_type == UBIFS_SB_NODE: 131 | sb_start = start + UBIFS_COMMON_HDR_SZ 132 | sb_end = sb_start + UBIFS_SB_NODE_SZ 133 | 134 | if chdr.len != len(buf[sb_start:sb_end]): 135 | f.seek(sb_start) 136 | buf = f.read(UBIFS_SB_NODE_SZ) 137 | else: 138 | buf = buf[sb_start:sb_end] 139 | 140 | sbn = nodes.sb_node(buf) 141 | block_size = sbn.leb_size 142 | f.close() 143 | return block_size 144 | 145 | f.close() 146 | return block_size 147 | -------------------------------------------------------------------------------- /src/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 | from __future__ import print_function 21 | import os 22 | import sys 23 | 24 | import ui 25 | 26 | 27 | class log(): 28 | def __init__(self): 29 | self.log_to_file = False 30 | self.log_file = 'ubifs_output.log' 31 | self.exit_on_except = False 32 | self.quiet = False 33 | 34 | def _out(self, s): 35 | if not self.quiet: 36 | if self.log_to_file: 37 | with open(os.path.join(ui.common.output_dir, self.log_file), 'a') as f: 38 | f.write('%s\n' % s) 39 | f.close() 40 | else: 41 | print('%s' % s) 42 | 43 | if self.exit_on_except: 44 | sys.exit() 45 | 46 | def write(self, s): 47 | self._out(s) 48 | 49 | def write_node(self, n): 50 | buf = '%s\n' % n 51 | for key, value in n: 52 | buf += '\t%s: %s\n' % (key, value) 53 | self._out(buf) 54 | -------------------------------------------------------------------------------- /src/ubi_reader/ubifs/lzo.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oe-alliance/openmultibootmanager/e4d532e693d98d7c82e922973be18ab93cc8e681/src/ubi_reader/ubifs/lzo.so -------------------------------------------------------------------------------- /src/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 | from __future__ import absolute_import 20 | #!/usr/bin/env python 21 | ############################################################# 22 | # ubi_reader/ubifs 23 | # (c) 2013 Jason Pruitt (jrspruitt@gmail.com) 24 | # 25 | # This program is free software: you can redistribute it and/or modify 26 | # it under the terms of the GNU General Public License as published by 27 | # the Free Software Foundation, either version 3 of the License, or 28 | # (at your option) any later version. 29 | # 30 | # This program is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | 35 | # You should have received a copy of the GNU General Public License 36 | # along with this program. If not, see . 37 | ############################################################# 38 | from . import lzo 39 | import struct 40 | import zlib 41 | from ubifs.defines import * 42 | 43 | # For happy printing 44 | ino_types = ['file', 'dir', 'lnk', 'blk', 'chr', 'fifo', 'sock'] 45 | node_types = ['ino', 'data', 'dent', 'xent', 'trun', 'pad', 'sb', 'mst', 'ref', 'idx', 'cs', 'orph'] 46 | key_types = ['ino', 'data', 'dent', 'xent'] 47 | 48 | 49 | def parse_key(key): 50 | """Parse node key 51 | 52 | Arguments: 53 | Str:key -- Hex string literal of node key. 54 | 55 | Returns: 56 | Int:key_type -- Type of key, data, ino, dent, etc. 57 | Int:ino_num -- Inode number. 58 | Int:khash -- Key hash. 59 | """ 60 | hkey, lkey = struct.unpack('> UBIFS_S_KEY_BLOCK_BITS 63 | khash = lkey 64 | 65 | #if key_type < UBIFS_KEY_TYPES_CNT: 66 | return {'type': key_type, 'ino_num': ino_num, 'khash': khash} 67 | 68 | 69 | def decompress(ctype, unc_len, data): 70 | """Decompress data. 71 | 72 | Arguments: 73 | Int:ctype -- Compression type LZO, ZLIB (*currently unused*). 74 | Int:unc_len -- Uncompressed data lenth. 75 | Str:data -- Data to be uncompessed. 76 | 77 | Returns: 78 | Uncompressed Data. 79 | """ 80 | if ctype == UBIFS_COMPR_LZO: 81 | return lzo.decompress(''.join(('\xf0', struct.pack('>I', unc_len), data))) 82 | elif ctype == UBIFS_COMPR_ZLIB: 83 | return zlib.decompress(data, -11) 84 | else: 85 | return data 86 | -------------------------------------------------------------------------------- /src/ubi_reader/ubifs/nodes/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/ubi_reader/ubifs/nodes 2 | 3 | install_PYTHON = \ 4 | __init__.py extract.py 5 | -------------------------------------------------------------------------------- /src/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 | 25 | class common_hdr(object): 26 | def __init__(self, buf): 27 | fields = dict(zip(UBIFS_COMMON_HDR_FIELDS, struct.unpack(UBIFS_COMMON_HDR_FORMAT, buf))) 28 | for key in fields: 29 | setattr(self, key, fields[key]) 30 | setattr(self, 'errors', []) 31 | 32 | def __repr__(self): 33 | return 'UBIFS Common Header' 34 | 35 | def __iter__(self): 36 | for key in dir(self): 37 | if not key.startswith('_'): 38 | yield key, getattr(self, key) 39 | 40 | 41 | class sb_node(object): 42 | def __init__(self, buf): 43 | fields = dict(zip(UBIFS_SB_NODE_FIELDS, struct.unpack(UBIFS_SB_NODE_FORMAT, buf))) 44 | for key in fields: 45 | setattr(self, key, fields[key]) 46 | 47 | def __repr__(self): 48 | return 'UBIFS Super Block Node' 49 | 50 | def __iter__(self): 51 | for key in dir(self): 52 | if not key.startswith('_'): 53 | yield key, getattr(self, key) 54 | 55 | 56 | class mst_node(object): 57 | def __init__(self, buf): 58 | fields = dict(zip(UBIFS_MST_NODE_FIELDS, struct.unpack(UBIFS_MST_NODE_FORMAT, buf))) 59 | for key in fields: 60 | setattr(self, key, fields[key]) 61 | 62 | def __repr__(self): 63 | return 'UBIFS Master Block Node' 64 | 65 | def __iter__(self): 66 | for key in dir(self): 67 | if not key.startswith('_'): 68 | yield key, getattr(self, key) 69 | 70 | 71 | class dent_node(object): 72 | def __init__(self, buf): 73 | fields = dict(zip(UBIFS_DENT_NODE_FIELDS, struct.unpack(UBIFS_DENT_NODE_FORMAT, buf))) 74 | for key in fields: 75 | if key == 'key': 76 | setattr(self, key, parse_key(fields[key])) 77 | else: 78 | setattr(self, key, fields[key]) 79 | setattr(self, 'name', '') 80 | 81 | def __repr__(self): 82 | return 'UBIFS Directory Entry Node' 83 | 84 | def __iter__(self): 85 | for key in dir(self): 86 | if not key.startswith('_'): 87 | yield key, getattr(self, key) 88 | 89 | 90 | class data_node(object): 91 | def __init__(self, buf): 92 | fields = dict(zip(UBIFS_DATA_NODE_FIELDS, struct.unpack(UBIFS_DATA_NODE_FORMAT, buf))) 93 | for key in fields: 94 | if key == 'key': 95 | setattr(self, key, parse_key(fields[key])) 96 | else: 97 | setattr(self, key, fields[key]) 98 | setattr(self, 'offset', 0) 99 | setattr(self, 'compr_len', 0) 100 | 101 | def __repr__(self): 102 | return 'UBIFS Data Node' 103 | 104 | def __iter__(self): 105 | for key in dir(self): 106 | if not key.startswith('_'): 107 | yield key, getattr(self, key) 108 | 109 | 110 | class idx_node(object): 111 | def __init__(self, buf): 112 | fields = dict(zip(UBIFS_IDX_NODE_FIELDS, struct.unpack(UBIFS_IDX_NODE_FORMAT, buf))) 113 | for key in fields: 114 | setattr(self, key, fields[key]) 115 | setattr(self, 'branches', []) 116 | 117 | def __repr__(self): 118 | return 'UBIFS Index Node' 119 | 120 | def __iter__(self): 121 | for key in dir(self): 122 | if not key.startswith('_'): 123 | yield key, getattr(self, key) 124 | 125 | 126 | class ino_node(object): 127 | def __init__(self, buf): 128 | fields = dict(zip(UBIFS_INO_NODE_FIELDS, struct.unpack(UBIFS_INO_NODE_FORMAT, buf))) 129 | for key in fields: 130 | if key == 'key': 131 | setattr(self, key, parse_key(fields[key])) 132 | else: 133 | setattr(self, key, fields[key]) 134 | setattr(self, 'data', '') 135 | 136 | def __repr__(self): 137 | return 'UBIFS Ino Node' 138 | 139 | def __iter__(self): 140 | for key in dir(self): 141 | if not key.startswith('_'): 142 | yield key, getattr(self, key) 143 | 144 | 145 | class branch(object): 146 | def __init__(self, buf): 147 | fields = dict(zip(UBIFS_BRANCH_FIELDS, struct.unpack(UBIFS_BRANCH_FORMAT, buf))) 148 | for key in fields: 149 | setattr(self, key, fields[key]) 150 | 151 | def __repr__(self): 152 | return 'UBIFS Branch' 153 | 154 | def __iter__(self): 155 | for key in dir(self): 156 | if not key.startswith('_'): 157 | yield key, getattr(self, key) 158 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /src/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 | 27 | def dents(ubifs, inodes, dent_node, path='', perms=False): 28 | inode = inodes[dent_node.inum] 29 | dent_path = os.path.join(path, dent_node.name) 30 | 31 | if dent_node.type == UBIFS_ITYPE_DIR: 32 | try: 33 | if not os.path.exists(dent_path): 34 | os.mkdir(dent_path) 35 | if perms: 36 | set_file_perms(dent_path, inode) 37 | except Exception as e: 38 | ubifs.log.write('DIR Fail: %s' % e) 39 | 40 | if 'dent' in inode: 41 | for dnode in inode['dent']: 42 | dents(ubifs, inodes, dnode, dent_path, perms) 43 | 44 | elif dent_node.type == UBIFS_ITYPE_REG: 45 | try: 46 | if inode['ino'].nlink > 1: 47 | if 'hlink' not in inode: 48 | inode['hlink'] = dent_path 49 | buf = process_reg_file(ubifs, inode, dent_path) 50 | write_reg_file(dent_path, buf) 51 | else: 52 | os.link(inode['hlink'], dent_path) 53 | else: 54 | buf = process_reg_file(ubifs, inode, dent_path) 55 | write_reg_file(dent_path, buf) 56 | 57 | if perms: 58 | set_file_perms(dent_path, inode) 59 | 60 | except Exception as e: 61 | ubifs.log.write('FILE Fail: %s' % e) 62 | 63 | elif dent_node.type == UBIFS_ITYPE_LNK: 64 | try: 65 | # probably will need to decompress ino data if > UBIFS_MIN_COMPR_LEN 66 | os.symlink('%s' % inode['ino'].data, dent_path) 67 | except Exception as e: 68 | ubifs.log.write('SYMLINK Fail: %s : %s' % (inode['ino'].data, dent_path)) 69 | 70 | elif dent_node.type in [UBIFS_ITYPE_BLK, UBIFS_ITYPE_CHR]: 71 | try: 72 | dev = struct.unpack(' len(buf): 144 | buf += '\x00' * (inode['ino'].size - len(buf)) 145 | 146 | return buf 147 | -------------------------------------------------------------------------------- /src/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 | 24 | def index(ubifs, lnum, offset, inodes={}): 25 | """Walk the index gathering Inode, Dir Entry, and File nodes. 26 | 27 | Arguments: 28 | Obj:ubifs -- UBIFS object. 29 | Int:lnum -- Logical erase block number. 30 | Int:offset -- Offset in logical erase block. 31 | Dict:inodes -- Dict of ino/dent/file nodes keyed to inode number. 32 | 33 | Returns: 34 | Dict:inodes -- Dict of ino/dent/file nodes keyed to inode number. 35 | 'ino' -- Inode node. 36 | 'data' -- List of data nodes if present. 37 | 'dent' -- List of directory entry nodes if present. 38 | """ 39 | chdr = extract.common_hdr(ubifs, lnum, offset) 40 | 41 | if chdr.node_type == UBIFS_IDX_NODE: 42 | idxn = extract.idx_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) 43 | 44 | for branch in idxn.branches: 45 | index(ubifs, branch.lnum, branch.offs, inodes) 46 | 47 | elif chdr.node_type == UBIFS_INO_NODE: 48 | inon = extract.ino_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) 49 | ino_num = inon.key['ino_num'] 50 | 51 | if not ino_num in inodes: 52 | inodes[ino_num] = {} 53 | 54 | inodes[ino_num]['ino'] = inon 55 | 56 | elif chdr.node_type == UBIFS_DATA_NODE: 57 | datn = extract.data_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ, chdr.len) 58 | ino_num = datn.key['ino_num'] 59 | 60 | if not ino_num in inodes: 61 | inodes[ino_num] = {} 62 | 63 | if not 'data' in inodes[ino_num]: 64 | inodes[ino_num]['data'] = [] 65 | 66 | inodes[ino_num]['data'].append(datn) 67 | 68 | elif chdr.node_type == UBIFS_DENT_NODE: 69 | dn = extract.dent_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) 70 | ino_num = dn.key['ino_num'] 71 | 72 | if not ino_num in inodes: 73 | inodes[ino_num] = {} 74 | 75 | if not 'dent' in inodes[ino_num]: 76 | inodes[ino_num]['dent'] = [] 77 | 78 | inodes[ino_num]['dent'].append(dn) 79 | -------------------------------------------------------------------------------- /src/ubi_reader/ui/Makefile.am: -------------------------------------------------------------------------------- 1 | installdir = $(libdir)/enigma2/python/Plugins/Extensions/OpenMultiboot/ubi_reader/ui 2 | 3 | install_PYTHON = \ 4 | __init__.py common.py -------------------------------------------------------------------------------- /src/ubi_reader/ui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oe-alliance/openmultibootmanager/e4d532e693d98d7c82e922973be18ab93cc8e681/src/ubi_reader/ui/__init__.py -------------------------------------------------------------------------------- /src/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 as 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 135 | --------------------------------------------------------------------------------