Parent Directory
|
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 |