|
Warning: include(../header.inc) [function.include]: failed to open stream: No such file or directory in /home/home4/varun/public_html/cps196/index.php on line 19 Warning: include() [function.include]: Failed opening '../header.inc' for inclusion (include_path='/cs/prophet/httpd/web-docs/include:/cs/prophet/httpd/php/lib/php/extensions/:/cs/prophet/httpd/php/lib/php:/cs/prophet/httpd/php:/cs/prophet/httpd/php/lib/php/extensions/no-debug-non-zts-20060613:.') in /home/home4/varun/public_html/cps196/index.php on line 19 |
|
|
force_printk explanation |
Using printk can be a pain if you have to go rooting through logs to find
out if the kernel has deigned to say anything to you. I've written a
function called force_printk that writes the output straight to your
console. Hopefully you find it useful.
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/tty.h>
int force_printk(char *format, ...)
{
struct tty_struct *current_tty;
va_list args;
char out_string[1024];
va_start(args,format);
vsnprintf(out_string,sizeof(out_string),format,args);
va_end(args);
current_tty = current->signal->tty;
if(current_tty == NULL)
return -1;
((current_tty->driver)->write) (current_tty,out_string,strlen(out_string));
((current_tty->driver)->write) (current_tty,"\r\n",2);
return 0;
}
I'll start from the top and go through it line by line. Here goes: int force_printk(char *format, ...)This says we're taking any number of parameters, the first of which will be a character pointer. The rest can be anything.
va_start(args,format); va_end(args);The va_start and va_end macros are defined in stdarg.h va_start takes the argument list found on the stack beyond the second argument (format) and builds a va_list structure, which it stores in the first argument (args). We're not passing args by reference since va_start is a macro (and hence we're not really passing anything anywhere) va_end cleans up after we're done. All this might seem like black magic, but they're actually very simple macros - they work by looking at the current function's stack.
vsnprintf(out_string,sizeof(out_string),format,args);vsnprintf does all the nice things that printf does, with some differences:
current_tty = current->signal->tty;Every process in Linux has a structure associated with it, of type task_struct, which contains all sorts of useful information about the process. Find the definition of task_struct in include/linux/sched.h. The current pointer points to the current structure's task_struct. Think of this as the kernel equivalent of the this pointer in C++. task_structs have a member called signal (also defined in sched.h) which in turn contains a pointer called tty to the current process's console. (Whew!) This is the value we want, so we get that and store it in current_tty. So now we have a pointer to the console we want to write to.
if(current_tty == NULL)
return -1;
Now we do some error checking. If the console we want to write to doesn't
exist, we return an error value. The console could not exist if
there is no console attached to the process, such as would happen if this
function was called by a daemon, but you will probably not
encounter any such situation. For the purposes of the lab, you should never
be returned a -1. If you do, let me know.
((current_tty->driver)->write) (current_tty,out_string,strlen(out_string));Now things get a little more complicated. The tty we were pointing to with current_tty was itself a structure called tty_struct defined in include/linux/tty.h. This structure contains an element called driver, which is another structure (did anyone tell you messing with the kernel was simple?) called tty_driver, which in turn contains a pointer called write to the function that is capable of writing to the specified console. So we call that function and let it write our constructed buffer to the screen. The parameters are pretty self-explanatory: the tty we're interested in writing to, the string to write, and the length of the string.
((current_tty->driver)->write) (current_tty,"\r\n",2);Like printf and unlike printk, vsnprintf does not automatically put a newline at the end of your line. I add a newline here. Take it out if you don't want it to do that. Note that the ttys implement the strict ASCII standard, so you need both \r\n instead of being able to get away with just \n. |