Linux - Looking under the hood


Differences between hard and soft links (details) :

hard links :
  • share a single inode with their target.
  • can not refer to : The target must be an existing regular file.
  • can only refer to a file found on the same filesystem (because inodes are not unique across filesystems).
  • How to spot a hard link ?
symbolic links :
  • can refer to directories, missing files, another symbolic link, and even cross file system boundaries.
  • have their own inode.

Interesting facts about symlinks (source) :

  • On Linux, the permissions of a symbolic link link are not used in any operations. The permissions are always 0777 and can't be changed.
  • You can change the owner of a symbolic link with chown -h.
  • When most operations (opening, reading, writing, ...) are passed to the symbolic link file, the kernel automatically "dereferences" the link and operates on the target of the link. But some operations (e.g., removing) work on the link file itself, rather than on its target.
  • Most commands dereference (i.e. follow) symbolic links, with the notable exception of :
    • mv
    • rm
    • file
    • ls
    • and MANY others when using their recursive (-R) flag

About symlinks exploits (details) :

There was a vulnerability exploiting symbolic links to overwrite arbitrary files (details). This has been fixed, and symbolic links can be followed only when :
  • outside a sticky world-writable directory. Sticky world-writable directories, like /tmp, have drwxrwxrwt permissions
  • OR when the UID of the symlink and follower match
  • OR when the directory owner matches the symlink's owner
This protection is enabled by :
echo 1 > /proc/sys/fs/protected_symlinks
(default setting on Debian Wheezy). It protects root too.
it is still recommend to create temporary files with mktemp

Why do some of my processes have a PPID value of 1 ?


I've just observed that one of my processes running in the GUI has a PPID value of 1 :
ps -u bob -o pid,ppid,etimes,cmd | awk '$2 == 1 && $3 > 3600'

92617       1   10694 vlc /media/bob/path/to/playlist.m3u



This has nothing to do with : But, it turns out that :

How to build a statically linked binary for a 32bit environment on a 64bit platform ?

  • I am far from being a specialist, so consider the information below cautiously : there may be missing / wrong / context-specific information. Use at your own risk.
  • sshpass may not be the best software in town as it leads to unsafe workflows (details) but in the context of this article (learning to build a custom binary), it does the job. Use the generated binary at you own risk (or —myadvice— just delete it once you've learnt everything you needed ).

Get the source code of the software you'd like to compile :

The fastest + easiest solution :
apt-get source sshpass
This requires :
  • the software to be available in your distro's list of packages
  • and your workstation to have a deb-src entry in /etc/apt/sources.list
This Debian wiki page gives a good description of what you'll get and alternate means.

Now, make it happen (inspired by) :

apt-get source sshpass
cd sshpass-1.06/
ldd sshpass (0x00007ffe45de8000) => /lib/x86_64-linux-gnu/ (0x00007f3830e37000)
/lib64/ (0x00007f38313da000)
make clean
make SHARED=0 CC='gcc -static'		not sure about the SHARED=0 part 
ldd sshpass
not a dynamic executable		what we were trying to do 

What happens after moving our new binary to 32bitMachine ?

kevin@32bitMachine ~$ ./sshpass
bash: ./sshpass: cannot execute binary file
kevin@32bitMachine ~$ file sshpass
sshpass: ELF 64-bit LSB executable, AMD x86-64, version 1 (GNU/Linux), for GNU/Linux 2.6.32, statically linked, not stripped
kevin@32bitMachine ~$ uname -a
Linux 32bitMachine 2.6.9-89.0.3.ELsmp #1 SMP Sat Jun 13 07:05:54 EDT 2009 i686 i686 i386 GNU/Linux

At that time, I didn't notice it, but I was also not building for the right kernel version : 2.6.32 vs 2.6.9 .

After that, I read + tried various methods that FAILED until... :

I note them here because knowing what doesn't work, albeit not the solution, is part of the solution (and possibly —later— I'll understand why they failed ).
  1. (source)
    ./configure --host=i686-linux-gnu --build=i686-linux-gnu CC="gcc -m32" CXX="g++ -m32" CFLAGS="-O2 -march=i686" CXXFLAGS="-O2 -march=i686"
    checking for a BSD-compatible install... /usr/bin/install -c
    checking whether build environment is sane... yes
    checking for a thread-safe mkdir -p... /bin/mkdir -p
    checking for gawk... gawk
    checking whether make sets $(MAKE)... yes
    checking whether make supports nested variables... yes
    checking for style of include used by make... GNU
    checking for i686-linux-gnu-gcc... gcc -m32
    checking whether the C compiler works... no
    configure: error: in `.../path/to/sshpass-1.06':
    configure: error: C compiler cannot create executables
    See `config.log' for more details
  2. (source)
    make clean && ./configure && make CC='gcc -static -m32'
    make all-am
    make[1]: Entering directory '.../path/to/sshpass-1.06'
    gcc -static -m32 -DHAVE_CONFIG_H -I.     -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
    main.c:25:23: fatal error: sys/types.h: No such file or directory
     #include <sys/types.h>
    compilation terminated.
    Makefile:415: recipe for target 'main.o' failed
    make[1]: *** [main.o] Error 1
    make[1]: Leaving directory '.../path/to/sshpass-1.06'
    Makefile:307: recipe for target 'all' failed
    make: *** [all] Error 2
  3. (source)
    apt-cache search libc | grep -E 'dev.*86'
    libc6-dev-i386 - GNU C Library: 32-bit development libraries for AMD64
    apt install libc6-dev-i386
    make clean && ./configure && make CC='gcc -static -m32'
    make all-am
    make[1]: Entering directory '.../path/to/sshpass-1.06'
    gcc -static -m32 -DHAVE_CONFIG_H -I.     -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
    In file included from /usr/include/sys/ioctl.h:26:0,
                     from main.c:28:
    /usr/include/bits/ioctls.h:23:24: fatal error: asm/ioctls.h: No such file or directory
     #include <asm/ioctls.h>
    compilation terminated.
    Makefile:415: recipe for target 'main.o' failed
    make[1]: *** [main.o] Error 1
    make[1]: Leaving directory '.../path/to/sshpass-1.06'
    Makefile:307: recipe for target 'all' failed
    make: *** [all] Error 2
  4. (source)
    apt install gcc-multilib
    make clean && ./configure && make CC='gcc -static -m32'
    no error
    file sshpass
    sshpass: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=886a41e4c4e7631776b20a44f2262b85ad3fa240, not stripped

