Owut: OpenWrt Upgrade Tool

Hi there,

New question:, a bit of background Running OW on pc, with larger rootfs:

root@OW:~#  df -Th

Filesystem           Type            Size      Used Available Use% Mounted on
/dev/root            ext4          470.8G      1.5G    469.3G   0% /

Previously all was set up 100% as v24, and chose to upgrade using the ASU (thinking it would auto-detect the special configuration and setup rootfs to match existing, OR ALERT and fail the upgrade), but instead, it wiped all rootfs content that was huge loss!!

So at that time quickly setup 25.12 rc3 :

DISTRIB_RELEASE='25.12.0-rc3'
DISTRIB_REVISION='r32486-30527a4c34'
DISTRIB_TARGET='x86/64'
DISTRIB_ARCH='x86_64'
DISTRIB_DESCRIPTION='OpenWrt 25.12.0-rc3 r32486-30527a4c34'

Now read that i should use owut that can handle different rootfs sizes (can it autodetect and just keep using the exact same layout automatically)?

however, running it failed with the ABI error:

# owut
Runtime error: Unable to dlopen file '/usr/lib/ucode/uclient.so': Error loading shared library libubox.so.20260213: No such file or directory (needed by /usr/lib/ucode/uclient.so)
In /usr/bin/owut, line 10, byte 34:

 `let PROG    = `${NAME}/${VERSION}`;`
  Near here -----------------------^

Tried many suggestions like:

root@OW:~# apk upgrade ucode libucode
OK: 274.6 MiB in 277 packages

But it did not help, still same error, until ran:

apk add libubox-lua 

That, SOLVED the error above, but, any check operation hangs indefinitely without any errors:

owut check -v
owut - OpenWrt Upgrade Tool 2026.04.09~5d6760b5-r1 (/usr/bin/owut)

running with 'strace' shows:

read(14, "\337\3531\246\345\317*%(\360\342\27\20j\24\205Y\202\224v>\241\321\226g\324\223%N\3400\252"..., 2389) = 2389
read(14, "\27\3\3\2+", 5)               = 5
read(14, "\3152\266\23\304e\373\326\317\"mLU\211\277\350\237\207\212\370\237\352\231G\374\"\257Y\251\3102P"..., 555) = 555
read(14, "\27\3\3\20\21", 5)            = 5
read(14, "\1\367\16\207\2314\320\375\326\33\277\345\332\246U\331\206\337\2f\373\331.f\367(\357&Oi\230\316"..., 4113) = 4113
epoll_ctl(7, EPOLL_CTL_MOD, 14, {events=EPOLLOUT|EPOLLET, data=0x7f1939358e28}) = 0
epoll_pwait(7, [{events=EPOLLOUT, data=0x7f1939358e28}], 10, -1, NULL, 8) = 1

it reads from socket and waits on some event that never happens :slight_smile: :slight_smile:

lrwx------    1 root     root            64 May 24 11:15 14 -> socket:[2410027]
l-wx------    1 root     root            64 May 24 11:16 15 -> /tmp/owut-overview.json
lrwx------    1 root     root            64 May 24 11:16 2 -> /dev/pts/0
lr-x------    1 root     root            64 May 24 11:16 3 -> pipe:[2408161]
l-wx------    1 root     root            64 May 24 11:16 4 -> pipe:[2408161]
lr-x------    1 root     root            64 May 24 11:16 5 -> /usr/bin/owut
lr-x------    1 root     root            64 May 24 11:16 6 -> /usr/share/ucode/utils/argparse.uc
lrwx------    1 root     root            64 May 24 11:16 7 -> anon_inode:[eventpoll]

any suggestion how to fix this or better yet, update to latest 25.12 official release without wiping out rootfs? I'm experienced linux user , but relatively new to openwrt eco..

Thanks for any suggestions!

PS: the router is fully connected, e.g.

# uclient-fetch -O /dev/null https://sysupgrade.openwrt.org  
Downloading 'https://sysupgrade.openwrt.org'
Connecting to 45.140.183.87:443
Writing to '/dev/null'
/dev/null            100% |*******************************|  9273   0:00:00 ETA
Download completed (9273 bytes)

PS2: Reading more, I think i'll move away to a smaller rootfs, and separate data partition, that way future updates should be safer? it will retain the 3rd partition in the new image I assume/hope so :slight_smile:

Yeah, that would be nice, but I have not even found a concise/reasonable way to detect which devices of the 1918 supported ones allow changing the partition size, much less what the layout and actual sizes are...

