1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
|
.\"
.\" libexplain - Explain errno values returned by libc functions
.\" Copyright (C) 2008-2012 Peter Miller
.\" Written by Peter Miller <pmiller@opensource.org.au>
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 3 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
.\" General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
.\"
.cp 0
.TH New\[hy]System\[hy]Call libexplain
.SH NAME
new system call \- How to add a new system call to libexplain
.XX "" "How to add a new system call to libexplain"
.SH DESCRIPTION
Adding a new system call to libexplain is both simple and tedious.
.PP
In this example, the system call is called \f[I]example\fP, and takes
two arguments, \f[I]pathname\fP and \f[I]flags\fP.
.RS
example(const char *pathname, int flags);
.RE
The libexplain library presents a C interface to the user, and explains
the C system calls. It tries to avoid dynamic memory, and has several
helper functions and structures to make this simpler.
.SS Naming Conventions
In general, one function per file. This gives the static linker more
opportunity to leave things out, thus producing smaller executables.
Exceptions to make use of \f[CR]static\fP common functions are
acceptable.
No savings for shared libraries, of course.
.PP
Functions that write their output into a
\f[I]explain_string_buffer_t\fP via the
\f[CR]explain_string_buffer_*\fP functions, all have a filename of
\f[CR]libexplain/buffer/\fP\f[I]something\fP.
.PP
Functions that write their output to a \f[I]message\fP,
\f[I]message_size\fP pair have a \f[CR]message\fP path component in
their file name.
.PP
Functions that accept an \f[I]errno\fP value as an argument have an
\f[CR]errno\fP path component in their file name, called \f[CR]errnum\fP.
If a function has
both a buffer and an errno, the buffer comes first, both in the argument
list, and the file's name. If a function has both a message+size and
an errno, the message comes first, both in the argument list, and the
file's name.
.\" ------------------------------------------------------------------------
.SH MODIFIED FILES
Note that the \f[I]codegen\fP command does most of the work for
you. Pass it the function prototype (in single quotes) and it will do
most of the work.
.PP
.RS
.ft CW
.nf
$ \f[CB]bin/codegen '\fP\f[CI]example(const char *pathname, \
int flags);\fP\f[CB]'\fP
creating catalogue/\f[CI]example\fP
$
.fi
.ft R
.RE
.PP
then you mast edit the \f[CW]catalogue/\fP\f[CI]example\fP file to
make any adjustment necessary.
This file is then used to do the boring stuff:
.RS
.nf
.ft CW
$ \f[CB]bin/codegen\fP \f[CI]example\fP
creating explain/syscall/\f[CI]example\fP.c
creating explain/syscall/\f[CI]example\fP.h
creating libexplain/buffer/errno/\f[CI]example\fP.c
creating libexplain/buffer/errno/\f[CI]example\fP.h
creating libexplain/\f[CI]example\fP.c
creating libexplain/\f[CI]example\fP.h
creating libexplain/\f[CI]example\f[P]_or_die.c
creating man/man3/explain_\f[CI]example\fP.3
creating man/man3/explain_\f[CI]example\f[P]_or_die.3
creating test_\f[CI]example\fP/main.c
modify explain/syscall.c
modify libexplain/libexplain.h
modify man/man1/explain.1
modify man/man3/explain.3
$
.ft R
.fi
.RE
.PP
All of these files have been added to the Aegis change set.
Edit the last 4 to place the appended line in their correct positions
within the files, respecting the symbol sort ordering of each file.
.\"
.SS libexplain/libexplain.h
The \f[CR]libexplain/libexplain.h\fP include file defines the
user API. It, and any files it includes,
are installed into \f[CR]$(prefix)/include\fP by \f[I]make install\fP.
.PP
This file needs another include line.
This means that the entire API is available to the user as a
single include directive.
.PP
.RS
\f[CR]#include <libexplain/\fP\f[I]example\fP\f[CR].h>\fP
.RE
.PP
This file is also used to decide which files are installed by the \f[I]make
install\fP command.
.PP
Take care that none of those files, directly or indirectly, wind
up including \f[CR]libexplain/config.h\fP which is generated by the
\f[I]configure\fP script, and has \f[B]no\fP namespace protection.
.PP
This means you can't \f[CR]#include <stddef.h>\fP, or use any of the
types it defines, because on older systems \f[I]configure\fP works quite
hard to cope with its absence.
Ditto \f[CR]<unistd.h>\fP and \f[CR]<sys/types.h>\fP.
.\"
.SS explain/main.c
Include the include file for the new function,
and add the function to the table.
.\"
.SS man/man1/explain.1
Add a description of the new system call.
.\"
.SS man/man3/libexplain.3
Add your new man pages,
man/man3/explain_\f[I]example\fP.3 and
man/man3/explain_\f[I]example\f[P]_or_die.3,
to the list.
Keep the list sorted.
.\" ------------------------------------------------------------------------
.SH NEW FILES
Note that the \f[I]codegen\fP command does most of the work for
you. Pass it the function prototype (in single quotes) and it will do
most of the work.
.\"
.SS libexplain/buffer/errno/\f[I]example\fP.c
The central file for adding a new example
is \f[CR]libexplain/buffer/errno/\fP\f[I]example\fP\f[CR].c\fP
Which defines a function
.RS
\f[CR]void explain_buffer_errno_\fP\f[I]example\fP\f[CR](\
explain_string_buffer_t *buffer, int errnum, \fP\fIconst char *pathname,
int flags\fP\f[CR]);\fP
.RE
The \f[CR]errnum\fP argument holds the \f[I]errno\fP value.
Note that calling \f[I]errno\fP usually has problems because many
systems have \f[I]errno\fP as a macro, which makes the compiler barf,
and because there are times you want access to the global \f[I]errno\fP,
and having it shadowed by the argument is a nuisance.
.PP
This function writes its output into the buffer via the
\f[CR]explain_string_buffer_printf\fP, \f[I]etc\fP, functions.
First the argument list is reprinted.
.PP
The \f[CR]explain_string_buffer_puts_quoted\fP
function should be used to print pathnames,
because it uses full C quoting and escape sequences.
.PP
If an argument is a file descriptor, it should be called \f[I]fildes\fP,
short for \[lq]file descriptor\[rq].
On systems capable of it, the file descriptor can be mapped to a pathname
using the \f[CR]explain_buffer_fildes_to_pathname\fP function. This
makes explanations for system calls like \f[I]read\fP and \f[I]write\fP
much more informative.
.PP
Next comes a switch on the errnum value,
and additional explanation is given for each errno value documented (or
sometimes undocumented)
for that system call.
Copy\[hy]and\[hy]paste of the man page is often useful as a basis for the text
of the explanation, but be sure it is open source documentation, and
not Copyright proprietary text.
.PP
Don't forget to check the existing \f[CW]libexplain/buffer/e*.h\fP
files for pre\[hy]canned explanations for common errors.
Some pre\[hy]canned explanations include
.TS
tab(;);
l l.
EACCES;explain_buffer_eacces
EADDRINUSE;explain_buffer_eaddrinuse
EAFNOSUPPORT;explain_buffer_eafnosupport
EBADF;explain_buffer_ebadf
EFAULT;explain_buffer_efault
EFBIG;explain_buffer_efbig
EINTR;explain_buffer_eintr
EINVAL;explain_buffer_einval_vague, \f[I]etc\fP
EIO;explain_buffer_eio
ELOOP;explain_buffer_eloop
EMFILE;explain_buffer_emfile
EMLINK;explain_buffer_emlink
ENAMETOOLONG;explain_buffer_enametoolong
ENFILE;explain_buffer_enfile
ENOBUFS;explain_buffer_enobufs
ENOENT;explain_buffer_enoent
ENOMEM;explain_buffer_enomem
ENOTCONN;explain_buffer_enotconn
ENOTDIR;explain_buffer_enotdir
ENOTSOCK;explain_buffer_enotsock
EROFS;explain_buffer_erofs
ETXTBSY;explain_buffer_etxtbsy
EXDEV;explain_buffer_exdev
.TE
.\"
.SS libexplain/buffer/errno/example.h
This file holds the function prototype
for the above function definition.
.\"
.SS libexplain/example.h
The file contains the user visible API for the \f[I]example\fP system call.
There are five function prototypes declared in this file:
.RS
\f[CR]void explain_\fP\f[I]example\fP\f[CR]_or_die(\
\fP\fIconst char *pathname, int flags\fP\f[CR]);\fP
.br
\f[CR]void explain_\fP\f[I]example\fP\f[CR](
\fP\fIconst char *pathname, int flags\fP\f[CR]);\fP
.br
\f[CR]void explain_errno_\fP\f[I]example\fP\f[CR](\
int errnum, \fP\fIconst char *pathname, int flags\fP\f[CR]);\fP
.br
\f[CR]void explain_message_\fP\f[I]example\fP\f[CR](\
const char *message, int message_size,
\fP\fIconst char *pathname, int flags\fP\f[CR]);\fP
.br
\f[CR]void explain_message_errno_\fP\f[I]example\fP\f[CR](\
const char *message, int message_size,
int errnum, \fP\fIconst char *pathname, int flags\fP\f[CR]);\fP
.RE
The function prototypes for these appear in the
\f[CR]libexplain/\f[I]example\fP.h include file.
.PP
Each function prototype shall be accompanied by thorough Doxygen style
comments. These are extracted and placed on the web site.
.PP
The buffer functions are \f[B]never\fP part of the user visible API.
.\"
.SS libexplain/\f[I]example\f[P]_or_die.c
One function per file,
\f[CR]explain_\fP\f[I]example\fP\f[CR]_or_die\fP in this case.
It simply calls \f[I]example\fP and then, if fails,
\f[CR]explain_\fP\f[I]example\fP to print why, and then exit(EXIT_FAILURE).
.\"
.SS libexplain/example.c
One function per file,
\f[CR]explain_\fP\f[I]example\fP in this case.
It simply calls \f[CR]explain_errno_\fP\f[I]example\fP to pass in the
global \f[I]errno\fP value.
.\"
.SS libexplain/errno/example.c
One function per file,
\f[CR]explain_errno_\fP\f[I]example\fP in this case.
It calls \f[CR]explain_message_errno_\fP\f[I]example\fP,
using the
\f[CR]<libexplain/global_message_buffer.h>\fP to hold the string.
.\"
.SS libexplain/message/example.c
One function per file,
\f[CR]explain_message_\fP\f[I]example\fP in this case.
It simply calls \f[CR]explain_message_errno_\fP\f[I]example\fP to
pass in the global \f[I]errno\fP value.
.\"
.SS libexplain/message/errno/example.c
One function per file,
\f[CR]explain_message_errno_\fP\f[I]example\fP in this case.
It declares and initializes a \f[CR]explain_string_buffer_t\fP instance,
which ensures that the message buffer will not be exceeded,
and passes that buffer to the
\f[CR]explain_buffer_errno_\fP\f[I]example\fP function.
.\"
.SS man/man3/explain_example.3
This file also documents the error explanations functions,
except \f[CR]explain_\fP\f[I]example\fP\f[CW]_or_dir\fP.
Use the same text as you did in \f[CR]libexplain/\fP\f[I]example\fP\f[CR].h\fP
.\"
.SS man/man3/explain_example_or_die.3
This file also documents the helper function.
Use the same text as you did in \f[CR]libexplain/\fP\f[I]example\fP\f[CR].h\fP
.\"
.SS explain/example.c
Glue to turn the command line into arguments to a call to
\f[CR]explain_\fP\f[I]example\fP
.\"
.SS explain/example.h
Function prototype for the above.
.\"
.SS test_example/main.c
This program should call \f[CR]explain_\fP\f[I]explain\fP\f[CW]_or_die\fP.
.\" ------------------------------------------------------------------------
.SH NEW IOCTL REQUESTS
Each different \f[I]ioctl\fP(2) request is, in effect, yet another
system call. Except that they all have appallingly bad type safety. I
have seen fugly C++ classes with less overloading than \f[I]ioctl\fP(2).
.TP
libexplain/iocontrol/request_by_number.c
This file has one include line for each \f[I]ioctl\fP(2) request.
There is a \f[CW]table\fP array that contains a pointer to the
explain_iocontrol_t variable declared in the include file (see next).
Keep both sets of lines sorted alphabetically,
it makes it easier to detect duplicates.
.TP
libexplain/iocontrol/\f[I]name\fP.h
Where \f[I]name\fP is the name of the \f[I]ioctl\fP(2) request in lower
case. This declares an global const variable describing how to handle
it.
.TP
libexplain/iocontrol/\f[I]name\fP.c
This defines the above global variable, and defines any static glue
functions necessary to print a representation of it.
You will probably have to read the kernel source to discover the errors
the ioctl can return, and what causes them, in order to write the
explanation function; they are almost never described in the man pages.
.\" ------------------------------------------------------------------------
.SH TESTS
Write at least one separate test for each case in the errnum switch.
.SH Debian Notes
You can check that the Debian stuff builds by using
.RS
.nf
apt\[hy]get install pbuilder
pbuiler create
pbuilder login
.fi
.RE
now copy the files from \f[I]web\[hy]site/debian/\fP into the chroot
.RS
.nf
cd libexplain\-*
dpkg\-checkbuilddeps
apt\-get install \f[I]what dpkg\-checkbuilddeps said\fP
apt\-get install devscripts
debuild
.fi
.RE
This should report success.
.SH COPYRIGHT
.if n .ds C) (C)
.if t .ds C) \(co
libexplain version \*(v)
.br
Copyright \*(C) 2008 Peter Miller
.SH AUTHOR
Written by Peter Miller <pmiller@opensource.org.au>
.\" vim: set ts=8 sw=4 et :
|