Let's move again our new binary to 32bitMachine :

kevin@32bitMachine ~$ file sshpass
sshpass: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), for GNU/Linux 2.6.32, statically linked, not stripped
kevin@32bitMachine ~$ (a command including sshpass)
FATAL: kernel too old
Segmentation fault
Indeed :
kevin@32bitMachine ~$ uname -a
Linux 32bitMachine 2.6.9-89.0.3.ELsmp #1 SMP Sat Jun 13 07:05:54 EDT 2009 i686 i686 i386 GNU/Linux
I compiled for a 2.6.32 kernel, while I have a 2.6.9.
Back to my 64bit workstation, I tried :
make clean && ./configure --enable-kernel=2.6.9 && make CC='gcc -static -m32'
... but it's not that simple

Conclusion :

I've not been able to build a binary as I wanted to. However, I've learnt some extra things in the process, which is GOOD .

Let me conclude with an inspiring quote by Bruce Lee :

Don't fear failure. Not failure, but low aim, is the crime. In great attempts it is glorious even to fail.


Process priority (PR) vs niceness (NI)


  • Priority is the actual priority value of a process at any given moment inside of the kernel.
  • Niceness is just a hint for the kernel what the priority the process should have.

More details

  • Priority is relevant for the kernel task scheduler.
  • In most cases, priority can be computed by : PR = 20 + NI
  • The kernel may change the priority value by itself (but not the niceness value). For instance :
    • reduce the priority of a process if it consumes too much CPU
    • increase the priority of a process if that process had no chance to run for a long time because of other higher priority processes
  • Priority is actually a dynamic value :
    • all of this is handled by scheduling policies
    • when using the default scheduling policy (SCHED_OTHER), process priority ranges from 0 to 39 (PR = 20 + NI with -20 ≤ NI ≤ 19)
    • some processes may use real time scheduling policies (SCHED_RR, SCHED_FIFO) and have a priority value less than 0
    • you may alter the priority value with :
      • sudo chrt -r -p 1 $(pidof vlc)
      • sudo chrt -r -p 99 $(pidof vlc)
      • sudo chrt -r -p 99 $(pidof pulseaudio)
        • while playing with the commands above, top displays a priority value which is -1 * (-p value +1)
        • when using 99, top displays rt because its column is only 2 characters wide, and -100 wouldn't fit