The part of sysupgrade that decided to overwrite your partition table is in /lib/upgrade/platform.sh, in the platform_check_image function. The actual overwriting itself is down in platform_do_upgrade.

That's due to a partial upgrade, which caused the ABI versions to go out of sync (the root cause of that is bugs in the packaging, and is the reason there are warnings about opkg upgrade and apk upgrade all over the place).

The addtion of libubox-lua probably helped by upgrading the libubox library, as lua itself is not used by owut anywhere.

Does apk version show anything else out of date?

The strace output might show us something if you output the full strings. Try adding --string-limit=1000, then maybe something meaningful will pop out of its usual binary noise.

1 Like

@efahl Eric, thanks for nice human, and informative reply!!!

  1. If I'm reading code correctly?

https://github.com/openwrt/openwrt/blob/d51fa9b28e1fb455bfa83610f418c9d1142c3dd9/target/linux/x86/base-files/lib/upgrade/platform.sh#L195

if existing partition table and one on generated sysupgrade image differ, then it will WIPE all.
I was hoping to abandon the 2 partitions (huge rootfs) like:

# cat /proc/partitions 
major minor  #blocks  name

 259        0  500107608 nvme0n1
 259        1      16384 nvme0n1p1
 259        2  500090951 nvme0n1p2
 259        3        239 nvme0n1p128

into a 3 (plus that 128), so /boot and / will be part of image, and say, /userdata will be separate and not part of the sysupgrade image, I just don't know enough about owut tool, if it would generate the same partition table from eixsting system, then all should be fine, even though image will not include the data, it would include the partition table header , and they will match. Sounds like good approach?

