[UnixCompendium] / trunk / unix.info-6 Repository:
ViewVC logotype

Annotation of /trunk/unix.info-6

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (view) (download)

1 : root 1 This is unix.info, produced by makeinfo version 4.0 from unix.texinfo.
2 :    
3 :     
4 :     File: unix.info, Node: Compiling large programs, Next: Makefiles, Prev: Make, Up: Make
5 :    
6 :     Compiling large projects
7 :     ------------------------
8 :    
9 :     Typing lines like
10 :    
11 :     cc -c file1.c file2.c ...
12 :     cc -o target file1.o ....
13 :    
14 :     repeatedly to compile a complicated program can be a real nuisance. One
15 :     possibility would therefore be to keep all the commands in a script.
16 :     This could waste a lot of time though. Suppose you are working on a big
17 :     project which consists of many lines of source code - but are editing
18 :     only one file. You really only want to recompile the file you are
19 :     working on and then relink the resulting object file with all of the
20 :     other object files. Recompiling the other files which hadn't changed
21 :     would be a waste of time. But that would mean that you would have to
22 :     change the script each time you change what you need to compile.
23 :    
24 :     A better solution is to use the `make' command. `make' was designed
25 :     for precisely this purpose. To use `make', we create a file called
26 :     `Makefile' in the same directory as our program. `make' is a quite
27 :     general program for building software. It is not specifically tied to
28 :     the C programming language-- it can be used in any programming language.
29 :    
30 :     A `make' configuration file, called a `Makefile', contains rules
31 :     which describe how to compile or build all of the pieces of a program.
32 :     For example, even without telling it specifically, `make' knows that in
33 :     order to go from `prog.c' to `prog.o' the command `cc -c prog.c' must
34 :     be executed. A Makefile works by making such associations. The
35 :     Makefile contains a list of all of the files which compose the program
36 :     and rules as to how to get to the finished product from the source.
37 :    
38 :     The idea is that, to compile a program, we just have to type `make'.
39 :     `make' then reads the Makefile and compiles all of the parts which need
40 :     compiling. It does not recompile files which have not changed since the
41 :     last compilation! How does it do this? `make' works by comparing the
42 :     time-stamp on the file it needs to create with the time-stamp on the
43 :     file which is to be compiled. If the compiled version exists and is
44 :     newer than its source then the source does not need to be recompiled.
45 :    
46 :     To make this idea work in practice, `make' has to know how to go
47 :     through the steps of compiling a program. Some default rules are
48 :     defined in a global configuration file, e.g.
49 :    
50 :     /usr/include/make/default.mk
51 :    
52 :     Let's consider an example of what happens for the the three files
53 :     `a.c', `b.c' and `c.c' in the example above - and let's not worry about
54 :     what the Makefile looks like yet.
55 :    
56 :     The first time we compile, only the `.c' files exist. When we type
57 :     `make', the program looks at its rules and finds that it has to make a
58 :     file called `myprog'. To make this it needs to execute the command
59 :    
60 :     gcc -o myprog a.o b.o c.o
61 :    
62 :     So it looks for `a.o' etc and doesn't find them. It now goes to a kind
63 :     of subroutine and looks to see if it has any rules for making files
64 :     called `.o' and it discovers that these are made by compiling with the
65 :     `gcc -c' option. Since the files do not exist, it does this. Now the
66 :     files `a.o b.o c.o' exist and it jumps back to the original problem of
67 :     trying to make `myprog'. All the files it needs now exist and so it
68 :     executes the command and builds `myprog'.
69 :    
70 :     If we now edit `a.c', and type `make' once again - it goes through
71 :     the same procedure as before but now it finds all of the files. So it
72 :     compares the dates on the files - if the source is newer than the
73 :     result, it recompiles.
74 :    
75 :     By using this recursive method, `make' only compiles those parts of
76 :     a program which need compiling.
77 :    
78 :     
79 :     File: unix.info, Node: Makefiles, Next: Suffix rules for C++, Prev: Compiling large programs, Up: Make
80 :    
81 :     Makefiles
82 :     ---------
83 :    
84 :     To write a Makefile, we have to tell `make' about _dependencies_.
85 :     The dependencies of a file are all of those files which are required to
86 :     build it. Thus, the dependencies of `myprog' are `a.o', `b.o' and
87 :     `c.o'. The dependencies of `a.o' are simply `a.c', the dependencies of
88 :     `b.o' are `b.c' and so on.
89 :    
90 :     A Makefile consists of rules of the form:
91 :    
92 :     target : dependencies
93 :     <TAB> rule;
94 :    
95 :     The target is the thing we want to build, the dependenices are like
96 :     subroutines to be executed first if they do not exist. Finally the rule
97 :     is to be executed if all if the dependenices exist; it takes the
98 :     dependencies and turns them into the target. There are two important
99 :     things to remember:
100 :    
101 :     * The file names must start on the first character of a line.
102 :    
103 :     * There must be a <TAB> character at the beginning of every rule or
104 :     action. If there are spaces instead of tabs, or no tab at all,
105 :     `make' will signal an error. This bizarre feature can cause a lot
106 :     of confusion.
107 :    
108 :     Let's look at an example Makefile for a program which consists of two
109 :     course files `main.c' and `other.c' and which makes use of a library
110 :     called `libdb' which lies in the directory `/usr/local/lib'. Our aim
111 :     is to build a program called `database':
112 :    
113 :    
114 :     #
115 :     # Simple Makefile for `database'
116 :     #
117 :    
118 :     # First define a macro
119 :    
120 :     OBJ = main.o other.o
121 :    
122 :     CC = gcc
123 :     CFLAGS = -I/usr/local/include
124 :     LDFLAGS = -L/usr/local/lib -ldb
125 :     INSTALLDIR = /usr/local/bin
126 :    
127 :     #
128 :     # Rules start here. Note that the $@ variable becomes the name of the
129 :     # executable file. In this case it is taken from the ${OBJ} variable
130 :     #
131 :    
132 :     database: ${OBJ}
133 :     ${CC} -o $@ ${OBJ} ${LDFLAGS}
134 :    
135 :     #
136 :     # If a header file changes, normally we need to recompile everything.
137 :     # There is no way that make can know this unless we write a rule which
138 :     # forces it to rebuild all .o files if the header file changes...
139 :     #
140 :    
141 :     ${OBJ}: ${HEADERS}
142 :    
143 :     #
144 :     # As well as special rules for special files we can also define a
145 :     # "suffix rule". This is a rule which tells us how to build all files
146 :     # of a certain type. Here is a rule to get .o files from .c files.
147 :     # The $< variable is like $? but is only used in suffix rules.
148 :     #
149 :    
150 :     .c.o:
151 :     ${CC} -c ${CFLAGS} $<
152 :    
153 :    
154 :     #######################################################################
155 :     # Clean up
156 :     #######################################################################
157 :    
158 :     #
159 :     # Make can also perform ordinary shell command jobs
160 :     # "make tidy" here performs a cleanup operation
161 :     #
162 :    
163 :     clean:
164 :     rm -f ${OBJ}
165 :     rm -f y.tab.c lex.yy.c y.tab.h
166 :     rm -f y.tab lex.yy
167 :     rm -f *% *~ *.o
168 :     rm -f mconfig.tab.c mconfig.tab.h a.out
169 :     rm -f man.dvi man.aux man.log man.toc
170 :     rm -f cfengine.tar.gz cfengine.tar cfengine.tar.Z
171 :     make tidy
172 :     rm -f cfengine
173 :    
174 :     install: ${INSTALLDIR}/database
175 :     cp database ${INSTALLDIR}/database
176 :    
177 :     The Makefile above can be invoked in several ways.
178 :    
179 :     make
180 :     make database
181 :     make clean
182 :     make install
183 :    
184 :     If we simple type `make' i.e. the first of these choices, `make' takes
185 :     the first of the rules it finds as the object to build. In this case
186 :     the rule is `database', so the first two forms above are equivalent.
187 :    
188 :     On the other hand, if we type
189 :     make clean
190 :    
191 :     then execution starts at the rule for `clean', which is normally used
192 :     to remove all files except the original source code. Make `install'
193 :     causes the compiled program to be installed at its intended destination.
194 :    
195 :     `make' uses some special variables (which resemble the special
196 :     variables used in Perl - but don't confuse them). The most useful one
197 :     is `$@' which represents the current _target_ - or the object which
198 :     `make' would like to compile. i.e. as `make' checks each file it would
199 :     like to compile, `$@' is set to the current filename.
200 :    
201 :     `$@'
202 :     This evaluates to the current target i.e. the name of the object
203 :     you are currently trying to build. It is normal to use this as the
204 :     final name of the program when compiling
205 :    
206 :     `$?'
207 :     This is used only outside of suffix rules and means the name of
208 :     all the files which must be compiled in order to build the current
209 :     target.
210 :     target: file1.o file2.o
211 :     <TAB> cc -o $@ $?
212 :    
213 :     `$<'
214 :     This is only used in suffix rules. It has the same meaning as `$?'
215 :     but only in suffix rules. It stands for the pre-requisite, or the
216 :     file which must be compiled in order to make a given object.
217 :    
218 :     Note that, because `make' has some default rules defined in its
219 :     configuration file, a single-file C program can be compiled very easily
220 :     by typing
221 :     make filename.c
222 :    
223 :     This is equivalent to
224 :     cc -c filename.c
225 :     cc -o filename filename.o
226 :    
227 :     
228 :     File: unix.info, Node: Suffix rules for C++, Prev: Makefiles, Up: Make
229 :    
230 :     New suffix rules for C++
231 :     ------------------------
232 :    
233 :     Standard rules for C++ are not often built into UNIX systems at the
234 :     time of writing, but we can create them in our own Makefiles very
235 :     easily. Here we shall use the GNU compiler g++'s conventions for C++
236 :     files. Here is a sample Makefile for using C++. Note that the
237 :     `.SUFFIXES' command must be used to declare new endings or file
238 :     extensions.
239 :    
240 :     ##################################################################
241 :     #
242 :     # This is the Makefile for g++
243 :     #
244 :     ##################################################################
245 :    
246 :     OBJ = cpp-prog.o X.o Y.o Z.o
247 :    
248 :     CCPLUS = g++
249 :    
250 :     .SUFFIXES: .C .o .h
251 :    
252 :     #
253 :     # Program Rules
254 :     #
255 :    
256 :    
257 :     filesys: ${OBJ}
258 :     $(CCPLUS) -o filesys $(OBJ)
259 :    
260 :     #
261 :     # Extra dependencies on the header file
262 :     # (if the header file changes, we need to rebuild *.o)
263 :     #
264 :    
265 :     cpp-prog.o: filesys.h
266 :     X.o: filesys.h
267 :     Y.o: filesys.h
268 :     Z.o: filesys.h
269 :    
270 :     #
271 :     # Suffix rules
272 :     #
273 :    
274 :     .C.o:
275 :     $(CCPLUS) -c $<
276 :    
277 :     The general rule here tells `make' that a `.o' file can be created
278 :     from a `.C' file by executing the command `$(CCPLUS) -c'. (This is
279 :     identical to the C case, exept for the name of the compiler). The extra
280 :     dependencies tell `make' that, if we change the header file
281 :     `filesys.h', then we must recompile all the files which read in
282 :     `filesys.h', since this could affect all of these. Finally, the highest
283 :     level rule says that to make `filesys' from the `.o' files, we have to
284 :     run `$(CCPLUS) -o filesys *.o'.
285 :    
286 :     
287 :     File: unix.info, Node: argv argc envp, Next: Environment variables in C, Prev: Make, Up: C programming
288 :    
289 :     The `argv', `argc' and `envp' paramters
290 :     =======================================
291 :    
292 :     When we write C programs which reads command line arguments, they are
293 :     fed to us as an array of strings called the argument vector. The
294 :     mechanisms for the C-shell and Perl are derived from the C argument
295 :     vector. To read in the command line, we write
296 :    
297 :    
298 :     main (argc,argv,envp)
299 :    
300 :     int argc;
301 :     char *argv[], *envp[];
302 :    
303 :     {
304 :     printf ("The first argument was %s\n",argv[1]);
305 :     }
306 :    
307 :     Argument zero is the name of the program itself and `argv[argc-1]' is
308 :     the last argument. The above definitions are in Kernighan and Ritchie C
309 :     style. In ANSI C, the arguments can be declared using prototype:
310 :    
311 :     main (int argc, char **argv)
312 :    
313 :     {
314 :    
315 :     }
316 :    
317 :     The array of strings `envp[]' is a list of values of the _environment
318 :     variables_ of the system, formatted by
319 :     NAME=value
320 :    
321 :     This gives C programmers access to the shell's global environment.
322 :    
323 :     
324 :     File: unix.info, Node: Environment variables in C, Next: C files and dirs, Prev: argv argc envp, Up: C programming
325 :    
326 :     Environment variables in C
327 :     ==========================
328 :    
329 :     In addition to the `envp' vector, it is possible to access the
330 :     environment variables through the call `getenv()'. This is used as
331 :     follows; suppose we want to access the shell environment variable
332 :     `$HOME'.
333 :     char *string;
334 :    
335 :     string = getenv("HOME");
336 :    
337 :     `string' is now a pointer to static but public data. You should not use
338 :     `string' as if it were you're own property because it will be used
339 :     again by the system. Copy it's contents to another string before using
340 :     the data.
341 :     char buffer[500];
342 :    
343 :     strcpy (buffer,string);
344 :    
345 :     
346 :     File: unix.info, Node: C files and dirs, Next: File test macros, Prev: Environment variables in C, Up: C programming
347 :    
348 :     Files and directories
349 :     =====================
350 :    
351 :     All of the regular C functions from the standard library are
352 :     available to Unix programmers. The standard functions only address the
353 :     issue of reading and writing to files however, they do not deal with
354 :     operating system specific attributes such as file permissions and file
355 :     types. Nor is there a mechanisms for obtaining lists of files within a
356 :     directory. The reason for these omissions is that they are operating
357 :     system dependent. To find out about these other attributes POSIX
358 :     describes some standard Unix system calls.
359 :    
360 :     * Menu:
361 :    
362 :     * opendir and readir::
363 :     * stat::
364 :     * lstat and readlink::
365 :    
366 :     
367 :     File: unix.info, Node: opendir and readir, Next: stat, Prev: C files and dirs, Up: C files and dirs
368 :    
369 :     opendir, readdir
370 :     ----------------
371 :    
372 :     Files and directories are handled by functions defined in the header
373 :     file `dirent.h'. In earlier UNIX systems the file `dir.h' was used -
374 :     and the definitions were slightly different, but not much. To get a
375 :     list of files in a directory we must open the directory and read from
376 :     it - just like a file. (A directory is just a file which contains data
377 :     on its entries). The commands are
378 :     opendir
379 :     closedir
380 :     readdir
381 :    
382 :     See the manual pages for dirent. These functions return pointers to a
383 :     `dirent' structure which is defined in the file
384 :     `/usr/include/dirent.h'. Here is an example `ls' command which lists
385 :     the contents of the directory `/etc'. This header defines a structure
386 :    
387 :    
388 :     struct dirent
389 :     {
390 :     off_t d_off; /* offset of next disk dir entry */
391 :     unsigned long d_fileno; /* file number of entry */
392 :     unsigned short d_reclen; /* length of this record */
393 :     unsigned short d_namlen; /* length of string in d_name */
394 :     char d_name[255+1]; /* name (up to MAXNAMLEN + 1) */
395 :     };
396 :    
397 :     which can be used to obtain information from the directory nodes.
398 :    
399 :    
400 :     #include <stdio.h>
401 :     #include <dirent.h>
402 :    
403 :     main ()
404 :    
405 :     { DIR *dirh;
406 :     struct dirent *dirp;
407 :     static char mydir[20] = "/etc";
408 :    
409 :     if ((dirh = opendir(mydir)) == NULL)
410 :     {
411 :     perror("opendir");
412 :     return;
413 :     }
414 :    
415 :     for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
416 :     {
417 :     printf("Got dir entry: %s\n",dirp->d_name);
418 :     }
419 :    
420 :     closedir(dirh);
421 :     }
422 :    
423 :     Notice that reading from a directory is like reading from a file with
424 :     `fgets()', but the entries are filenames rather than lines of text.
425 :    
426 :     
427 :     File: unix.info, Node: stat, Next: lstat and readlink, Prev: opendir and readir, Up: C files and dirs
428 :    
429 :     `stat()'
430 :     --------
431 :    
432 :     To determine the file properties or _statistics_ we use the function
433 :     call `stat()' or its corollory `lstat()'. Both these functions find out
434 :     information about files (permissions, owner, filetype etc). The only
435 :     difference between them is the way in which they treat symbolic links.
436 :     If `stat' is used on a symbolic link, it stats the file the link points
437 :     to rather than the link itself. If `lstat' is used, the data refer to
438 :     the link. Thus, to detect a link, we must use `lstat', *Note lstat and
439 :     readlink::.
440 :    
441 :     The data in the `stat' structure are defined in the file
442 :     `/usr/include/sys/stat.h'. Here are the most important structures.
443 :    
444 :    
445 :     struct stat
446 :     {
447 :     dev_t st_dev; /* device number*/
448 :     ino_t st_ino; /* file inode */
449 :     mode_t st_mode; /* permission */
450 :     short st_nlink; /* Number of hardlinks to file */
451 :     uid_t st_uid; /* user id */
452 :     gid_t st_gid; /* group id */
453 :     dev_t st_rdev;
454 :     off_t st_size; /* size in bytes */
455 :     time_t st_atime; /* time file last accessed */
456 :     time_t st_mtime; /* time file contents last modified */
457 :     time_t st_ctime; /* time last attribute change */
458 :     long st_blksize;
459 :     long st_blocks;
460 :     };
461 :    
462 :     
463 :     File: unix.info, Node: lstat and readlink, Prev: stat, Up: C files and dirs
464 :    
465 :     lstat and readlink
466 :     ------------------
467 :    
468 :     The function `stat()' treats symbolic links as though they were the
469 :     files they point to. In other words, if we use `stat()' to read a
470 :     symbolic link, we end up reading the file the link points to and not
471 :     the link itself-- we never see symbolic links. To avoid this problem,
472 :     there is a different version of the stat function called `lstat()'
473 :     which is identical to `stat()' except that it treats links as links and
474 :     _not_ as the files they point to. This means that we can test whether a
475 :     file is a symbolic link, only if we use `lstat()'. (See the next
476 :     paragraph.)
477 :    
478 :     Once we have identified a file to be a symbolic link, we use the
479 :     `readlink()' function to obtain the name of the file the link points to.
480 :    
481 :     #define bufsize 512
482 :     char buffer[bufsize];
483 :    
484 :     readlink("/path/to/file",buffer,bufsize);
485 :    
486 :     The result is returned in the string buffer.
487 :    
488 :     
489 :     File: unix.info, Node: File test macros, Next: Process control, Prev: C files and dirs, Up: C programming
490 :    
491 :     `stat()' test macros
492 :     ====================
493 :    
494 :     As we have already mentioned, the Unix mode bits contain not only
495 :     information about what permissions a file has, but also bits describing
496 :     the type of file - whether it is a directory or a link etc. There are
497 :     macros defined in UNIX to extract this information from the `st_mode'
498 :     member of the `stat' structure. They are defined in the `stat.h'
499 :     headerfile. Here are some examples.
500 :    
501 :     #define S_ISBLK(m) /* is block device */
502 :     #define S_ISCHR(m) /* is character device */
503 :     #define S_ISDIR(m) /* is directory */
504 :     #define S_ISFIFO(m) /* is fifo pipe/socket */
505 :     #define S_ISREG(m) /* is regular (normal) file */
506 :    
507 :     #define S_ISLNK(m) /* is symbolic link */ /* Not POSIX */
508 :     #define S_ISSOCK(m) /* is a lock */
509 :    
510 :    
511 :     #define S_IRWXU /* rwx, owner */
512 :     #define S_IRUSR /* read permission, owner */
513 :     #define S_IWUSR /* write permission, owner */
514 :     #define S_IXUSR /* execute/search permission, owner */
515 :     #define S_IRWXG /* rwx, group */
516 :     #define S_IRGRP /* read permission, group */
517 :     #define S_IWGRP /* write permission, grougroup */
518 :     #define S_IXGRP /* execute/search permission, group */
519 :     #define S_IRWXO /* rwx, other */
520 :     #define S_IROTH /* read permission, other */
521 :     #define S_IWOTH /* write permission, other */
522 :     #define S_IXOTH /* execute/search permission, other */
523 :     These return true or false when acting on the mode member. Here is
524 :     an example *Note readdir example::.
525 :    
526 :     struct stat statvar;
527 :    
528 :     stat("file",&statvar);
529 :    
530 :     /* test return values */
531 :    
532 :     if (S_ISDIR(statvar.st_mode))
533 :     {
534 :     printf("Is a directory!");
535 :     }
536 :    
537 :     * Menu:
538 :    
539 :     * readdir example::
540 :    
541 :     
542 :     File: unix.info, Node: readdir example, Prev: File test macros, Up: File test macros
543 :    
544 :     Example filing program
545 :     ----------------------
546 :    
547 :     The following example program demonstrates the use of the directory
548 :     functions in `dirent' and the `stat' function call.
549 :    
550 :     /********************************************************************/
551 :     /* */
552 :     /* Reading directories and `statting' files */
553 :     /* */
554 :     /********************************************************************/
555 :    
556 :     #include <stdio.h>
557 :     #include <dirent.h>
558 :     #include <sys/types.h>
559 :     #include <sys/stat.h>
560 :    
561 :    
562 :     #define DIRNAME "/."
563 :     #define bufsize 255
564 :    
565 :     /********************************************************************/
566 :    
567 :     main ()
568 :    
569 :    
570 :     { DIR *dirh;
571 :     struct dirent *dirp;
572 :     struct stat statbuf;
573 :     char *pathname[bufsize];
574 :     char *linkname[bufsize];
575 :    
576 :     if ((dirh = opendir(DIRNAME)) == NULL)
577 :     {
578 :     perror("opendir");
579 :     exit(1);
580 :     }
581 :    
582 :     for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
583 :     {
584 :     if (strcmp(".",dirp->d_name) == 0 || strcmp("..",dirp->d_name) == 0)
585 :     {
586 :     continue;
587 :     }
588 :    
589 :     if (strcmp("lost+found",dirp->d_name) == 0)
590 :     {
591 :     continue;
592 :     }
593 :    
594 :     sprintf(pathname,"%s/%s",DIRNAME,dirp->d_name);
595 :    
596 :     if (lstat(pathname,&statbuf) == -1) /* see man stat */
597 :     {
598 :     perror("stat");
599 :     continue;
600 :     }
601 :    
602 :     if (S_ISREG(statbuf.st_mode))
603 :     {
604 :     printf("%s is a regular file\n",pathname);
605 :     };
606 :    
607 :     if (S_ISDIR(statbuf.st_mode))
608 :     {
609 :     printf("%s is a directory\n",pathname);
610 :     }
611 :    
612 :     if (S_ISLNK(statbuf.st_mode))
613 :     {
614 :     bzero(linkname,bufsize); /* clear string */
615 :     readlink(pathname,linkname,bufsize);
616 :     printf("%s is a link to %s\n",pathname,linkname);
617 :     }
618 :    
619 :     printf("The mode of %s is %o\n\n",pathname,statbuf.st_mode & 07777);
620 :     }
621 :    
622 :     closedir(dirh);
623 :     }
624 :    
625 :     
626 :     File: unix.info, Node: Process control, Next: A more secure popen, Prev: File test macros, Up: C programming
627 :    
628 :     Process control, `fork()', `exec()', `popen()' and system
629 :     =========================================================
630 :    
631 :     There is a number of ways in which processes can interact with one
632 :     another and in which we can control their behaviour. We shall not go
633 :     into great detail in this course, only provide examples for reference.
634 :    
635 :     The UNIX `fork()' function is used to create child processes. This
636 :     is the basis of all `heavyweight' multitasking under unix. Here is a
637 :     simple example of fork in which we start a child process from within a
638 :     program and wait for it to finish. Note that the code for the parent
639 :     and the child is is the same file. The only thing that distinguishes
640 :     parent from child is the value returned by the fork function.
641 :    
642 :     When `fork()' is called, it duplicates the entire current process so
643 :     that two parallel processes are then running. The only difference
644 :     between these is that the child process (the copy) gets a return value
645 :     of zero from `fork()', whereas the parent gets a return value equal to
646 :     the process identifier (pid) of the child. This value can be used by
647 :     the parent to send messages or to wait for the child. Here we show a
648 :     simple example in which the `wait(NULL)' command is used to wait for
649 :     the last child spawned by the parent.
650 :    
651 :     /**************************************************************/
652 :     /* */
653 :     /* A brief demo of the UNIX process duplicator fork(). */
654 :     /* */
655 :     /**************************************************************/
656 :    
657 :     #include <stdio.h>
658 :    
659 :    
660 :     /***************************************************************/
661 :    
662 :     main ()
663 :    
664 :     { int pid, cid;
665 :    
666 :     pid = getpid();
667 :    
668 :     printf ("Fork demo! I am the parent (pid = %d)\n",pid);
669 :    
670 :     if (! fork())
671 :     {
672 :     cid = getpid();
673 :     printf ("I am the child (cid = %d) of (pid=%d)\n",cid,pid);
674 :     ChildProcess();
675 :     exit(0);
676 :     }
677 :    
678 :    
679 :     printf("Parent waiting here for the child...\n");
680 :    
681 :     wait(NULL);
682 :    
683 :     printf("Child finished, parent quitting too!\n");
684 :     }
685 :    
686 :     /**************************************************************/
687 :    
688 :     ChildProcess()
689 :    
690 :     { int i;
691 :    
692 :     for (i = 0; i < 10; i++)
693 :     {
694 :     printf ("%d...\n",i);
695 :     sleep(1);
696 :     }
697 :     }
698 :    
699 :     Another possibility is that we might want to execute a program and
700 :     wait to find out what the result of the program is before continuing.
701 :     There are two ways to do this. The first is a variation on the theme
702 :     above and uses `fork()'.
703 :    
704 :     Let's create a function which runs a shell command from within a C
705 :     program, and determines its return value. We make the result a boolean
706 :     (integer) value, so that the function returns `true' if the shell
707 :     command exits normally, *Note Return codes::.
708 :    
709 :     if (ShellCommandReturnsZero(SHELL-COMMAND))
710 :     {
711 :     printf ("Command %s went ok\n",SHELL-COMMAND);
712 :     }
713 :    
714 :     To do this we first have to fork a new process and then use one of the
715 :     `exec' commands to load a new code image on top of the new process.
716 :     shell commands from C This sounds complicated, but it is necessary
717 :     because of the way unix handles processes. If we had no use for the
718 :     return value, we could simply execute a shell command using the
719 :     `system("shell command")' function, (which does all this for us) but
720 :     when `system()' exits, we can only tell if the command was executed
721 :     successfully or unsuccessfully--we learn nothing about what actually
722 :     failed (the shell or command which was executed under the shell?) If
723 :     we require detailed information about what happened to the child
724 :     process then we need to do the following.
725 :    
726 :     #include <sys/types.h>
727 :     #include <sys/wait.h>
728 :    
729 :     /* Send complete command as a string */
730 :     /* including all arguments */
731 :    
732 :     ShellCommandReturnsZero(comm)
733 :    
734 :     char *comm;
735 :    
736 :     { int status, i, argc;
737 :     pid_t pid;
738 :     char arg[maxshellargs][bufsize];
739 :     char **argv;
740 :    
741 :     /* Build argument array for execv call*/
742 :    
743 :     for (i = 0; i < maxshellargs; i++)
744 :     {
745 :     bzero (arg[i],bufsize);
746 :     }
747 :    
748 :     argc = SplitCommand(comm,arg);
749 :    
750 :     if ((pid = fork()) < 0)
751 :     {
752 :     FatalError("Failed to fork new process");
753 :     }
754 :     else if (pid == 0) /* child */
755 :     {
756 :     argv = malloc((argc+1)*sizeof(char *));
757 :    
758 :     for (i = 0; i < argc; i++)
759 :     {
760 :     argv[i] = arg[i];
761 :     }
762 :    
763 :     argv[i] = (char *) NULL;
764 :    
765 :     if (execv(arg[0],argv) == -1)
766 :     {
767 :     yyerror("script failed");
768 :     perror("execvp");
769 :     exit(1);
770 :     }
771 :     }
772 :     else /* parent */
773 :     {
774 :     if (wait(&status) != pid)
775 :     {
776 :     printf("Wait for child failed\n");
777 :     perror("wait");
778 :     return false;
779 :     }
780 :     else
781 :     {
782 :     if (WIFSIGNALED(status))
783 :     {
784 :     printf("Script %s returned: %s\n",comm,WTERMSIG(status));
785 :     return false;
786 :     }
787 :    
788 :     if (! WIFEXITED(status))
789 :     {
790 :     return false;
791 :     }
792 :    
793 :     if (WEXITSTATUS(status) == 0)
794 :     {
795 :     return true;
796 :     }
797 :     else
798 :     {
799 :     return false;
800 :     }
801 :     }
802 :     }
803 :    
804 :     }
805 :    
806 :     /*******************************************************************/
807 :    
808 :     SplitCommand(comm,arg)
809 :    
810 :     char *comm, arg[maxshellargs][bufsize];
811 :    
812 :     { char *sp;
813 :     int i = 0, j;
814 :     char buff[bufsize];
815 :    
816 :     for (sp = comm; *sp != NULL; sp++)
817 :     {
818 :     bzero(buff,bufsize);
819 :    
820 :     if (i >= maxshellargs-1)
821 :     {
822 :     yyerror("Too many arguments in embedded script");
823 :     FatalError("Use a wrapper");
824 :     }
825 :    
826 :     while (*sp == ' ' || *sp == '\t')
827 :     {
828 :     sp++;
829 :     }
830 :    
831 :     switch (*sp)
832 :     {
833 :     case '\"': sscanf (++sp,"%[^\"]",buff);
834 :     break;
835 :     case '\'': sscanf (++sp,"%[^\']",buff);
836 :     break;
837 :     default: sscanf (sp,"%s",buff);
838 :     break;
839 :     }
840 :    
841 :     for (j = 0; j < bufsize; j++)
842 :     {
843 :     arg[i][j] = buff[j];
844 :     }
845 :    
846 :     sp += strlen(arg[i]);
847 :     i++;
848 :     }
849 :     return (i);
850 :     }
851 :    
852 :     In this example, the script waits for the exit signal from the child
853 :     process before continuing. The return value from the child is available
854 :     from the wait function with the help of a set of macros defined in
855 :     `/usr/include/sys/wait.h'. The value is given by `WTERMSIG(status)'.
856 :    
857 :     In the final example, we can open a pipe to a process directly in a
858 :     C program as though it were a file, by using the function `popen()'.
859 :     Pipes may be opened for reading or for writing, in exactly the same way
860 :     as a file is opened. The child process is automatically synchronized
861 :     with the parent using this method. Here is a program which opens a unix
862 :     command for reading (both stdout and stderr) from the child process are
863 :     piped into the program. Notice that the syntax used in this call is
864 :     that used by the Bourne shell, since this is build deeply into the unix
865 :     execution design.
866 :    
867 :    
868 :     #define bufsize 1024
869 :    
870 :     FILE *pp;
871 :     char VBUFF[bufsize];
872 :    
873 :     ...
874 :    
875 :     if ((pp = popen( "/sbin/mount -va 2<&1","r")) == NULL)
876 :     {
877 :     printf("Failed to open pipe\n");
878 :     return errorcode;
879 :     }
880 :    
881 :     while (!feof(pp))
882 :     {
883 :     fgets(VBUFF,bufsize,pp);
884 :    
885 :     /* Just write the output to stdout */
886 :    
887 :     printf ("Pipe read: %s\n",VBUFF);
888 :     }
889 :    
890 :     pclose(pp);
891 :    
892 :     
893 :     File: unix.info, Node: A more secure popen, Next: Traps and signals, Prev: Process control, Up: C programming
894 :    
895 :     A more secure `popen()'
896 :     =======================
897 :    
898 :     One problem with the `popen()' system call is that it uses a shell
899 :     to execute the command it obtains a pipe to. In the past this has been
900 :     used to allow Unix security breaches, using a so-called `IFS' attack
901 :     which can trick the shell into executing a program with the name of the
902 :     first node in the directory of the executable. For instance,if the pipe
903 :     was to open the program `/bin/ps', this coudl be tricked into executing
904 :     a program in the current working directory of the process called `bin'
905 :     with argument `ps'.
906 :    
907 :     The solution is not to use a shell at all, but to replace `popen()'
908 :     with a version which calls `exec()' directly. Here is a safe version
909 :     from the source code of cfengine:
910 :    
911 :    
912 :     #define bufsize 4096
913 :     #define maxshellargs 20
914 :    
915 :     pid_t *CHILD;
916 :     int MAXFD = 20; /* Max number of simultaneous pipes */
917 :    
918 :     /***************************************************************/
919 :    
920 :     FILE *cfpopen(command, type)
921 :    
922 :     char *command, *type;
923 :    
924 :     { char arg[maxshellargs][bufsize];
925 :     int i, argc, pd[2];
926 :     char **argv;
927 :     pid_t pid;
928 :     FILE *pp = NULL;
929 :    
930 :     if ((*type != 'r' && *type != 'w') || (type[1] != '\0'))
931 :     {
932 :     errno = EINVAL;
933 :     return NULL;
934 :     }
935 :    
936 :     if (CHILD == NULL) /* first time */
937 :     {
938 :     if ((CHILD = calloc(MAXFD,sizeof(pid_t))) == NULL)
939 :     {
940 :     return NULL;
941 :     }
942 :     }
943 :    
944 :     if (pipe(pd) < 0) /* Create a pair of descriptors to this process */
945 :     {
946 :     return NULL;
947 :     }
948 :    
949 :     if ((pid = fork()) == -1)
950 :     {
951 :     return NULL;
952 :     }
953 :    
954 :     if (pid == 0)
955 :     {
956 :     switch (*type)
957 :     {
958 :     case 'r':
959 :    
960 :     close(pd[0]); /* Don't need output from parent */
961 :    
962 :     if (pd[1] != 1)
963 :     {
964 :     dup2(pd[1],1); /* Attach pp=pd[1] to our stdout */
965 :     dup2(pd[1],2); /* Merge stdout/stderr */
966 :     close(pd[1]);
967 :     }
968 :    
969 :     break;
970 :    
971 :     case 'w':
972 :    
973 :     close(pd[1]);
974 :    
975 :     if (pd[0] != 0)
976 :     {
977 :     dup2(pd[0],0);
978 :     close(pd[0]);
979 :     }
980 :     }
981 :    
982 :     for (i = 0; i < MAXFD; i++)
983 :     {
984 :     if (CHILD[i] > 0)
985 :     {
986 :     close(CHILD[i]);
987 :     }
988 :    
989 :     argc = SplitCommand(command,arg);
990 :     argv = (char **) malloc((argc+1)*sizeof(char *));
991 :    
992 :     if (argv == NULL)
993 :     {
994 :     FatalError("Out of memory");
995 :     }
996 :    
997 :     for (i = 0; i < argc; i++)
998 :     {
999 :     argv[i] = arg[i];
1000 :     }
1001 :    
1002 :     argv[i] = (char *) NULL;
1003 :    
1004 :     if (execv(arg[0],argv) == -1)
1005 :     {
1006 :     sprintf(OUTPUT,"Couldn't run %s",arg[0]);
1007 :     CfLog(cferror,OUTPUT,"execv");
1008 :     }
1009 :    
1010 :     _exit(1);
1011 :     }
1012 :     }
1013 :     else
1014 :     {
1015 :     switch (*type)
1016 :     {
1017 :     case 'r':
1018 :    
1019 :     close(pd[1]);
1020 :    
1021 :     if ((pp = fdopen(pd[0],type)) == NULL)
1022 :     {
1023 :     return NULL;
1024 :     }
1025 :     break;
1026 :    
1027 :     case 'w':
1028 :    
1029 :     close(pd[0]);
1030 :    
1031 :     if ((pp = fdopen(pd[1],type)) == NULL)
1032 :     {
1033 :     return NULL;
1034 :     }
1035 :     }
1036 :    
1037 :     CHILD[fileno(pp)] = pid;
1038 :     return pp;
1039 :     }
1040 :     }
1041 :    
1042 :    
1043 :     /***************************************************************/
1044 :    
1045 :     cfpclose(pp)
1046 :    
1047 :     FILE *pp;
1048 :    
1049 :     { int fd, status;
1050 :     pid_t pid;
1051 :    
1052 :     Debug("cfpclose(pp)\n");
1053 :    
1054 :     if (CHILD == NULL) /* popen hasn't been called */
1055 :     {
1056 :     return -1;
1057 :     }
1058 :    
1059 :     fd = fileno(pp);
1060 :    
1061 :     if ((pid = CHILD[fd]) == 0)
1062 :     {
1063 :     return -1;
1064 :     }
1065 :    
1066 :     CHILD[fd] = 0;
1067 :    
1068 :     if (fclose(pp) == EOF)
1069 :     {
1070 :     return -1;
1071 :     }
1072 :    
1073 :     Debug("cfpopen - Waiting for process %d\n",pid);
1074 :    
1075 :     #ifdef HAVE_WAITPID
1076 :    
1077 :     while(waitpid(pid,&status,0) < 0)
1078 :     {
1079 :     if (errno != EINTR)
1080 :     {
1081 :     return -1;
1082 :     }
1083 :     }
1084 :    
1085 :     return status;
1086 :    
1087 :     #else
1088 :    
1089 :     if (wait(&status) != pid)
1090 :     {
1091 :     return -1;
1092 :     }
1093 :     else
1094 :     {
1095 :     if (WIFSIGNALED(status))
1096 :     {
1097 :     return -1;
1098 :     }
1099 :    
1100 :     if (! WIFEXITED(status))
1101 :     {
1102 :     return -1;
1103 :     }
1104 :    
1105 :     return (WEXITSTATUS(status));
1106 :     }
1107 :     #endif
1108 :     }
1109 :    
1110 :     /*******************************************************************/
1111 :     /* Command exec aids */
1112 :     /*******************************************************************/
1113 :    
1114 :     SplitCommand(comm,arg)
1115 :    
1116 :     char *comm, arg[maxshellargs][bufsize];
1117 :    
1118 :     { char *sp;
1119 :     int i = 0, j;
1120 :     char buff[bufsize];
1121 :    
1122 :     for (sp = comm; sp < comm+strlen(comm); sp++)
1123 :     {
1124 :     bzero(buff,bufsize);
1125 :    
1126 :     if (i >= maxshellargs-1)
1127 :     {
1128 :     CfLog(cferror,"Too many arguments in embedded script","");
1129 :     FatalError("Use a wrapper");
1130 :     }
1131 :    
1132 :     while (*sp == ' ' || *sp == '\t')
1133 :     {
1134 :     sp++;
1135 :     }
1136 :    
1137 :     switch (*sp)
1138 :     {
1139 :     case '\0': return(i-1);
1140 :    
1141 :     case '\"': sscanf (++sp,"%[^\"]",arg[i]);
1142 :     break;
1143 :     case '\'': sscanf (++sp,"%[^\']",arg[i]);
1144 :     break;
1145 :     case '`': sscanf (++sp,"%[^`]",arg[i]);
1146 :     break;
1147 :     default: sscanf (sp,"%s",arg[i]);
1148 :     break;
1149 :     }
1150 :    
1151 :     sp += strlen(arg[i]);
1152 :     i++;
1153 :     }
1154 :    
1155 :     return (i);
1156 :     }
1157 :    
1158 :     
1159 :     File: unix.info, Node: Traps and signals, Next: Regular expressions in C, Prev: A more secure popen, Up: C programming
1160 :    
1161 :     Traps and signals
1162 :     =================
1163 :    
1164 :     Processes can receive signals from the UNIX kernel at any time.
1165 :     Some of these signals terminate the execution of the program. This can
1166 :     cause problems if the program is in the middle of critical activity
1167 :     such as writing to a file. For that reason we can trap signals and
1168 :     provide our own routine for handling them in a special way.
1169 :    
1170 :     A signal handler is made by calling the function `signal()' for each
1171 :     signal and by specifying a pointer to a function which will be called
1172 :     in the event of a signal. For example:
1173 :    
1174 :     main ()
1175 :    
1176 :     { int HandleSignal();
1177 :    
1178 :     signal(SIGTERM,HandleSignal);
1179 :     }
1180 :    
1181 :    
1182 :     HandleSignal()
1183 :    
1184 :     {
1185 :     /* Tidy up and exit cleanly */
1186 :    
1187 :     exit(0);
1188 :     }
1189 :     `SIGTERM' is the usual signal sent by the command `kill'. There are
1190 :     many other signals which can be sent to programs. Here is list. You
1191 :     have to decide for yourself whether or not you want to provide your own
1192 :     signal handling function. To ignore a signal, you write
1193 :    
1194 :     signal(SIGTYPE,SIG_IGN);
1195 :    
1196 :     To remove a signal handler and re-activate a signal, you write
1197 :    
1198 :     signal(SIGTYPE,SIG_DFL);
1199 :    
1200 :     
1201 :     File: unix.info, Node: Regular expressions in C, Next: DES encryption, Prev: Traps and signals, Up: C programming
1202 :    
1203 :     Regular expressions
1204 :     ===================
1205 :    
1206 :     A regular expression is a pattern for matching strings of text. We
1207 :     have met regular expressions earlier in connection with the shell and
1208 :     Perl. Naturally these earlier encounters have their roots in C
1209 :     functions for handling expressions. A regular expression is used by
1210 :     first `compiling' it into a convenient data structure. Then a matching
1211 :     function is used to compare the expression with a test string. In this
1212 :     example program we show how a regular expression typed in as an
1213 :     argument to the program is found within strings of input entered on the
1214 :     keyboard.
1215 :    
1216 :    
1217 :     #include <stdio.h>
1218 :     #include <regex.h>
1219 :    
1220 :     main (argc,argv)
1221 :    
1222 :     int argc;
1223 :     char **argv;
1224 :    
1225 :     {
1226 :     char buffer[1024];
1227 :     regex_t rx;
1228 :     regmatch_t match;
1229 :     size_t nmatch = 1;
1230 :    
1231 :     if (regcomp(&rx, argv[1], REG_EXTENDED) != 0)
1232 :     {
1233 :     perror("regcomp");
1234 :     return;
1235 :     }
1236 :    
1237 :     while (!feof(stdin))
1238 :     {
1239 :     fgets(buffer,1024,stdin);
1240 :    
1241 :     if (regexec(&rx,buffer,1,&match,0) == 0)
1242 :     {
1243 :     printf("Matched:(%s) at %d to %d",buffer,match.rm_so,match.rm_eo);
1244 :     }
1245 :    
1246 :     }
1247 :    
1248 :     regfree(&rx);
1249 :     }
1250 :    
1251 :     Here is an example of its use. The output of the program is in
1252 :     _italics_
1253 :    
1254 :    
1255 :     % a.out xyz
1256 :     this is a string
1257 :     another string
1258 :     an xyz string
1259 :     _Matched: (an xyz string
1260 :     ) at 3 to 6_
1261 :     another xyz zyxxyz string
1262 :     _Matched: (another xyz xyz string
1263 :     ) at 8 to 11_
1264 :    
1265 :     % a.out 'xyz|abc'
1266 :     This is a string
1267 :     An abc string
1268 :     _Matched: (An abc string
1269 :     ) at 3 to 6_
1270 :     Or an xyz string
1271 :     _Matched: (Or an xyz string
1272 :     ) at 6 to 9_
1273 :     If you don't want the match data set `&pm' to `NULL'. To get an
1274 :     exact match rather than a substring check that the bounds are 0 and
1275 :     `strlen(argv[1])-1'.
1276 :    
1277 :     
1278 :     File: unix.info, Node: DES encryption, Next: ioctl, Prev: Regular expressions in C, Up: C programming
1279 :    
1280 :     DES encryption
1281 :     ==============
1282 :    
1283 :     Encryption with the SSLeay library, compile with command
1284 :    
1285 :    
1286 :     gcc crypto.c -I/usr/local/ssl/include -L/usr/local/ssl/lib -lcrypto
1287 :     Example of normal triple DES encryption which works only on an 8-byte
1288 :     buffer:
1289 :    
1290 :     /*****************************************************************************/
1291 :     /* */
1292 :     /* File: crypto.c */
1293 :     /* */
1294 :     /* Compile with: gcc program.c -lcrypto (SSLeay) */
1295 :     /* */
1296 :     /*****************************************************************************/
1297 :    
1298 :     #include <stdio.h>
1299 :     #include <des.h>
1300 :    
1301 :     #define bufsize 1024
1302 :    
1303 :     /* Note how this truncates to 8 characters */
1304 :    
1305 :     main ()
1306 :    
1307 :     { char in[bufsize],out[bufsize],back[bufsize];
1308 :     des_cblock key1,key2,key3,seed = {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10};
1309 :     des_key_schedule ks1,ks2,ks3;
1310 :    
1311 :     strcpy(in,"1 2 3 4 5 6 7 8 9 a b c d e f g h i j k");
1312 :    
1313 :     des_random_seed(seed);
1314 :    
1315 :     des_random_key(key1);
1316 :     des_random_key(key2);
1317 :     des_random_key(key3);
1318 :    
1319 :     des_set_key((C_Block *)key1,ks1);
1320 :     des_set_key((C_Block *)key2,ks2);
1321 :     des_set_key((C_Block *)key3,ks3);
1322 :     des_ecb3_encrypt((C_Block *)in,(C_Block *)out,ks1,ks2,ks3,DES_ENCRYPT);
1323 :    
1324 :     printf("Encrypted [%s] into [%s]\n",in,out);
1325 :    
1326 :     des_ecb3_encrypt((C_Block *)out,(C_Block *)back,ks1,ks2,ks3,DES_DECRYPT);
1327 :    
1328 :     printf("and back to.. [%s]\n",back);
1329 :     }
1330 :     Triple DES, chaining mode, for longer strings (which must be a
1331 :     multiple of 8 bytes):
1332 :    
1333 :     /*****************************************************************************/
1334 :     /* */
1335 :     /* File: crypto.c */
1336 :     /* */
1337 :     /* Compile with: gcc program.c -lcrypto (SSLeay) */
1338 :     /* */
1339 :     /*****************************************************************************/
1340 :    
1341 :     #include <stdio.h>
1342 :     #include <des.h>
1343 :    
1344 :     #define bufsize 1024
1345 :    
1346 :     /* This can be used on arbitrary length buffers */
1347 :    
1348 :     main ()
1349 :    
1350 :     { char in[bufsize],out[bufsize],back[bufsize],workvec[bufsize];
1351 :     des_cblock key1,key2,key3,seed = {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10};
1352 :     des_key_schedule ks1,ks2,ks3;
1353 :    
1354 :     strcpy(in,"1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z");
1355 :    
1356 :     des_random_seed(seed);
1357 :    
1358 :     des_random_key(key1);
1359 :     des_random_key(key2);
1360 :     des_random_key(key3);
1361 :    
1362 :     des_set_key((C_Block *)key1,ks1);
1363 :     des_set_key((C_Block *)key2,ks2);
1364 :     des_set_key((C_Block *)key3,ks3);
1365 :    
1366 :     /* This work vector can be intialized t anything ...*/
1367 :    
1368 :     memset(workvec,0,bufsize);
1369 :    
1370 :     des_ede3_cbc_encrypt((C_Block *)in,(C_Block *)out,(long)strlen(in),
1371 :     ks1,ks2,ks3,(C_Block *)workvec,DES_ENCRYPT);
1372 :    
1373 :     printf("Encypted [%s] into [something]\n",in);
1374 :    
1375 :     /* .. but this must be initialized the same as above */
1376 :    
1377 :     memset(workvec,0,bufsize);
1378 :    
1379 :     /* Note that the length is the original length, not strlen(out) */
1380 :    
1381 :     des_ede3_cbc_encrypt((C_Block *)out,(C_Block *)back,(long)strlen(in),
1382 :     ks1,ks2,ks3,(C_Block *)workvec,DES_DECRYPT);
1383 :    
1384 :     printf("and back to.. [%s]\n",back);
1385 :     }
1386 :    
1387 :     
1388 :     File: unix.info, Node: ioctl, Next: Database example in C, Prev: DES encryption, Up: C programming
1389 :    
1390 :     Device control: ioctl
1391 :     =====================
1392 :    
1393 :     The C function `ioctl' (I/O control) is used to send special control
1394 :     commands to devices like the disk and the network interface. The
1395 :     syntax of the function is
1396 :     int ioctl(fd, request, arg)
1397 :     int fd, request;
1398 :     long arg;
1399 :    
1400 :     The first parameter is normally as device handle or socket descriptor.
1401 :     The second is a control parameter. Lists of valid control parameters are
1402 :     normally defined in the system `include' files for a particular device.
1403 :     They are device and system dependent so you need a local manual and som
1404 :     detective work to find out what they are. The final parameter is a
1405 :     pointer to a variable which receives return data from the device.
1406 :    
1407 :     `ioctl' commands are device specific, by their nature. The commands
1408 :     for the ethernet interface device are only partially standardized, for
1409 :     example. We could read the ethernet device (which is called `le0' on a
1410 :     Sun workstation), using the following command:
1411 :    
1412 :     # include <sys/socket.h> /* Typical includes for internet */
1413 :     # include <sys/ioctl.h>
1414 :     # include <net/if.h>
1415 :     # include <netinet/in.h>
1416 :     # include <arpa/inet.h>
1417 :     # include <netdb.h>
1418 :     # include <sys/protosw.h>
1419 :     # include <net/route.h>
1420 :    
1421 :     struct ifreq IFR;
1422 :     int sk;
1423 :     struct sockaddr_in sin;
1424 :    
1425 :     strcpy(IFR.ifr_name,"le0");
1426 :     IFR.ifr_addr.sa_family = AF_INET;
1427 :    
1428 :     if ((sk = socket(AF_INET,SOCK_DGRAM,IPPROTO_IP)) == -1)
1429 :     {
1430 :     perror("socket");
1431 :     exit(1);
1432 :     }
1433 :    
1434 :     if (ioctl(sk,SIOCGIFFLAGS, (caddr_t) &IFR) == -1)
1435 :     {
1436 :     perror ("ioctl");
1437 :     exit(1);
1438 :     }
1439 :    
1440 :     We shall not go into the further details of `ioctl', but simply note
1441 :     its role in system programming.
1442 :    
1443 :     
1444 :     File: unix.info, Node: Database example in C, Next: lex and yacc, Prev: ioctl, Up: C programming
1445 :    
1446 :     Database example (Berkeley db)
1447 :     ==============================
1448 :    
1449 :    
1450 :     DBT key,value;
1451 :     DB *dbp;
1452 :     DBC *dbcp;
1453 :     db_recno_t recno;
1454 :    
1455 :     if ((errno = db_open(CHECKSUMDB,DB_BTREE, DB_CREATE, 0664, NULL, NULL, &dbp)) != 0)
1456 :     {
1457 :     sprintf(OUTPUT,"cfd: couldn't open checksum database %s\n",CHECKSUMDB);
1458 :     CfLog(cferror,OUTPUT,"db_open");
1459 :     return false;
1460 :     }
1461 :    
1462 :     bzero(&value,sizeof(value));
1463 :     bzero(&key,sizeof(key));
1464 :    
1465 :     key.data = filename;
1466 :     key.size = strlen(filename)+1;
1467 :     value.data = dbvalue;
1468 :     value.size = sizeof(dbvalue);
1469 :    
1470 :     if ((errno = dbp->del(dbp,NULL,&key,0)) != 0)
1471 :     {
1472 :     CfLog(cferror,"","db_store");
1473 :     }
1474 :    
1475 :     key.data = filename;
1476 :     key.size = strlen(filename)+1;
1477 :    
1478 :     if ((errno = dbp->put(dbp,NULL,&key,&value,0)) != 0)
1479 :     {
1480 :     CfLog(cferror,"put failed","db->put");
1481 :     }
1482 :    
1483 :     if ((errno = dbp->get(dbp,NULL,&key,&value,0)) == 0)
1484 :     {
1485 :     /* Not found ... */
1486 :     return;
1487 :     }
1488 :    
1489 :     dbp->close(dbp,0);
1490 :    

Administrator
ViewVC Help
Powered by ViewVC 1.0.3