path: root/lib
AgeCommit message (Collapse)Author
2021-05-05mtd-utils: flash_erase: Add flash erase chipLarisa Ileana Grigore
Some flash types support full erase chip command which can reduce the flash erase time. Try first to erase the entire flash and fall back to the old method if the operation fails. Signed-off-by: Larisa Ileana Grigore <> Signed-off-by: David Oberhollenzer <>
2021-01-20Remove headers from EXTRA_DISTDavid Oberhollenzer
This commit removes the C header files from the EXTRA_DIST variables and instead assigns them to the SOURCE variable of the respective components they belong to. This takes care of having them distributed in the release tar ball and helps with dependency tracking a little. Signed-off-by: David Oberhollenzer <>
2020-11-29libmtd: avoid divide by zeroChris Packham
The concept of erase blocks doesn't apply to mtd-ram devices. Such devices set MTD_NO_ERASE to indicate this and some report 0 for the erase block size. Avoid a divide by zero when calculating the erase block count for such devices. Signed-off-by: Chris Packham <> Acked-by: Richard Weinberger <> Signed-off-by: David Oberhollenzer <>
2020-02-09mtd-utils: Fix potentially unterminated stringsDavid Oberhollenzer
This commit fixes some uses of strncpy that could leave the destination buffer unterminated. Signed-off-by: David Oberhollenzer <>
2020-02-09mtd-utils: Fix "are we really at EOF" test logic in libubi read_dataDavid Oberhollenzer
The function reads file data into a buffer and then checks if we actually are at the end-of-file by trying to read one more byte. For whatever reason, the code uses an int instead of a char. It's not pretty but works. But again, this is something that every static analysis tool barks at. Further more, the error messages are inverted. "We aren't at EOF yet" is printed on failure and something like "read error %m" is printed on success. This patch fixes all of the above. Signed-off-by: David Oberhollenzer <>
2020-02-09mtd-utils: Fix some simple cases of uninitialized value readsDavid Oberhollenzer
This patch modifies the internal helpers to read and parse integers from sysfs files by initializing them first and removes turns an obscure "a = open(...) if (a >= 0) {...} if (a == -1) {...}" inside recv_image into a more straight forward if/else branch. Signed-off-by: David Oberhollenzer <>
2020-02-09mtd-utils: Fix various TOCTOU issuesDavid Oberhollenzer
This patch restructures various code parts that follow the pattern of "stat(x, &sb) ... makes_sense(&sb) ... open(x)". Signed-off-by: David Oberhollenzer <>
2019-11-10libmtd: don't leak temporary buffersDavid Oberhollenzer
Signed-off-by: David Oberhollenzer <>
2018-10-02mtd-utils: Instead of doing preprocessor magic, just output off_t as long longThorsten Glaser
Fix warnings abot PRIdoff_t in libmtd.c, in mtd_read (and mtd_write): In file included from ../git/lib/libmtd.c:40:0: ../git/lib/libmtd.c: In function 'mtd_read': ../git/include/common.h:110:18: warning: format '%ld' expects argument of type 'long int', but argument 5 has type 'off_t {aka long long int}' [-Wformat=] ../git/include/common.h:120:2: note: in expansion of macro 'errmsg' errmsg(fmt, ##__VA_ARGS__); \ ^~~~~~ ../git/lib/libmtd.c:1082:10: note: in expansion of macro 'sys_errmsg' return sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t, ^~~~~~~~~~ /usr/lib/klibc/include/inttypes.h:28:17: note: format string is defined here #define PRId32 "d" Signed-off-by: Thorsten Glaser <> Signed-off-by: David Oberhollenzer <>
2018-09-20libmtd: don't print an error message for devices without ecc supportDavid Oberhollenzer
The libmtd library tries to obtain the available OOB size via the sysfs with a fallback to the ECCGETLAYOUT ioctl. For some devices (e.g. plat-ram), the fallback path is always taken and prints an error message to stderr since the ioctl fails. This patch fixes the fallback path by suppressing the error message if errno is set to EOPNOTSUPP (i.e. the device simply doesn't support that). Fixes: a10353584f93 ("libmtd: Add support to access OOB available size") Reported-by: Chris Packham <> Reviewed-by: Xiaolei Li <> Tested-by: Chris Packham <> Signed-off-by: David Oberhollenzer <>
2018-06-28libubi: add volume flags to ubi_mkvol_requestQuentin Schulz
Now that we have per-UBI volume flags (for instance for skipping CRC check when opening it) from the Linux header, let's add it to the ubi_mkvol_request in libubi and assign the flags to ubi_mkvol_req from the Linux header from ubi_mkvol. Suggested-by: Boris Brezillon <> Reviewed-by: Boris Brezillon <> Signed-off-by: Quentin Schulz <> Signed-off-by: David Oberhollenzer <>
2018-06-09Revert "Return correct error number in ubi_get_vol_info1"David Oberhollenzer
This reverts commit dede98ffb706676309488d7cc660f569548d5930. The original commit tried to fix a descrepancy between the implementation and the documentation by making the implementation comply. When making the change, it was overlooked, that ubinfo and ubirename were written against the implementation instead of the behaviour specified by the documentation. So were further internal functions like ubi_get_vol_info1_nm which further breaks ubirmvol. A report with an outline of a resulting problem can be read on the mailing list: From the report: steps to reproduce: have mtd-utils 2.0.1 or 2.0.2 0. make a bunch of ubi volumes in sequential order ubimkvol /dev/ubi0 -s 64KiB -N test1 ubimkvol /dev/ubi0 -s 64KiB -N test2 ubimkvol /dev/ubi0 -s 64KiB -N test3 ubimkvol /dev/ubi0 -s 64KiB -N test4 .. 1. delete the test1 volume, making a hole in the volume table ubirmvol /dev/ubi0 -N test1 2. try an affected tool (i.e. "ubirmvol /dev/ubi0 -N test4" ) |root at mr24:/# ubirmvol /dev/ubi0 -N test4 |ubirmvol: error!: cannot find UBI volume "test4" | error 19 (No such device) or "ubinfo -a" | root at mr24:/# ubinfo -a | UBI version: 1 | Count of UBI devices: 1 | UBI control device major/minor: 10:59 | Present UBI devices: ubi0 | | ubi0 | Volumes count: 11 | Logical eraseblock size: 15872 bytes, 15.5 KiB | Total amount of logical eraseblocks: 1952 (30982144 bytes, 29.5 MiB) | Amount of available logical eraseblocks: 75 (1190400 bytes, 1.1 MiB) | Maximum count of volumes 92 | Count of bad physical eraseblocks: 0 | Count of reserved physical eraseblocks: 40 | Current maximum erase counter value: 984 | Minimum input/output unit size: 512 bytes | Character device major/minor: 251:0 | ubinfo: error!: libubi failed to probe volume 5 on ubi0 | error 19 (No such device) | Present volumes: 0, 1, 2, 3, 4root at mr24:/# Reported-by: Christian Lamparter <> Signed-off-by: David Oberhollenzer <>
2018-04-10libmtd_legacy: Fix some function description mismatchesXiaolei Li
Signed-off-by: Xiaolei Li <> Signed-off-by: David Oberhollenzer <>
2018-04-10libmtd: Add support to access OOB available sizeXiaolei Li
This patch exposes OOB available size to user. Then user can use OOB free area according to OOB available size. Steps to get OOB available size: First, access /sys/class/mtd/mtdX/oobavail. If not exist, then try to get ecc layout by ioctl "ECCGETLAYOUT". If none of them work, set OOB available size to 0. Signed-off-by: Xiaolei Li <> Signed-off-by: David Oberhollenzer <>
2018-01-30mtd-utils: common.c: convert to integer arithmeticAndrea Adami
We use floating point just to print out KiB, MiB, GiB. Avoid that to be klibc friendly. Fixes compilation for aarch64 against klibc: error: '-mgeneral-regs-only' is incompatible with floating-point argument | printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024)); etc. Signed-off-by: Andrea Adami <> Signed-off-by: David Oberhollenzer <>
2017-11-15libmtd: fix a comment typo in dev_node2numRock Lee
Signed-off-by: Rock Lee <> Signed-off-by: David Oberhollenzer <>
2017-11-02Remove self-assignments of unused paramtersDavid Oberhollenzer
Use casts to void instead. Clang generates warnings about that by default. Signed-off-by: David Oberhollenzer <>
2017-06-28Silence warnings about unused argumentsDavid Oberhollenzer
Signed-off-by: David Oberhollenzer <>
2017-06-28Remove unused variables and functionsDavid Oberhollenzer
Signed-off-by: David Oberhollenzer <>
2017-06-28Eliminate warnings about missing prototypesDavid Oberhollenzer
This patch eliminates warnings generated by the -Wmissing-prototypes option. With this flag set, we are now forced to have prototypes for all global, exported functions, that have to be made visible to the definitions and we are forced to mark all local functions as static. Signed-off-by: David Oberhollenzer <>
2017-06-28Move libfec declarations to public header in global include directoryDavid Oberhollenzer
Signed-off-by: David Oberhollenzer <>
2017-06-28Use autoconf header detection correctly for libmissingDavid Oberhollenzer
AC_CHECK_HEADERS already makes sure our config header contains a HAVE_$FOO_H macro if a header was found. There is no need to awkwardly set our own Automake conditionals and check for it all over the place in the Automake files. Signed-off-by: David Oberhollenzer <>
2017-03-29libiniparser: remove unused function needing floatAndrea Adami
Fixes: | LD ubi-utils/ubiformat | .../git/ubi-utils/libiniparser.a(libiniparser.o): In function | ` LD ubi-utils/ubirename | iniparser_getdouble': | .../git/ubi-utils/libiniparser.c:336: undefined reference to `atof' Grep doesn't reveal any occurrence of iniparser_getdouble(), using atof() so remove it: floating-point is not supported in klibc Upstream-Status: Pending Signed-off-by: Andrea Adami <> Signed-off-by: David Oberhollenzer <>
2017-03-29libubi.c: add klibc specific fixes for ioctlAndrea Adami
First issue is that ioctl() in klibc doesn't expect a constant as arg3. Second issue is that arg3 in klibc ioctl() implementation is not optional. Fixes: | ubi-utils/libubi.c: In function 'do_attach': | ubi-utils/libubi.c:698:8: warning: passing argument 3 of 'ioctl' discards | 'const' qualifier from pointer target type | ret = ioctl(fd, UBI_IOCATT, r); | ^ | In file included from ubi-utils/libubi.c:32:0: | .../lib/klibc/include/sys/ioctl.h:15:14: note: expected 'void *' but argument | is of type 'const struct ubi_attach_req *' | __extern int ioctl(int, int, void *); | ^ | ubi-utils/libubi.c: In function 'ubi_vol_block_create': | ubi-utils/libubi.c:1118:9: error: too few arguments to function 'ioctl' | return ioctl(fd, UBI_IOCVOLCRBLK); | ^ | In file included from ubi-utils/libubi.c:32:0: | .../lib/klibc/include/sys/ioctl.h:15:14: note: declared here | __extern int ioctl(int, int, void *); | ^ | ubi-utils/libubi.c: In function 'ubi_vol_block_remove': | ubi-utils/libubi.c:1123:9: error: too few arguments to function 'ioctl' | return ioctl(fd, UBI_IOCVOLRMBLK); | ^ | In file included from ubi-utils/libubi.c:32:0: | .../usr/lib/klibc/include/sys/ioctl.h:15:14: note: declared here | __extern int ioctl(int, int, void *); | ^ Signed-off-by: Andrea Adami <> Signed-off-by: David Oberhollenzer <>
2017-03-22Return correct error number in ubi_get_vol_info1David Oberhollenzer
If the specified UBI device or volume does not exist, the function is supposed to set errno to ENODEV. This patch adds a check to ubi_get_vol_info1 to change the errno to ENODEV if vol_get_major cannot access the underlying sysfs file, so the function propperly returns that the device or volume does not exist, instead of failing with errno set to ENOENT. Signed-off-by: David Oberhollenzer <>
2017-03-15Fix libmtd behaviour if MTD is not present on the systemDavid Oberhollenzer
The documentation of libmtd_open says, if it returns NULL and errno is zero, MTD is not present. However, the current version always returns a libmtd_t object. The function internally checks, if it can access the MTD sysfs files and, if not, sets a flag to use the procfs fallback. This patch adds an additional check to libmtd_open, to test if the MTD procfs file can be read and fails with errno cleared if it does not exist. Furhtermore, mtd_get_info is documented to fail with errno set to ENODEV if MTD is not present. First of all, this was broken in the original version. It was implemented to specification for the sysfs code path, but if MTD is not present, that won't be executed, because of the flag set by libmtd_open. This makes the check not only redundant, but masks an actual error (the sysfs paths suddenly not being readable anymore). The legacy path that was used if the sysfs files are not avaible fails with ENOENT if it cannot read the procfs file. With the above changes in addition, we don't have a libmtd_t object if neither sysfs nor procfs is readable, so this error status no longer makes sense. This patch removes the documentation on the ENODEV errno, and makes sure that mtd_get_info always returns with apropriate errno on failure. Signed-off-by: David Oberhollenzer <>
2017-02-20Remove UDEV_SETTLE_HACKRichard Weinberger
UDEV_SETTLE_HACK addresses a problem which does no longer exist on Linux. These days we have devtmpfs. New devices will automatically created on the kernel side and user space has no longer to wait for udev. As udev has a hard dependency on devtmpfs we can depend on it too. People which don't use udev nor plain devtmpfs are anyways on their own. Android, I'm looking at you... Signed-off-by: Richard Weinberger <> Signed-off-by: David Oberhollenzer <>
2016-11-17Move ubi-utils libraries to common library locationDavid Oberhollenzer
Historically, the mtd-utils and ubi-utils were seperate packages. The ubi-utils were at some point merged into the mtd-utils. They first appeared in the release tar-ball in version 1.1.0 in their own sub-hirarchy with their own buildsystem, readme, documentation, etc. A lot of the duplicated stuff got centralized/removed over time. This patch further cleans up the directory hirarchy duplication by moving common libraries from the ubi-utils/ into the central lib/ and include/ directories in the top directory of the mtd-utils package. This includes: - libuib.a & libubigen.a used by the ubi utilities - libscan.a currently only used by ubiformat - libiniparser.a used by ubinize Signed-off-by: David Oberhollenzer <>
2016-11-17Merge rest of ubiutils-common into libmtd commonDavid Oberhollenzer
This patch moves the remaining 3 functions from ubiutils-common.{c,h} into libmtd common.{c,h}. The functions are only generic utility functions that other mtd-utils programs may also find usefull and every program that uses libubi links against libmtd anyway so there is no real reason for keeping around a seperate ubiutils-common with only generic helper functions. Signed-off-by: David Oberhollenzer <>
2016-11-17Add support for sysfs mockingDaniel Walter
In order to use test files, allow sysfs root to be set during compile time Signed-off-by: Daniel Walter <>
2016-11-17Fix uninitialized buffersDaniel Walter
Uninitialized buffers lead to failing unittests, since padding was not set to 0. Additionally this stops valgrind from complaining as well. Signed-off-by: Daniel Walter <>
2016-11-17mtd-utils: Add multi-block erase functionDavid Oberhollenzer
Signed-off-by: David Oberhollenzer <> Signed-off-by: Richard Weinberger <>
2016-11-17Add libmissingDavid Oberhollenzer
This patch adds a libmissing library to mtd-utils, containing implementations of functionality found in glibc but typically missing from embedded C libraries such as uclibc ot musl. For now, the library only contains stub implementations of the backtrace*() family of functions. Signed-off-by: David Oberhollenzer <> Signed-off-by: Richard Weinberger <>
2016-11-17Change build system to autotoolsRichard Weinberger
This patch is largely based on Richards original RFC. The major differences to the RFC patch are: - Add missing sumtools & mtdpart targets - Fix name of mkfs.jffs2 target - Add missing subdir-objects option for non-recursive make - Move all automake options to - Add manpages to install target - Make XATTR & LZO support configurable - Install binaries to sbin directory like in the old build system - Install flash_erase wrapper script - Add files missing from distribution target Signed-off-by: David Oberhollenzer <> Signed-off-by: Richard Weinberger <>
2016-11-17Remove unused and broken mtd_write_img function from libmtdDavid Oberhollenzer
The function _tries_ to support short reads but doesn't adjust the pointer into the buffer. If a short read happens, we scrambles the flash contents. Interrupted reads aren't handled. Short or interrupted writes aren't handled at all. Either a write succeeds writing the entire buffer or the function gives up. During an attempt at fixing it, it was discovered, that no mtd-utils program uses this function. Furthermore, its highly specific nature makes it more of a "feature looking for use case". Signed-off-by: David Oberhollenzer <> Signed-off-by: Richard Weinberger <>
2016-11-17Remove unused legacy_libmtd_open internal libmtd functionDavid Oberhollenzer
Signed-off-by: David Oberhollenzer <> Signed-off-by: Richard Weinberger <>
2016-11-17Eliminate warnings about implicit non-const casting in libmtdDavid Oberhollenzer
The mtd_get_dev_info1 function reads (among other things) name and type string into coresponding struct mtd_dev_info fields. The struct mtd_dev_info has the string fields marked const, requiring them to be cast to non-const version during initialization. This cast was previously omitted from the dev_read_data calls, triggering warnings during compilation. Signed-off-by: David Oberhollenzer <> Signed-off-by: Richard Weinberger <>
2016-07-13libmtd: Fix return status in mtd_torture test functionDavid Oberhollenzer
This patch fixes the return status of the mtd_torture function in libmtd. The torture test function is currently only used by the ubiformat utility to check if a block is bad after a write fails (blocks are marked bad if the function returns an error status). However, the way the function was written, it ALWAYS returns an error value regardless of whether it failed or not. Signed-off-by: David Oberhollenzer <> Signed-off-by: Richard Weinberger <> Reviewed-by: Boris Brezillon <> Signed-off-by: Brian Norris <>
2015-11-17libmtd: mtd_read: Take the buffer offset into account when readingMarcus Prebble
Assuming the read() call does not return zero and the result is less than len, the current implementation will overwrite the data already read in buf which doesn't seem correct. With this patch, subsequent calls to read() within the loop will now no longer overwrite the existing contents of buf. Signed-off-by: Marcus Prebble <> Signed-off-by: Brian Norris <>
2015-05-28libmtd: fix comment typoBaruch Siach
Signed-off-by: Baruch Siach <> Signed-off-by: Brian Norris <>
2015-05-28mtd-utils: libfec: use standard C type instead of u_longImre Kaloz
Fixes compilation on hosts with the musl C library. Also drops the unused u_short typedef. Signed-off-by: Imre Kaloz <> Signed-off-by: Brian Norris <>
2014-11-04libmtd: don't ignore "region index" parameter in mtd_regioninfo()Brian Norris
ioctl(MEMGETREGIONINFO) has one input parameter (regionindex) and three output parameters (info about the erase region). There are two problems in mtdinfo/libmtd here: 1. mtdinfo.c doesn't initialize its region_info_user struct, instead passing uninitialized data to mtd_regioninfo() 2. mtd_regioninfo() fails to utilize the 'regidx' parameter to fill out the regionindex parameter properly, so the garbage from mtdinfo.c is propagated to the ioctl() This means that mtdinfo will continuously probe the same (possibly out-of-range) erase region, instead of looping over the valid regions. Let's fix this in the mtd_regioninfo() helper, and at the same time, let's zero out the mtdinfo.c buffer, as an additional precaution to keep from using uninitialized data. Initial error report from Yang, when running "mtdinfo /dev/mtd0" on a Cavium 6100 board: root@CN61XX:~# mtdinfo /dev/mtd0 mtd0 Name: phys_mapped_flash Type: nor Eraseblock size: 65536 bytes, 64.0 KiB Amount of eraseblocks: 128 (8388608 bytes, 8.0 MiB) Minimum input/output unit size: 1 byte Sub-page size: 1 byte Additional erase regions: 0 Character device major/minor: 90:0 Bad blocks are allowed: false Device is writable: true libmtd: error!: MEMGETREGIONINFO ioctl failed for erase region 0 error 22 (Invalid argument) Eraseblock region 0: info is unavailable libmtd: error!: MEMGETREGIONINFO ioctl failed for erase region 1 error 22 (Invalid argument) Eraseblock region 1: info is unavailable Reported-by: Yang Wei <> Signed-off-by: Brian Norris <>
2014-09-15libmtd: fix mtd_dev_present return value on legacy systemsGuido Martínez
On legacy systems, if "/proc/mtd" doesn't exist or gives a read error, mtd_dev_present returns -1 (since it calls legacy_dev_present), contrary to what's specified in the header file. This causes checks like if (mtd_dev_present(n)) { ... } to give false positives. Fix this by comparing the return value to 1. Signed-off-by: Guido Martínez <> Signed-off-by: Brian Norris <>
2013-10-22check the MLC nand typeHuang Shijie
In the current code, the MTD_NANDFLASH stands for both the SLC and MLC. In the kernel, the MTD_NANDFLASH only stands for the SLC now, so in order to keep the logic unchanged, we should also check the MLC NAND by MTD_MLCNANDFLASH. Signed-off-by: Huang Shijie <> Signed-off-by: Brian Norris <>
2013-10-22add the MTD_MLCNANDFLASH caseHuang Shijie
The MTD_MLCNANDFLASH case is missed in the current code. This patch adds it. Signed-off-by: Huang Shijie <> Signed-off-by: Brian Norris <>
2012-09-25consistency between u_int32_t / off_t / off64_tRichard Genoud
We should use the off_t type instead of off64_t or u_int32_t as its length is controlled by the WITHOUT_LARGEFILE flag. Signed-off-by: Richard Genoud <> Signed-off-by: Artem Bityutskiy <>
2012-02-29libmtd_legacy: don't open device in R/WBrian Norris
On legacy kernels with ROM devices, we can get mtdinfo errors like: libmtd: error!: cannot open "/dev/mtd4" error 13 (Permission denied) mtdinfo: error!: libmtd failed get MTD device 4 information error 13 (Permission denied) We don't need O_RDRW access for informational ioctls(), so make this O_RDONLY. Signed-off-by: Brian Norris <> Signed-off-by: Artem Bityutskiy <>
2012-02-29libmtd: perform device checking firstBrian Norris
If we don't check for the MTD before calling `legacy_get_dev_info1', we may get errors like: libmtd: MTD subsystem is old and does not support sysfs, so MTD character device nodes have to exist libmtd: error!: "/dev/mtd2" is not a character device mtdinfo: error!: libmtd failed get MTD device 2 information error 22 (Invalid argument) So reverse the order of these two checks. Signed-off-by: Brian Norris <> Signed-off-by: Artem Bityutskiy <>
2012-02-14libmtd: fix mtd_write() issues for large data-only writesBrian Norris
ioctl(MEMWRITE) is implemented with memdup_user(), and so it allocates kernel memory in contiguous regions. This limits its usefulness for large amounts of data, since contiguous kernel memory can become scarce. I have experienced "out of memory" problems with ubiformat, for instance, which writes in eraseblock-sized regions: ... ubiformat: flashing eraseblock 12 -- 72 % complete ubiformat: page allocation failure. order:8, mode:0xd0 Call Trace: [<8043fa7c>] dump_stack+0x8/0x34 [<8008c940>] __alloc_pages_nodemask+0x408/0x618 [<800bd748>] cache_alloc_refill+0x400/0x730 [<800bdbbc>] __kmalloc+0x144/0x154 [<8009cae4>] memdup_user+0x24/0x94 [<802d04e4>] mtd_ioctl+0xba8/0xbd0 [<802d0544>] mtd_unlocked_ioctl+0x38/0x5c [<800d43c0>] do_vfs_ioctl+0xa4/0x6e4 [<800d4a44>] sys_ioctl+0x44/0xa0 [<8000f95c>] stack_done+0x20/0x40 ... libmtd: error!: MEMWRITE ioctl failed for eraseblock 12 (mtd0) error 12 (Cannot allocate memory) ubiformat: error!: cannot write eraseblock 12 error 12 (Cannot allocate memory) This error can be mitigated for now by only using ioctl(MEMWRITE) when we need to write OOB data, since we can only do this in small transactions anyway. Then, data-only transactions (like those originating from ubiformat) can be carried out with write() calls. This issue can also be solved within the kernel ioctl(), but either way, this patch is still useful, since write() is more straightforward (and efficient?) than ioctl() for data-only writes. Signed-off-by: Brian Norris <> Signed-off-by: Artem Bityutskiy <>
2012-02-14libmtd: fix segmentation fault on lib->mtdBrian Norris
Legacy systems do not initialize lib->mtd, so we shouldn't perform strlen(lib->mtd); this produces a segmentation fault. As this code isn't used in the legacy codepath, we can just move it down to an 'else' branch. Signed-off-by: Brian Norris <> Signed-off-by: Artem Bityutskiy <>