Just trying to make upgrades easier without wiping all /userdata (which currently sits on / (rootfs)).

  1. As for apk version, I don't think I've updated massively, I did add adguardhome, maybe that changed things, here is the output: https://paste.laravel.io/fd1515c9-8588-4065-960a-d048e5eb0cce
  2. As for strace, output with string limit to 1000 is here https://paste.laravel.io/2c37fc9a-0037-45dd-b537-b58ec7e778d5
  3. Noticed open("/tmp/owut-overview.json", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 15
    ioctl(15, TIOCGWINSZ, 0x7ffe5c37f968) = -1 ENOTTY (Not a tty)
    That was/is a file, deleting it gets re-created, so yeah, it's not a tty or pipe, not sure if important:

-rw-r--r-- 1 root root 0 May 24 23:51 /tmp/owut-overview.json

5. This is the process (pid):
26747 root 10484 t {owut} /usr/bin/ucode -S /usr/bin/owut check

6. tail of lsof is:

owut    26747 root   7u  a_inode               0,11        0   1036 [eventpoll:3,8,10,14]
owut    26747 root   8r     FIFO               0,10      0t0 227762 pipe
owut    26747 root   9w     FIFO               0,10      0t0 227762 pipe
owut    26747 root  10u     unix 0x00000000e714187b      0t0 226594 type=STREAM (CONNECTED)
owut    26747 root  11u  a_inode               0,11        0   1036 [eventpoll:12]
owut    26747 root  12r     FIFO               0,10      0t0 227763 pipe
owut    26747 root  13w     FIFO               0,10      0t0 227763 pipe
owut    26747 root  14u     IPv4             224254      0t0    TCP <GC IP>:33200->sysupgrade.openwrt.org:https (CLOSE_WAIT)
owut    26747 root  15w      REG               0,19        0    460 /tmp/owut-overview.json

modified the above output to remove the IP, which is CGNAT (carrier Grade), maybe that's the issue? it's trying to pull to the CG IP and that may not work? 

Again, a notmal "ping" or "wget" works fine as original post.

Eager to heave any ideas/insights!!

Stormy.

Just upgraded my Rasp Pi4B from 25.12.2 to 25.12.4 using owut. Everything initially appeared ok, but just noticed it hadn't copied across the rclone config file?
Not a big problem to reconfig, but just thought it was worthy noting.
Great job on making this upgrade happen, many thanks to all involved.

1 Like

None of the upgrade tools actually look at that partition table until that very last moment in sysupgrade where it decides to overwrite it or not. The imagebuilder has no means for changing anything except the rootfs partition size, so you end up with just /boot and / in the partition table it generates (and the size of n1p2 is constrained by the ASU server, so 1024 MB is the biggest you can currently request from sysupgrade.openwrt.org).

I think some people tack on a big partition after n1p128, and then manually rewrite the partition table on reboot after an upgrade, but that always seemed pretty brittle to me.

If you run owut check -v -v -v --keep then you'll see all the downloads reported as the occur, along with output regarding where they end up being saved in the file system. That might help us figure out what's up with the failure.

Wow, sounds like ur very knowledgeable.!! thanks for your time!

I'm coming from "enterprise grade" software trying to help/improve better understand the flow. Problem is previous lesson took few days to restore network access :slight_smile: :slight_smile: I was just naive :slight_smile:

Can u pls confirm if I read the code correctly? "if existing partition table and one on generated sysupgrade image differ, then it will WIPE all."

If that is TRUE, then it seems the 4th partition is "doomed" since it will always overwrite since they would DIFFER (the sysupgrade engine does not know of this extra huge partition) :slight_smile:

Can we tell the tool to JUST over write specific partition, not ALL of it? i.e. make it a user choice, wipe all, or "copy to existing partitions" and run resizefs/checkfs etc.

if you or anyone are aware of a page with such discussions/suggestions of real users, i'd LOVE to help, I wish to run extra software on the openwrt, but hot have to reinstall each upgrade..

Also, is there a way to upgrade like on linux distros, dnf/yum ? maybe the "release" would simply post a repo, where one would sync to, and that would be essentially an in-place upgrade without having to regenerate ffull images, just update to a given well tested consistent repo , reboot and it's same as a full image built from scratch? sorry for naive questions...

As for hanging owut tool, running w/o strace produces absolutely NO output even with -v -v -v, with strace as follows:

strace -Ttt -s 1024 owut check -v -v -v --keep  >& owut-strace.lis

wc -l owut-strace.lis
2758 owut-strace.lis

The tail end is posted here: I'm pretty capable linux friend, if u give any tips/ideas, can even recompile whatever to help sort it out, esp, if the tool can help do this upgrade without wiping entire partitions each time :slight_smile:

Stormy.

https://pastes.io/nluiADMc

Some ideas as I see things that might help you...

OpenWrt has focused on supporting the many "plastic" routers with low resource built-for-purpose hardware meant for home and small office use. These devices mostly have a small amount of ram and flash storage. X86 boards and some arm based systems have more resources but there hasn't been much change made in the build process for these few devices.
OpenWrt is also a volunteer effort so minimizing complexity looks to have been a priority. It looks like long ago a process to use common and reused build tools was developed with minimal changes for the few big resource devices available.

You used the term "WIPE". The installer generally just copies the image to the device and not to a partition. The image has the partitions and partition table as built by the image builder. If you have or want a different partition setup, you are welcome to run your own instance of the image builder and customize the build settings to your needs. I refer to the containerized build system which uses pre-compiled binaries. It is not compiling from source and takes far less resources and time. See the wiki and or search the forum for more info. Resizing or not_wiping_partitions is a frequent question.

I've only done it once as a test but it worked fine to create a data partition starting a couple gig away from the start of the storage, backed up the partition table entry and then did a normal OpenWrt installation and restored the partition table entry for the data partition. I can't guarantee that it is reliable but it is common advice to simply restore the partition table entry from backup after an accidental change so it is something to consider if it fits your use case. I advise to have reliable full backups that can be used to restore important data due to any reason for loss.

1 Like

Correct, provided you understand what "wiping" means.

Not doomed, because the "wipe" consist of simply dd if=image of=/dev/whatever, so it only overwrites however much data is required to store the image. So, if you had a partition beyond that, its data remains untouched and you can regenerate the partition table entry to access it and it should still be there. (This always seemed pretty sketchy to me, so I don't recommend it, but some people apparently do it with success.)

That's not good, it should at least do the simple printfs up front and show you the version number. What do you get when you run this? (Should show us if the ucode interpreter is working...)

$ ucode -l uclient -e 'printf("%.2J\n", uclient);'

Dear friends..

Yes, well aware of the openwrt history/footprint, and need for simplicity, at same time, things are "moving" and it might be nice to have a more robust solution for this common case, it might open up door to more users..

What about the other idea with updating to a fixed and consistent repo (i.e. the same one used to generate the image), why can't it update 10 or 100 packages instead of a "clean image", there could be another / alternate path.

Right, by "wipe" i meant it clears MBR , (sector 0) , now sure, if the (new) image is not larger then the /data will not be over written.. it will require a lot of care to be sure no mistakes otherwise all is lost..

ok, will think a day or two then try something..

As for command:

# ucode -l uclient -e 'printf("%.2J\n", uclient);'
{
  "new": "function new(...) { [native code] }"
}

not sure if that is good or bad :slight_smile:

That's good, the ucode interpreter loads, runs and executes a print. The ucode-mod-uclient code is there and loads as expected.

Let's trace owut execution, to see how far it's getting. Try running this and grab the last 30-40 lines. Note that this might take few minutes, as the tracing is extremely verbose...

$ ucode -t /usr/bin/owut check -v
... 
  1. An honor to exchange here.. is there a chat/forum to provide such feedback, or help test (within available time of course, as you say.. it's voluanteered, same here) Maybe simplest is to enable another "bypass/skip" flag for partition, and dd skip the partition table, then "power users" can pass that, and retain their partition without each having to reinvent.. not sure how/if possible to pass params to that stage, but if so, should be simple, and only for "power users" that know the partition layout will not change from upgrade to upgrade. Also, I'd love to help explore the update to a specific repo point in time (same as image generation uses), that will allow quick linux-like update? or, sorry, let me know where best to share/say these. here? https://forum.openwrt.org/c/devel/8

  2. As for the trace, here u go: https://pastes.io/6yHLBGLO seems something with redirect ...

network appears ok, simple wget appears as follows:

# wget https://sysupgrade.openwrt.org 
--2026-06-02 10:21:14--  https://sysupgrade.openwrt.org/
Resolving sysupgrade.openwrt.org... 45.140.183.87, 2001:678:6e1:1001:be24:11ff:fe23:4c6d
Connecting to sysupgrade.openwrt.org|45.140.183.87|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 9314 (9.1K) [text/html]
Saving to: 'index.html'

index.html           100%[===================>]   9.10K  --.-KB/s    in 0.002s  

2026-06-02 10:21:15 (5.89 MB/s) - 'index.html' saved [9314/9314]

Again, proud to help and get to know folks so much involved! Thanks!!

Yes, that looks like it's trying to redirect for some reason, but that file is a direct link, so there should be nothing in the way. Unless you are running a proxy maybe?

In any case, let's see what wget is seeing for headers, add a -S and get the actual file itself:

$ wget -S https://sysupgrade.openwrt.org/json/v1/overview.json
...
  HTTP/1.1 200 OK
  Access-Control-Allow-Credentials: true
  Access-Control-Allow-Headers: *
  Access-Control-Allow-Methods: POST, GET, OPTIONS
  Access-Control-Allow-Origin: *
  Access-Control-Expose-Headers: Authorization
  Alt-Svc: h3=":443"; ma=2592000
  Content-Length: 18471
  Content-Type: application/json
  Date: Tue, 02 Jun 2026 15:12:04 GMT
  Server: uvicorn
  Vary: Origin
  Via: 1.1 Caddy

No proxy.. adguard home, but same with it disabled, here is wget:

# wget -S https://sysupgrade.openwrt.org/json/v1/overview.json
--2026-06-02 19:23:43--  https://sysupgrade.openwrt.org/json/v1/overview.json
Resolving sysupgrade.openwrt.org... 45.140.183.87, 2001:678:6e1:1001:be24:11ff:fe23:4c6d
Connecting to sysupgrade.openwrt.org|45.140.183.87|:443... connected.
HTTP request sent, awaiting response... 
  HTTP/1.1 200 OK
  Access-Control-Allow-Credentials: true
  Access-Control-Allow-Headers: *
  Access-Control-Allow-Methods: POST, GET, OPTIONS
  Access-Control-Allow-Origin: *
  Access-Control-Expose-Headers: Authorization
  Alt-Svc: h3=":443"; ma=2592000
  Content-Length: 18471
  Content-Type: application/json
  Date: Tue, 02 Jun 2026 16:23:43 GMT
  Server: uvicorn
  Vary: Origin
  Via: 1.1 Caddy
Length: 18471 (18K) [application/json]
Saving to: 'overview.json.1'

overview.json.1      100%[===================>]  18.04K  --.-KB/s    in 0.08s   

2026-06-02 19:23:44 (218 KB/s) - 'overview.json.1' saved [18471/18471]

there is nothing behind the openwrt, it's just a dumb isp box, the openwrt does the ppp/network connection, oh, wait, there is a DUAL connection, 2 ISPs maybe that matters, not sure?