This guide is based off the work I did to produce Multiuser Puppy, and the discussions we had here and here. I am assuming the reader is comfortable with Puppy's internals and with utilities such as grep, sed, and diff. I will reference the following files:
- user_utils-0.1.pet
- shadow-4.1.4.2.pet
- Linux-PAM-1.1.0.pet
- sudo-1.7.2p1.pet
- timezone-set.tar.gz
- mount-stuff.tar.gz
- power-stuff.tar.gz
- x-stuff.tar.gz
- makestuffuserfriendly.diff
- shadow_DOC-4.1.4.2.pet
- shadow_NLS-4.1.4.2.pet
- Linux-PAM_DEV-1.1.0.pet
- Linux-PAM_DOC-1.1.0.pet
- Linux-PAM_NLS-1.1.0.pet
- sudo_DOC-1.7.2p1.pet
Misc. Small Changes
- Create an empty directory '/home'.
- Make /tmp 1777 (sticky and globally writable). The stickiness makes it so that if Alice creates the file /tmp/my_temporary_file, Bob can't modify that file unless Alice sets the permissions to let him. Otherwise he could move or delete the file, which could obviously be a pretty bad thing. The downside is that a user can spam /tmp with a bunch of files that other users might want to create...
- Make /dev/zero and /dev/ptmx globally writable. The former is needed for a number of programs to run for some reason. The latter is needed by rxvt.
- Make ddcprobe setuid. The scripts supporting X needed this.
- Make /usr/X11R7/bin/Xvesa setuid.
- IceWM's toolbar has some paths within ~/ but it can't handle variables. So I just trimmed off the /root/ part, making them relative. That seems to work. It may have problems if you start icewm from a location other than your home directory however.
- Upgrade pcursorsel-0.1 to 0.2, which is multiuser-friendly (link)
- Add a line in /usr/sbin/puppyinstaller that copies /home when it's setting up a full install.
- The /usr/share/applications/file_sharing.desktop file had an Exec line like this:
But that obviously won't do. I couldn't get it to work with variables either. So I changed it to this:
Code: Select all
Exec=rox -d /root/File-Sharing
and then added the script /usr/sbin/filesharedir with the following contents:Code: Select all
Exec=filesharedir
Code: Select all
#!/bin/sh exec rox -d ${HOME}/File-Sharing
Xlock and box_splash (from pwidgets and ptray)
These use some GTK dialog stuff that had absolute paths into /root/. Changing them is pretty easy, but you have to be careful about the quotes. Here are the diffs:
/usr/local/apps/Xlock/AppRun:
Code: Select all
- puppy-unleashed/packages/xlockmore-5.20.1patched/usr/local/apps/Xlock/AppRun -
index e7fc9b3..77f102c 100755
@@ -23,11 +23,11 @@ if [ "$PARAM1" = "-password" ];then
<vbox>
<text><label>"The first time Xlock runs, it will ask for a key, meaning a
password. To change the password, you need to delete the
-file /root/.xlockrc, which is all that this button does..."</label>
+file '"${HOME}/.xlockrc"', which is all that this button does..."</label>
</text>
<button>
<label>Click to clear password</label>
- <action>rm -f /root/.xlockrc</action>
+ <action>rm -f ${HOME}/.xlockrc</action>
<action>exit:PASSWD</action>
</button>
</vbox>
@@ -196,7 +196,7 @@ if [ ! "`echo "$PARAM1" | grep --extended-regexp "configure|inroot"`" = "" ];the
fi
-if [ ! -f /root/.xlockrc ];then
+if [ ! -f ${HOME}/.xlockrc ];then
XLOCKPARAMS="`cat /etc/xlockscreenparams`"
rxvt -bg orange -g 36x1 -title "Create key (password)" -e xlock $XLOCKPARAMS
else
Code: Select all
---- puppy-unleashed/packages/pwidgets-2.0.8/usr/local/pwidgets/box_splash ----
index d6a57e8..ea4d39f 100755
@@ -5,10 +5,10 @@ export pwidgets_splash='
<frame>
<text><label>""</label></text>
<text use-markup="true"><label>"<b>Pwidgets</b>"</label></text>
- <text><input file>/root/.pwidgets/tmp/pwidgets-splashtext</input></text>
+ <text><input file>'"${HOME}/.pwidgets/tmp/pwidgets-splashtext"'</input></text>
<progressbar>
<label>Sigmund Berglund, GPL 2008,2009</label>
- <input>while [ "$I" != "100" ]; do I=`cat /root/.pwidgets/tmp/pwidgets-splash`; echo $I; usleep 500000; done</input>
+ <input>while [ "$I" != "100" ]; do I=`cat ${HOME}/.pwidgets/tmp/pwidgets-splash`; echo $I; usleep 500000; done</input>
<action type="exit">Ready</action>
</progressbar>
</frame>
Code: Select all
-------- puppy-unleashed/packages/ptray-0.5/usr/local/ptray/box_splash --------
index bbe07ac..171950b 100755
@@ -4,10 +4,10 @@ export ptray_splash='
<vbox>
<frame>
<text><label>""</label></text>
- <text><input file>/root/.ptray/tmp/ptray-splashtext</input></text>
+ <text><input file>'"${HOME}/.ptray/tmp/ptray-splashtext"'</input></text>
<progressbar>
<label>Sigmund Berglund, GPL 2008,2009</label>
- <input>while [ "$I" != "100" ]; do I=`cat /root/.ptray/tmp/ptray-splash`; echo $I; usleep 500000; done</input>
+ <input>while [ "$I" != "100" ]; do I=`cat ${HOME}/.ptray/tmp/ptray-splash`; echo $I; usleep 500000; done</input>
<action type="exit">Ready</action>
</progressbar>
</frame>
Add more virtual terminals (optional, but makes life easier).
This one is pretty simple. You just have to edit /etc/inittab and add more lines, incrementing the tty numbers. For example, to go from two to six, you change:
Code: Select all
::sysinit:/etc/rc.d/rc.sysinit
tty1::respawn:/sbin/getty -n -l /bin/autologinroot 38400 tty1
tty2::respawn:/sbin/getty 38400 tty2
::ctrlaltdel:/sbin/reboot
Code: Select all
::sysinit:/etc/rc.d/rc.sysinit
tty1::respawn:/sbin/getty -n -l /bin/autologinroot 38400 tty1
tty2::respawn:/sbin/getty 38400 tty2
tty3::respawn:/sbin/getty 38400 tty3
tty4::respawn:/sbin/getty 38400 tty4
tty5::respawn:/sbin/getty 38400 tty5
tty6::respawn:/sbin/getty 38400 tty6
::ctrlaltdel:/sbin/reboot
If you have implemented toggleable autologin as described below, be sure to edit the /etc/inittab-AUTO and /etc/inittab-NOAUTO files too.
Set Puppy up to be able to optionally stop booting at a login prompt. (Included within user_utils-0.1.pet)
Make two copies of /etc/inittab, one named inittab-AUTO and one named inittab-NOAUTO. In the NOAUTO one, edit the tty1 line to look more like the others. As in, rather than
Code: Select all
tty1::respawn:/sbin/getty -n -l /bin/autologinroot 38400 tty1
Code: Select all
tty1::respawn:/sbin/getty 38400 tty1
You could also do this without the AUTO and NOAUTO versions by using sed to edit the tty1 line. However, if the user wanted to change the structure of the file, they'd have to modify the script too. This way they just have to modify the other two inittab-* files.
Proper user utilities such as useradd and gpasswd (shadow-4.1.4.2.pet)
Puppy includes limited versions of the real tools courtisy of Busybox. They don't have as many features and aren't as nice. So you'll need to replace them with the real thing. They are in a package called Shadow and I've provided a package above. I made a few changes from the default configuration, as follows:
Code: Select all
./configure --build=i486-t2-linux-gnu --prefix=/
- Prevent it from telling the user he has no mail after every login.
- Change MAIL_CHECK_ENAB from yes to no
- Add ENCRYPT_METHOD MD5
- Change ENV_PATH from PATH=/bin:/usr/bin to PATH=/sbin:/bin:/usr/sbin:/usr/bin
- /bin/su
/bin/chage
/bin/chfn
/bin/chsh
/bin/expiry
/bin/gpasswd
/bin/newgrp
/bin/passwd
- /bin/addgroup
/bin/adduser
/bin/delgroup
/bin/deluser
/bin/login
/bin/su
/usr/bin/passwd
/etc/skel
It's nice to have a template to create users' home directories from. That template is generally /etc/skel. When you use the useradd program with the -m option, it will automatically create the user's home directory and populate it from /etc/skel. But where is /etc/skel populated from? I'm a lazy person, so I decided to populate /etc/skel from /root, and to not bother being picky about only copying specific files. Of course, some things will need adjusting so that their paths work out right. Sometimes you'll have relative symlinks that point from /root/the_link to ../usr/bin/wherever_the_target_is. That link would no longer work if it started in /home/alice/. And sometimes a link named /root/link_name will be an absolute link pointing at /root/link_target, which wouldn't break when moved to /home/alice/, but it wouldn't help much either. And obviously, some files will have '/root/' specified in them. So, I wrote a script that will automatically take care of all that:
Code: Select all
usage: populate_skel [-u|-c|-n|-e] [-s SOURCE_DIR ] [ -d DEST_DIR ]
This is a script to populate the /etc/skel directory from the
/root directory, which attempts to also correct any absolute
symlinks pointing into /root and any relative symlinks pointing
out of /root, so those would break during the move. It also
uses sed to convert instances of "/root/" to "${HOME}/" in the
files copied.
-u Only copy newer files
-c Delete DEST_DIR before the copy
-n Do not attempt to correct symlinks
-e Do no change instances of "/root/" to "${HOME}/"
-s SOURCE_DIR Specify a different source than /root
-d DEST_DIR Specify a different destination than /etc/skel
The script is included in the user_utils-0.1.pet package.
I also modified my createpuppy script from Unleashed to run populate_skel. That way I don't need to mess with modifying all the packages to put things in /etc/skel. I just let them populate /root normally, then createpuppy will run populate_skel -n. I don't remember why I had it use the -n option, but I'm sure there was a good reason for that... I also added a line to clear out the mozilla profile after populate_skel finishes. Here is the diff:
Code: Select all
diff --git a/puppy-unleashed/createpuppy b/puppy-unleashed/createpuppy
index 0b5d20b..d8429b2 100755
--- a/puppy-unleashed/createpuppy
+++ b/puppy-unleashed/createpuppy
@@ -17,6 +17,7 @@
#v406 kernels/<sub dir> name can now be named <kern version>-<text>
#v411 remove stray unipup scripts.
#v412 add ssb.ko module to initrd (needed by ohci-hcd.ko).
+#vPP4 add option to create /etc/skel based on /root
APATTERN='^".\+" ".\+" .\+ ".*" \\'
ERRPKG="`cat packages.txt | grep -v "$APATTERN"`"
@@ -815,6 +816,19 @@ sync
cp -f /tmp/PuppyPinfixed rootfs-complete/root/Choices/ROX-Filer/PuppyPin
+#To support multiuser, create /etc/skel from /root
+if [ -x rootfs-complete/usr/sbin/populate_skel ]; then
+ echo "Press ENTER to create /etc/skel from /root using 'populate_skel', or"
+ echo "any printable character and then ENTER to not create /etc/skel: "
+ read CREATE_SKEL
+ if [ "$CREATE_SKEL" = "" ]; then
+ rootfs-complete/usr/sbin/populate_skel -n -s rootfs-complete/root -d rootfs-complete/etc/skel
+ #the populate script seems to corrupt the mozilla profile, so clear that out
+ rm -r rootfs-complete/etc/skel/.mozilla
+ echo
+ fi
+fi
+
echo -n "Press ENTER to build files that will be in the iso: "
read yabbo
echo
Code: Select all
#make sure the gtk files have the home directory rather than ${HOME}, as they can't handle that
for i in $HOME/.gtkrc*; do sed -i "s|\\\${HOME}|$HOME|g" "$i"; done
Code: Select all
#!/bin/sh
find "$HOME" -name '.jwm*' -type f -exec sed -i "s|\\\${HOME}|$HOME|g" "{}" \+
find "$HOME/.jwm" -type f -exec sed -i "s|\\\${HOME}|$HOME|g" "{}" \+
exec jwm.bin "$@"
During this guide I will often say that I did something in /etc/skel/ or ~/. Technically I did those things in /root and the populate_skel script propagated the changes into /etc/skel for me. Meaning that those changes also apply to /root, not only /etc/skel. Something to be aware of.
Configuring bashrc
A confusing point is that Bash doesn't support a global bashrc, but many sites refer to /etc/bashrc as being global. How it actually works is that you set up the default ~/.bashrc file to include the "global" /etc/bashrc file at the top. The user of course can edit his own .bashrc file if he wants, eliminating that inclusion. But this way if he leaves it and you later decide to change something in /etc/bashrc, all users who still include that from their .bashrc files will automatically inherit the changes. If you had instead just defined those defaults in the /etc/skel/.bashrc file, you would have to look though and maybe modify every user's .bashrc, which isn't desirable for many reasons (privacy, laziness, etc.)
So, in the /etc/skel/.bashrc file, you'll want to add something like this up near the top:
Code: Select all
#source the global bashrc file
[ -f /etc/bashrc ] && . /etc/bashrc
For Multiuser Puppy, I also removed the sourcing of /etc/profile from the /etc/skel/.bashrc file, so that the above is the only code actually being run (I did leave some commented out stuff).
As for what to put into /etc/bashrc, that would be things like aliases and what not. In a default Puppy, ~/.bashrc sources /etc/profile, but it mostly doesn't need to. The main thing you gain from that is the aliases defined there. Well, we can just move them out into /etc/bashrc.
The following is the contents of my /etc/bashrc:
Code: Select all
#global bashrc file
#(actually, it must be sourced in each user's ~/.bashrc, but whatever)
#Allow limited users to set their timezone with the ~/Choices/localtime file
[ "$USER" != "root" ] && [ -e ${HOME}/Choices/localtime ] && export TZ=$(cat ${HOME}/Choices/localtime)
#use color in ls if o/p to a tty, not in a script...
alias ls='ls --color=auto'
#add some common ls aliases
alias ll='ls -l'
alias la='ls -a'
alias lA='ls -A'
alias lal='ls -al'
#v4.00 run e3vi whenever vi excuted...
alias vi=e3vi
You may also want to add alias grep='grep --color=auto' to /etc/bashrc. I do that on my personal systems, but I left it out of this one because some people take offense to colored grepping. You'll note that I did add some ls aliases though. I figured they wouldn't bother anybody. And people can always override them in their ~/.bashrc file.
I'll explain the code about the timezone in the next section.
One last thing you should probably do is to create a symlink named /etc/skel/.profile pointed at .bashrc. I don't recall off the top of my head which one gets run under which circumstances, but this helps it remain more consistent if you log in under SSH.
Add sudo (Linux-PAM-1.1.0.pet, sudo-1.7.2p1.pet)
Sudo is useful in that you can use it to let individual users run specific commands with root privileges, without giving them the root password or letting them be able to run any arbitrary command as root (though if you make them a member of the "wheel" group, that does happen). Sudo depends on PAM support, so first you need to install Linux-PAM-1.1.0.pet. Then you can install sudo-1.7.2p1.pet. Sudo is configured by the files /etc/pam.d/sudo and /etc/sudoers. The former tells PAM what kinds of authentication need to happen for a user to use sudo. The file I included in the above package just requires the user to enter his password (not the root password). The latter file, /etc/sudoers, defines who is allowed to run what, along with some options for sudo. To edit it, use the visudo command. I created the "wheel" group and uncommented the option in /etc/sudoers that lets member of "wheel" run any command. I also set the default editor to be mp, but you can change it to geany or whatever you want by finding the line that looks like this:
Code: Select all
Defaults editor=/usr/local/bin/mp
Code: Select all
Defaults editor=/usr/bin/geany
Note that /usr/bin/sudo must be setuid, and /etc/sudoers must be chmod 0440.
The sources for these packages are here: Linux-PAM, Sudo.
Let users use the GUI timezone wizard to set their timezone
Anybody can set their timezone simply be specifying the TZ variable in ~/.bashrc. But to make things more GUI-friendly, you can modify the /usr/sbing/timezone-set script to detect if the user is not root, and if so, create a file named ~/Choices/localtime that contains the timezone (the path to the file in /usr/share/zoneinfo for the timezone in question). An example timezone-set script is provided in timezone-set.tar.gz.
Next add a couple lines in /etc/bashrc to check for the existance of that file, and if found set the TZ variable accordingly. The lines to add to /etc/bashrc are these:
Code: Select all
#Allow limited users to set their timezone with the ~/Choices/localtime file
[ "$USER" != "root" ] && [ -e ${HOME}/Choices/localtime ] && export TZ=$(cat ${HOME}/Choices/localtime)
Note: That code is also shown up above in the bashrc section, so don't add it twice...
Making the Prompt More Informative
Some people like long prompts that tell them the date and their location in the filesystem and who they are and whether it's sunny out and all kinds of other nonsense. I'm not going to get into all that. Since I'm trying to make this essentially look and work like a stock Puppy with minimal changes to become multiuser friendly, I opted to only make a very small change to the prompt. The prompt is controlled by the PS1 variable, which is set in /etc/profile. I changed it from being a hardcoded # to using \$, which causes it to show # only when you are root, otherwise it shows a $:
Code: Select all
PS1='\$ '
It's also possible to set the prompt to be a different color. I generally set mine to be red if I'm root, and yellow or green otherwise. It's easier to distinguish the difference in color than the difference between # and $, IMHO. Also, it makes the prompt stand out from the rest of the text better, and generally just looks nicer. Again, because I'm trying to keep things as close to stock as possible, I did not do that here.
If you're interested in making things fancy, read this.
Mounting (mount-stuff.tar.gz)
If you do nothing, only root will be able to mount drives. Depending on how you want to use Puppy, that may be the desired behavior. For most desktop users however, it is not. They'll want to be able to mount their USB drives and what-not without su-ing to root. But opening the system to let any user mount is a Bad Idea, as some server programs will run as their own limited user to minimize the damage should they be compromised. So, what to do? This is where the concept of "groups" kicks in. You can set the "group" option in /etc/fstab for a partition, and then any member of the group that owns the partition will be able to mount it. So first things first: add a "disk" group:
Code: Select all
groupadd disk
Next there needs to be an entry in /etc/fstab for every partition. That's where things get ugly. The sysadmin could of course add them manually, but that's a pain, and doesn't account for when Bob plugs in his USB drive. So, I wrote some scripts that latch into either Barry's "pup_event" system or udev, whichever is being used, and run another script (/sbin/pup_event_backend_fstab) when a new drive is detected. pup_event_backend_fstab then adds an entry to /etc/fstab. Since pup_event and udev run as root, the script will have enough permission to do this. While it's at it, it also makes sure that the device file belongs to the disk group. And to take care of any drives that are already connected on boot, I added some code to /etc/rc.d/rc.sysinit to run pup_event_backend_fstab on the existing drives too. Since in some situations a drive may have a different partition type than the last time it was used (two different USB drives for example) I made sure it's capible of editing lines. I also set it up so that if you manually change an fstab entry to remove the "group" option, the script will not touch that entry anymore. In case you want to have a root-only drive.
The partitions need to be mounted with mount-FULL, not the busybox mount, so I added some code to the mount script that takes care of this automatically, so the user can still use plain old "mount". Also, since a limited user cannot supply his own options, I added some lines to have it detect when just passing the raw commandline to mount-FULL fails and try to send it only the mountpoint. That allows things like Pmount to work with for limited users without actually being modified itself.
For the desktop icons to be updated, I needed to adjust /etc/rc.d/functions4puppy4, /sbin/pup_event_frontend_d, and /sbin/clean_desk_icons to be multiuser friendly. I didn't make pup_event_frontend_d completely multiuser friendly - it has functions involving saving USB installs and such that need to be done as root. But it's good enough to set up the desktop icons.
The modified files are availible in the mount-stuff.tar.gz file.
One catch is that NTFS partitions require mounting with ntfs-3g, but that doesn't work properly with the "group" option in /etc/fstab, and I couldn't get it to be user-friendly. So I added an extra option to the umount-client and umount-daemon (described below) to allow a limited user who is a member of the group owning the device node to tell the daemon to mount the partition (the daemon runs as root). The mount script has been modified to handle this automatically.
So, that takes care of mounting for any user who is a member of the 'disk' group.
Unmounting (mount-stuff.tar.gz)
If you set up mounting as described above, all seems fine and dandy. Until you try to unmount the partition. The "group" option doesn't let users unmount a partition. Probably because there's a chance that another user is now poking around in the partition. Anyway, we want to be able to unmount things so we can remove our USB drives.
So, I wrote /etc/init.d/umount-daemon, which runs as root and monitors /tmp/.umount-requests/. To unmount a partition, I added some code to the umount script that will call the /bin/umount-client script I wrote. umount-client will create a file in /tmp/.umount-request/ with a random name and which contains the path to the mountpoint of the partition. umount-daemon will detect the creation of the file, read the contents, determine if the user is authorized to unmount the partition (check that the group option is set in fstab and that the user and device node have the same group), unmount the partition, and delete the file umount-client created. Then umount-client will return you to the prompt. As mentioned above, it also can be used to mount partitions as root when you are actually a limited user, but that feature is strongly discrouaged. It is only included for rare situations where a limited user simply cannot mount the partition properly, such as with NTFS partitions.
The files needed are included in the mount-stuff.tar.gz file along with the ones for mounting.
So, the user should now be able to mount and unmount his drives with the normal mount and unmount commands, pmount, and the desktop icons. And since they'll all have proper /etc/fstab entries, you can even go into /mnt/ and click the mountpoints to mount them (ROX-Filer handles this automatically).
Audio
Initially, some audio devices in Puppy are globally usable, and some are not. This is not very nice. So, what you can do is make them all 660, and then set their group to "audio" (after creating the audio group of course...). Then, any user who belongs to the audio group can use the audio devices. I used the following commands:
Code: Select all
#create the audio group
groupadd audio
cd /
#have the "audio" group own the audio devices
chgrp audio ./dev/snd/* ./dev/audio ./dev/admmidi ./dev/adsp ./dev/aloadC0 ./dev/amidi ./dev/amixer ./dev/audio ./dev/audio0 ./dev/dmmidi ./dev/dsp ./dev/midi ./dev/mixer ./dev/music ./dev/seq ./dev/sequencer ./dev/sequencer2 ./dev/sndstat ./dev/speaker
#make sure only authorized users can do audio things
chmod 660 ./dev/snd/* ./dev/audio ./dev/admmidi ./dev/adsp ./dev/aloadC0 ./dev/amidi ./dev/amixer ./dev/audio ./dev/audio0 ./dev/dmmidi ./dev/dsp ./dev/midi ./dev/mixer ./dev/music ./dev/seq ./dev/sequencer ./dev/sequencer2 ./dev/sndstat ./dev/speaker
Poweroff and Reboot (power-stuff.tar.gz)
In the stock Puppy, a limited user cannot poweroff or reboot the machine. As with mounting and audio, this may or may not be desireable. Thus, the solution is to add a "power" group and put people who should be able to do such actions into it. Then chmod 750 the poweroff and reboot commands. That's enough to limit who can run the commands to the right people, but it still doesn't grant them the permission to actually do the deed. So I wrote a daemon named /etc/init.d/power-daemon, which is very similar to the umount-daemon. It monitors /tmp/.power-requests/ for files containing "poweroff" or "reboot". The /tmp/.power-requests/ directory has it's permissions set to 770 and is owned by the power group, so only authorized users can create such files. The actual file creation is handled by the poweroff and reboot scripts. When run by non-root users, they create a file with the appropriate contents in /tmp/.power-requests/, which then runs the command again as root. When they are run as root, they skip the /tmp/.power-requests stuff and do what they normally do - run /etc/rc.d/rc.shutdown and then poweroff or reboot the computer.
Adding Users (included in user_utils-0.1.pet)
To avoid the need to remember all these groups when creating a new user, I wrote the /usr/sbin/adduser-wizard script. It gives you a GUI way to createa user, select whether he should be a part of the disk, audio, power, and wheel groups, and lets you set his password. It also uses the -m option when running useradd, so that the user gets his home directory created as well. After the home directory is created, it goes ahead and chmods it to 750 to keep it private. Finally, it goes ahead and adds the /etc/X11/$USER/ directory and sets the ownership to the new user. This wizard is a part of the user_utils-0.1.pet package I made.
Changing the Password (included in user_utils-0.1.pet)
I tried to make a gui for setting your password, but passwd doesn't have a way to accept a password from STDIN or environment variables. There is a program included in shadow called chpasswd that lets you do this, but it only works for root (that's the method I used for the adduser-wizard). I could do it with an "expect" script, but that would mean adding another dependency... So instead, I just wrote a script that pops up an rxvt window and runs the passwd command inside it. This way it can at least be run from the menu. I named it passwd-wizard and included it in the user_utils-0.1.pet.
Pwidgets background
Pwidgets was storing the background in /usr/share/backgrounds/Pwidgets_background, which is root only. So you can get around that by editing /usr/local/pwidgets/func and /usr/sbin/fixwidgets to store it at $HOME/.pwidgets/Pwidgets_background instead. That's in addition to replacing instances of /root/ with $HOME of course.
PetGet
Installing software is something that must be done as root. So added a couple lines near the top to throw an error message if you are not root:
Code: Select all
#Don't bother attempting to run unless root
if [ "$(whoami)" != "root" ]; then
[ "$(ps -eo comm | grep ^X)" = "X" ] && Xdialog -title "PETget package manager" --msgbox "Sorry, but only the root user\nhas permission to run petget" 0 0
echo "ERROR: Must be root to run petget" >&2
exit 1
fi
Fixmenus
This can be made mostly multiuser friendly with just a couple changes to convert /root into ${HOME}
Code: Select all
diff --git a/puppy-unleashed/packages/xdg_puppy-0.7.6-5_4.2/usr/sbin/fixmenus b/puppy-unleashed/packages/xdg_puppy-0.7.6-5_4.2/usr/sbin/fixmenus
index 2dde04b..5eb8038 100755
--- a/puppy-unleashed/packages/xdg_puppy-0.7.6-5_4.2/usr/sbin/fixmenus
+++ b/puppy-unleashed/packages/xdg_puppy-0.7.6-5_4.2/usr/sbin/fixmenus
@@ -7,6 +7,8 @@
#...the '_' will be converted to a '/', so the generated JWM config file is:
# /root/.jwmrc
# 5jan2008: fbpanel,lxpanel support developed by plinej.
+#06Sept2009 PG: Don't bother attempting to run unless root
+#31Oct2009 PG: Allow running as non-root
#Puppy 2.14: XDG menu
@@ -15,7 +17,7 @@ TEMPLATES="`ls -1 /etc/xdg/templates | tr '\n' ' '`"
for ONETPL in $TEMPLATES
do
[ "$ONETPL" = "README.txt" ] && continue
- ONEDEST="`echo -n "$ONETPL" | sed -e 's/_/\//g'`"
+ ONEDEST="`echo -n "$ONETPL" | sed -e 's|_|/|g' -e "s|^/root/|$HOME/|"`"
ONESRC="/etc/xdg/templates/$ONETPL"
echo "Generating $ONEDEST..."
@@ -24,6 +26,7 @@ do
cat $ONESRC |
while read ONELINE
do
+ ONELINE="`echo -n "$ONELINE" | sed "s%\([='\\\"> ]\+\)/root/%\1$HOME/%g"`"
EXECMENU="`echo -n "$ONELINE" | grep -o 'PUPPYMENU.*' | cut -f 2-5 -d ' '`"
if [ "$EXECMENU" = "" ];then
echo "$ONELINE" >> $ONEDEST
The X Windows System (x-stuff.tar.gz)
Beside the following changes, this also needed the permissions of /dev/zero changed, and ddcprobe and Xvesa setuid as described above.
~/.xinitrc
- Change all instances of /root/ into $HOME/
Use ~/Choices/windowmanager rather than /etc/windowmanager
- Use /tmp/${USER}-<filename> rather than /tmp/<filename> for temporary files.
/usr/sbin/chooselocale- Use ~/Choices/windowmanager rather than /etc/windowmanager
- If the user is not root, use /etc/X11/$USER/xorg.conf rather than /etc/X11/xorg.conf.
- Use ${HOME}/Choices/videomode rather than /etc/videomode
- Use ${HOME}/Choices/videomode rather than /etc/videomode
- Use /tmp/${USER}-<filename> rather than /tmp/<filename> for temporary files.
Use ${HOME}/Choices/videomode rather than /etc/videomode
- Change all instances of /root/ into $HOME/
Use ~/Choices/windowmanager rather than /etc/windowmanager
Use /tmp/${USER}-<filename> rather than /tmp/<filename> for temporary files.
If the user is not root, use /etc/X11/$USER/xorg.conf rather than /etc/X11/xorg.conf
Use ${HOME}/Choices/videomode rather than /etc/videomode
- Moved to ~/Choices/windowmanager
- Use ~/Choices/windowmanager rather than /etc/windowmanager
Use /tmp/${USER}-<filename> rather than /tmp/<filename> for temporary files.
- Use /tmp/${USER}-<filename> rather than /tmp/<filename> for temporary files.
- Use /tmp/${USER}-<filename> rather than /tmp/<filename> for temporary files.
- Change all instances of /root/ into $HOME/
Use /tmp/XLOADED instead of /etc/.XLOADED
Make /tmp/XLOADED world-writable (rather than doing it per-user, because you don't want Alice starting X if Bob is already running it!)
Use /tmp/${USER}-<filename> rather than /tmp/<filename> for temporary files.
Use ${HOME}/Choices/windowmanager rather than /etc/windowmanager
Use /etc/X11/$USER/xorg.conf if it exists, otherwise use /etc/X11/xorg.conf as usual.
Use ${HOME}/Choices/videomode rather than /etc/videomode
Also modified /usr/bin/seahaven-multi to use ${HOME}/Choices/videomode, and the following files in the icewm and jwm packages to support using ~/Choices/windowmanager rather than /etc/windowmanager:- pinstall
/root/.icewm/startup
/usr/bin/icewm2jwm
/usr/bin/jwm2icewm
Grep and Sed Work
Finally, I did some grep and sed work on a large number of files. The sed command itself was this:
Code: Select all
sed -i 's|/root/|${HOME}/|' <FILENAME>
Code: Select all
grep -lIR '/root/' * 2>/dev/null | cut -f 1 -d '/' | sort -u > /tmp/list
Code: Select all
grep --color -IR '/root/' package_1 package_2 package_3
Code: Select all
find package_1 package_2 package_3 -type f -exec sed -i 's|/root/|${HOME}/|'
Since there were so friggin' many, I didn't do a good job of documenting them. Sorry. However, all of the work I've done on this project was done through Git, so I can provide the diff from that commit. That could be perused by and applied by hand, or if you have things laid out the same as my unleashed tree was it could be fed into the patch program. You could probably also feed it through patch without unleashed and just have patch strip off the first three components of the path. I'm not sure how well that would work though because there may be some duplication due to multiple versions of some packages. Anyway, here is the diff file: makestuffuserfriendly.diff
Git (for masochists who want to see exactly what I did)
I used Git when working on Multiuser Puppy. Git isn't for everybody, especially when working on large binary projects such as a Puppy derivatives. Because Git was primarily designed for dealing with source code, not large binary projects, there are a number of pitfalls a person desiring to use it for Puppy development should be aware of. I already wrote a lot of information on the subject when we were considering moving official Puppy development into a Git repository. That information now lives here: (link). You don't need to use Git. But you are free to clone my tree if you want to play around with exactly the build environment I used when creating Multiuser Puppy. My Multiuser Puppy work is under the "multiuser" branch.
git://pizzasgood.no-ip.org/puppy
Conclusion
That sums up what I did to make Multiuser Puppy work. Feel free to ask questions, suggest improvements, and point out gaping security holes I left open. A brief warning: I have no intention to maintain this. My goal was only to forge the path to make a multiuser Puppy possible. I've succeeded in that goal. So I'm moving on to other projects. I will of course still answer any questions and what-not, and maybe address any major problems. But it's up to "you" to reapply this to newer/older versions of Puppy where needed. They shouldn't be different enough to make a huge difference.
Last updated 2009-10-31