Why can't I delete or rename a file I own with 700 rights ?

  1. tempDir=$(mktemp -d tempDir.XXXXXXXX); touch "$tempDir/file1" "$tempDir/file2"
  2. chmod 000 "$tempDir/file1"; chmod 700 "$tempDir"; rm "$tempDir/file1"
    rm: remove write-protected regular empty file 'tempDir.AVVTQONL/file1'? y			Not completely happy but does it though
  3. chmod 700 "$tempDir/file2"; chmod 000 "$tempDir"; rm "$tempDir/file2"
    rm: cannot remove 'tempDir.AVVTQONL/file2': Permission denied					Total disagreement. Why ?
  4. mv "$tempDir/file2" "$tempDir/file3"
    mv: failed to access 'tempDir.AVVTQONL/file3': Permission denied				"Why ?" again 
  5. chmod 700 "$tempDir"; rm "$tempDir/file2"; rmdir "$tempDir"
This is because deleting or renaming a file actually alters its parent directory, not the file itself. In Unix, a directory is just a file containing a list of files.

How to install new fonts ?

  1. make a new directory for fonts :
    mkdir -p ~/.local/share/fonts
  2. copy font files there
  3. rebuild the font cache :
    fc-cache -f -v
  4. the new fonts will be available after a logout + login

To make a font available to all users, copy it into /usr/share/fonts instead.

On the Internets, some answers / comments specify ~/.fonts as the personal fonts dir, while others prefer ~/.local/share/fonts. Some even state one or the other should be preferred or is obsolete...


