Discussion:
How to upgrade glibc
Christophe Osuna
2008-04-16 14:34:13 UTC
Permalink
I am facing a problem that some of you have probably encountered; I
hope you can provide me with some advice.

I am unsuccessfully trying to upgrade the glibc on my busybox system
with the following steps:

1. remount / rw

Here everything is fine.

2. copy new files

Using the "cp" command crashes the system (the system will not respond
to key presses and the library file is corrupted).

# WARNING ! THIS WILL PROBABLY CRASH YOUR COMPUTER
$ cp /lib/libc-2.5.so /tmp/libc-2.5.so.new
$ cp /tmp/libc.so.new /lib/libc-2.5.so

I have managed to install the file by installing a home-made RPM
package with the "new" file (in fact same as the old one); it also
works with a .tar archive.

3. remount / ro

Things in step 2 didn't go so well even though they looked successful,
for mount will not remount / ro because of a "device or resource
busy".

4. reboot

As the root filesystem could not be remounted read-only fsck complains
and finds problems.

Below is the output of the "lsof" command before and after a glibc
upgrade. It shows that the init process (busybox) is using glibc files
and references files by their inode number after the upgrade.

~# /tmp/lsof|head
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
init 1 root cwd DIR 3,1 1024 2 /
init 1 root rtd DIR 3,1 1024 2 /
init 1 root txt REG 3,1 618184 73446 /bin/busybox
init 1 root mem REG 0,0 0 [heap] (stat:
No such file or directory)
init 1 root mem REG 3,1 1491141 20429 /lib/libc-2.5.so
init 1 root mem REG 3,1 190963 20427 /lib/libm-2.5.so
init 1 root mem REG 3,1 47607 20436 /lib/libcrypt-2.5.so
init 1 root mem REG 3,1 129767 20432 /lib/ld-2.5.so
init 1 root 0u CHR 5,1 219 /dev/console (deleted)
~# mount -o remount,rw /
~# rpm -ivh /tmp/glibc-2.5-1.i586.rpm
Preparing... ########################################### [100%]
1:glibc ########################################### [100%]
~# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
~# /tmp/lsof|head
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
init 1 root cwd DIR 3,1 1024 2 /
init 1 root rtd DIR 3,1 1024 2 /
init 1 root txt REG 3,1 618184 73446 /bin/busybox
init 1 root mem REG 0,0 0 [heap] (stat:
No such file or director)
init 1 root mem REG 3,1 20429
/lib/libc-2.5.so (path inode=20462)
init 1 root mem REG 3,1 20427
/lib/libm-2.5.so (path inode=116283)
init 1 root mem REG 3,1 20436
/lib/libcrypt-2.5.so (path inode=11628)
init 1 root mem REG 3,1 20432
/lib/ld-2.5.so (path inode=20461)
init 1 root 0u CHR 5,1 219 /dev/console (deleted)

Well, this makes sense but is quite annoying: does that mean that I
cannot upgrade the glibc in a dynamically-linked busybox?

I have two solutions in mind but I would greatly appreciate others:

1. Use a static link. This means that the glibc will be "installed"
twice: in the busybox executable and in the system, I don't like it.
Besides this was discouraged in some busybox versions if I remember
well.

2. Upgrade from an initramfs. This is annoying because I download
updates from the network, which means that the network would have to
be configured (DHCP...) in the initramfs and also in the system.

Busybox version is 1.8.2 and glibc is a copy of OpenSUSE 10.2 files,
but I think this does not matter here.

