How Puppy works |
|
Page updated: 9 Sept 2006
In January 2006 I commenced work on a total redesign of the underlying structure of Puppy, nicknamed "puppy2". If you have a Puppy with version number 0.x or 1.x then you have the previous architecture -- let's call it "puppy1". As puppy1 is widely in use, the explanation of how he works is retained and I have split this page into two: the top half is for puppy2 and the bottom half for puppy1.
How Puppy works, take 2
Puppy2 is revolutionary, and the question on your mind if you have
studied Puppy1 is "Will I have to relearn everything?", or "Is it more
complicated than puppy1?"
The answer to the first question is no, you will find much in common. From a users point of view, it is still the same Puppy, apparently unchanged. Under the hood, from the developers point of view, the basic ideas, such as running in RAM, are still there -- just some implementation details have changed.
The answer to the second question is no, puppy2 is actually simpler.
The startup and shutdown scripts are simpler. Options required in the
isolinux.cfg or syslinux.cfg files are simpler.
Is puppy2's underlying architecture based on another distro? In
other words, did I get the idea from somewhere? No, it gradually
crystallised in my mind. There is a slight resemblance to Noppenlinux,
but I found that out afterward.
The rationale for puppy2
As puppy1 was chugging along quite nicely, why make the change?
I can give several reasons, but I guess what it comes down to is the
change just had to happen. The improvements of puppy2 are just too
good. Um, let me have a go at itemising how puppy2 is better:
- Works with any size Flash drive (minimum 128M).
- Saves ramdisk (your working files) to Flash drive every 30 minutes, so extending lifetime of flash media (by restricting the number of writes).
- Works on PCs with very little RAM, probably as little as 32M.
- Boots very fast.
- Defaults to running totally in ramdisk on first boot.
- The entire filesystem, that is, "/", is writable and is saved.
- Much simpler structure.
- Simplified boot params. Ex: "PMEDIA=usbflash" is all that is needed to boot from usb pen drive.
- "image.gz size problem" eliminated.
- Iso file can now grow from 60-65M to 65-70M.
- Improved security.
- Simplified, more reliable multisession CD/DVD management.
- One iso for normal and multisession.
1. Works with any size Flash drive
USB and CF (CF card may be plugged into USB or IDE interfaces by a
suitable adapter) Flash drives are getting bigger. 1G is now common and
dropping in price. The way that we have been using Puppy1 is to create
a "pup100" file (the name of the personal storage file in Puppy1) on the USB drive, which has a ext2 filesystem. This
file is copied into RAM at bootup, if there is enough RAM, thus
avoiding writes to the Flash drive during a session. Then the files are
copied back at shutdown.
One of the problems is that we find it difficult to make the pup100
file bigger than about 750M. Feedback on the Forum is that there are
problems if we try to put a ext2 f.s. into anything bigger. Also, to
avoid writes to Flash during a session, you would need to copy all of
the pup100 files contents into RAM, meaning that you will need a massive amount of RAM.
Puppy2 has two solutions.
Solution 1:
One solution is not to use a "pup100" file at all. When you purchase a
Flash drive, it is invariably pre-formatted with a FAT16 filesystem,
and we normally leave that as-is. However, if we replace that with a
ext2, ext3 or reiserfs filesystem (a Linux filesystem), then the entire
partition can be used for personal data storage.
Meaning
that you have the entire drive available for personal storage, nothing to resize later. Furthermore,
writes to Flash during a session are eliminated, regardless of how big
the partition is, and regardless how small your PC's RAM.
Oh, a little note. The ext2/3 personal storage file "pup100" is renamed as "pup_save.3fs". Previously, we used a naming scheme "pupxxx" where the "xxx" was an arbitrary number. To simplify the naming, puppy2 has just one name, "pup_save.3fs", where the ".3fs" means that the file has a ext3 filesystem.
The downside of reformatting the Flash drive with a Linux filesystem
is it becomes more difficult to share files with Windows. That is, if
you boot Windows, plug in the Flash drive, Windows won't recognise it.
However, there is a native ext2/3 driver for NT/XP, and there are also
some Windows applications that allow viewing and reading files from a
ext2/3 filesystem.
Solution 2:
If you want to stay with the puppy1 approach and retain a personal
storage file, now named pup_save.3fs, no problems. Now, you can make it
any size, up to 750M (or bigger maybe), and writes
to Flash during a session are eliminated, regardless of how big the
pup_save.3fs file is, and regardless how small your PC's RAM.
2. Eliminates writes to Flash drive
Notice the bold text above. If you have, say, a 750M pup_save.3fs
file and the PC has only 256M total RAM, maybe not even any swap
partition or swap file, how on earth does puppy2 avoid writing to the
Flash drive during a session?
This is one of the key architectural points of puppy2. At bootup,
pup_save.3fs is mounted read-only from where it is on the Flash drive,
and it's contents are not copied into RAM. Instead, a tmpfs filesystem
in RAM holds all new and changed files. This is still actually very
fast, as all the "working files" are in RAM.
Periodically and at end of session, those "working files" are
written back to the pup_save.3fs file. Or to the partition if you chose
the "solution 1" described above.
What this means in practice is you could have a PC with maybe as
little as 64M RAM, booting off a 1G Flash drive, and all writes to
Flash are eliminated during a session, and it runs fast.
Seems like magic, hey?
3. Works on PCs with very little RAM
Puppy2 will take advantage of more RAM, but if your PC is RAM-challenged, no problem.
The key point here is that the personal storage (I also refer to
this as the persistent storage) partition or pup_save.3fs file is not
loaded into RAM, only mounted read only, and only the "working files"
are in RAM.
What you will have in a RAM-challenged PC is the kernel, initrd.gz
(uncompressed) and the "working files" in RAM. Those "working files"
are only new and changed files, so there will hardly be anything in
RAM, meaning that we are going to find our Pup running on very minimal
systems ....we have yet to find out how little RAM will work.
Note though, the set of "working files" will grow during a session.
Any new or modified file will get added to it. However, there is a
daemon (a background program) that will warn if RAM space is running
low, then there is a simple fix -- flush the "working files" to the
persistent storage (which currently requires a reboot).
Now, you may think, isn't that still going to be slow? Okay, having
the "working files" in RAM is good, but when you want to start a big
application, such as Mozilla, all of the Moz libraries will have to
load off the Flash drive.
Yes, true, so the RAM-challenged PC will run a bit slower.
If your PC does have more RAM, say 128M or more, puppy2 will
automatically see that and will load the "pup_xxx.sfs" file into RAM.
This file is the same as the "usr_cram.sfs" and "image.gz" files in
puppy1 combined. Puppy1 also loaded image.gz and if enough RAM also
loaded usr_cram.fs into RAM.
So, if the PC has enough RAM then all the library files will be
preloaded into RAM, so you will get the advantage of fast application
startup for which Puppy is so famous.
4. Boots very fast
Booting from USB Flash is now much faster.
The puppy1 boot sequence is the file image.gz is loaded into a
ramdisk, then the file usr_cram.fs, which has most of the Puppy files,
is copied into the ramdisk (if there is enough RAM) and then mounted on
/usr. The image.gz file is about 6.5M, and this takes awhile to load.
If the USB interface is USB2 (rather than the older USB1) then the
usr_cram.fs file should load quite fast, although being about 53M.
Puppy2 has a much smaller initial ramdisk file, named initrd.gz
(instead of image.gz), only about 1.1M, and this accounts for a
significantly faster boot time.
5. Defaults to running totally in ramdisk on first boot
Puppy1 users will know about a problem, a
"catch 22" situation. The very first time that you boot the Puppy
live-CD on a computer, a personal storage file named "pup001" is
created automatically. This is a problem if it gets created on, say,
/dev/hda1, the "C: drive", but you want to install Puppy to that
partition. Our workaround was a menu with boot option to not create
pup001 and just run in ramdisk.
I'm trying to get Puppy2 away from needing any menu (and subsequent
pause) at bootup. Puppy2 tackles the problem the other way round, by
always booting up in ramdisk-only the first time you boot on a PC, then at
shutdown you are asked if you want to create a personal storage file.
If you answer yes, it will get created and automatically used next time
you boot Puppy.
Note, some people considered that Puppy should boot up only in
ramdisk by default, for "ethical" reasons. Or maybe, "stealth" or
"non-invasive" reasons. Whatever, your wish is now reality.
6. The entire filesystem is writable
Puppy1 has a rather complicated system whereby the home directory
(/root) is writable, and /etc and /usr are made writable by actually
saving the files inside /root.
The persistent storage file pup001 mounts on /root. The original files
of /usr are in a compressed read only file called usr_cram.fs.
Puppy2 mounts the persistent storage file pup_save.sfs at the top
level, that is, on "/". The read only compressed file with all the
Puppy files, pup_xxx.sfs, mounts on "/" also.
Having only part of the directory hierarchy writable is a hassle when installing packages. Puppy2 solves this problem.
7. Mucher simpler structure
Point 6 above also means that the directory hierarchy is now "normal", like other
Linux distros. Puppy1 had /etc as a symbolic link to /root/.etc, and
writes to /usr saved in /root/.usr. Puppy2 does not have /root/.etc or
/root/.usr.
In fact, simplification can be seen everywhere. Especially the
bootup and shutdown scripts. Look inside /etc/rc.d and you will find
less scripts and they are also smaller and simpler.
8. Simplified boot params
Puppy1 has various parameters that can be placed in the isolinux.cfg, syslinux.cfg, Grub or Lilo boot configuration files. These are kernel boot paramters, that get passed through to the bootup scripts. Some of them are PHOME, PROOTFS, PSLEEP, PFILE, PKEYS (see here for details).
Puppy2 has retained only two Puppy-specific boot parameters, PMEDIA
and PKEYS, greatly simplifying the procedure of setting up a bootable
Puppy
installation.
Puppy users will already know about PKEYS, which specifies a
keyboard layout, for example "PKEYS=us". PMEDIA provides a hint to
Puppy as to what media you are booting off, for example
"PMEDIA=usbflash", however even this is optional, and if there is no
PMEDIA parameter Puppy will ransack the entire PC and find the Puppy
files.
9. "image.gz size problem" eliminated
People who have remastered Puppy1 may have encountered this problem.
The kernel is configured with a 12288K maximum ramdisk (increased to 13824K for Puppy 1.0.8), and image.gz
once expanded has to fit into this. If bigger, the boot parameter
"ramdisk_size=" has to be used.
Puppy2 uses a tiny initial ramdisk, initrd.gz, that is only 0.9M compressed.
Installing extra applications, such as DotPups that install into
/root/my-applications, does not add to initrd.gz. The initial ramdisk
file remains fixed in size, and everything under "/" goes into
pup_save.3fs, the squashfs file that gets attached later in the boot
process.
A technical detail here: it is only the initial ramdisk file that
loads into the fixed-size-limit ramdisk. The boot sequence then creates
a tmpfs ramdisk, which is variable in size, and will use as much RAM
and swap space as available.
Puppy1's image.gz has another problem: most of its files are "dead
weight". It has about 5M of kernel modules, of which only a few get
loaded at bootup, and then they just sit there in RAM taking up space.
On a RAM-challenged PC, 5M is a lot to throw away.
10. Iso file size can grow from 60-65M to 65-70M
The live-CD version 1.0.x is about 55M - 60M, and that size is very
deliberate. One of the mission statements was that Puppy will run
"fast" in a PC with only 128M RAM. On a PC with less RAM, Puppy will
still run, but slower. To run "fast", the RAM must hold both image.gz
and usr_cram.fs. Less RAM, and usr_cram.fs has to be left on the CD or
wherever. Or there may be a swap file/partition, but that is
going to be slow also.
image.gz is 6.5M compressed, about 12.5M uncompressed, and it is the latter that occupies the ramdisk in RAM.
Puppy2's initrd.gz is 0.9M compressed and 1.6M uncompressed, and it
is the latter that occupies the ramdisk in RAM. Calculate the freed-up
RAM: 12.5 - 1.6 gives about 11M.
Well, I won't torture you with laborious calculations, just get to
the point: as much of what was previously in the uncompressed initial
ramdisk has moved to the squashfs compressed pup_xxx.sfs file, it turns
out that the Puppy2 live-CD iso file can now grow
to 70M and still run "fast" in a 128M PC.
11. Imroved security
To be written
12. Simplified, more reliable multisession CD/DVD
Puppy 1.0.x has a complex multisession management mechanism. It also has reliability problems.
Puppy2 leverages off the unionfs layer management mechanism.
Basically, the top layer (pup_rw), is a tmpfs filesystem in ramdisk,
containing all the new and changed directories and files. At shutdown,
the top layer is saved to a new folder on the CD/DVD -- that's it, session
saved.
At bootup, the saved folders are read off the DVD in reverse order
(latest first), writing the latest of each file to the second layer
(pup_ro1). Thus, all the previous personal data is loaded into the
second layer. The top layer once again will become the next saved
folder. (these "layers" are explained below)
Note, unionfs has a mechanism for handling deleted directories and
files, and Puppy's multisession management utilises this. A file named,
say, /bin/testfile in the second layer, is deleted at the top layer by
creation of /bin/.wh.testfile. At shutdown, this "deletion marker" file
is saved to a the latest session folder on the DVD. At bootup, Puppy
reads the folders in reverse order and is able to determine what
directories and files in lower folders have been deleted and hence must
not be loaded back to the second layer, pup_ro1.
13. One iso for normal and multisession
There is only the one iso file that is burnt to CD or DVD. At first
bootup, Puppy runs totally in RAM. The difference comes at shutdown.
Assuming that the user has burnt the iso file to CD/DVD as "open" or
multisession, at shutdown the user can choose to either save the
session in the normal way as a pup_save.3fs file in a partition of
choice, or there is the option of saving the session back to the CD/DVD.
At the second bootup, Puppy will recognise that a session has been
saved on the CD/DVD media and from then on will behave as a multisession
CD/DVD.
Summary
In summary, puppy2 is faster at bootup and shutdown, works better on
older hardware, more flexible and expandable in the future, more
standardised, and considerably simpler.
Architecture Overview
This diagram (created in Sodipodi) is the big picture:
The way to understand the diagram is to view each of those layers as
a complete filesystem, that is, a complete directory hierarchy from "/"
down. These layers are laid one on top of the other, which is achieved
by the unionfs filesystem. The way it works is very simple: say that
the "off-pink" layer has a file /usr/lib/libgdkxft.so. This file will be
visible at the top layer. If the "off-blue" layer has the same file,
it will not be visible, as it is overlaid by the same file on a higher
layer.
Anyway, here is a description of each layer:
ramdisk |
This is the tmpfs filesystem running in RAM, with new and changed files. |
pup_save.3fs |
This is the persistent storage,
where all your data, settings, email, installed packages, etc., get
saved permanently. The ".3fs" means that the file contains a ext3
filesystem. |
pup_xxx.sfs |
This is Puppy. The builtin
applications, window manager, scripts, everything. The ".sfs" means the
file contains a squashfs compressed filesystem. The "xxx" is the Puppy
version number without the dots, for example "200". |
*_xxx.sfs |
These are additional squashfs
files. The "*" can be anything. For example, devx_xxx.sfs is the
complete environment for compiling C/C++ applications. |
What needs to be emphasised however is that all of this is "under
the hood". While running Puppy, all you see is one filesystem, which is
the top layer. Thus you see /usr/lib/libgdkxft.so and you don't care
what layer it is actually on.
An exciting alternative to the squashfs extensions is to use an existing installed Linux distro as the bottom layer:
What the above diagram is intended to convey is that the bottom layer
is a partition, not the "underdog.lnx" file itself. File underdog.lnx
is just a text file, containing the name of a partition, for example
"hda1".
At bootup Puppy will read underdog.lnx and will mount the partition as
the bottom layer. If that partition happens to have a Linux distro
installed in it, then the entire distro filesystem will "show through"
on the top layer of Puppy's unionfs.
It will look like a normal Puppy, running JWM window manager or
whatever, same desktop, but everything in the underlying distro is
available to be executed. All the applications, compile environment,
package manager, etc.
So, you have seen from the above two diagrams that the unionfs
layers can vary. There are other variations, and Puppy has a "state
variable" named PUPMODE that shows what state (configuration of layers)
Puppy is currently using.
There is a file, /etc/rc.d/PUPSTATE that has the PUPMODE variable defined in it, for
example, "12", and this is the current layer-configuration. Each
PUPMODE value needs its own description...
PUPMODE 5
This is the configuration the very first time that Puppy is booted
from live-CD or USB Flash drive. I'll concentrate the description for
now on the live-CD, as that will most likely be your first exposure to
Puppy.
The first time that you plug in the live-CD and bootup, there is no
persistent storage, and the "union" consists of only two layers, the
top "working files" and the pup_xxx.sfs squashfs filesystem that has
all the Puppy files. These two layers appear overlaid at "/", however
they can be viewed individually, at their respective mount points. The
tmpfs ramdisk is mounted read-write on /initrd/pup_rw and pup_xxx.sfs
is mounted read-only on /initrd/pup_ro2.
So, you are using Puppy but not touching the hard drive at all. You
can run applications, configure, download, install packages, but it is
all happening in the tmpfs ramdisk, so not getting saved. The amount
of space you have in the ramdisk depends on how much RAM is in the PC
(and whether there is a Linux swap partition).
The really interesting part is when you decide to end the session
and shutdown the PC. The shutdown script, which is actually
/etc/rc.d/rc.shutdown, will execute and will bring up a dialog window
asking you where you want to save the session to. That is, whatever
directories and files that have been created in the ramdisk can now be
saved. At this point you have many choices...
Okay, if this is a live-CD that you have booted off, you would
choose to save to a hard drive partition normally, but you could also
choose a floppy drive, a USB drive, or even back to the CD/DVD (as long
as it was burned "open" or "multisession"). It's very simple: a GUI
dialog window offers a list of partitions and you choose the one you
want.
Not
only does the shutdown dialog offer a wide range of devices to save to,
but it also gives a choice of saving to a file or to a
partition. That is, you can have a file named pup_save.3fs with a ext3
filesystem inside it, nominally 512M in size (actually, the size is also selectable), or Puppy can take over an
entire partition in which to save. The choice of file or partition
depends on whether a partition is a Linux filesystem -- if only a FAT
filesystem, then only a pup_save.3fs file can be created.
For now, let's go for the most common choice, saving to a pup_save.3fs file in a hard drive partition...
PUPMODE 12
The second time that you boot your Puppy live-CD, assuming that you chose to save the previous session to a pup_save.3fs file in a Linux, FAT or NTFS partition, Puppy will be in PUPMODE 12.
What has happened here is that at bootup Puppy found the pup_save.3fs
file is on a fast hard drive partition, so decided to mount it directly
on the top layer. Thus, there is no tmpfs ramdisk intermediary. File
pup_save.3fs is directly read and written to.
This scenario is very good for RAM-challenged PCs. The initial
ramdisk, that is, the file initrd.gz that gets loaded first when Puppy
boots, is still there in ram, mounted at /initrd, however it only uses
about 1.9M.
Okay, let's change to a different situation. Say that you installed Puppy to a USB Flash drive...
PUPMODE 13
If you install Puppy to a USB Flash drive, perhaps by using the
Puppy Universal Installer program, or manually, you will have a
bootable drive with the files vmlinuz (the Linux kernel), initrd.gz
(the initial ramdisk), pup_xxx.sfs (squashfs filesystem with all the
Puppy files) and syslinux.cfg (Syslinux config file). The situation is
just like booting from a live-CD -- on first boot Puppy will be in
PUPMODE 5, as no persistent storage has yet been created. On first
shutdown, as described in the PUPMODE 5 section above, you will create
a persistent storage -- either a pup_save.3fs file or an entire
partition.
On the second boot, Puppy will discover the persistent storage, but in this case will realise that it is on a media for which writes need to be severely constrained. Therefore, Puppy will come up in PUPMODE 13.
In the above diagram, the top layer is a tmpfs ramdisk, into which all new and modified directories go. It is the working area, and has the potential limitation of the amount of RAM available. But of course, if the hard drive has a Linux swap partition that will be used to increase the effective size of the ramdisk.
In the case of the persistent storage on Flash memory, which is the
second layer (off-orange color), Puppy will save everything from the
top layer to the second layer every 30 minutes. From the "unionfs"
point of view, the second layer is mounted read-only, it is only the
top layer that is written to, however Puppy is able to "flush" the top
layer down to the next layer at periodic intervals.
Actually, a technical detail here. "Flush" is not quite the right
word. Ideally, I would have liked to do that, save everything down to
the persistent storage layer, then the top layer would be empty thus
giving you a completely empty ramfisk. However, when I tried to do
that, unionfs crashed. So, the compromise is that the contents of the
top layer is copied down to the next layer -- that is officially
supported by unionfs.
it does mean however, that the ramdisk never gets really flushed, so if
you download lots of stuff, or install a big package, you can fill it
up. To get around this problem, Puppy has a background program (a
daemon) that will warn if RAM space is getting low. Perchance you do
run low on RAM, the cure is simple: reboot.
A note about the second layer. It is the persistent storage, but as mentioned in the PUPMODE 5 section above, at the first shutdown you are offered to create persistent storage in either a file (pup_save.3fs) or a partition. In the latter case, the session can be saved to an entire partition, but only if it is a Linux partition. In that case, what gets mounted on the second layer (off-orange layer) will be a partition, not a file.
In the case of booting off a USB Flash device, to use the entire
partition for personal storage is real nice. The pup_save.3fs file is a
limited size, nominally 512M or smaller if the partition does not have
enough room. There are also reports on the Puppy forum that it can only
be increased to 750M - 1G. ...well, I guess that's okay for most USB
Flash drives!
If you did choose to save sessions directly to the USB partition, it
has to be a Linux partition, that is, have a ext2, ext3 or reiserfs
filesystem. Whereas, saving to a pup_save.3fs file, the USB partition
can be anything -- it's factory setting is a FAT16 filesystem, which is
fine.
PUPMODE 2
Many Puppy users will know that there are two ways to install Puppy
to hard drive: what we called "option1" or "option2" installations.
Option1 is the less-invasive choice, which just copies the files
vmlinuz, initrd.gz and pup_xxx.sfs to a chosen partition. The Puppy
Universal Installer offers to create a floppy boot disk to boot Puppy
installed in this way (but currently the boot floppy will only boot
Puppy installed on a FAT partition). It is also possible to configure
Grub or Lilo to
boot Puppy. The advantage of this option is that it doesn't impact on
the partiton in any way and whatever is already in the partition, like
Windows or another Linux distro, is unaffected.
For an option1 h.d. installation, Puppy will bootup in PUPMODE 12.
Option2 is to install Puppy to an entire partition, which has to be a Linux partition (ext2, ext3, or reiserfs). This is recommended for developers or anyone wanting to compile applications, as it gives you lots of room.
This is the absolute simplest configuration. There is no ramdisk,
the partition itself is mounted directly on the top "layer". In fact,
if there are no ".sfs" extensions to load then Puppy will not use
unionfs at all, so there are no layers.
PDEV1 is actually a variable in the file /etc/rc.d/PUPSTATE, that contains the name of
a partition, for example "hda1", which is the partition to mount. The
partition is mounted directly on "/".
Heh heh, but of course, how to know what PDEV1 is at bootup? Saying
it is in /etc/rc.d/PUPSTATE in the partition itself is putting the egg
before the chicken. That file is really just for scripts, so that they
know what Puppy has booted off.
The way Puppy is booted in this case is from a floppy disk or USB
Flash drive "boot disk", or via Grub or Lilo. The Puppy Universal
Installer allows you to create any or all of these three: floppy, USB,
Grub.
PUPMODE 77
This is for the multisession CD or DVD. In this case, the persistent storage is composed of folders on the CD/DVD. At each shutdown, the session is saved to a folder, so the CD/DVD accumulates folders. At bootup, these folders are read in reverse order and loaded into ramdisk.
At bootup, the folders are read from the CD/DVD and loaded into the
second layer (off-orange). During a session, new and changed
directories and files will be written to the top layer (off-green). At
shutdown, the top layer is written as a new folder on the CD/DVD.
The rationale behind PUPMODE numbering
I was duscussing PUPMODEs recently with "Phil" on the Puppy Forum. He booted Puppy2 using GRUB,
where initrd.gz (initial ramdisk file), vmlinuz (the kernel) and
pup_xxx.sfs (all the Puppy files) are in a hard drive partition. He then saved the session direct to the boot partition.
Say the partition is /dev/hda2, then the situation looks like this:
partition hda2
all saved sessions here, including file /etc/puppyversion.
/initrd.gz
/pup_xxx.sfs
/vmlinuz
I mention file /etc/puppyversion as that always gets saved at every
session, and Puppy looks for it at bootup to determine that the
partition has saved Puppy files in it.
Note, the files initrd.gz, pup_xxx.sfs and vmlinuz could be in a folder, say /boot, as long as GRUB is configured appropriately.
In Phil's case, Puppy will run in PUPMODE 7, but how is that determined? What is the logic behind it?
The PUPMODE is
a number where each bit ( ... 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0)
is a flag:
BIT-SET DECIMAL-WEIGHT MEANINGFor example, the multisession CD/DVD runs with PUPMODE=77, which is 1+4+8+64. You see, it is quite logical!
0 1 using tmpfs top layer (/initrd/pup_rw) of union.
1 2 boot partition (PDEV1) has puppy sessions saved in it.
2 4 pup_xxx.sfs file exists on boot partition (PDEV1)
3 8 pup_save.3fs file exists (sessions saved to file).
4 16
5 32
6 64 multisession flag.
In Phil's case, Puppy will run in PUPMODE=6 (2+4), as the saved sessions are on a fast media with unlimited write capability so no need for a tmpfs top layer in ram. Note, a tmpfs top layer is an intermediary to hold the working and new files & directories, and is only really needed where we have to restrict writes (ex: flash memory) or where the session is to be saved to very slow media or at specific times (burning a track to multisession CD), or we deliberately want to run totally in ram (as in the very first bootup of Puppy).
A full hard drive installation ("option 2") will run in PUPMODE 2.
The decision which mode to run in is made in the first boot script, /initrd/sbin/init. Though, in the case of a full h.d. install, the initrd.gz is not used at all and the first script that runs is /etc/rc.d/rc.sysinit -- in that case, Puppy assumes PUPMODE=2.
The initial ramdisk
At bootup, the first thing that happens is the Linux kernel,
vmlinuz, is loaded into RAM, followed by the initial ramdisk, which is
file initrd.gz. Note, the exception to this is PUPMODE 2, which is the
full hard drive installation, which does not have a separate initrd.gz
file.
When the initial ramdisk has loaded, the first script that executes is
/sbin/init. Inserted below is a simplified content of this script. This
is for explanation purposes only and the latest version of the script
will be different.
#!/bin/ash
#(c) Copyright 2006 Barry Kauler, www.puppylinux.com
PATH="/bin:/sbin"
KERNVER="`uname -r`"
#Boot param PMEDIA= usbflash|usbhd|usbcd|ideflash|idehd|idecd|idezip|satahd|scsihd|scsicd
#unionfs layers: RW RO1 RO2 PUPMODE
#PUPSFS only: tmpfs pup_xxx.sfs 5
#PDEV1 has puppy: tmpfs PDEV1* 3
#PDEV1 has puppy, no tmpfs: PDEV1 2
#PDEV1, PUPSFS: tmpfs PDEV1* pup_xxx.sfs 7
#unionfs layers: RW RO1 RO2 PUPMODE
#found PUPSFS, PUPSAVE: tmpfs pup_save.3fs* pup_xxx.sfs 13
#PUPSAVE(multi), PUPSFS: tmpfs folders(tmpfs2) pup_xxx.sfs 13+64 = 77
#PUPSAVE, PUPSFS, no tmpfs: pup_save.3fs pup_xxx.sfs 12
fsfunc() #f.s. type param passed in
{
FSTYPE="$1"
[ "$FSTYPE" = "Ext2" ] && FSTYPE="ext2"
[ "$FSTYPE" = "ReiserFS" ] && FSTYPE="reiserfs"
[ "$FSTYPE" = "Ext3" ] && FSTYPE="ext3"
[ "$FSTYPE" = "FAT16" ] && FSTYPE="vfat"
[ "$FSTYPE" = "FAT32" ] && FSTYPE="vfat"
[ "$FSTYPE" = "NTFS" ] && FSTYPE="ntfs"
[ "$FSTYPE" = "ISO9660" ] && FSTYPE="iso9660"
}
guesspmediafunc() {
code to guess PMEDIA if not provided as boot param
}
ispupfunc() #fstype partition
{
code to find persistent storage
}
searchsavefunc() {
code to find pup_save.3fs persistent storage file.
}
findpupfunc() #list of drives (not partitions) to check passed in.
{
code to find boot partition and puppy files
}
loadfolders() { #source folder, dest. folder passed in.
code to load saved session folders off multisession CD/DVD
}
mount -t proc none /proc
PUPPYVERSION="`cat /PUPPYVERSION`"
####LOAD MODULES###########################################
code to load kernel modules here
###########################################################
PDEV1=""
case $PMEDIA in
idecd)
CDDRIVES="`test-eide | grep '\- cdrom \-' | cut -f 1 -d " " | cut -f 3 -d "/" | tr "\n" " "`"
findpupfunc $CDDRIVES
#...return with PDEV1=hdc FSTYPE=iso9660 PUPSFS=pup_001.sfs (for example)
[ ! "$PUPSAVE" ] && searchsavefunc #search for PUPSAVE.
;;
idehd)
HDDRIVES="`test-eide | grep '\- disk \-' | cut -f 1 -d " " | cut -f 3 -d "/" | tr "\n" " "`"
findpupfunc $HDDRIVES
#...return with PDEV1=hda3 FSTYPE=ext3 PUPSFS=pup_001.sfs (for example)
;;
usbflash)
#note, this could be a "superfloppy" with no mbr and no partitions.
USBDRIVES="`cat /proc/partitions | grep "sd[a-z]$" | tr -s " " | cut -f 5 -d " " | tr "\n" " "`"
findpupfunc $USBDRIVES
#...return with PDEV1=sda1 FSTYPE=ext2 PUPSFS=pup_001.sfs DEV1PUP="" (for example)
;;
ideflash)
#this looks like a normal ide drive. Note, may require boot param "ide=nodma"
HDDRIVES="`test-eide | grep '\- disk \-' | cut -f 1 -d " " | cut -f 3 -d "/" | tr "\n" " "`"
findpupfunc $HDDRIVES
#...return with PDEV1=hda1 FSTYPE=ext3 PUPSFS=pup_001.sfs (for example)
;;
idezip) code here
;;
satahd) code here
;;
satacd) code here
;;
usbhd) code here
;;
*) #ransack the entire PC looking for puppy!
#load usb-storage driver...
usbstoragefunc #loads usb-storage.o
ALLDRIVES="`probedisk | grep '^/dev/' | cut -f 1 -d '|' | cut -f 3 -d '/' | tr "\n" " "`"
findpupfunc $ALLDRIVES
#...return with PDEV1=hdc FSTYPE=iso9660 PUPSFS=pup_001.sfs (for example)
guesspmediafunc
[ ! "$PUPSAVE" ] && searchsavefunc #search for PUPSAVE.
;;
esac
#...exit with PDEV1= full device name.
#total ram, less any shared video...
PCRAMSIZE=`free | head -n 2 | tail -n 1 | tr -s " " | cut -f 3 -d " "`
SIZEFILLK=`expr $PCRAMSIZE \/ 2` #half of ram.
#for 128M PC, have to tweak this to get pup_xxx.sfs to load into ram...
if [ $SIZEFILLK -gt 50000 ];then
[ $SIZEFILLK -lt 70000 ] && SIZEFILLK=71680 #70M.
fi
PHYSICALFILLK="$SIZEFILLK"
#want to know if there is a swap partition available...
SWAPINFO="`fdisk -l | grep "Linux swap" | head -n 1`"
if [ ! "$SWAPINFO" = "" ];then
#we can make the ramdisk real big now...
SWAPPART="`echo "$SWAPINFO" | cut -f 1 -d " "`"
SWAPSIZE=`fdisk -s $SWAPPART`
SWAPSIZ4=`expr $SWAPSIZE \/ 4`
SWAPSIZ2=`expr $SWAPSIZE \/ 2`
SWAPSIZE=`expr $SWAPSIZ2 + $SWAPSIZ4` #3/4 of original
SIZEFILLK=`expr $SIZEFILLK + $SWAPSIZE`
echo "Loading swap partition $SWAPPART..."
swapon $SWAPPART
fi
#mount the main puppy f.s....
PUPMODE=1 #using tmpfs.
[ "$DEV1PUP" = "yes" ] && PUPMODE=`expr $PUPMODE + 2` #PDEV1 has puppy installed.
[ "$PUPSFS" ] && PUPMODE=`expr $PUPMODE + 4` #pup_xxx.sfs exists (on PDEV1).
[ "$PUPSAVE" ] && PUPMODE=`expr $PUPMODE + 8` #pup_save.3fs exists.
if [ $PUPMODE -eq 13 ];then
#multisession cd, run in PUPMODE 13+64=77
[ ! "`echo -n "$PUPSAVE" | grep '/20[0-9][0-9]'`" = "" ] && PUPMODE=77
fi
UMNT1='/pup_rw=rw'
DEV1MNT="/pup_ro1"
case $PUPMODE in
3) #PDEV1 has puppy, and using tmpfs (maybe).
echo -n "Mounting /dev/${PDEV1}..."
if [ ! "`echo -n "$PMEDIA" | grep --extended-regexp "idehd|satahd|scsihd"`" = "" ];then
#do not use unionfs at all, just mount on /pup_new instead of /pup_rw...
mount -o rw -t $FSTYPE /dev/$PDEV1 /pup_new
PUPMODE=2
else
mount -o ro -t $FSTYPE /dev/$PDEV1 /pup_ro1
mount tmpfs /pup_rw -t tmpfs -o size=${SIZEFILLK}k
UMNT1='/pup_rw=rw:/pup_ro1=ro'
fi
;;
5) #tmpfs, no persistent storage layer, pup_xxx.sfs
#this will be the case for first boot. ***FIRST BOOT SITUATION***
echo -n "Mounting ${PDEV1}..."
mount -o rw,noatime -t $FSTYPE /dev/$PDEV1 /mnt/dev_ro1
echo -n "Mounting tmpfs..."
mount tmpfs /pup_rw -t tmpfs -o size=${SIZEFILLK}k
UMNT1='/pup_rw=rw:/pup_ro2=ro'
#if enough room in ramdisk, copy it...
if [ $SIZEFILLK -gt `du /mnt/dev_ro1/$PUPSFS | cut -f 1` ];then
echo -n "Copying $PUPSFS to ramdisk..."
cp -f /mnt/dev_ro1/$PUPSFS /pup_rw/
sync
losetup /dev/loop0 /pup_rw/$PUPSFS
echo "Unmounting ${PDEV1}..."
umount /dev/$PDEV1
else
echo -n "Mounting $PUPSFS directly off /dev/$PDEV1..."
losetup /dev/loop0 /mnt/dev_ro1/$PUPSFS
fi
mount -r -t squashfs -o noatime /dev/loop0 /pup_ro2
;;
7) #tmpfs, PDEV1 is persistent storage, pup_xxx.sfs.
echo -n "Mounting /dev/${PDEV1}..."
mount -o rw -t $FSTYPE /dev/$PDEV1 /pup_ro1
echo -n "Mounting tmpfs..."
mount tmpfs /pup_rw -t tmpfs -o size=${SIZEFILLK}k
UMNT1='/pup_rw=rw:/pup_ro1=ro:/pup_ro2=ro'
#if enough room in ramdisk, copy it...
if [ $SIZEFILLK -gt `du /pup_ro1/$PUPSFS | cut -f 1` ];then
echo "Copying $PUPSFS to ramdisk..."
cp -f /pup_ro1/$PUPSFS /pup_rw/
sync
losetup /dev/loop0 /pup_rw/$PUPSFS
else
echo "Mounting $PUPSFS directly off /dev/$PDEV1..."
losetup /dev/loop0 /pup_ro1/$PUPSFS
fi
echo -n "Mounting ${PUPSFS}..."
mount -r -t squashfs -o noatime /dev/loop0 /pup_ro2
;;
13) #tmpfs, pup_save.3fs is persistent storage, pup_xxx.sfs.
SAVEFS="`echo -n "$PUPSAVE" | cut -f 1 -d ','`" #f.s. and partition where pup_save.3fs is located.
SAVEPART="`echo -n "$PUPSAVE" | cut -f 2 -d ','`" # "
SAVEFILE="`echo -n "$PUPSAVE" | cut -f 3 -d ','`"
echo -n "Mounting ${PDEV1}..."
mount -o rw,noatime -t $FSTYPE /dev/$PDEV1 /mnt/dev_ro1
TMPFSMNT="/pup_rw" #tmpfs layer on top.
EFSMNT="/pup_ro1" #pup_save.3fs next layer.
UMNT1='/pup_rw=rw:/pup_ro1=ro:/pup_ro2=ro'
#maybe drop down to PUPMODE=12...
if [ ! "`echo -n "$PMEDIA" | grep --extended-regexp "idecd|usbcd|scsicd"`" = "" ];then
#booting off a cd. if pup_save.3fs exists in a fast media, can load direct...
[ ! "`echo -n "$SAVEPART" | grep '^hd'`" = "" ] && SAVEDIRECT="yes"
#...TODO not detecting sata and scsi fast drives.
fi
if [ ! "`echo -n "$PMEDIA" | grep --extended-regexp "idehd|satahd|scsihd"`" = "" ];then
#assumption that pup_save.3fs is also on the fast media...
SAVEDIRECT="yes"
fi
if [ "$SAVEDIRECT" = "yes" ];then
#pup_save.sfs is on a fast media, allows unlimited writes, so let us not use tmpfs layer...
PUPMODE=12 #rc.shutdown will know nothing to save.
#still need a tmpfs, to load pup_xxx.sfs...
TMPFSMNT="/mnt/tmpfs" #tmpfs created elsewhere, not a layer.
EFSMNT="/pup_rw" #pup_save.3fs top layer.
UMNT1='/pup_rw=rw:/pup_ro2=ro'
fi
echo -n "Mounting tmpfs..."
mount tmpfs $TMPFSMNT -t tmpfs -o size=${SIZEFILLK}k
#if enough room in ramdisk, copy it...
if [ $SIZEFILLK -gt `du /mnt/dev_ro1/$PUPSFS | cut -f 1` ];then
echo -n "Copying $PUPSFS to ramdisk..."
cp -f /mnt/dev_ro1/$PUPSFS $TMPFSMNT/
sync
losetup /dev/loop0 $TMPFSMNT/$PUPSFS
umount /dev/$PDEV1
else
echo -n "Mounting $PUPSFS directly off /dev/$PDEV1..."
losetup /dev/loop0 /mnt/dev_ro1/$PUPSFS
fi
mount -r -t squashfs -o noatime /dev/loop0 /pup_ro2
#now do PUPSAVE...
SMNTPT="`mount | grep "/dev/$SAVEPART" | tr -s " " | cut -f 3 -d " "`"
if [ "$SMNTPT" = "" ];then
SMNTPT="/mnt/dev_save"
mount -t $SAVEFS -o noatime,rw /dev/$SAVEPART /mnt/dev_save
fi
#about to mount pup_save.3fs, but before that check if need to resize it...
if [ -f $SMNTPT/pupsaveresize.txt ];then #created by /usr/sbin/resizepfile.sh
KILOBIG=`cat $SMNTPT/pupsaveresize.txt`
rm -f $SMNTPT/pupsaveresize.txt
echo "Increasing $SAVEFILE by $KILOBIG Kbytes, please wait..."
dd if=/dev/zero bs=1k count=$KILOBIG | tee -a $SMNTPT$SAVEFILE > /dev/null
sync
e2fsck -y -f $SMNTPT$SAVEFILE
resize2fs -pf $SMNTPT$SAVEFILE #no size, will fill all of file.
sync
sleep 6 #so we can see result
fi
losetup /dev/loop1 $SMNTPT$SAVEFILE
echo -n "Mounting ${SAVEFILE}..."
FILEFS="ext3"
[ ! "`echo -n "$SAVEFILE" | grep "2fs"`" = "" ] && FILEFS="ext2"
mount -t $FILEFS -o noatime,rw /dev/loop1 $EFSMNT
;;
77) #multisession cd/dvd
SAVEFS="`echo -n "$PUPSAVE" | cut -f 1 -d ','`" #f.s. and partition where pup_save.3fs is located.
SAVEPART="`echo -n "$PUPSAVE" | cut -f 2 -d ','`" # "
SAVEFILE="`echo -n "$PUPSAVE" | cut -f 3 -d ','`"
echo -n "Mounting ${PDEV1}..."
mount -o rw,noatime -t $FSTYPE /dev/$PDEV1 /mnt/dev_ro1;check_status $?
TMPFSMNT="/pup_rw" #tmpfs layer on top.
EFSMNT="/pup_ro1" #folders from cd next layer.
UMNT1='/pup_rw=rw:/pup_ro1=ro:/pup_ro2=ro'
#now do PUPSAVE...
SMNTPT="`mount | grep "/dev/$SAVEPART" | tr -s " " | cut -f 3 -d " "`"
if [ "$SMNTPT" = "" ];then
SMNTPT="/mnt/dev_save"
mount -t $SAVEFS -o noatime,rw /dev/$SAVEPART /mnt/dev_save
fi
#personal data is saved in dated folders.
#create a tmpfs on /pup_ro1 and load folders to it... in physical mem only...
ALMOSTFILLK=`expr $PHYSICALFILLK \/ 4`
ALMOSTFILLK=`expr $PHYSICALFILLK - $ALMOSTFILLK`
mount tmpfs /pup_ro1 -t tmpfs -o size=${ALMOSTFILLK}k;check_status $?
loadfolders $SMNTPT /pup_ro1
ALMOSTFILLK=`free | grep 'Mem:' | tr -s " " | cut -f 5 -d " "`
ALMOSTFILLK=`expr $ALMOSTFILLK \/ 2`
SIZEFILLK=`expr $ALMOSTFILLK + $SWAPSIZE`
echo -n "Mounting tmpfs..."
mount tmpfs $TMPFSMNT -t tmpfs -o size=${SIZEFILLK}k;check_status $?
#if enough room in ramdisk, copy it...
if [ $SIZEFILLK -gt `du /mnt/dev_ro1/$PUPSFS | cut -f 1` ];then
echo -n "Copying $PUPSFS to ramdisk..."
cp -f /mnt/dev_ro1/$PUPSFS $TMPFSMNT/
sync
losetup /dev/loop0 $TMPFSMNT/$PUPSFS
umount /dev/$PDEV1
else
echo -n "Mounting $PUPSFS directly off /dev/$PDEV1..."
losetup /dev/loop0 /mnt/dev_ro1/$PUPSFS
fi
mount -r -t squashfs -o noatime /dev/loop0 /pup_ro2;check_status $?
sync
umount /dev/$SAVEPART 2>/dev/null
;;
*) #incomplete combination.
#nothing to save to and/or no puppy found.
echo "ERROR, cannot find Puppy on $PMEDIA boot media."
echo "PUPMODE=$PUPMODE PDEV1=$PDEV1"
sleep 10
exit
;;
esac
UMNTRO=""
#Look for *_$PUPPYVERSION.sfs (ex: dev_200.sfs)...
[ $PUPMODE -eq 7 ] && EXTRASFS="/pup_ro1"
[ $PUPMODE -eq 13 ] && EXTRASFS="`mount | grep "/dev/$SAVEPART" 2>/dev/null | tr -s " " | cut -f 3 -d " "`"
[ $PUPMODE -eq 77 ] && EXTRASFS="`mount | grep "/dev/$SAVEPART" 2>/dev/null | tr -s " " | cut -f 3 -d " "`"
if [ "$EXTRASFS" ];then
cd $EXTRASFS
if [ -f underdog.lnx ];then
#this is an idea to overlay Puppy on top of an existing Linux distro.
UNDERDOGPART="`cat underdog.lnx`"
UDMNTPT="`mount | grep "/dev/$UNDERDOGPART" | tr -s " " | cut -f 3 -d " "`"
if [ "$UDMNTPT" = "" ];then
UNDERDOGFS="`disktype /dev/$UNDERDOGPART | grep 'file system' | head -n 1 | cut -f 1 -d " "`"
[ "$UNDERDOGFS" = "Ext2" ] && UNDERDOGFS="ext2"
[ "$UNDERDOGFS" = "Ext3" ] && UNDERDOGFS="ext3"
[ "$UNDERDOGFS" = "Reiserfs" ] && UNDERDOGFS="reiserfs"
if [ ! "`echo -n "$UNDERDOGFS" | grep --extended-regexp 'ext2|ext3|reiserfs'`" = "" ];then
mount -r -t $UNDERDOGFS /dev/$UNDERDOGPART /pup_ro3
if [ $? -eq 0 ];then
UMNTRO="${UMNTRO}:/pup_ro3=ro"
#fixes to prevent library clashes...
MNTFIX='/pup_rw'
[ ! "`echo -n "$UMNTRO" | grep 'pup_ro1'`" = "" ] && MNTFIX='/pup_ro1'
[ ! -f $MNTFIX/lib/.wh.i686 ] && touch $MNTFIX/lib/.wh.i686 #hides /lib/i686
#puppy needs dir name /usr/lib/qt at bootup (see rc.profile)...
REALQTDIR="`find /pup_ro3/usr/lib -maxdepth 1 -type d -name qt* | tail -n 1 | sed -e 's/\/pup_ro3\/usr\/lib\///g'`"
if [ "$REALQTDIR" ];then
if [ ! -e $MNTFIX/usr/lib/qt ];then
[ "`find /pup_ro3/usr/lib -maxdepth 1 -xtype d -name qt`" = "" ] && ln -s $REALQTDIR $MNTFIX/usr/lib/qt
fi
fi
fi
fi
else
UMNTRO="${UMNTRO}:${UDMNTPT}=ro"
fi
else
CNTLOOP=3
for ONESFS in `ls -1 *_${PUPPYVERSION}.sfs | grep -v "^pup_" | tr "\n" " "`
do
losetup-FULL /dev/loop${CNTLOOP} $EXTRASFS/$ONESFS
mount -r -t squashfs -o noatime /dev/loop${CNTLOOP} /pup_ro${CNTLOOP}
[ $? -eq 0 ] && UMNTRO="${UMNTRO}:/pup_ro${CNTLOOP}=ro"
CNTLOOP=`expr $CNTLOOP + 1`
done
fi
cd /
fi
#now do the unionfs thing...
mkdir -p /pup_rw/etc/rc.d
echo -n "$PUPMODE" > /pup_rw/etc/rc.d/PUPMODE #to be read by rc.shutdown.
echo -n "$PDEV1" > /pup_rw/etc/rc.d/PDEV1 # "
echo -n "$FSTYPE" > /pup_rw/etc/rc.d/DEV1FS # "
echo -n "$PUPSFS" > /pup_rw/etc/rc.d/PUPSFS # "
echo -n "$PUPSAVE" > /pup_rw/etc/rc.d/PUPSAVE # "
echo -n "$PMEDIA" > /pup_rw/etc/rc.d/PMEDIA # "
echo -n "$PUPPYVERSION" > /pup_rw/etc/puppyversion #used to check saved session at bootup (ispupfunc)
mkdir /pup_rw/initrd
sync
echo -n "Creating unionfs..."
mount -t unionfs -o dirs=${UMNT1}${UMNTRO} none /pup_new
#want to launch dnotify from init script as it is pristine...
#/sbin/launchpupsafe &
cd /pup_new
sync
umount /proc
#echo "pivot_root now changing from initial ramdisk..."
pivot_root . initrd
exec chroot . sh -c "exec /bin/busybox init" <dev/console >dev/console 2>&1
Okay, that looks like a lot of stuff happening! Actually though, it is all quite simple.
In a nutshell, the script searches for the boot partition and Puppy persistent storage
file or partition, using the PMEDIA boot parameter as a guide. When
found, the script then determines the appropriate PUPMODE, then creates
the unionfs layers accordingly.
The end of the script executes pivot_root, which switches to folder
/pup_new as the new "/" (top of the filesystem). Directory /pup_new is
where all the unionfs layers have been merged.
The initial ramdisk is left in memory, and after pivot_root, will
be in directory /initrd. That is, everything under "/" before the
pivot_root will be in /initrd after pivot_root. It is inside /initrd
that you will still be able to access the individual layers of the
union -- but this capability is of interest for developers only, not
normal users.
After pivot_root, the next script to execute is
/etc/rc.d/rc.sysinit. Note that unlike puppy1, everything in /etc/rc.d
is editable, as everything under "/" gets saved. The only script not
directly editable is /initrd/sbin/init, the initial ramdisk startup
script.
How Puppy works, take 1
The level of interest in Puppy is steadily rising, and many people ask questions on the Puppy Discussion Forum about how Puppy works "under the hood".
So, I decided to put this page together to explain a few concepts about the structure of Puppy, version 0.9.8+. One thing to understand is that Puppy is unique. I built Puppy from scratch, file by file, so the architecture is not based on any other distro. Puppy has evolved from my first experiments with the "Boot disk HOWTO" early in 2003, to the amazing phenomenon we have today.
I'm using Amaya to write this web page, and I used Dia to create the
images you see below. I could have written this page with Abiword,
Composer
or Bluefish, and I could have created the image in Xpaint, Figurine,
mtPaint
or Sodipodi -- this amazing choice of applications is all in the tiny
approx
50-60M Puppy distro. However, if not satisfied with the in-built
choices, Puppy has the powerful PupGet and DotPup package managers
offering a growing choice of packages that you can download and install
with just a few clicks of the mouse. You can even rebuild the live-CD
with the precise selection of packages that you want.
In fact, with the new CD-remaster program in Puppy 1.0.5, creating a
custom live-CD or USB stick has become extremely easy ...anyway, that's
another story!
The Puppy live-CD
The main purpose of this page is to explain how Puppy differs from other distros, and why, and therefore what you can and cannot do, that perhaps you can or cannot do in other distros. Take a look at this diagram:
The above diagram shows the layout of Puppy when booted from a live-CD.
The ramdisk
When the live-CD boots, vmlinuz, the Linux kernel, loads into RAM, followed by image.gz, which loads into a "ramdisk" (a filesystem that is totally in RAM). The ".gz" means that the file is compressed, so it is uncompressed into the ramdisk and then becomes the basic Puppy filesystem, that is, the "/" or top directory and all the subdirectories /bin, /sbin, /lib, /dev, /tmp, etc.
A fundamental objective of Puppy is that everything should load into ramdisk, thus freeing up the CD drive so that you can use the CD drive for any other purpose. Also, if everything is in RAM, application startup and running speed is stunning.
pup001 file
There is a problem if everything runs in the RAM though -- when the power goes off, RAM contents are lost. What is needed is some way to retain your settings, such as configuration changes, email, browser history, and so on. What Puppy does is during bootup look for a suitable hard drive partition, and if one is found, then create a file on it called "pup001". Actually, the name of the file could be anything, but I arbitrarily chose "pupxxx" where the "xxx" is three numeric digits. The three numeric digits have no particular meaning either, except we are currently using pup001 for the live-CD and pup100 for USB installations of Puppy.
pup001 is a single file, but internally is a complete ext2 filesystem. After creating this file, Puppy then mounts it, by means of what is called a "loopback device", onto /root directory. This directory /root is your home directory -- all your personal stuff goes in there. Thus, when you shutdown, it will be there next time you start Puppy.
I do need to explain the bootup steps properly though -- Puppy first has
to mount the hard drive partition onto /mnt/home. This must be done before
Puppy can get access to pup001 and mount it on /root. That's why you can see
two mount points in the diagram.
There has been a great deal of
interest on the Forum in having a live-CD that does not need the hard
drive at all, yet is still able to save personal data. I therefore
developed the "multisession live-CD", introduced with version 1.0.0,
that saves the contents of /root back to the CD, thus not requiring a
pup001 file at all. This new concept is described further down -- keep
reading! Note that the multisession technique does not replace the use
of pup001 -- they are both available.
usr_cram.fs file
Note, if reading this page for the first time, these details on usr_cram.fs may get you mentally bogged down, so skim read onto the next heading -- you can always come back later if you want to understand more precisely how the usr_cram.fs file gets placed in memory.
Most of the files in Puppy, in any Linux distro for that matter, are in /usr, and furthermore there is normally no need to write to anything inside /usr (that is, no need to edit, create or delete files). Therefore, the contents of /usr could be compressed, and that is what Puppy does. The entire contents of /usr is compressed as a single file, named usr_cram.fs. This file is not uncompressed, it is mounted as-is on /usr, by means of what is called a "loopback device" -- the actual technique is not the main issue here, but you need to be aware that all of /usr is really only a single file, containing a compressed and read-only filesystem.
You can see that I have shown part of the diagram in an orange color. This is to illustrate the different places where the file usr_cram.fs may be located. Those four numbers, 1, 2, 3, and 4, are the search order. That is, at bootup, Puppy will first look to see if usr_cram.fs is at "/" in the ramdisk (which meant that it was inside image.gz originally). Secondly, Puppy will look in /root (that is, inside pup001), thirdly in /mnt/home (in the hard drive partition), finally Puppy will look on the CD.
Even if Puppy falls through to option 4, Puppy will do his best not to
leave usr_cram.fs on the CD. We don't want to leave usr_cram.fs on the
CD. We really want to copy it to the ramdisk, or failing that into pup001 in
the hard drive. If we left it on the CD and just mounted it on /usr, Puppy
will run slowly and the CD drive will not be available for other purposes.
So, Puppy looks to see if there is enough RAM, and if so, copies usr_cram.fs
to "/" in the ramdisk and then mounts it on /usr.
Update: Puppy 1.0.5 does the
above slightly differently. This is just a small technical detail, a
deviation from before. usr_cram.fs now gets mounted on directory
/.usr_cram and then joined with /usr by UNIONFS. If that makes no
sense, don't worry as the end result is the same.
How much RAM is "enough"? Puppy is happiest on a PC with at least
128M
RAM. 128M is a good size -- it is enough for image.gz (uncompressed)
and
usr_cram.fs to both be in the ramdisk. For the normal Puppy that is --
we have some fatter custom Puppies, notably Chubby Puppy (it has
OpenOffice) that is 90M and that needs a 256M PC to run in RAM.
But, what if your PC has only 64M, 48M, or even only 32M RAM? Well, usr_cram.fs is not going to fit in the ramdisk. Just ball-park figures, image.gz uncompressed is about 10M, usr_cram.fs is about 50M.
Puppy does have a card up his sleeve, so to speak -- if the PC has a Linux swap partition Puppy will automatically use that, which is used to increase the effective size of the ramdisk. If you have ever installed another Linux distro on the PC, chances are it created a swap partition, so it is already sitting there ready for Puppy to use. If your PC has 128M of RAM, Puppy 0.9.8 will allocate 62M of that to ramdisk (version 1.0.2+ allocates 70M), however if the PC also has a 250M (for example) swap partition, then the effective size of the ramdisk becomes 62+250 = 312M!
However, I made a decision with the startup logic of Puppy, only to copy usr_cram.fs into ramdisk if there is at least 62M of physical RAM allocated to the ramdisk. So, for PCs with less physical RAM than 128M, usr_cram.fs will never be copied into ramdisk, even if there is a swap partition.
Another thing to think about is the search order, those four numbers 1, 2, 3, and 4. When you have booted up Puppy from the CD, if you copy usr_cram.fs from the CD or /, to /root (ie., inside pup001), that will be the second place Puppy looks next time he boots. Or, copy it onto "/" on the hard drive -- that's the 3rd place Puppy will look. So even on a PC with only 32M RAM, you can bootup from a live-CD and have the CD drive freed up for other purposes.
However, PCs with less than 128M really do need a swap partition for Puppy to work properly. Even though Puppy can boot up from live-CD on a PC with only 32M RAM, some of the applications are memory hogs -- Mozilla for example. Mozilla is not viable on a PC with less than 128M RAM. However, as mentioned above, a swap partition increases the effective size of the ramdisk, so you can get Mozilla to work on PCs with very little RAM, albiet slowly. It is also a good idea to add a swap file, if you have some spare space on the hard drive.
Think about that search order a bit more... #3 is interesting. Puppy looks
on the hard drive for usr_cram.fs, but how would the file get there? If you
put it there, it would, but also if you run the
install-to-hard-drive-option-1 script.
...in that case, there's a "gotcha" as when you bootup a new version of Puppy
on the CD, Puppy will find the old usr_cram.fs. Argh! ...not so good. Or, an
old usr_cram.fs if you put it in /root, for that matter.
To get around that problem Puppy has a technique for checking that
usr_cram.fs is the correct version. Puppy checks this, and will ignore any
usr_cram.fs files it finds that have the wrong version number. The technique
used is when usr_cram.fs is created, its size, in bytes, is recorded in
/etc/sizeusrcram, which can then be used to check against usr_cram.fs at
boot-time.
The explanation above states
that /usr is read-only, as it has a compressed read-only usr_cram.fs
mounted on it. However, Puppy version 1.0.1 has changed all that. /usr
is now writable. Once again, keep reading!
Package installation
A most important point about this architecture is that /usr is read-only.
Therefore, if you download a .tar.gz "tarball" or RPM package and you want to
install it into Puppy, you can't! At least, most packages want to install
part of themselves into /usr.
However, Puppy version 1.0.1 has revolutionised package management
by using UNIONFS to make /usr read-write. Any files written to /usr are
actually stored in /root/.usr, however as far as the user is concerned,
they are in /usr. This picture illustrates:
"/root/.usr" is just a directory inside pup001, but it is mounted on
/usr, and any writes to /usr actually get stored into /root/.usr. So,
you see, as /root/.usr is actually inside pup001 then it will be saved
at end of session and reloaded next time Puppy is booted. (Heh, heh,
I'm drawing lines all over the place, this mounted on that and so on --
but final usage is very simple!)
An outcome of having /usr read-write is that Puppy can have a
package management system to install and remove packages. I looked
around at what is available, but as usual decided to reinvent the
wheel, and the result is PupGet, a package manager with installation, removal and dependency checking.
PupGet offers the packages of the Puppy Unleashed
package suite. All of these packages are available for download -- it
is simply a matter of going to the Puppy menu, "Setup -> PupGet
package manager", and follow the simple steps.
The Unleashed packages are all on the Internet, and PupGet can
download them individually to install them, however Linux developers
can create their own live-CDs from the complete Unleashed package
suite. The live-CD that you are using now was created from Puppy
Unleashed.
Puppy Unleashed
enables you to build your own custom Puppy from a choice of hundreds of
packages (applications). For further information, see the Puppy Unleashed page.
Puppy 1.0.5 adds a new
dimension to creating a custom CD, with a program codenamed PCCC, or
Puppy Custom CD Creator. This program enables you to use the current
live-CD as the starting point, then add or remove packages as you wish.
PCCC is tied in with the PupGet package manager, and can also move
DotPup packages (Puppy has two packaging systems) to the live-CD. PCCC
is much easier to use than it is to explain!
Booting from USB
USB Flash memory drives have become very popular, and the entry-level capacity is now 128M, which is the equivalent of about 80 floppy disks. So, the floppy disk is becoming history, and most PCs these days can be configured to boot from USB, meeting the need for an emergency "boot disk" (or you can boot from a CD of course).
I do need to make a comment on that though. A friend of mine purchased a
brand new Compaq laptop, rather expensive model (Presario R3000), in October 2004, and I was
amazed that the BIOS setup did not have an option to boot from USB. It did
have a "boot from CD" setting, but not USB. That's incredible, and a warning,
if you are shopping for a new PC.
Another warning. Most USB Flash drives are generic, that is, they
have an interface that conforms to the standard USB mass-storage
specification. However there are some that do not conform, thus you
probably cannot boot from them, nor use them with Linux. There is an
easy way to pick a "conforming" Flash drive -- if it states on the
packet that it will work with Windows XP without needing a special
driver installed, then it is probably okay. In fact, I purchased one
recently that didn't even have a CD and it stated specifically on the
packet that it works with XP and Linux without any special driver.
Flash technology
A 128M Flash drive matches perfectly with Puppy. Consider, Puppy is only about 50-60M, so will fit on a 128M USB drive leaving over 70M free for personal data. Yes, a complete portable operating system and personal data, all on the one tiny device!
However, there is a downside to Flash technology, and that is it is not designed for unlimited writes. That is, you can save onto it just so many times, then it will collapse. I did read somewhere that someone installed Windows 95 on a USB Flash drive and it failed after about 6 months of daily use. The number of writes each memory location can sustain depends on what documentation you read -- also, be careful about figures from the vendor, as they may quote something like 1,000,000 write cycles, but that may not mean to each memory cell. I have seen figures as low as 50,000 writes.
Anyway, the good news is that Puppy is especially designed to have no writes to the Flash drive during a session, enormously extending its life span. Take a look at this diagram:
When Puppy boots from USB, the steps are much the same as for the live-CD. The kernel vmlinuz is loaded into RAM, image.gz is uncompressed and loaded into a ramdisk.
usr_cram.fs
Puppy then searches for usr_cram.fs, first looking in "/" in the ramdisk, then in "/" in the USB partition. The first case would only be if Puppy had been created with usr_cram.fs inside image.gz, which is not the normal situation. So it falls back to number 2. Puppy will find usr_cram.fs in the USB partition and will mount it on /usr.
But, Puppy will attempt an optimisation. If there is enough RAM,
Puppy
will copy usr_cram.fs into the ramdisk and then mount it on /usr. This
will
slow down bootup slightly, but will improve running speed. However,
even if
Puppy does leave usr_cram.fs on the USB drive and mounts it from there
onto
/usr, that is not a problem as /usr is read-only. There will be no
writes to
/usr, so the lifetime of the Flash drive is not compromised (Puppy
version 1.0.1 has UNIONFS which makes /usr read-write, but all writes
actually go to /root/.usr, which is in the ramdisk, as described below).
pup100
The very first time that Puppy boots from USB, the file pup100 does not yet exist -- Puppy has to create it. Puppy creates it, and mounts it directly on /root, by means of a loopback device.
So far, the architecture is basically the same as for the live-CD.
The lifetime of the Flash device is compromised by writes to /root, that is, to pup100. This is your home directory, and applications store all kinds of stuff in it. A lot of writing will be happening to /root. The Linux kernel does cache the writes, but even so, the cache will be flushed frequently.
A significant difference occurs the second time that Puppy is booted from USB. If there is enough RAM (remembering that the ramdisk can also use a swap partition if it exists, so the available space is effectively (half) the size of RAM plus size of the swap partition), then Puppy will mount pup100 onto /mnt/pupxxx directory and will then copy all the files from /mnt/pupxxx to /root.
Thus, a complete copy of pup100 is in /root, and no writing will occur to pup100 during a session. At shutdown, all the files in /root are copied back to /mnt/pupxxx, thus updating pup100. We could, in theory, backup to pup100 at regular intervals, rather than only at shutdown, but that is not implemented in the current version of Puppy -- quite frankly, I have very rarely had Puppy crash, and the only situation that would cause backup not to occur would be a power failure.
Puppy is highly intelligent, and the optimisations described above are only implemented if there is enough RAM (+swap). If there is not enough RAM, then obviously pup100 cannot be copied into /root in the ramdisk.
Just to give an idea of what is "enough" RAM, a PC with 256M RAM matches well with a 128M Flash drive. The pup100 file will be about 60M, and there's enough RAM for everything to load into ramdisk. On the otherhand, a 256M Flash drive would have a 180M pup100 file which would be too big. But, if the PC has a swap partition, Puppy will automatically use this to increase the effective maximum size of the ramdisk.
Whatever the situation on your PC, Puppy will work out the best configuration, totally automatically.
Updating and archiving
As you can see, Puppy consists of only 4 files. (actually, it is possible to have usr_cram.fs inside image.gz, reducing Puppy down to just 3 files -- the web download sites may have that configuration available. It is convenient for booting off a network to have just the two files vmlinuz and image.gz to worry about)
To update to the latest version of Puppy, you just need to get the latest vmlinuz, image.gz and usr_cram.fs. Updating is so very simple, but with v0.9.8 I made it even simpler by building an update option into the installation scripts. That is, boot up the latest live-CD and run the install-to-USB, install-to-Zip or install-to-hard-drive script and choose "update" rather than "new installation".
...but, it's so simple, you could do it manually if you wish.
Puppy does have a couple of archive programs, including one that I wrote that backs up only the changed files from /root each time. However, all your personal data, really, a snapshot of the entire the state of the system, is in the pup001 or pup100 file, so you can save a complete system snapshot just by making a copy of the pup001/100 file. Then compress it, like this (assuming the copy is named pup100-12dec04):
# gzip pup100-12dec04
and you will have pup100-12dec04.gz. Or use "zip" or "bzip2", Puppy has them all! Archive that anywhere you want.
You can mount an archived pup100 file at any time, and view its contents:
# losetup-FULL /dev/loop2 pup100-12dec04
# mount -t ext2 /dev/loop2 /mnt/data
You can also view the contents of pup100-12dec04 from Windows, by using
the Explore2fs program. There is also a free native ext2 filesystem driver for Windows NT/XP.
Multisession live-CD
This is a most exciting new development. When I introduced this with
v1.0.0, I thought it was a world first, but I discovered that the
Morphix Linux people had been experimenting with a similar concept (but
nowhere near as developed).
With v1.0.2, there is only one ISO file, for example
puppy-1.0.2-mozilla.iso, and it becomes multisession if it is burnt
that way when writing to CD. The concept here is that there is no
pupxxx file at all! No hard drive required. Sessions are saved back to
the CD, each session saved as a folder on the CD.
I won't draw another diagram... looking at the diagram at the top of
this page, just remove the "pup001" box and the hard drive partition
box, and there you have it. Folder /root is totally in ramdisk, and
when Puppy boots the saved sessions are copied off the CD into /root in
the ramdisk. The downside of this is that lots of RAM is required --
256M at least, although it will use a Linux swap partition if it exists
so 128M of RAM or less will work.
To read more: Puppy multisession live-CD introduction.
Booting steps
This section not finished.
Way back in the early days of Puppy, I did write a page on the steps that Puppy goes through when booting. Way out of date, but you may like to see it: Booting Puppy Linux.
Making a start at writing this section...
Step 1
The first things that happen is the Linux kernel, file "vmlinuz" loads into RAM and file "image.gz" is uncompressed and loaded into /dev/ram0, a 11264K fixed-size ramdisk (increased to 12288K for Pup 1.0.4+).
In the case of a "big image" Puppy, that is, with file usr_cram.fs inside image.gz, there has to be the kernel boot parameter "ramdisk_size=" to specify a suitable size to hold all of image.gz (uncompressed) and usr_cram.fs plus some spare space. For example:
ramdisk_size=63488
For the "big image" situation, /dev/ram0 will be large, in the above example 63488 Kbytes.
Step 2
The program "/sbin/init" is executed. In the case of the "big image" Puppy, /sbin/init is just a link to /bin/busybox, as init is a program built-in to busybox. The normal situation though, is that /sbin/init is a shell script. Here it is:
#!/bin/sh
#v0.9.8 booting up in /dev/ram0, move root / to tmpfs...
INITARGS="`echo -n "$@" | sed -e 's/\/dev\/ram0/tmpfs/g'`"
PATH=/bin:/sbin
mount -t proc none /proc
mount -o remount,rw / #-n option not needed with busybox mount.
STARTUPFSSIZE=`cat /root0/.etc/ramdiskfssize` #currently set to 11264K (file gets updated below)
#specifying ram1 here as it isn't in use...
SIZERAMDISKM=`disktype /dev/ram1 | grep "Block device" | cut -f 4 -d " "`
SIZERAMDISKK=`expr $SIZERAMDISKM \* 1024`
#total ram, less any shared video...
PCRAMSIZE=`free | head -n 2 | tail -n 1 | tr -s " " | cut -f 3 -d " "`
#...note, busybox free output format different from standard free program.
if [ $PCRAMSIZE -gt 220000 ];then #256M
SIZEFILLK=`expr $PCRAMSIZE \/ 2` #half of ram.
else
if [ $PCRAMSIZE -gt 117000 ];then #128M
SIZEFILLK=67584 #63488
else
if [ $PCRAMSIZE -gt 60000 ];then #64M
SIZEFILLK=16384 #leaves about 7M free in f.s.
else
SIZEFILLK=11264 #only about 2M free in f.s.
fi
fi
fi
#precaution...
if [ $SIZEFILLK -lt $STARTUPFSSIZE ];then
SIZEFILLK=$STARTUPFSSIZE
fi
PHYSICALFILLK="$SIZEFILLK"
#want to know if there is a swap partition available...
SWAPPART=""
SWAPINFO="`fdisk -l | grep "Linux swap" | head -n 1`"
if [ ! "$SWAPINFO" = "" ];then
#we can make the ramdisk real big now...
SWAPPART="`echo "$SWAPINFO" | cut -f 1 -d " "`"
SWAPSIZE="`fdisk -s $SWAPPART`"
#SWAPSIZE=`expr $SWAPSIZE \/ 2` #let's use half of the swap partition.
#...nah, grab the whole lot. Puppy can create a swap file later if reqd.
SIZEFILLK=`expr $SIZEFILLK + $SWAPSIZE`
#0.9.8... but have to delay swapon until rc.sysinit running... see below...
fi
mkdir /new_root
mount tmpfs /new_root -t tmpfs -o size=${SIZEFILLK}k;check_status $?
cp -a /bin /new_root/
cp -a /dev /new_root/
cp -a /etc /new_root/
cp -a /lib /new_root/
cp -a /mnt /new_root/
cp -a /root /new_root/
cp -a /root0 /new_root/
cp -a /sbin /new_root/
cp -a /usr /new_root/
cp -a /proc0 /new_root/proc
cp -a /var0 /new_root/var
mkdir /new_root/tmp
chmod 777 /new_root/tmp
sync
#0.9.8R2 rc.sysinit will start the swap partition running...
if [ ! "$SWAPPART" = "" ];then
echo -n "$SWAPPART" > /new_root/root0/.etc/swappartition1
fi
#i want to know the max size if not going to use the swap partition...
echo -n "$PHYSICALFILLK" > /new_root/root0/.etc/ramdiskphysicalfssize
echo -n "$SIZERAMDISKK" > /new_root/root0/.etc/ramdisksize
echo -n "$SIZEFILLK" > /new_root/root0/.etc/ramdiskfssize #size of f.s.
cat /etc/fstab | sed -e 's/\/dev\/ram0/tmpfs/g' > /new_root/etc/fstab
#if ever run install-to-hd script, /sbin/init must be normal symlink...
mv -f /new_root/sbin/init /new_root/sbin/init_ORIG
ln -s /bin/busybox /new_root/sbin/init
cd /new_root
mkdir old_root
umount /proc
#have code in /etc/rc.d/rc.sysinit which will umount /dev/ram0...
pivot_root . old_root
exec chroot . sh -c "exec /bin/busybox init $INITARGS"dev/console 2>&1
In a nutshell, what this script does is copy all of /dev/ram0 to a new tmpfs ramdisk, which has the advantage of variable size and it can use a swap partition to create a very large effective size for the ramdisk. After the swap, /dev/ram0 is no longer being used.
Notice the very last line of the script. After the swap-over, "/bin/busybox init" is executed. This causes the init program built into Busybox to execute, the same as if /sbin/init was a link to /bin/busybox and init had been executed.
Step 3
Coming soon.
(c)Copyright Barry Kauler 2005,2006 Puppy Linux http://www.puppylinux.com/
No part of this page is to be reproduced anywhere else. I have found
that there is a problem where parts of my web pages are being inserted
at other sites, then not updated, whereas I am updating my pages
regularly. This is not a desirable situation, so please just link to my
pages.