What if I accidentally moved /* to a different location ?


Don't type the commands below since I'm basically explaining here how I shot my own leg

What I meant is :
mv $D/* .
$D being an existing directory, and . the location I wanted files to land into.
But I actually typed :
mv $d/* .
... and did this as root.


When receiving the command :
mv $d/* .
Bash will expand variables. Here, since $d is undefined, it is considered as an empty string, and my command becomes :
mv /* .
I stopped it as quick as I could with CTRL-c, but /bin and /lib (and many others) were already gone . What's "fun" then is that the shell commands ls, cp or mv don't work anymore since there is no /bin/ls, /bin/cp or /bin/mv. Even invoking binaries as ./bin/ls, ./bin/cp or ./bin/mv fails : /lib64/ bad ELF interpreter, they say (but no big surprise either since /lib and /lib64 have been moved to...). And I can't even create symlinks because I have no /bin/ln anymore .


In such situation, there are not many solutions. The obvious one is to boot the computer on a rescue media, mount the partition and restore files manually to their normal location.

But another solution may save your life : BusyBox. This is a binary with lots of standard utilities (like mv, sh, ls, ...) built into it. To restore the system, you just have to :

busybox mv {bin,boot,dev,etc,lib,lib64} /

To prevent this from happening again, I considered adding set -u to ~/.bashrc, but this breaks the TAB completion. (investigate this !!!)


I'm having DNS resolution issues and /etc/resolv.conf is continuously overwritten


Well, it's all in the title.


The DNS servers configured in /etc/resolv.conf don't provide any useful service anymore (problem on ISP side ?)


systemctl -a | grep resolv
	pppd-dns.service			loaded	inactive dead	Restore /etc/resolv.conf if the system crashed before the ppp link was shut down.

systemctl status pppd-dns.service

 pppd-dns.service - Restore /etc/resolv.conf if the system crashed before the ppp link was shut down.
	Loaded: loaded (/lib/systemd/system/pppd-dns.service; enabled)
	Active: inactive (dead) since Sat 2016-02-27 14:36:27 CET; 3 weeks 1 days ago
 Main PID: 619 (code=exited, status=0/SUCCESS)

Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.

nameserver 2001:41d0:3:163::1
nameserver 2001:41d0:1:e2b8::1

systemctl disable pppd-dns.service
	Synchronizing state for pppd-dns.service with sysvinit using update-rc.d...
	Executing /usr/sbin/update-rc.d pppd-dns defaults
	Executing /usr/sbin/update-rc.d pppd-dns disable
	insserv: warning: current start runlevel(s) (empty) of script `pppd-dns' overrides LSB defaults (S).
	insserv: warning: current stop runlevel(s) (S) of script `pppd-dns' overrides LSB defaults (empty).

/etc/init.d/pppd-dns stop
update-rc.d pppd-dns remove

==> Still not working :-(
This is quick and dirty, but works until I find WTF is going on :
echo -e 'nameserver\nnameserver' > /etc/resolv.conf && chattr +i /etc/resolv.conf

How to change the default text editor ?

Even though I'm rather an Emacs guy (especially when it comes to development), I've learnt the basics of Vi and I admit it's more than enough for quick edits like configuration files, crontabs, Git commit messages, ... On top of that, I don't particularly appreciate Nano and I just can't get used to its keyboard shortcuts (yeah : kinda weird in an Emacs/Vi talk, I know ), and I _always_ have to look at the bottom line reminding me of them.
Enough is enough : how can I just change that to a decent text editor ?

Temporary solution (i.e. not reboot-proof) :

Set a new value to the EDITOR environment variable :

  1. Run : export EDITOR=vi|emacs|nano|
  2. Check it with : crontab -e

By changing the EDITOR value for that single command only :

EDITOR=vi|emacs|nano| <command options >

Permanent solution (reboot-proof) :

  1. Append to ~/.profile :
    export EDITOR=vi|emacs|nano|
  2. Reload changes : source ~/.profile
  3. Check it with : crontab -e

Permanent Debian-specific solution :

  1. As root, run : update-alternatives --config editor
  2. Follow the on-screen instructions
  3. Check it with : crontab -e
Tested but doesn't seem to work on Debian Jessie Try : select-editor.

How to stop the X Server ?


For any reason, I need to turn off the X Server. How to proceed ?


This can be done easily by switching to a lower runlevel with init newRunlevel
However, this doesn't work on Debianoids if network or multiuser are required since the default runlevel is 2.


Stop the display manager, which can be : If necessary, it's possible to explicitly stop (kill) the X Server with : Ctrl-Alt-[backspace]

Linux performance tools

Observability :

  • /proc
  • blktrace
  • dstat
  • dtrace
  • ebpf
  • ethtool
  • free
  • ftrace
  • iostat
  • iotop
  • ip
  • iptraf
  • ktap
  • lldptool
  • ltrace
  • lttng
  • mpstat

Tuning :


How to stop the /usr/sbin/ModemManager process and prevent it from restarting ?


  • This article has little to nothing practical use except for some future reference or further investigations on the D-Bus service
  • In previous software versions, we had :
    • process name : modem-manager
    • binary : /usr/sbin/modem-manager
    • service name : ModemManager1.service
    • D-BUS file : /usr/share/dbus-1/system-services/org.freedesktop.ModemManager.service

top -p $(pidof ModemManager)

553	root	20	0	422444	8724	7244	S	0.0	0.2	0:00.04	ModemManager
which looks BAD to me as I don't use a modem anymore.


ModemManager is a child process of NetworkManager : if you try to kill ModemManager, NetworkManager will try to start it again.
ModemManager is implemented as a D-Bus service and it's autostarted by D-Bus when a call is made on it. NetworkManager pokes it every 2 minutes and thus restarts it.


  1. watch it still alive :
    top -p $(pidof ModemManager)
        PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
      21267 root      20   0  317952  12544  10632 S   0.0   0.0   0:00.05 ModemManager
  2. disable + stop ModemManager :
    systemctl disable --now ModemManager.service
  3. check it's not running anymore :
    (should return nothing)
  4. Congratulations : you've just saved about 12MB of memory (the RES part).

/var/log/auth.log is missing


  1. The file /var/log/auth.log is missing. No process has even tried to create it, nor complained about it not found.
  2. If I create it manually with 640 permissions and owning it by root:adm, no process even tries to write into it.


Creating log files manually is useless : should any process require a log file, it will create it if missing.
/var/log/auth.log is declared in /etc/rsyslog.conf.


In my situation, restarting rsyslogd made it back to normal : /etc/init.d/rsyslog restart

How to recover deleted / lost / corrupted files ?

With lsof :

It is possible to recover a deleted file with lsof provided there is still a process holding it. Otherwise, keep reading below.

With grep (source) :

The magic with this trick is that :
  • "deleted" files are not actually deleted : instead, the storage space they use is marked as available. So information is still there until it's overwritten; the sooner you try to recover data, the higher your chances of success
  • grep can not only search in regular files, but also in a whole disk
grep -a -C 2000 needle /dev/sdXY | tee recovered.txt

Last-minute tips :

  • needle is any word / phrase / regular expression than can "as uniquely as possible" be found in the deleted file you're trying to recover
  • if you're not sure needle is in the start / middle / end of the deleted file, provide -C with a value that is twice the number of lines of the deleted file
  • to increase chances of success :
    • stop writing to /dev/sdXY
    • unmount it (if possible)
    • write recovered.txt on another partition / storage media

With Scalpel :

  1. install : apt install scalpel
  2. edit /etc/scalpel/scalpel.conf (append rules such as these for OpenOffice files)
  3. edit the recovered file size (10MB on this example) : upon finding the start tag, Scalpel will recover 10MB as if they were part of the recovered file.
  4. umount the volume to analyze
  5. mkdir -p /directory/for/recovered/files
  6. scalpel /dev/sdXY -b -o /directory/for/recovered/files
  7. wait...
  8. once done, hope you'll find anything valuable in /directory/for/recovered/files
Flags (need more details):
-b : recover a file even if it's missing a footer
-o : output directory (?)

How to handle text file encoding and transcode between us-ascii, iso-8859-15, utf-8, ..., charsets ?

Detect file encoding

You can detect file encoding with : file -i fileName.

  • If this returns the file MIME type instead of its encoding, you may try creating a new file next to fileName : it's very likely to have the same encoding.
  • If fileName contains no special character (i.e. ASCII characters only), its charset will be a basic *-ascii. To have it use an "advanced" charset, it must contain some non-ASCII characters : éêèàâî....


From the shell :

  • iconv --from-code=ISO-8859-1 --to-code=UTF-8 iso_file.txt > utf8_file.txt

    The source and destination must be distinct files.

    fileToTranscode='itr_install_db_050000.ksh'; cp "$fileToTranscode"{,_BITI}; iconv --from-code=ISO-8859-1 --to-code=UTF-8 "${fileToTranscode}_BITI" > "$fileToTranscode"

  • recode Latin1..UTF8 file.txt (recode -l to list available encodings)

With Emacs (source : 1, 2) :

  1. Open the file to transcode
  2. Notice some letters in the lower left corner identifying the charset :
    Letters charset Comment
    UU- us-ascii
    UU0 iso-8859-15 file -i reports iso-8859-15 as iso-8859-1
    UU1 iso-8859-1
    UUU utf-8
    • CTRL-x f
    • OR : CTRL-x CTRL-m f
  3. At the prompt, type the new coding system : iso-8859-1 / utf-8 / ...
  4. Save the transcoded file

With Vim (source) :

  1. Open the file to transcode
  2. :write ++enc=utf-8

With Notepad++ :

There is a built-in transcoding function : Encoding | Convert to ....

How to alter environment variables of a running process ?

Method 1 (source) :

  1. gdb -p PID (consider $(pidof command))
  2. (gdb) p setenv("variableName", "variableValue")
  3. (gdb) q
  4. (gdb) Really detach? y

Method 2 (source) :

  1. gdb
  2. (gdb) attach PID
  3. (gdb) call putenv ("variableName"="variableValue")
  4. (gdb) detach
  5. (gdb) y

File permissions and setuid / setgid / sticky bits

File permissions using the symbolic syntax (source : 1, 2) :

Example File type all
user group others
-rw-r--r-- regular file
  • r : read permission
  • w : write permission
  • x : execute permission
drwxr-xr-x directory
  • r : the contents of the directory can be shown
  • w : new files can be created
  • x : a user / group member / other can cd into this directory

Subtleties about traditional Unix permissions (sources : 1, 2)

When a process tries to open a file with traditional Unix permissions :
  • If the file's owning user is the process's effective UID, then the user permission bits are used.
  • Otherwise, if the file's owning group is the process's effective GID or one of the process's supplementary group ID, then the group permission bits are used.
  • Otherwise, the other permission bits are used.

Special Permissions (sources : Wikipedia)

the Setuid bit
used only for binaries or scripts, this permission indicates that the file is to be executed with the permissions of the owner of the file, and not with the permissions of the user executing the file (which is the case without setuid). This is indicated by the character s in the place of the x in the owner category. If the owner of the file does not have execute permissions, a capital S reflects this fact.
the Setgid bit
used primarily for binaries, this permission indicates that the file is executed with the permissions of the group owning the file and not with the permissions of the group of the user executing the file (which is the case without setgid).
If applied to a directory, all files created within the directory are owned by the group owning the directory, and not by the group of the user creating the file. The setgid permission is indicated by the character s in place of the x in the group category. If the group owning the file or directory does not have execute permissions, a capital S reflects this fact.
the Sticky bit
used primarily on directories, this bit dictates that a file created in the directory can be removed only by the user who created the file. It is indicated by the character t in place of the x in the everyone category. If the everyone category does not have execute permissions, the T is capitalized to reflect this fact.
Under Red Hat Enterprise Linux, the sticky bit is set by default on the /tmp/ directory for exactly this reason.

Octal permissions (source) :

Bit Symbol Number
setuid s 4000
setgid s 2000
sticky t 1000 If this attribute is assigned to a directory, it will prevent users from deleting each other's files.
r 400 for user, 40 for group, 4 for other
w 200 for user, 20 for group, 2 for other
x 100 for user, 10 for group, 1 for other

Environment Variables

Definition (source 1, 2) :

An environment variable is basically just a shell variable that is available system-wide (i.e.: to sub-shells). A shell variable can be changed into an environment variable with export.

List all environment variables :

  • $ + TAB : names only. By convention, environment variables names are all UPPERCASE.
  • export -p
  • printenv
  • env or set : names and values (need details of the difference, if any)

Display the value of an environment variable :

  • env | grep VARNAME
  • printenv VARNAME
doesn't discriminate environment from shell variables and will always display the corresponding value (or nothing if unset).

Alter temporarily (source) :

for several / all commands

  1. in the shell, type :
  2. this value will last as long as the current Bash process is running (i.e. until logout or exit).
  3. to share the variable with the children of the current Bash process :
    export VARNAME

for a single command

It's is possible to set a shell variable so that its scope is limited to a single command by placing it just before this command (source) :
foo=bar bash -c 'echo "$foo"'; echo "$foo"
(empty line)
In this example, the first echo is single-quoted, meaning it's passed as-is (without variable substitution) to the child Bash process.
foo=bar bash -c echo\ $foo; echo "$foo"
(empty line)
(empty line)
Several things to mention here :
  • the first echo is unquoted, which is why a \ is necessary after echo : the whole echo $foo is a single argument passed to bash -c, and this \ is just there to escape the space in the middle of this argument
  • since the first echo $foo is unquoted, it is subject to variable substitution, and $foo is replaced with its value in the current shell : an empty string
Don't forget that the variable only exists while the command runs.

ignore temporarily source :

You may also want to ignore all environment variables for the duration of a single command. To do so (in bash/ksh/zsh) :
env -i anyCommand

Alter permanently (sources : 1, 2) :

Keep in mind that
  • changes made in ~/whatever will only exist in the current user scope
  • changes made in /etc/whatever will exist system-wide

Depending on the shell type, i.e. (non-)?(login|interactive) :

  1. edit one of :
    • ~/.bashrc
    • ~/.bash_profile
    • ~/.profile
    • /etc/profile
  2. add export VARNAME=value
  3. reload changes : source theFileYouJustEdited
Example :
export http_proxy=http://bob:password@host:port/
export https_proxy=$http_proxy

in /etc/environment (source) :

when it comes to the http_proxy configuration, things may get shitty when using wget, because of its configuration files that may also have some additional / conflicting settings :
  • /etc/wgetrc
  • ~/.wgetrc
Consider giving a try with curl to have a clear picture of what's going on

Set with :

  • Bash : export VARNAME=value This is NOT permanent !
  • C-Shell : setenv VARNAME value

Unset with :


How to create a loop filesystem ?

The loop devices are a possibility under GNU/Linux to mount regular files. It is often used to mount an iso image, but it can also be used to play with RAID, LVM, or a file system.
Loading the loop module is required before using loop devices : modprobe loop. This will create the loop devices /dev/loop0, /dev/loop1, etc.
Consider working inside a tmpfs like /dev/shm to gain speed when running tests.

Create a filesystem out of a file, then mount it :

  1. Create a file having the size of your future filesystem : dd bs=1M count=100 if=/dev/zero of=fsInAFile
  2. Format the file (using any filesystem you like) : mkfs.ext4 fsInAFile
    mkfs will ask : fsInAFile is not a block special device. Proceed anyway? (y,n). Answer y.
  3. Mount the file with a loop device : mount -o loop fsInAFile /path/to/mount/point
    When using the option -o loop the first available loop device is taken. It is possible to select the loop device to use by giving the option -o loop=/dev/loop0.
  4. You can check that the device is perfectly mounted with mount. It should display a line such as :
    fsInAFile on /mount/point type ext4 (rw,loop=/dev/loop0)
  5. It is now possible to create files and directories within /mount/point, then unmount the device and remount it back as any removable device.


This has been obsoleted by systemd.

Runlevels are defined in /etc/inittab :

Runlevel on Debianoids
(source 1, 2)
on Red Hatoids
0 system halt
1 single user mode
2 full multi-user mode (default) local multi-user mode without remote network (i.e. NFS)
3 full multi-user mode with network
4 (not used)
5 full multi-user mode with network and XDM (default)
6 system reboot

To detect the current runlevel : /sbin/runlevel.


How to install software from sources with .tar.gz, .tgz, .tar.bz2, .tbz packages ?

On Linux (and other Unices), file extensions have no special meaning for the system. They're just a hint for users to "guess" what's inside any given file. Linux would perfectly work without these, as it determines a file type (and what it can do with it) from file headers. See file for details.

To install such a package :

  1. uncompress it:
    • for gzip'ed archives : gunzip archiveName.tar.gz
    • for bzip2'ed archives : bunzip2 archiveName.tar.bz2
    This will result in a archiveName.tar file.
  2. unpack it: tar -xf archiveName.tar
    It _may_ create a directory called archiveName depending on how the archive was created.
  3. you can also uncompress + unpack in a single operation : tar -zxf archiveName.tar.gz or tar -xjf archiveName.tar.bz2
  4. inside the corresponding directory, have a look at the README file.
  5. ./configure
  6. make
  7. as root : make install

Generate a custom and optimized /etc/apt/sources.list

  1. append deb lenny stable main to /etc/apt/sources.list to be able to install netselect-apt
  2. apt-get install netselect-apt
  3. configure it to your Debian version : netselect-apt -n lenny stable (-n is to include non-free packages)
  4. netselect-apt will run some tests and generate a custom sources.list in the current directory. Edit it and uncomment the lines matching your needs.
  5. copy the new sources.list as /etc/apt/sources.list (should be smart to backup the previous one, or copy-paste lines from the new to the previous)
  6. then : apt-get update

LILO details

The first 512 bytes of the HDD are called the MBR. At boot time, the BIOS :
  1. reads the MBR
  2. loads the MBR into memory
  3. executes the MBR

The MBR can not actually store the Linux kernel itself since the kernel is about 500Kb. This is why the MBR only holds a loader that locates the kernel on the HDD then loads it into memory.

LILO itself is about 5Kb, which means still too big to fit the MBR ! Hence, LILO is split in 2 parts:
  1. one 512 bytes section that is designed to fit the MBR. Its role is to load the 2nd part of LILO.
  2. another one that contains the remaining, stored in /boot/boot.b

At boot time, the word LILO is displayed, printing letters one by one to show the booting steps:

  1. LILO then expects a parameter indicating which kernel (Linux or other system) is to be loaded.
  2. Once this parameter has been received (from user input or default choice (1st /etc/lilo.conf entry) after timeout), LILO reads /boot/map to find out which HDD blocks contain the required kernel.
  3. LILO loads those blocks into memory. Loading Linux .... is displayed.
  4. The kernel is uncompressed. Uncompressing Linux .... is displayed.
  5. Once uncompression is done, OK, booting the kernel. is displayed: the kernel starts.

Related files :