Thanks.
Christophe Osuna
2008-04-17 09:03:50 UTC
Permalink
Post by Christophe Osuna
I am unsuccessfully trying to upgrade the glibc on my busybox system
(...)
In fact the issue is not specific to glibc; any file in use will lead
to the same problem. The kernel wants to delete the old file from the
filesystem, but since it is still in use it can't do that.
Post by Christophe Osuna
1. Use a static link. This means that the glibc will be "installed"
twice: in the busybox executable and in the system, I don't like it.
Besides this was discouraged in some busybox versions if I remember
well.
This does not solve the problem.
Post by Christophe Osuna
2. Upgrade from an initramfs. This is annoying because I download
updates from the network, which means that the network would have to
be configured (DHCP...) in the initramfs and also in the system.
3. Tell the kernel not to delete the file when it is overwritten. How?
By creating a hard link. When the file is no longer used (next reboot)
it is safe to delete the hard link. This is more satisfactory than the
previous solution but it is not still perfect.

Any other idea?
Denys Vlasenko
2008-04-17 09:23:25 UTC
Permalink
Post by Christophe Osuna
I am facing a problem that some of you have probably encountered; I
hope you can provide me with some advice.
I am unsuccessfully trying to upgrade the glibc on my busybox system
1. remount / rw
Here everything is fine.
2. copy new files
Using the "cp" command crashes the system (the system will not respond
to key presses and the library file is corrupted).
# WARNING ! THIS WILL PROBABLY CRASH YOUR COMPUTER
$ cp /lib/libc-2.5.so /tmp/libc-2.5.so.new
$ cp /tmp/libc.so.new /lib/libc-2.5.so
Do not use cp. You need to replace files atomically. mv is better.

mv /somewhere/else/libc-2.5.so /lib/libc-2.5.so

You may need mv which is statically linked (does not require /lib/libc-2.5.so).
But since libc has more than one file, more generic way is:

