Outline:
$ gpho[tab] $ gphoto2You can learn about programs by reading the man page:
$ man gphoto2Or by getting a help message:
$ gphoto2 --helpOr looking in /usr/share/doc/<program name and version>:
$ less /usr/share/doc/gphoto2-2.1.0Or by doing a web search. There are vast amounts of Linux documentation available online.
Another method is to use the keyword search feature of man:
$ man -k photoYou can use the menu of the window manager you are using to track down programs as well - just click on the start menu icon, usually located in about the same place as the Windows start menu.
Let's compile a hello world program. Download this program and run:
$ cc -o hello hello.c $ ./hello Hello, world!Run only the preprocessor on it:
$ gcc -E hello.cGenerate assembly output in hello.s:
$ gcc -S hello.c
$ strace ./hello
execve("./hello", ["./hello"], [/* 33 vars */]) = 0
uname({sys="Linux", node="localhost.localdomain", ...}) = 0
brk(0) = 0x8ef7000
[...]
As you can see, a whole lot goes on during program startup and
teardown that you aren't interested in. Let's limit the output of
strace to write() system calls:
$ strace -e write ./hello write(1, "Hello, world!\n", 14Hello, world! ) = 14The output of the program ends up mixed in with the output of strace. Send the program's output to /dev/null:
$ strace -e write ./hello 1>/dev/null write(1, "Hello, world!\n", 14) = 14
$ ltrace ./hello __libc_start_main(0x8048368, 1, 0xfee7f254, 0x804839c, 0x80483f0printf("Hello, world!\n"Hello, world! ) = 14 +++ exited (status 0) +++
#include <stdlib.h> #include <mcheck.h> mtrace(); (void) malloc(1000); muntrace();Recompile:
$ make hello_mtraceThen you must specify a file for the output:
$ export MALLOC_TRACE=mtrace.outNow run the program and process the output:
$ ./hello_mtrace Hello, world! $ mtrace hello_mtrace mtrace.out Memory not freed: ----------------- Address Size Caller 0x09a2b378 0x3e8 at 0x804844aThat's nice, but what do those addresses mean? Let's recompile with debugging information on so we can get line numbers.
$ cc -g -o hello_mtrace hello_mtrace.c $ ./hello_mtrace Hello, world! $ ./mtrace hello_mtrace mtrace.out Memory not freed: ----------------- Address Size Caller 0x0985b378 0x3e8 at /home/val/class/web/hello_mtrace.c:12
Let's introduce a bug that causes a core dump. Copy hello.c to hello_core.c (or download it) and add the following line:
int i = * (int *) 0;Recompile with debugging information:
$ gcc -g -o hello_core hello_core.cMost likely, you will not get a core dump unless you increase the core dump limit:
$ su Password: # ulimit -c unlimited # suNow run gdb with both the binary and the core file:$ ./hello_core Segmentation fault (core dumped)
$ gdb hello_core core.* [...] #0 main () at hello_core.c:6 6 int i = * (int *) 0; (gdb)Seems like line 6 of hello_core.c would be a good place to look for a bug. Get a backtrace with the "bt" command:
(gdb) bt #0 main () at hello_core.c:6The online help can be accessed with the "help" command.
int i; for (i = 0; i < 10000; i++)Now recompile the program to produce profile data:
$ cc -pg -g -fprofile-arcs -ftest-coverage -o hello_gcov hello_gcov.cNow run the program. This generates the profiling data and puts it into files in the local directory.
$ ./hello_gcovNow run gcov:
$ gcov hello_gcov.c File `hello_gcov.c' Lines executed:100.00% of 5 hello_gcov.c:creating `hello_gcov.c.gcov'Looks like we have 100% test coverage - every line was executed at least once. The file gives us the following information:
-: 0:Source:hello_gcov.c
-: 0:Graph:hello_gcov.gcno
-: 0:Data:hello_gcov.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include
-: 2:
-: 3:int
-: 4:main(void)
function main called 1 returned 100% blocks executed 100%
1: 5:{
1: 6: int i;
-: 7:
10001: 8: for (i = 0; i < 10000; i++)
10000: 9: printf("Hello, world!\n");
1: 10: return (0);
-: 11:}
On the performance side, it looks like we executed line 8 10001 times
and line 9 10000 times... perhaps this would be a good place to
optimize the program.
Later on, after we have recompiled the kernel, we will use oprofile,
another profiling tool.
The best way to find an rpm you want is to search for it on http://rpmfind.net. We are going to search for the package for yum, a software installer which is much easier to use than rpm. Type in "yum" to the search box. You get a lot of results, click on "yum-2.2.1-0.fc3.noarch.html". Click on the big link at the top of the page for "yum-2.2.1-0.fc3 RPM for noarch" and download the file. Now we will install it - make sure you are root.
$ rpm -ivv yum-2.2.1-0.fc3.noarch.rpmrpm includes a query interface. Find out what version of yum is installed:
$ rpm -q yum yum -2.2.1-0.fc3Find out which rpm provided a particular file:
$ rpm -q --file /sbin/init SysVinit-2.85-34There are many other options for querying. If you decide you don't want yum installed anymore, uninstall it:
$ rpm -e yumNow that we have yum, we can often skip looking at the rpmfind.net website and just install what we want using just the name of the package. We'll install xsnow:
$ yum install xsnow
Traceback (most recent call last):
File "/usr/bin/yum", line 6, in ?
import yummain
File "/usr/share/yum-cli/yummain.py", line 23, in ?
import yum
ImportError: No module named yum
Whoa! That didn't work. Let's follow rule number one for when
something doesn't work in Linux: cut and paste the most unique part of
the error message into Google. Clicking on the first link gets
someone who has the same problem. Click on "Next message" at the
bottom and we get an answer:
rhel3 doesn't have python 2.3 - which the yum 2.2.0 noarch rpm was built for. You need to rebuild the src.rpm for rhel3 and the problem will go away.So now we remove the yum package we installed:
$ rpm -e yumGo back and get the source rpm for this version of yum and install it:
$ rpm -ivv yum-2.2.1-0.fc3.src.rpmCd to the rpm specification directory and build the rpm:
$ cd /usr/src/redhat/SPECS $ rpmbuild -bb yum.specNow install the rpm file we just built:
$ rpm -ivv /usr/src/redhat/RPMS/noarch/yum-2.2.1-0.fc3.noarch.rpmNow install xsnow:
$ yum install xsnowWe get a message about importing GPG keys. Using Google, we find that we can import the keys we need thusly:
$ rpm --import http://www.fedora.us/FEDORA-GPG-KEY $ rpm --import http://www.fedora.us/FEDORA-LEGACY-GPG-KEYTry again:
$ yum install xsnow Setting up Install Process Setting up Repos No Repositories Available to Set UpArgh! Still foiled! But reading the man page for yum tells us to look at http://linux.duke.edu/yum/, which tells us... that there are simply too many repositories to list any more, so ask a mailing list or a friend. In this case, we will copy my list of repositories, which I got from people in LinuxChix.
# cd / # tar xzvf yum_repos.tar.gzTry again:
$ yum install xsnowNow run it:
$ xsnowAnd let it snow!
Some documentation on setting up repositories is here.
$ tar xzvf source.tar.gz $ cd source/ $ ./configure $ make $ make installDownload the gnuplot source from the Sourceforge web site and follow the above steps to compile and install it.
There are many books available as well, but they are even more out of date. In general, reader beware. Often the best documentation is in the kernel source tree itself, in /usr/src/linux/Documentation.
$ cd /usr/src/linux-<version>Normally, you would copy a pre-made configuration file into the local directory:
$ cp configs/kernel-2.4.21-i686.config .configHowever, this configuration file has almost everything turned on, and so compiling the kernel takes a very long time (around an hour). We will use a cut-down configuration file instead.
The kernel is configured by running "make menuconfig".
$ make menuconfigTurn on profiling support so we can run oprofile later. Select "Profile support" and then turn on Profiling support and hit "y" to include OProfile system profiling. Exit saving your configuration. Now start compiling. This will take a long time.
$ make bzImage && make modules && make modules_installWhile the kernel is compiling, set up the bootloader for a new kernel. Edit /etc/grub.conf and copy the last 4 lines. Change the title and path to the kernel and initrd:
title My Linux root (hd0,0) kernel /my_vmlinuz ro root=LABEL=/ initrd /my_initrdNow put your entry before the old entry so that it will boot automatically.
After your kernel and modules are finished compiling, make a new initrd and copy your new kernel and System.map into place:
$ mkinitrd /boot/my_initrd 2.4.21-27.ELcustom $ cp arch/i386/boot/bzImage /boot/my_vmlinuz $ cp System.map /boot/System.map-2.4.21-27.ELcustomNow reboot! If the system does not boot with your new kernel, select the old entry in the grub screen shortly after boot.
$ dmesg | less $ dmesg | grep eth0
$ cat /proc/meminfo
$ cat /proc/sys/net/ipv4/ip_forward 0 $ echo 1 > /proc/sys/net/ipv4/ip_forward $ cat /proc/sys/net/ipv4/ip_forward 1This machine will now forward third party IP packets. To set these values permanently, edit /etc/sysctl.conf (there is a man page for more information).
$ echo 1 > /proc/sys/kernel/sysrqNow ask it to do something. Originally, it was easiest to use the sysrq on the keyboard, but now it is often overloaded as something else, so the easiest way is to use the /proc/sysrq-trigger:
$ echo h > /proc/sysrq-trigger $ tail dmesg [...] SysRq : HELP : loglevel0-8 reBoot Crash tErm kIll saK showMem powerOff showPc unRaw Sync showTasks UnmountTry a few of the less dangerous ones, like t to show all tasks:
$ echo t > /proc/sysrq-trigger $ dmesg | less
$ lspci $ lspci -vvv
My favorite is a way to get root access on most Linux machines. You should of course only do this if it is legal, moral, ethical, etc. Reboot the Linux machine, and stop the automatic grub boot. Edit the command line by typing "a" in the grub boot screen and add to the command line:
init=/bin/bashThen boot. This will drop you directly into a shell when init begins. First we will mount the /proc file system, since nothing other that the root file system is mounted at this point and /proc is necessary for most commands to work:
# mount /proc /proc -t procNow remount the root file system read-write and edit /etc/shadow:
# mount -o remount,rw / # vi /etc/shadowYour editor will complain about the file being read only, but that is fine. Make a copy of the line for root, comment it out, and remove the password field from the uncommented line so it looks like this:
root::12734:0:99999:7::: #root:[encrypted password]:12734:0:99999:7:::Reboot the machine and you will be able to login as root without a password. Be sure to put it back the way you found it as a courtesy. (The password program will complain about easy to guess passwords but will allow you to change it to one anyway.)
# passwdYou can do a lot more than get a login using the kernel command line. You can set the maximum amount of memory or cpus, set the root device, set debugging level, and much more. See the file Documentation/kernel-parameters.txt in your kernel source directory for details.
Start oprofile with the location of the uncompressed kernel image:
$ opcontrol --start --vmlinux=/usr/src/linux-2.4/vmlinuxNow dump the collected information for analysis:
$ opcontrol --dumpWe have a variety of tools to use at this point - try typing "op" and hitting tab to see a few. Let's start with timing information:
$ op_timeNow let's profile a user application to see how much time it spends in each part of the program. If you haven't already done so, download and extract the newmemory program. Cd into the new directory:
$ cd newmemoryEdit the Makefile to build the application with debugging information:
newmemory: newmemory.c
gcc -g -o newmemory -Wall -lpthread newmemory.c
Rebuild the application:
$ make clean $ make newmemoryBefore we start running the application, reset the oprofile information and restart it:
$ opcontrol --reset $ opcontrol --startNow run the applicaiton for a while so we can gather some samples:
$ ./newmemory -s 100 -f -t 50Wait for a few minutes to get a significant number of samples, then dump the information:
$ opcontrol --dumpCheck to see how many samples we got that were in our application:
$ op_time [...] 45244 94.4709 0.0000 /root/newmemory/newmemoryGood, that's a lot of samples. Now we will annotate the source file with information about how often the program was executing at that line when oprofile sampled it.
$ op_to_source --source-dir /root/newmemory/ --output-dir /root/oprofile_out /root/newmemory/newmemoryNow look at the file in the output directory:
$ ls /root/oprofile_out newmemory.c $ less /root/oprofile_out/newmemory.cLet's look at the first function:
:static int
:rand_num(int max)
30 0.985% :{^M /* rand_num total: 273 8.971% */
216 7.098% : return (random() % max);
27 0.887% :}
On the left are the number of samples and percentage of total samples
that were taken at that line. All samples for this function are
aggregrated and reported at the comment at the beginning of the
function. As we can see, the program spends about 9% of its time in
this function, most of it spent in the random() library call.
We can sort the lines of output to find out where most of the time is spent:
$ sort -r -n /root/oprofile_out/newmemory.c | headYou should see this line at the top of the list with something like 65% of total samples::
if (loc != *loc) {
This program is intended to find memory corruption (usually at the
software level), so it steps through memory randomly and reads each
location. Since the access pattern is random, each time it reads a
memory location it almost certainly is not in cache (or in the TLB)
and so it is expected that we are spending most of our time in this
part of the code.See /usr/share/doc/oprofile-0.5.4/oprofile.html for more information on oprofile.