<HTML ><HEAD ><TITLE >Replacing Printks</TITLE ><META NAME="GENERATOR" CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK REL="HOME" TITLE="The Linux Kernel Module Programming Guide" HREF="book1.htm"><LINK REL="PREVIOUS" TITLE="Blocking Processes" HREF="c1012.htm"><LINK REL="NEXT" TITLE="Scheduling Tasks" HREF="c1149.htm"></HEAD ><BODY CLASS="CHAPTER" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#840084" ALINK="#0000FF" ><DIV CLASS="NAVHEADER" ><TABLE SUMMARY="Header navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TH COLSPAN="3" ALIGN="center" >The Linux Kernel Module Programming Guide</TH ></TR ><TR ><TD WIDTH="10%" ALIGN="left" VALIGN="bottom" ><A HREF="c1012.htm" ACCESSKEY="P" >Prev</A ></TD ><TD WIDTH="80%" ALIGN="center" VALIGN="bottom" ></TD ><TD WIDTH="10%" ALIGN="right" VALIGN="bottom" ><A HREF="c1149.htm" ACCESSKEY="N" >Next</A ></TD ></TR ></TABLE ><HR ALIGN="LEFT" WIDTH="100%"></DIV ><DIV CLASS="CHAPTER" ><H1 ><A NAME="AEN1115" ></A >Chapter 10. Replacing Printks</H1 ><DIV CLASS="SECT1" ><H1 CLASS="SECT1" ><A NAME="AEN1117" ></A >Replacing <TT CLASS="FUNCTION" >printk</TT ></H1 ><A NAME="AEN1120" ></A ><P >In <A HREF="x49.htm#USINGX" >the Section called <I >Using X</I > in Chapter 1</A >, I said that X and kernel module programming don't mix. That's true for developing kernel modules, but in actual use, you want to be able to send messages to whichever tty<A NAME="AEN1125" HREF="#FTN.AEN1125" ><SPAN CLASS="footnote" >[1]</SPAN ></A > the command to load the module came from.</P ><A NAME="AEN1129" ></A ><A NAME="AEN1131" ></A ><A NAME="AEN1134" ></A ><A NAME="AEN1136" ></A ><P >The way this is done is by using <TT CLASS="VARNAME" >current</TT >, a pointer to the currently running task, to get the current task's <SPAN CLASS="STRUCTNAME" >tty</SPAN > structure. Then, we look inside that <SPAN CLASS="STRUCTNAME" >tty</SPAN > structure to find a pointer to a string write function, which we use to write a string to the tty.</P ><A NAME="AEN1143" ></A ><DIV CLASS="EXAMPLE" ><A NAME="AEN1146" ></A ><P ><B >Example 10-1. print_string.c</B ></P ><PRE CLASS="PROGRAMLISTING" >/* print_string.c - Send output to the tty you're running on, regardless of whether it's * through X11, telnet, etc. We do this by printing the string to the tty associated * with the current task. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> // For current #include <linux/tty.h> // For the tty declarations MODULE_LICENSE("GPL"); MODULE_AUTHOR("Peter Jay Salzman"); void print_string(char *str) { struct tty_struct *my_tty; my_tty = current->tty; // The tty for the current task /* If my_tty is NULL, the current task has no tty you can print to (this is possible, * for example, if it's a daemon). If so, there's nothing we can do. */ if (my_tty != NULL) { /* my_tty->driver is a struct which holds the tty's functions, one of which (write) * is used to write strings to the tty. It can be used to take a string either * from the user's memory segment or the kernel's memory segment. * * The function's 1st parameter is the tty to write to, because the same function * would normally be used for all tty's of a certain type. The 2nd parameter * controls whether the function receives a string from kernel memory (false, 0) or * from user memory (true, non zero). The 3rd parameter is a pointer to a string. * The 4th parameter is the length of the string. */ (*(my_tty->driver).write)( my_tty, // The tty itself 0, // We don't take the string from user space str, // String strlen(str)); // Length /* ttys were originally hardware devices, which (usually) strictly followed the * ASCII standard. In ASCII, to move to a new line you need two characters, a * carriage return and a line feed. On Unix, the ASCII line feed is used for both * purposes - so we can't just use \n, because it wouldn't have a carriage return * and the next line will start at the column right after the line feed. * * BTW, this is why text files are different between Unix and MS Windows. In CP/M * and its derivatives, like MS-DOS and MS Windows, the ASCII standard was strictly * adhered to, and therefore a newline requirs both a LF and a CR. */ (*(my_tty->driver).write)(my_tty, 0, "\015\012", 2); } } int print_string_init(void) { print_string("The module has been inserted. Hello world!"); return 0; } void print_string_exit(void) { print_string("The module has been removed. Farewell world!"); } module_init(print_string_init); module_exit(print_string_exit);</PRE ></DIV ></DIV ></DIV ><H3 CLASS="FOOTNOTES" >Notes</H3 ><TABLE BORDER="0" CLASS="FOOTNOTES" WIDTH="100%" ><TR ><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="5%" ><A NAME="FTN.AEN1125" HREF="c1115.htm#AEN1125" ><SPAN CLASS="footnote" >[1]</SPAN ></A ></TD ><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="95%" ><P ><SPAN CLASS="emphasis" ><I CLASS="EMPHASIS" >T</I ></SPAN >ele<SPAN CLASS="emphasis" ><I CLASS="EMPHASIS" >ty</I ></SPAN >pe, originally a combination keyboard-printer used to communicate with a Unix system, and today an abstraction for the text stream used for a Unix program, whether it's a physical terminal, an xterm on an X display, a network connection used with telnet, etc.</P ></TD ></TR ></TABLE ><DIV CLASS="NAVFOOTER" ><HR ALIGN="LEFT" WIDTH="100%"><TABLE SUMMARY="Footer navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" ><A HREF="c1012.htm" ACCESSKEY="P" >Prev</A ></TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="book1.htm" ACCESSKEY="H" >Home</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" ><A HREF="c1149.htm" ACCESSKEY="N" >Next</A ></TD ></TR ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" >Blocking Processes</TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" > </TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" >Scheduling Tasks</TD ></TR ></TABLE ></DIV ></BODY ></HTML >