Assuming that all new .so files are staged in /somewhere/else/*:

cp -dpR /lib /lib.old # backup copy of entire dir
mv /somewhere/else/* /lib

Again, you may need "static" mv for second step.
--
vda
Alessandro Rubini
2008-04-17 10:03:33 UTC
Permalink
Post by Christophe Osuna
3. Tell the kernel not to delete the file when it is overwritten. How?
By creating a hard link.
Not really. When you open the file for writing, it gets truncated. Anybody
who is using the file will have problems.

If you first unlink the file, any user will remain happy (the
filesystem storage is recovered when the file is no more in use, no
need to unlink at next reboot).

However, after you unlinked a shared library, no dynamic executable
using it can start any more (but the ones running keep happily
running).

So, right after the unlink(2) you need rename(2). You need them both
in the same executable. And it's safer if it is a static one
(as Denys suggested) although you might as well manage to work
with a dynamic one. After the "mv" (unlink and rename) new programs
will start with the new library, and old ones will continue to run
with the old library until killed.

Actually, shared libraries are often symlinks, so you can install the
new one (different minor number), change symlink (unlink and
ln from a single program) and then delete the old library.

Example: keeping a file open after it's deleted:

rudo% touch deleteme
rudo% sleep 60 < deleteme &
[3] 23219
rudo% rm deleteme
rudo% ls -l /proc/23219/fd
total 0
lr-x------ 1 rubini staff 64 Apr 17 11:57 0 -> /tmp/deleteme (deleted)
lrwx------ 1 rubini staff 64 Apr 17 11:57 1 -> /dev/ttyq6
lrwx------ 1 rubini staff 64 Apr 17 11:57 2 -> /dev/ttyq6

Example: reading a file after it's deleted:

rudo% echo bu > deleteme
rudo% ( sleep 2 ; cat ) < deleteme ; rm deleteme
bu

/alessandro
Denys Vlasenko
2008-04-17 10:56:07 UTC
Permalink
Post by Alessandro Rubini
Post by Christophe Osuna
3. Tell the kernel not to delete the file when it is overwritten. How?
By creating a hard link.
Not really. When you open the file for writing, it gets truncated. Anybody
who is using the file will have problems.
If you first unlink the file, any user will remain happy (the
filesystem storage is recovered when the file is no more in use, no
need to unlink at next reboot).
However, after you unlinked a shared library, no dynamic executable
using it can start any more (but the ones running keep happily
running).
So, right after the unlink(2) you need rename(2). You need them both
in the same executable.
unlink is not really needed, rename will succeed even without it:

# >z
# >zz
# strace mv z zz
execve("/bin/mv", ["mv", "z", "zz"], [/* 32 vars */]) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
getuid32() = 0
stat64("zz", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
access("zz", W_OK) = 0
rename("z", "zz") = 0 <============ atomically deleted zz and moved z to zz
_exit(0) = ?
Post by Alessandro Rubini
And it's safer if it is a static one
(as Denys suggested) although you might as well manage to work
with a dynamic one.
I recommend having static mv (and a few other utils)
for this use case purely for paranoid reasons - if you _do_
screw up your /lib by accident, you may want to have
tools which continue working.
--
vda
Christophe Osuna
2008-04-17 12:30:48 UTC
Permalink
Post by Alessandro Rubini
Post by Christophe Osuna
3. Tell the kernel not to delete the file when it is overwritten. How?
By creating a hard link.
Not really. When you open the file for writing, it gets truncated. Anybody
who is using the file will have problems.
If you first unlink the file, any user will remain happy (the
filesystem storage is recovered when the file is no more in use, no
need to unlink at next reboot).
However, after you unlinked a shared library, no dynamic executable
using it can start any more (but the ones running keep happily
running).
So, right after the unlink(2) you need rename(2). You need them both
in the same executable.
"mv" does succeed and the applications are not annoyed by this change;
the filesystem is, however. See below:

~# cd /lib
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
/lib#

And after rebooting:

Checking root filesystem...
e2fsck 1.40.2 (12-Jul-2007)
/dev/hda1 was not cleanly unmounted, check forced.
Pass 1: Checking inodes, blocks, and sizes
Deleted inode 26549 has zero dtime. Fix? yes

Deleted inode 44964 has zero dtime. Fix? yes

Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
Block bitmap differences: -(113601--114688) -(114946--115321) -(182785--183392)
Fix? yes

Free blocks count wrong for group #13 (6238, counted=7326).
Fix? yes

Free blocks count wrong for group #14 (5150, counted=5526).
Fix? yes

Free blocks count wrong for group #22 (4872, counted=5480).
Fix? yes

Free blocks count wrong (407568, counted=409640).
Fix? yes

Inode bitmap differences: -26549 -44964
Fix? yes

Free inodes count wrong for group #13 (1979, counted=1980).
Fix? yes

Free inodes count wrong for group #22 (1956, counted=1957).
Fix? yes

Free inodes count wrong (119071, counted=119073).
Fix? yes


/dev/hda1: ***** FILE SYSTEM WAS MODIFIED *****
/dev/hda1: 1287/120360 files (2.6% non-contiguous), 71144/480784 blocks


Below is an example of the "hard links" solution:

~# cd /lib
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# ln libc-2.5.so libc-2.5.so.old
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
/lib#

On the next reboot I have to delete /lib/libc-2.5.so.old

This would probably work. Since I am using RPM packages I intend to do
the hard link in the preinstall-script.

I am a bit confused: how do the Linux distributions handle this? I had
a look at the glibc SRPM from OpenSUSE 10.2 and the only thing related
to this is a call to "telinit u" so that it re-executes itself. But
why that, since /sbin/init is not a dynamic executable? I believe I
would need something similar in busybox but I can't imagine the amount
of work it would be to allow busybox to re-execute itself while
preserving its state.
Denys Vlasenko
2008-04-17 12:40:39 UTC
Permalink
Post by Christophe Osuna
"mv" does succeed and the applications are not annoyed by this change;
~# cd /lib
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
/lib#
This should work, 100%. You need to report this to kernel mailing list.

I take it that if you skip "mv" command, second mount cmd succeeds?
--
vda
Ralf Friedl
2008-04-17 12:54:19 UTC
Permalink
Post by Christophe Osuna
~# cd /lib
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
/lib#
...
You should do a normal shutdown after that, not a failed remount to rw
and after that a power cycle.

If you can't use a normal shutdown, your solution to keep the old file
till the next reboot is probably necessary.

Regards
Ralf Friedl
Denys Vlasenko
2008-04-17 12:40:39 UTC
Permalink
Post by Christophe Osuna
"mv" does succeed and the applications are not annoyed by this change;
~# cd /lib
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
/lib#
This should work, 100%. You need to report this to kernel mailing list.

I take it that if you skip "mv" command, second mount cmd succeeds?
--
vda
Ralf Friedl
2008-04-17 12:54:19 UTC
Permalink
Post by Christophe Osuna
~# cd /lib
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
/lib#
...
You should do a normal shutdown after that, not a failed remount to rw
and after that a power cycle.

If you can't use a normal shutdown, your solution to keep the old file
till the next reboot is probably necessary.

Regards
Ralf Friedl
Alessandro Rubini
2008-04-17 12:49:27 UTC
Permalink
Post by Christophe Osuna
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
That's interesting. Most likely the filesystem is pending a write
when the old lib will be closed. It makes sense.
Post by Christophe Osuna
/dev/hda1 was not cleanly unmounted, check forced.
The messages you show are definitely the removal of the old library.
Post by Christophe Osuna
[...]
On the next reboot I have to delete /lib/libc-2.5.so.old
This is what I do not like...
Post by Christophe Osuna
I am a bit confused: how do the Linux distributions handle this?
They don't work with read-only filesystems.

They unlink the old library, after changing the symlink in /lib .
The dangling file, pending a removal when finally closed, is not
a problem with r/w filesystems.

If you want to remount r/o, I fear you must clean up at next reboot
as you suggest.

/alessandro
Christophe Osuna
2008-04-17 13:28:31 UTC
Permalink
Post by Alessandro Rubini
That's interesting. Most likely the filesystem is pending a write
when the old lib will be closed. It makes sense.
Yes, the pending write operation is the removal of the old library,
replaced by the new one. This can never happen since the library is
used until the very end of the shutting down process (init - busybox,
is dynamically linked on my system).
Post by Alessandro Rubini
If you want to remount r/o, I fear you must clean up at next reboot
as you suggest.
Well, I am not entirely satisfied with a design where "an error is
normal" (fsck complaining), but for now it would be either that or
removing old files at boot (also not very satisfying).

How do people here deal with that kind of upgrades?
Alessandro Rubini
2008-04-17 14:28:57 UTC
Permalink
Post by Christophe Osuna
Yes, the pending write operation is the removal of the old library,
replaced by the new one. This can never happen since the library is
used until the very end of the shutting down process (init - busybox,
is dynamically linked on my system).
I see. So that's why they "init u". I didn't think about it.
Post by Christophe Osuna
How do people here deal with that kind of upgrades?
I think most embedded systems nowadays use initramfs. At least that's
what I do, but I don't use x86, only arm and the like. There, you
don't upgrade packaged but the whole system (they call it "firmware
upgrade"). I prefer to upgrade in parts: /usr is external (flash) and
done file-by-file, while / is initramfs and is erased and rewritten
as a whole.

Unfortunately, I don't think it's trivial to split an hda1 install
into an initramfs + external /usr .

/alessandro
Christophe Osuna
2008-04-17 13:28:31 UTC
Permalink
Post by Alessandro Rubini
That's interesting. Most likely the filesystem is pending a write
when the old lib will be closed. It makes sense.
Yes, the pending write operation is the removal of the old library,
replaced by the new one. This can never happen since the library is
used until the very end of the shutting down process (init - busybox,
is dynamically linked on my system).
Post by Alessandro Rubini
If you want to remount r/o, I fear you must clean up at next reboot
as you suggest.
Well, I am not entirely satisfied with a design where "an error is
normal" (fsck complaining), but for now it would be either that or
removing old files at boot (also not very satisfying).

How do people here deal with that kind of upgrades?
Alessandro Rubini
2008-04-17 14:28:57 UTC
Permalink
Post by Christophe Osuna
Yes, the pending write operation is the removal of the old library,
replaced by the new one. This can never happen since the library is
used until the very end of the shutting down process (init - busybox,
is dynamically linked on my system).
I see. So that's why they "init u". I didn't think about it.
Post by Christophe Osuna
How do people here deal with that kind of upgrades?
I think most embedded systems nowadays use initramfs. At least that's
what I do, but I don't use x86, only arm and the like. There, you
don't upgrade packaged but the whole system (they call it "firmware
upgrade"). I prefer to upgrade in parts: /usr is external (flash) and
done file-by-file, while / is initramfs and is erased and rewritten
as a whole.

Unfortunately, I don't think it's trivial to split an hda1 install
into an initramfs + external /usr .

/alessandro
Christophe Osuna
2008-04-17 12:30:48 UTC
Permalink
Post by Alessandro Rubini
Post by Christophe Osuna
3. Tell the kernel not to delete the file when it is overwritten. How?
By creating a hard link.
Not really. When you open the file for writing, it gets truncated. Anybody
who is using the file will have problems.
If you first unlink the file, any user will remain happy (the
filesystem storage is recovered when the file is no more in use, no
need to unlink at next reboot).
However, after you unlinked a shared library, no dynamic executable
using it can start any more (but the ones running keep happily
running).
So, right after the unlink(2) you need rename(2). You need them both
in the same executable.
"mv" does succeed and the applications are not annoyed by this change;
the filesystem is, however. See below:

~# cd /lib
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
/lib#

And after rebooting:

Checking root filesystem...
e2fsck 1.40.2 (12-Jul-2007)
/dev/hda1 was not cleanly unmounted, check forced.
Pass 1: Checking inodes, blocks, and sizes
Deleted inode 26549 has zero dtime. Fix? yes

Deleted inode 44964 has zero dtime. Fix? yes

Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
Block bitmap differences: -(113601--114688) -(114946--115321) -(182785--183392)
Fix? yes

Free blocks count wrong for group #13 (6238, counted=7326).
Fix? yes

Free blocks count wrong for group #14 (5150, counted=5526).
Fix? yes

Free blocks count wrong for group #22 (4872, counted=5480).
Fix? yes

Free blocks count wrong (407568, counted=409640).
Fix? yes

Inode bitmap differences: -26549 -44964
Fix? yes

Free inodes count wrong for group #13 (1979, counted=1980).
Fix? yes

Free inodes count wrong for group #22 (1956, counted=1957).
Fix? yes

Free inodes count wrong (119071, counted=119073).
Fix? yes


/dev/hda1: ***** FILE SYSTEM WAS MODIFIED *****
/dev/hda1: 1287/120360 files (2.6% non-contiguous), 71144/480784 blocks


Below is an example of the "hard links" solution:

~# cd /lib
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# ln libc-2.5.so libc-2.5.so.old
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
/lib#

On the next reboot I have to delete /lib/libc-2.5.so.old

This would probably work. Since I am using RPM packages I intend to do
the hard link in the preinstall-script.

I am a bit confused: how do the Linux distributions handle this? I had
a look at the glibc SRPM from OpenSUSE 10.2 and the only thing related
to this is a call to "telinit u" so that it re-executes itself. But
why that, since /sbin/init is not a dynamic executable? I believe I
would need something similar in busybox but I can't imagine the amount
of work it would be to allow busybox to re-execute itself while
preserving its state.
Alessandro Rubini
2008-04-17 12:49:27 UTC
Permalink
Post by Christophe Osuna
/lib# mount -o remount,rw /
/lib# cp libc-2.5.so libc-2.5.so.new
/lib# mv libc-2.5.so.new libc-2.5.so
/lib# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
That's interesting. Most likely the filesystem is pending a write
when the old lib will be closed. It makes sense.
Post by Christophe Osuna
/dev/hda1 was not cleanly unmounted, check forced.
The messages you show are definitely the removal of the old library.
Post by Christophe Osuna
[...]
On the next reboot I have to delete /lib/libc-2.5.so.old
This is what I do not like...
Post by Christophe Osuna
I am a bit confused: how do the Linux distributions handle this?
They don't work with read-only filesystems.

They unlink the old library, after changing the symlink in /lib .
The dangling file, pending a removal when finally closed, is not
a problem with r/w filesystems.

If you want to remount r/o, I fear you must clean up at next reboot
as you suggest.

/alessandro
Denys Vlasenko
2008-04-17 10:56:07 UTC
Permalink
Post by Alessandro Rubini
Post by Christophe Osuna
3. Tell the kernel not to delete the file when it is overwritten. How?
By creating a hard link.
Not really. When you open the file for writing, it gets truncated. Anybody
who is using the file will have problems.
If you first unlink the file, any user will remain happy (the
filesystem storage is recovered when the file is no more in use, no
need to unlink at next reboot).
However, after you unlinked a shared library, no dynamic executable
using it can start any more (but the ones running keep happily
running).
So, right after the unlink(2) you need rename(2). You need them both
in the same executable.
unlink is not really needed, rename will succeed even without it:

# >z
# >zz
# strace mv z zz
execve("/bin/mv", ["mv", "z", "zz"], [/* 32 vars */]) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
getuid32() = 0
stat64("zz", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
access("zz", W_OK) = 0
rename("z", "zz") = 0 <============ atomically deleted zz and moved z to zz
_exit(0) = ?
Post by Alessandro Rubini
And it's safer if it is a static one
(as Denys suggested) although you might as well manage to work
with a dynamic one.
I recommend having static mv (and a few other utils)
for this use case purely for paranoid reasons - if you _do_
screw up your /lib by accident, you may want to have
tools which continue working.
--
vda
Luciano Rocha
2008-04-17 14:29:19 UTC
Permalink
Post by Christophe Osuna
I am facing a problem that some of you have probably encountered; I
hope you can provide me with some advice.
I am unsuccessfully trying to upgrade the glibc on my busybox system
1. remount / rw
Here everything is fine.
2. copy new files
Using the "cp" command crashes the system (the system will not respond
to key presses and the library file is corrupted).
# WARNING ! THIS WILL PROBABLY CRASH YOUR COMPUTER
$ cp /lib/libc-2.5.so /tmp/libc-2.5.so.new
$ cp /tmp/libc.so.new /lib/libc-2.5.so
A suggestion: don't change /lib. Create a copy, like /lib.new, make
changes (unlink any existing file prior to updating, or the kernel may
tell you that text (code) file is busy), then do the move:

1. mv /lib /lib.old
2. mv /lib.new /lib

If mv isn't statically compiled, you *may* have luck running it like:
/lib.new/ld-linux.so.2 --library-path /lib.new /bin/mv /lib.new /lib

Afterwards, as some programs will still be using the old libc, you won't
be able to remount read-only.
--
lfr
0/0
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://busybox.net/lists/busybox/attachments/20080417/e7d36ff4/attachment.pgp
Christophe Osuna
2008-04-16 14:34:13 UTC
Permalink
I am facing a problem that some of you have probably encountered; I
hope you can provide me with some advice.

I am unsuccessfully trying to upgrade the glibc on my busybox system
with the following steps:

1. remount / rw

Here everything is fine.

2. copy new files

Using the "cp" command crashes the system (the system will not respond
to key presses and the library file is corrupted).

# WARNING ! THIS WILL PROBABLY CRASH YOUR COMPUTER
$ cp /lib/libc-2.5.so /tmp/libc-2.5.so.new
$ cp /tmp/libc.so.new /lib/libc-2.5.so

I have managed to install the file by installing a home-made RPM
package with the "new" file (in fact same as the old one); it also
works with a .tar archive.

3. remount / ro

Things in step 2 didn't go so well even though they looked successful,
for mount will not remount / ro because of a "device or resource
busy".

4. reboot

As the root filesystem could not be remounted read-only fsck complains
and finds problems.

Below is the output of the "lsof" command before and after a glibc
upgrade. It shows that the init process (busybox) is using glibc files
and references files by their inode number after the upgrade.

~# /tmp/lsof|head
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
init 1 root cwd DIR 3,1 1024 2 /
init 1 root rtd DIR 3,1 1024 2 /
init 1 root txt REG 3,1 618184 73446 /bin/busybox
init 1 root mem REG 0,0 0 [heap] (stat:
No such file or directory)
init 1 root mem REG 3,1 1491141 20429 /lib/libc-2.5.so
init 1 root mem REG 3,1 190963 20427 /lib/libm-2.5.so
init 1 root mem REG 3,1 47607 20436 /lib/libcrypt-2.5.so
init 1 root mem REG 3,1 129767 20432 /lib/ld-2.5.so
init 1 root 0u CHR 5,1 219 /dev/console (deleted)
~# mount -o remount,rw /
~# rpm -ivh /tmp/glibc-2.5-1.i586.rpm
Preparing... ########################################### [100%]
1:glibc ########################################### [100%]
~# mount -o remount,ro /
mount: mounting /dev/hda1 on / failed: Device or resource busy
~# /tmp/lsof|head
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
init 1 root cwd DIR 3,1 1024 2 /
init 1 root rtd DIR 3,1 1024 2 /
init 1 root txt REG 3,1 618184 73446 /bin/busybox
init 1 root mem REG 0,0 0 [heap] (stat:
No such file or director)
init 1 root mem REG 3,1 20429
/lib/libc-2.5.so (path inode=20462)
init 1 root mem REG 3,1 20427
/lib/libm-2.5.so (path inode=116283)
init 1 root mem REG 3,1 20436
/lib/libcrypt-2.5.so (path inode=11628)
init 1 root mem REG 3,1 20432
/lib/ld-2.5.so (path inode=20461)
init 1 root 0u CHR 5,1 219 /dev/console (deleted)

Well, this makes sense but is quite annoying: does that mean that I
cannot upgrade the glibc in a dynamically-linked busybox?

I have two solutions in mind but I would greatly appreciate others:

1. Use a static link. This means that the glibc will be "installed"
twice: in the busybox executable and in the system, I don't like it.
Besides this was discouraged in some busybox versions if I remember
well.

2. Upgrade from an initramfs. This is annoying because I download
updates from the network, which means that the network would have to
be configured (DHCP...) in the initramfs and also in the system.

Busybox version is 1.8.2 and glibc is a copy of OpenSUSE 10.2 files,
but I think this does not matter here.

Thanks.
Christophe Osuna
2008-04-17 09:03:50 UTC
Permalink
Post by Christophe Osuna
I am unsuccessfully trying to upgrade the glibc on my busybox system
(...)
In fact the issue is not specific to glibc; any file in use will lead
to the same problem. The kernel wants to delete the old file from the
filesystem, but since it is still in use it can't do that.
Post by Christophe Osuna
1. Use a static link. This means that the glibc will be "installed"
twice: in the busybox executable and in the system, I don't like it.
Besides this was discouraged in some busybox versions if I remember
well.
This does not solve the problem.
Post by Christophe Osuna
2. Upgrade from an initramfs. This is annoying because I download
updates from the network, which means that the network would have to
be configured (DHCP...) in the initramfs and also in the system.
3. Tell the kernel not to delete the file when it is overwritten. How?
By creating a hard link. When the file is no longer used (next reboot)
it is safe to delete the hard link. This is more satisfactory than the
previous solution but it is not still perfect.

Any other idea?
Denys Vlasenko
2008-04-17 09:23:25 UTC
Permalink
Post by Christophe Osuna
I am facing a problem that some of you have probably encountered; I
hope you can provide me with some advice.
I am unsuccessfully trying to upgrade the glibc on my busybox system
1. remount / rw
Here everything is fine.
2. copy new files
Using the "cp" command crashes the system (the system will not respond
to key presses and the library file is corrupted).
# WARNING ! THIS WILL PROBABLY CRASH YOUR COMPUTER
$ cp /lib/libc-2.5.so /tmp/libc-2.5.so.new
$ cp /tmp/libc.so.new /lib/libc-2.5.so
Do not use cp. You need to replace files atomically. mv is better.

mv /somewhere/else/libc-2.5.so /lib/libc-2.5.so

You may need mv which is statically linked (does not require /lib/libc-2.5.so).
But since libc has more than one file, more generic way is:

Assuming that all new .so files are staged in /somewhere/else/*:

cp -dpR /lib /lib.old # backup copy of entire dir
mv /somewhere/else/* /lib

Again, you may need "static" mv for second step.
--
vda
Alessandro Rubini
2008-04-17 10:03:33 UTC
Permalink
Post by Christophe Osuna
3. Tell the kernel not to delete the file when it is overwritten. How?
By creating a hard link.
Not really. When you open the file for writing, it gets truncated. Anybody
who is using the file will have problems.

If you first unlink the file, any user will remain happy (the
filesystem storage is recovered when the file is no more in use, no
need to unlink at next reboot).

However, after you unlinked a shared library, no dynamic executable
using it can start any more (but the ones running keep happily
running).

So, right after the unlink(2) you need rename(2). You need them both
in the same executable. And it's safer if it is a static one
(as Denys suggested) although you might as well manage to work
with a dynamic one. After the "mv" (unlink and rename) new programs
will start with the new library, and old ones will continue to run
with the old library until killed.

Actually, shared libraries are often symlinks, so you can install the
new one (different minor number), change symlink (unlink and
ln from a single program) and then delete the old library.

Example: keeping a file open after it's deleted:

rudo% touch deleteme
rudo% sleep 60 < deleteme &
[3] 23219
rudo% rm deleteme
rudo% ls -l /proc/23219/fd
total 0
lr-x------ 1 rubini staff 64 Apr 17 11:57 0 -> /tmp/deleteme (deleted)
lrwx------ 1 rubini staff 64 Apr 17 11:57 1 -> /dev/ttyq6
lrwx------ 1 rubini staff 64 Apr 17 11:57 2 -> /dev/ttyq6

Example: reading a file after it's deleted:

rudo% echo bu > deleteme
rudo% ( sleep 2 ; cat ) < deleteme ; rm deleteme
bu

/alessandro
Luciano Rocha
2008-04-17 14:29:19 UTC
Permalink
Post by Christophe Osuna
I am facing a problem that some of you have probably encountered; I
hope you can provide me with some advice.
I am unsuccessfully trying to upgrade the glibc on my busybox system
1. remount / rw
Here everything is fine.
2. copy new files
Using the "cp" command crashes the system (the system will not respond
to key presses and the library file is corrupted).
# WARNING ! THIS WILL PROBABLY CRASH YOUR COMPUTER
$ cp /lib/libc-2.5.so /tmp/libc-2.5.so.new
$ cp /tmp/libc.so.new /lib/libc-2.5.so
A suggestion: don't change /lib. Create a copy, like /lib.new, make
changes (unlink any existing file prior to updating, or the kernel may
tell you that text (code) file is busy), then do the move:

1. mv /lib /lib.old
2. mv /lib.new /lib

If mv isn't statically compiled, you *may* have luck running it like:
/lib.new/ld-linux.so.2 --library-path /lib.new /bin/mv /lib.new /lib

Afterwards, as some programs will still be using the old libc, you won't
be able to remount read-only.
--
lfr
0/0
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.busybox.net/pipermail/busybox/attachments/20080417/e7d36ff4/attachment-0002.pgp
Loading...