Вы находитесь на странице: 1из 1037

 

Books.Ru 
ISBN 5932860898,
UNIX. , 2 
 Books.Ru  . 
 , 

. ,
 (piracy@symbol.ru),
.

Advanced Programming
in the UNIX Environment

Second Edition

W. Richard Stevens,
Stephen A. Rago

UNIX

. ,
.


2007

High tech

. , .

UNIX. ,
2
.

.

.
.
.
.
.
.

., .
UNIX. , 2 . .: 
, 2007. 1040 ., .
ISBN 5932860898
UNIX. 
, 
UNIX. 
,
. ,
UNIX.
, 
, 
(IPC), , 
POSIX.1.
, 
4 : FreeBSD 5.2.1, Linux 2.4.22, Slaris 9 Mac OS X 10.3.
,
UNIX, , ,
POSIX.1 Single UNIX Specification.
ISBN13: 9785932860892
ISBN10: 5932860898
ISBN 0201433079 ()
, 2007
Authorized translation of the English edition 2005 Pearson Education, Inc. This
translation is published and sold by permission of Pearson Education, Inc., the owner
of all rights to publish and sell the same.
, 
. 
, , .

. 199034, , 16 , 7,
. (812) 3245353, edit@symbol.ru. N 000054 25.12.98.

00593, 2; 953000 .
18.04.2007. 701001/16 . .
65 . . 2000 . N

199034, , 9 , 12.


. . . . . . . . . . . . . . . . . . . . . . . . 15
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
. . . . . . . . . . . . . . . . . . . 19

1. UNIX. . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.2. UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
1.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
1.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.11. . . . . . . . . . . . . . . . . 49
1.12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

2. UNIX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.2. UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.2.1. ISO C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.2.2. IEEE POSIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.2.3. Single UNIX Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
2.2.4. FIPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.3. UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.3.1. UNIX System V Release 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.3.2. 4.4BSD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.3.3. FreeBSD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.3.4. Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.3.5. Mac OS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.3.6. Solaris . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.3.7. UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.4. . . . . . . . . . . . . . . . . . . . 68

7
2.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.5.1. ISO C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
2.5.2. POSIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.5.3. XSI. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.5.4. sysconf, pathconf fpathconf . . . . . . . . . . . . . . . . 75
2.5.5. . . . . . . . . 84
2.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.7. . . . 92
2.8. . . . . . . . . . . . . . . . . . . . . . . 93
2.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
2.10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

3.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
3.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
3.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
3.3. open. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
3.4. creat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
3.5. close . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
3.6. lseek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
3.7. read . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
3.8. write . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
3.9.  . . . . . . . . . . . . . . . . . . . . . 107
3.10. . . . . . . . . . . . . . . . . . . . . . . . . . 109
3.11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
3.12. dup dup2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
3.13. sync, fsync fdatasync . . . . . . . . . . . . . . . . . . . . . . . . . . 117
3.14. fcntl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
3.15. ioctl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
3.16. /dev/fd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
3.17. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
4.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
4.2. stat, fstat lstat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
4.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
4.4. setuserID setgroupID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
4.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
4.6. . . . . . . . . . . . . . . . . . 138
4.7. access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
4.8. umask . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
4.9. chmod fchmod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
4.10. sticky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
4.11. chown, fchown lchown . . . . . . . . . . . . . . . . . . . . . . . . . 146

8
4.12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
4.13. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
4.14. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
4.15. link, unlink, remove rename. . . . . . . . . . . . . . . . . . . . . 153
4.16. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
4.17. symlink readlink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
4.18. . . . . . . . . . . . . . . . . . . . . . . . 161
4.19. utime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
4.20. mkdir rmdir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
4.21. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
4.22. chdir, fchdir getcwd . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
4.23. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
4.24. . . . . . . . . . . . . . . . . . . . . 177
4.25. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179

5.  . . . . . . . . . . . . . . . . . . . . . 181
5.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
5.2. FILE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
5.3. , . . . 183
5.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
5.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
5.6. . . . . . . . . . . . . . . . . . . . . . . . . . . 189
5.7.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
5.8.  . . . . . . . . . . 193
5.9.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
5.10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
5.11.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
5.12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
5.13. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
5.14.  . . . . . . . . 211
5.15. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212

6. . . . . . . . . . . . . . . . . . . . . . 213
6.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
6.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
6.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
6.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
6.5. . . . . . . . . . . . . . . . . . . . . 220
6.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
6.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
6.8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
6.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225

9
6.10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
6.11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232

7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
7.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
7.2. main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
7.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
7.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
7.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
7.6. C . . . . . . . . . . . . . . . . . . . 241
7.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
7.8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
7.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
7.10. setjump longjump . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
7.11. getrlimit setrlimit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
7.12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264

8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
8.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
8.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
8.3. fork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
8.4. vfork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
8.5. exit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
8.6. wait waitpid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
8.7. waitid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
8.8. wait3 wait4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
8.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
8.10. exec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
8.11. . . . . . . . . 298
8.12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
8.13. system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
8.14. . . . . . . . . . . . . . . . . . . 313
8.15. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
8.16. . . . . . . . . . . . . . . . . . . . . . . 320
8.17. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323

9. . . . . . . . . . . . . . . . . . . . . . . . 325
9.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
9.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
9.3. . . . . . . . . . . . . . . . . . . . . 331
9.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
9.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
9.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337

10
9.7. tcgetpgrp, tcsetpgrp tcgetsid . . . . . . . . . . . . . . . . . . . . . 339
9.8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
9.9. . . . . . . . . . . . . . . . . 343
9.10. . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
9.11. FreeBSD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
9.12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355

10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
10.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
10.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
10.3. signal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
10.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
10.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
10.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
10.7. SIGCLD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
10.8. . . . . . . . . . . . . . 382
10.9. kill raise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
10.10. alarm pause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
10.11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
10.12. sigprocmask . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
10.13. sigpending . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
10.14. sigaction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
10.15. sigsetjmp siglongjmp . . . . . . . . . . . . . . . . . . . . . . . . . 403
10.16. sigsuspend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
10.17. abort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
10.18. system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
10.19. sleep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
10.20. . . . . . . . . . . . . . . . . . . . . . . . . . 424
10.21. . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
10.22. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429

11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
11.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
11.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
11.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
11.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
11.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
11.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445
11.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464

12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
12.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
12.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465

11
12.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466
12.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
12.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
12.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485
12.7. . . . . . . . . . . . . . . . . . . . . . . 490
12.8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494
12.9. fork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498
12.10.  . . . . . . . . . . . . . . . . . . . . . . . . . 502
12.11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503

13.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504
13.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504
13.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504
13.3. . . . . . . . . . . . . . . . . . . . . . . 506
13.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510
13.5. . . . . . . . . . . . . . . . . . . . . . . . 515
13.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517
13.7.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
13.8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522

14.  . . . . . . . . . . . . . . . . . . . . . . 523
14.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523
14.2.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523
14.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527
14.4. STREAMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544
14.5.  . . . . . . . . . . . . . . . . . . . . . . . 558
14.5.1. select pselect . . . . . . . . . . . . . . . . . . . . . . . . . . 561
14.5.2. poll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
14.6.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569
14.6.1.  System V . . . . . . . . . . . . . . . 570
14.6.2.  BSD. . . . . . . . . . . . . . . . . . . . 571
14.7. readv writev . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
14.8. readn writen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574
14.9.  . . . . . . . . . . . 576
14.10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583

15. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585
15.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585
15.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586
15.3. popen pclose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
15.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
15.5. FIFO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605
15.6. XSI IPC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 609

12
15.6.1. . . . . . . . . . . . . . . . . . . . . . . . . . 610
15.6.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . 611
15.6.3. . . . . . . . . . . . . . . . . . . . . . . . 612
15.6.4. . . . . . . . . . . . . . . . . . . . . . . . 613
15.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
15.8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621
15.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 628
15.10.
 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636
15.11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639

16. : . . . . . . . . . . . . . . 642
16.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
16.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
16.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
16.3.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
16.3.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649
16.3.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651
16.3.4. . . . . . . . . . . . . . . . . . . . . . . . 659
16.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 660
16.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664
16.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679
16.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682
16.8.  . . . . . . . . . . . . . . . 683
16.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684

17. IPC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686


17.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686
17.2. STREAMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686
17.2.1. STREAMS . . . . . . . . . . . . . . . . . . . 690
17.2.2. . . . . . . . . . . . . . . . . . . . . . . . . . . 691
17.3. UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 695
17.3.1. UNIX . . . . . . . . . . . . . . . . . 696
17.3.2. . . . . . . . . . . . . . . . . . . . . . . . . . . 698
17.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . 703
17.4.1.
STREAMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
17.4.2.
UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708
17.5. , 1 . . . . . . . . . . . . . . . . . . . . . . . . 717
17.6. , 2 . . . . . . . . . . . . . . . . . . . . . . . . 723
17.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731

13
18.  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
18.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
18.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
18.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 742
18.4. . . . . . . . . . . 748
18.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 749
18.6. stty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757
18.7. . . . . . . . . . . . . . . . . 758
18.8. . . . . . . . . . . . . . . . . . . . . . . . 759
18.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760
18.10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766
18.11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
18.12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 776
18.13. termcap, terminfo curses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778
18.14. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779

19. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
19.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
19.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
19.3. . . . . . . . . . . . . . . . . . . . . 788
19.3.1. STREAMS . . . . . . . . . . . . . 790
19.3.2. BSD . . . . . . . . . . . . . . . . . . . . . . . . . . 793
19.3.3. Linux . . . . . . . . . . . . . . . . . . . . . . . . . 797
19.4. pty_fork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 799
19.5. pty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801
19.6. pty . . . . . . . . . . . . . . . . . . . . . . . . . . . . 806
19.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 814
19.8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 815

20. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 818
20.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 818
20.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 818
20.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 820
20.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 822
20.5. ? . . . . . . . . . . . . . . . . . . . . 826
20.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 828
20.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 829
20.8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 830
20.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858
20.10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864

14
21. . . . . . . . . . . . . . . . . . . . . . . . 866
21.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866
21.2. . . . . . . . . . . . . . . . . . . . . . . . . . . 866
21.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . 869
21.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 870
21.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 872
21.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919

A. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921
B. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 956
C. . . . . . . . . . . . . . . . . . . 965
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1000
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1008


, (Stephen Rago), , 
, 
UNIX UNIX
.
. , 

UNIX UNIX . 
, .
(Mukesh Kacker),
Pronto Networks, Inc.

, 
UNIX.
. (Eric S. Raymond),
The Art of UNIX Programming


, UNIX.

, . 
.
, 
UNIX, ,
, , POSIX 1003.1
( 2004 ) Single UNIX Specification, Version 3.
(Andrew Josey),
The Open Group POSIX 1003.1

,
UNIX.
,  
.
, GNU/Linux App
le OS X, 
, .
.
(Dr. Benjamin Kuperman),
. (Swarthmore)


Advanced Programming in the UNIX Environment
, UNIX
C. ,
.
UniForum Monthly

Advanced Program
ming in the UNIX Environment, (
AddisonWesley), . 
, 1992 .
, .
Open Systems Today

UNIX
Advanced Programming in the UNIX Environment, 
(AddisonWesley). 
,
.
RS/Magazine



: , UNIX ?.
, : ,
. ,
.
. 70
,
, 
,
. , 
Microsoft Intel, 
, 

.
, UNIX, ,
, ,
. 70 80 XX AT&T 
UNIX,
, 
. , AT&T SVID (System V Interface Defi
nition, System V),
POSIX . , UNIX

, , , 
. , UNIX

, 
.
, , UNIX, 
, ,
.
(Maurice Bach) The Design of the Unix Operating System. ,
,
, 
. (Brian Kernighan)
, , (Rich Stevens). 
, , 

18

,
.
,
Linux UNIX
, , 
. (Steve Rago) 
, , 
ISO IEEE
.
.
.
(Dennis Ritchie)
,
2005

,
UNIX Network Programming.
, , 
. 1999 
. ,
 , 
. USENIX 
, .
. 1993
UNIX System V Network Programming, ,
UNIX Network Programming, 
System V.
, ,
. TCP/IP
Illustrated, STREAMS. 
, , , , 

.
AddisonWesley ,
, , . 
13 . 
UNIX , 
.

System V Linux.
,
UNIX, 
Linux, .
Solaris, , System V Release 4, 
.

4.4BSD 
(CSRG Computing Science Research Group)

UNIX, 
,
.

20

Linux, , 
,
UNIX 
, . Linux
, , 
BSD.

, Apple
Computer Mac 
, Mach FreeBSD.

, , 
.
1992 Advanced Programming in the
UNIX Environment, 
UNIX. : Ad
vanced Programming in the UNIX Environment. ,
.


. 
, 
13 . ,
UNIX.
, , ,
. 
2, . 
POSIX.1 2001 
1990 , .
ISO C 1990 1999 ,
, POSIX.1.
POSIX.1
. Single UNIX Specification (
The Open Group, X/Open) POSIX.1.
POSIX.1 1003.1 
, .
,
. ,

.
POSIX.1.
(IPC Interprocess Com
munication), ,
, IPC.

21

, 
POSIX.1. ,
.
.
,
. , 
PostScript
. , 
, 
, .
, , 
. , ,
 : PostScript (http://www.apue;
book.com/lostchapter/modem.ps) PDF (http://www.apuebook.com/lostchapter/
modem.pdf).
www.apue;
book.com. 
:
1. FreeBSD 5.2.1 , 4.4BSD, 
Intel Pentium.
2. Linux 2.4.22 ( Mandrake 9.2)
UNIX , Intel
Pentium.
3. Solaris 9 System V Release 4 Sun Microsys
tems, 64 UltraSPARCIIi.
4. Darwin 7.4.0 , FreeBSD Mach, 
Apple Mac OS X, 10.3, PowerPC.

, , 
.
, 
.
( , ), 
,
. (Jeanne)
, Linux .

.
(David Bausum), (David Boreham),
(Keith Bostic), (Mark Ellis), (Phil Ho
ward), (Andrew Josey), (Mukesh Kacker), 

22

(Brian Kernighan), (Bengt Kleberg), 


(Ben Kuperman), (Eric Raimond)
(Andy Rudoff).
, ,
Solaris, , , 
, UNIX. 
AddisonWesley,
. (Tyrrell Albaugh), (Mary
Franz), (John Fuller), (Karen Gettman),
(Jessica Goldstein), (Noreen Regina)
(John Wait). (Evelyn Pyle)
.
, 
, .
,
2005


sar@apuebook.com

UNIX:
, 
C. , 
, UNIX.
, UNIX 
: ,
, ,
. . (system
call interface). C 
,
, C (
, ).

Unix Programmers Manual (
UNIX). .
,
.

23

UNIX
UNIX, 80 ,
,
80. ANSI 
C, IEEE POSIX ( 
) X/Open.
. , 
System V Release 4
4.4BSD. 
, , 
.


:
1. ,
UNIX, ( 1).
UNIX UNIX ( 2).
2. :  ( 3),
( 4),  (
5) ( 6).
3. : UNIX ( 7), 
( 8), ( 9)
( 10).
4. : 
( 11),  ( 12) 
( 13).
5. IPC ( 14 15).
6. : ( 16), Post
Script ( 17), ( 18) 
( 19).
C,
UNIX.
UNIX. 
, UNIX 
, 
UNIX.


10 000 
. C. , 
ANSI C. , 

24

Unix Programmers Manual


( UNIX) ,

.

. ,
, 
. 
,
( 16, 17, 18 19).
, .

. 
FTP ftp.uu.net, published/books/stevens.ad;
vprog.tar.Z.
.

,

, 
. UNIX .
System V 4.xBSD.
4.3 + BSD
4.3BSD

4.3BSD Tahoe

4.3BSD Reno
BSD Net 1

1986

1987

1988

1989

SVR3.0

SVR3.1

SVR3.2
XPG3

4.4BSD ?
BSD Net 2

1990

1991

1992

SVR4
ANSI C

POSIX.1

4.xBSD 
Computer Systems Research Group 
. BSD Net 1
BSD Net 2 
4.xBSD. SVRx System V Release x
AT&T. XPG3 X/Open Portability Guide, issue 3 ( X/Open
, 3). ANSI C ANSI 
C. POSIX.1 ISO IEEE
UNIX .
UNIX 2.2 2.3.

25

4.3+BSD UNIX,
BSD Net 2 4.4BSD.
4.4BSD ,
4.4BSD. 
 , 
4.3+BSD.


UNIX:
1. UNIX System V/386 Release 4.0 Version 2.0 ( SVR4) U.H. Corp.
(UHC), Intel 80386.
2. 4.3+BSD Computer Systems Research Group, ,
,
Hewlett Packard.
3. BSD/386 ( BSD Net 2) Berkeley Software Design Inc., 
Intel 80386.
, 4.3+BSD.
4. SunOS, 4.1.1 4.1.2 Sun Microsystems (, 
, , 
System V), SPARC SLC.

.

,
, . 
. , , , .

. 
, , 
. 

System V. 
AddisonWesley,
: (Maury Bach), (Mark
Ellis), (Jeff Gitlin), (Piter Honeyman),
(John Linderman),  (Doug McIlroy),
(Evi Nemeth), (Craig Partridge),
(Dave Presotto), (Gary Wilson) (Gary Wright).
(Keith Bostic) c (Kirk McKusick) U.C. Ber
keley CSRG , 
BSD (
(Peter Salus)). (Sam Nataros) (Joachim
Sacksen) UHC SVR4 

26

. (Trent Hein)  
 BSD/386.

: (Paul Lucchina), (Joe Godsil),
(Jim Hogue), (Ed Tankus) (Gary Wright).
AddisonWesley, (John Wait),
. 
.
(NOAO)
(Sidney Wolff), (Richard Wolff)
(Steve Grandi) .
UNIX troff,
. , 
, groff,
(James Clark). 
. 
,  troff.
,
, .
,
1992


rstevens@kohala.com
http://ww.kohala.com/~rstevens

1
UNIX
1.1.
.
, 
, , , 
. 
, UNIX.
UNIX
, , 
( , , ). 
UNIX. 
,
. 
. , 
UNIX, , .

1.2. UNIX
, 
, 
. 
(kernel),
. . 1.1 
, UNIX.
, ;
( . 1.1).
,
, 
( 

28

1. UNIX

. 1.1. UNIX

1.11). , 
.

, 
.
, , 
, .
, Linux GNU.
GNU/Linux, 
Linux. , ,
, ,
. ( , ,
.)

1.3.

UNIX .
;
/etc/passwd. , 
, : ,
, (205), 
(105), , (/home/sar) 
(/bin/ksh).
sar:x:205:105:Stephen Rago:/home/sar:/bin/ksh

. 6
.

29

1.3.



, ,
. ( 
, ,
, , 
.) 
,
. 
( ) (
). 
. 1.1.
1.1. ,
UNIX

FreeBSD 5.2.1 Linux 2.4.22

Bourne shell

/bin/sh

Bourneagain
shell

/bin/bash

C shell

/bin/csh

Korn shell

/bin/ksh

TENEX C shell

/bin/tcsh

Mac OS X 10.3 Solaris 9

bash bash

tcsh tcsh tcsh

, ,
.
Bourne shell Bell Labs
(Steve Bourne).
UNIX, Version 7. Bourne
shell  Algol 68.
C shell
(Bill Joy) BSD. , C shell 
System V/386 Release 3.2 AT&T, System V Release 4 (SVR4).
( UNIX .) 
C shell 6 UNIX,
Bourne shell.
C, ,
, Bourne shell: , 
.
Korn shell Bourne
shell. SVR4. Bell Labs 
(David Korn), UNIX,
SVR4
, 

30

1. UNIX

. Bourne
shell , C shell 
: , 
.
Bourneagain shell GNU,
Linux. 
POSIX Bourne shell,
, C shell Korn shell.
TENEX C shell
C shell. , 
, TENEX, 1972 Bolt
Beranek and Newman. TENEX C shell C shell
.
Linux Bourneagain shell .
/bin/sh /bin/bash. FreeBSD
Mac OS X TENEX C
shell, Bourne shell, 
C shell .
Solaris BSD System V , 
. 1.1.
.

UNIX. 
.


, 
. ,
Bourne shell, Korn shell Bourneagain shell.

1.4.

UNIX
, . ,
(root), 
/.
, 
. ,
,
. , 
( ), , , 
( ), 
. stat fstat , 

1.4.

31

. 4 
.
,
. UNIX
 ,
, . ,
4.


.
(/)
(\0). ,
( ), .

. ( , 

, 
, .)
, ,
: . ( ) .. ( ;).
, 
.  
, .
UNIX System V 
14 . BSD 255 
.
UNIX 255 .


, ,
. 
, ,
. 
. 
(/) , 
.

. 
ls(1).
1.1.
#include "apue.h"
#include <dirent.h>

32

1. UNIX
int
main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
if (argc != 2)
err_quit(": ls _");
if ((dp = opendir(argv[1])) == NULL)
err_sys(" %s", argv[1]);
while ((dirp = readdir(dp)) != NULL)
printf("%s\n", dirp>d_name);
closedir(dp);
exit(0);
}

ls(1) 
UNIX. , 
ls .
1 8,
. ,
UNIX.
, ,
UNIX Programmers Manual ( UNIX).
, 
: ,
.
UNIX ,
. , 
AT&T [1990e] 3S, fopen(3S). 
,
C .

.
,
ls :
man 1 ls

man sl ls

,
. 
myls.c
a.out:
cc myls.c

1.4.

33

cc(1) C. , 
GNU C, gcc(1). 
cc gcc.

:
$ ./a.out /dev
.
..
console
tty
mem
kmem
null
mouse
stdin
stdout
stderr
zero
,
cdrom
$ ./a.out /var/spool/cron
/var/spool/cron: Permission denied
$ ./a.out /dev/tty
/dev/tty: Not a directory


: , , 
, 
. ,
, . 
; 
. 
.
,
. ls .
20 .

apue.h. 
. 

, .
B.
main ISO C. ( 
.)
, argv[1], 
, . 7
, main

34

1. UNIX


.


,
opendir, readdir closedir.

opendir DIR,
readdir. ( 
DIR.) readdir,
. readdir
dirent , . ,
dirent, (d_name).
, stat ( 4.2),
.


: err_sys err_quit. ,
err_sys , (Permis
sion denied ( ) Not a directory ( 
)). 
B. , 
1.7.

exit 0.
exit . 
0 
, 1 255
. 8.5 , ,
, .


, 
. ,
, . 
chdir.
, doc/memo/joe ,
joe memo, doc, 
. 
, , doc memo ,
, joe . /usr/lib/lint
lint lib, 
usr, .


, ;
. 
( 1.3).

1.5.

35

1.5.

, ,
, , 
. , 
, , 
.

, ,


:
,
. , 
,
ls


.
ls > file.list

ls
file.list.


 open, read, write,
lseek close. .

, 
. 
.
1.2.
#include "apue.h"
#define BUFFSIZE 4096
int
main(void)
{
int n;
char buf[BUFFSIZE];
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)

36

1. UNIX
if (write(STDOUT_FILENO, buf, n) != n)
err_sys(" ");
if (n < 0)
err_sys(" ");
exit(0);
}

<unistd.h>, apue.h,
STDIN_FILENO STDOUT_FILENO POSIX (
). 
, , 
UNIX, read write, .
STDIN_FILENO STDOUT_FILENO, <unistd.h>, 
.
0 1, 

.
BUFFSIZE 3.9, ,
.

.
read . 
write , .
read 0 
. , read 
1. 1.

(a.out) :
./a.out > data

data, 
.
, .
, ,
,  ( ControlD).
:
./a.out < infile > outfile

infile outfile.
3  
.

1.5.

37


 
. 
 
, 
BUFFSIZE .
 , 
( 
UNIX). , fgets ,
read .
5.4, 
, .
 
printf. , ,
<stdio.h> (
apue.h),
.

, 1.3, ( 
5.8), , 
read write. ,
, 
.
1.3.
;
#include "apue.h"
int
main(void)
{
int c;
while ((c = getc(stdin)) != EOF)
if (putc(c, stdout) == EOF)
err_sys(" ");
if (ferror(stdin))
err_sys(" ");
exit(0);
}

getc , 
putc. , getc
EOF ( <stdio.h>). stdin
stdout <stdio.h>
.

38

1. UNIX

1.6.

, . 

exec. 8.10.


, , .
.

.
UNIX
, . 
.

1.4 , 
.
1.4.
#include "apue.h"
int
main(void)
{
printf(" %d\n", getpid());
exit(0);
}

a.out , 
:
$ ./a.out
851
$ ./a.out
854


getpid.


: fork, exec wa
itpid. ( exec , 
exec.)

1.6.

39

UNIX 
( 1.5), 
.
. , 
.
fgets.
( ControlD),
fgets , 
. 18 , 
, , 
, , .
, fgets,
, , 
strlen 
. , 
, execlp , 
, .
1.5.
#include "apue.h"
#include <sys/wait.h>
int
main(void)
{
char buf[MAXLINE]; /* apue.h */
pid_t pid;
int
status;
printf("%% ");

/* (printf */
/* %%, %) */
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf)  1] == \n)
buf[strlen(buf)  1] = 0; /* */
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) {
/* */
execlp(buf, buf, (char *)0);
err_ret(" : %s", buf);
exit(127);
}
/* */
if ((pid = waitpid(pid, &status, 0)) < 0)
err_sys(" waitpid");
printf("%% ");

40

1. UNIX
}
exit(0);
}

fork,
. 
, . 
fork , 
0. fork ,
, , 
, .

, ,
execlp. 
. fork exec
, .
UNIX . 
8.

exe
clp, ,
. wait
pid,
pid. waitpid (
status), .
, ,
.

,
. , ,
, 
. ls .
, 
, 
(, )
execlp. 
, 
.

, 
. : % 
,  .
$ ./a.out
% date
Sun Aug 1 03:04:47 EDT
% who
sar :0 Jul 26 22:54
sar pts/0 Jul 26 22:54
sar pts/1 Jul 26 22:54
sar pts/2 Jul 26 22:54

2004

(:0)
(:0)
(:0)

41

1.7.
% pwd
/home/sar/bk/apue/2e
% ls
Makefile
a.out
shell1.c
% D
$

^D . 
, Cont
rol Ctrl ( )
. ControlD, ^D, .
,
 18.



. 
, 
. , 

.
, 
, . 
, 
, .
, 
. 
. , 
, .

. , UNIX 
,
, 12.

1.7.
UNIX
,
errno , 
. , open 
, 1
. errno open 15
, ,
. 

42

1. UNIX

. , , 
 , .
errno 
<errno.h>. 
E. , 
UNIX, intro(2), 
. , errno ,
EACCES, ,
, .
Linux 
errno(3).

POSIX ISO C errno ,


lvalue ( ,
) . ,
, ,
. errno
extern int errno;



errno, . Linux, 
, errno,
:
extern int *__errno_location(void);
#define errno (*__errno_location())

, errno. , er
rno , . 
, , ,
, , . 
, errno 0, 
, <errno.h>, 0.
C .
#include <string.h>
char *strerror(int errnum);

errnum, err
no, .
perror, errno, 
.

1.7.

43

#include <stdio.h>
void perror(const char *msg);

msg, ,
, errno.
.

1.6 .
1.6. strerror perror
#include "apue.h"
#include <errno.h>
int
main(int argc, char *argv[])
{
fprintf(stderr, "EACCES: %s\n", strerror(EACCES));
errno = ENOENT;
perror(argv[0]);
exit(0);
}

a.out,
$ ./a.out
EACCES: Permission denied
./a.out: No such file or directory

: perror
a.out, argv[0]. 
, UNIX. ,
,
prog1 < inputfile | prog2 | prog3 > outputfile

, , , 
.
strerror perror
, 
B.
, 
C.


, <errno.h>,
. 
. , ,

44

1. UNIX


.
.
(, ), 
.
, , EAGAIN,
ENFILE, ENOBUFS, ENOLCK, ENOSPC, ENOSR, EWOULDBLOCK ENOMEM.
EBUSY ,
, . 
EINTR, 
(
10.5).
, , 
. 
. ,
,
. 

, .
,
. 
,
.

1.8.


,
. 

. , 
. , 
.
0 ,
root. root. 
, 
. 4,
, 
. 
. 
.
Mac OS X ,
. 

1.8.

45

 Apple: http://docs.info.ap
ple.com/article.html?artnum=106290.


, ;
. 
. , 
. 
.
, , 
. 4.5 , 
,
.
,
. /etc/group.

.
.
, 
.
, 
.
,
.
, 
,
, 
. , ls l 
,
.
UNIX 16
, 32.

, 1.7, 
.
1.7.
#include "apue.h"
int
main(void)
{
printf("uid = %d, gid = %d\n", getuid(), getgid());
exit(0);
}

46

1. UNIX


getuid getgid. :
$ ./a.out
uid = 205, gid = 105


, , 
UNIX .
4.2BSD,
16 , .
/etc/group 16 , 
, 
. 
, POSIX , 
, 
16 .

1.9.
,
. , ,
SIGFPE (floatingpoint exception
). 
.
1. . , 
(
, 
), .
2. .
.
3. , (
). 
, 
.
. , 
(ControlC DELETE)
( Control\), .
kill.
. 
, : ,
( ).

47

1.9.

1.5.
(ControlC),
, , 
SIGINT, .
, ,
.
, sig
nal, ,
SIGINT. sig_int.
.
11 1.5, , 
1.8 ( +).
1.8.
#include "apue.h"
#include <sys/wait.h>
+ static void sig_int(int); /*  */
+
int
main(void)
{
char buf[MAXLINE];
/* apue.h */
pid_t pid;
int status;
+
+
+

if (signal(SIGINT, sig_int) == SIG_ERR)


err_sys(" signal");
printf("%% ");

/* (printf */
/* %%, */
/* %) */

while (fgets(buf, MAXLINE, stdin) != NULL) {


if (buf[strlen(buf)  1] == \n)
buf[strlen(buf)  1] = 0; /* */
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) {
/* */
execlp(buf, buf, (char *)0);
err_ret(" : %s", buf);
exit(127);
}
/* */
if ((pid = waitpid(pid, &status, 0)) < 0)
err_sys(" waitpid");
printf("%% ");
}

48

1. UNIX
exit(0);
}
+
+
+
+
+
+

void
sig_int(int signo)
{
printf("\n%% ");
}

10 , 
.

1.10.
UNIX 
.
1. . 
, : 00:00:00 1 1970 
(Coordinated Universal Time UTC). (
UTC Greenwich Mean Time
.) , ,
.
2. . 
, .
(ticks).
, 50,
60 100 . 
clock_t. ( 2.5.4 , 
sysconf.)
3.9 ,
UNIX :
(Clock time)
(User CPU time)
(System CPU time)
, , 
, .
, 
. , , 
.
,
. ,
. ,
, , read
write, , ,
.
.

1.11.

49

, : 
() time(1), ,
. :
$ cd /usr/include
$ time p grep _POSIX_SOURCE */*.h > /dev/null
real
user
sys

0m0.81s
0m0.11s
0m0.07s

, 
/usr/bin/time 
, .
8.16 , 
.
6.10.

1.11.

. UNIX 
, 
( 1.1). Research UNIX
System 50 , 4.4BSD 110,
SVR4 120. Linux 240 260 
. FreeBSD 320 .

UNIX. C 
,
. , 
.
UNIX 
C.
C.
,
, . , 

, 
.
C.
3 UNIX 
, . 
, 
. , printf write
, strcpy ( ) atoi (
ASCII ) .

50

1. UNIX


. 
.
,
C. , 
. ,
, 
, .
malloc. 

( , . .).
, 
. sbrk(2), ,
.

, . 
malloc(3) . 
, 
malloc, , , 
sbrk.

sbrk. . 1.2 
, malloc sbrk.
: 
,
malloc .
,
, , UNIX
. 


malloc

sbrk

. 1.2. malloc sbrk

1.11.

51

: , 
. , , 
. UNIX
, ,
0 00 1 1970 
(UTC). 
,
, .
C .
, , ,
.
,
. , ,
.
. 1.3.

,
,
. 
sbrk malloc. 
,
 ( 3)  ( 5).
(fork, exec wait) 
. ( 
1.5.) 
, : 
, system popen. 8.3 
system,
. 10.18 .

. 1.3. C

52

1. UNIX

UNIX, 
, 
, . , , 
sbrk, 
malloc, .

, , , 
.

1.12.
UNIX. 
, 
, 
, , .
UNIX 
. , ISO C POSIX.1,
.

1.1. , . .. 
, .
1.2. , 
1.4, ,
852 853.
1.3. perror 1.7
const ( ISO C), 
strerror . ?
1.4. err_sys ( B) errno 
. ?
1.5. , 32
, ? 
?
?
1.6. , 32
100 . 
?

2
UNIX
2.1.
UNIX
C. 
UNIX, 
UNIX 80 ,
, ,
.
,
,
UNIX,
. 
, 
, 
.

2.2. UNIX
2.2.1. ISO C
1989 ANSI 
C X3.1591989.
ISO/IEC 9899:1990. ANSI
American National Standards Institute ( 
,
International Organization for Standardization, ISO). 
IEC International Electrotechnical Commission (
).
C 
ISO/IEC C, 

54

2. UNIX

ISO/IEC JTC1/SC22/WG14, WG14.


ISO C , , 
C, ,
UNIX. , 
[ISO 1999, 7; Plauger 1992; Kernighan and
Ritchie 1988, B]. ,
UNIX, , 
, C.
1999 ISO C ISO/IEC 9899:1999.
, 
. POSIX,
, restrict 
. ,
, , 
.

, ,
 . 
ISO C.
gcc ISO C 1999 
: http://www.gnu.org/software/gcc/c99status.html.

ISO C 24 , 
, . . 2.1 
, C.
POSIX.1 , , 
. ,
(FreeBSD 5.2.1, Linux 2.4.22,
MAC X 10.3 Solaris 9).
2.1. , ISO C
 FreeBSD Linux MAC OS Sola
5.2.1
2.4.22 X 10.3 ris 9
<assert.h>

<complex.h>

<ctype.h>

<errno.h>

( 1.7)

<fenv.h>

<float.h>

<inttypes.h>

55

2.2. UNIX
 FreeBSD Linux MAC OS Sola
5.2.1
2.4.22 X 10.3 ris 9
<iso646.h>

<limits.h>

( 2.5)

<locale.h>

(
)

<math.h>

<setjmp.h>

( 7.10)

<signal.h>

( 10)

<stdarg.h>

<stdbool.h>

<stddef.h>

<stdint.h>

<stdio.h>


( 5)

<stdlib.h>

<string.h>

<tgmath.h>

<time.h>

( 6.10)

<wchar.h>

<wctype.h>

ISO C C, 
. . 2.1, ,
FreeBSD 5.2.1 gcc 3.3.3, Solaris 9 gcc,
2.95.3 3.2, Mandrake 9.2 (Linux 2.4.22) gcc 3.3.1, MAC OS X 10.3 gcc
3.3. MAC OS X gcc.

2.2.2. IEEE POSIX


POSIX , IEEE (Insti
tute of Electrical and Electronics Engineers 
). POSIX Portable
Operating System Interface ( ).
IEEE 1003.11988
( ), 

1003, (1003.2).

56

2. UNIX


1003.1, 
UNIX. 
,
, POSIX. 
1003.1 UNIX,
UNIX UNIX . 
,
, POSIX,
.
1003.1 , ,

. .
, 1003.1 
. 1988 , IEEE Standard 1003.11988,

(ISO). ,
 
. IEEE Std 1003.11990
[IEEE 1990]. ISO/IEC 9945
1:1990. POSIX.1, 
.
IEEE 1003.1 .
1993 IEEE 1003.1.
1003.11990
1003.1b1993. 1996 
ISO/IEC 99451:1996. 
, pthreads ( POSIX threads, 
POSIX). 1999 IEEE Standard
1003.1d1999 .
IEEE Standard 1003.1j2000, 

. IEEE Standard 1003.1q2000, 
.
1003.1 2001
, 1003.1,
1003.2 Single UNIX Specification (SUS UNIX)
2 ( . ). 
IEEE Standard 1003.12001 :

ISO/IEC 99451 (IEEE Standard 1003.11996),


IEEE Standard 1003.11990
IEEE Standard 1003.1b1993 ( )
IEEE Standard 1003.1c1995 (pthreads)
IEEE Standard 1003.1i1995 ( )

57

2.2. UNIX

IEEE P1003.1a ( 
)
IEEE Standard 1003.1d1999 ( )
IEEE Standard 1003.1j2000 (
)
IEEE Standard 1003.1q2000 ()
IEEE Standard 1003.2d1994 ( )
IEEE P1003.2b ( )
IEEE Standard 1003.1g2000 (
)
ISO/IEC 99452 (IEEE Standard 1003.21993)
Single UNIX Specification 2,

System Interface Definitions, Issue 5 ( 


, 5)
Commands and Utilities, Issue 5 ( , 5)
System Interfaces and Headers, Issue 5 ( 
, 5)
Open Group Technical Standard, Networking Services, Issue 5.2 (
, 5.2)
ISO/IEC 9899:1999, Programming Languages C ( 
C)

. 2.2, 2.3 2.4 


, POSIX.1.
POSIX.1 ISO C,
, . 2.1. 
,
.
2.2. ,
POSIX


FreeBSD Linux MAC OS Sola


5.2.1
2.4.22 X 10.3 ris 9

<dirent.h>

( 4.21)

<fcntl.h>

( 3.14)

<fnmatch.h>

<glob.h>

<grp.h>

<netdb.h>

<pwd.h>

( 6.2)

( 6.4)

58

2. UNIX

2.2 ()


FreeBSD Linux MAC OS Sola


5.2.1
2.4.22 X 10.3 ris 9

<regex.h>

<tar.h>

tar

<termios.h>

 ( 18)

<unistd.h>

<utime.h>


(
4.19)

<wordexp.h>

<arpa/inet.h>

( 16)

<net/if.h>

( 16)

<netinet/in.h>

(
16.3)

<netinet/tcp.h>

TCP

<sys/mman.h>

<sys/select.h>

select ( 14.5.1)

<sys/socket.h>

( 16)

<sys/stat.h>

(
4)

<sys/times.h>

( 8.16)

<sys/types.h>


( 2.8)

<sys/un.h>

UNIX
( 17.3)

<sys/utsname.h>

( 6.9)

<sys/wait.h>

( 8.6)

2.3. XSI,
POSIX
FreeBSD Linux MAC OS Sola

5.2.1
2.4.22 X 10.3 ris 9
<cpio.h>

<dlfcn.h>

<fmtmsg.h>

<ftw.h>

cpio

( 4.21)

59

2.2. UNIX
FreeBSD Linux MAC OS Sola

5.2.1
2.4.22 X 10.3 ris 9
<iconv.h>

<langinfo.h>

<libgen.h>

<monetary.h>

<ndbm.h>

(
dbm)

<nl_types.h>

<poll.h>

poll ( 14.5.2)

<search.h>

<strings.h>

<syslog.h>

(
13.4)

<ucontext.h>

<ulimit.h>

IPC ( 15.6)

( 15.7)

<utmpx.h>
<sys/ipc.h>

<sys/msg.h>

<sys/resource.h>


( 7.11)

<sys/sem.h>

( 15.8)

<sys/shm.h>

( 15.9)

<sys/statvfs.h>

<sys/time.h>

<sys/timeb.h>

<sys/uio.h>


( 14.7)

POSIX.1 2001 ,
, ISO C.
.
, 
50 . 
. 2.5 .

60

2. UNIX

 , 
. 
, 
. 
.
2.4. ,
POSIX


FreeBSD Linux MAC OS Solaris


5.2.1
2.4.22 X 10.3 9

<aio.h>

<mqueue.h>

<pthread.h>

<sched.h>

<semaphore.h>

<spawn.h>

<stropts.h>

( 11 12)

XSI STREAMS
( 14.4)

<trace.h>

2.5. POSIX.1


SUS

ADV

_POSIX_ADVISORY_INFO


( )

AIO

_POSIX_ASYNCHRONOUS_IO

 (
)

BAR

_POSIX_BARRIERS

(
)

CPT

_POSIX_CPUTIME


( 
)

CS

_POSIX_CLOCK_SELECTION

( 
)

CX

FSC

IP6
MF
ML

ISO C
_POSIX_FSYNC

_POSIX_IPV6

IPv6

_POSIX_MAPPED_FILES

_POSIX_MEMLOCK


( )

61

2.2. UNIX


SUS

MLR

_POSIX_MEMLOCK_RANGE

(
)

MON

_POSIX_MONOTONIC_CLOCK

(
)

_POSIX_MEMORY_PROTECTION

_POSIX_MESSAGE_PASSING

(
)

MPR

MSG
MX

,
IEC 60599

PIO

_POSIX_PRIORITIZED_IO

PS

_POSIX_PRIORITIZED_SCHEDULING (
)

RS

_POSIX_RAW_SOCKETS

RTS

_POSIX_REALTIME_SIGNALS

SEM

_POSIX_SEMAPHORES

(
)

SHM

_POSIX_SHARED_MEMORY_OBJECTS
( )

SIO

_POSIX_SYNCHRONIZED_IO


( )

SPI

_POSIX_SPIN_LOCKS

(
)

SPN

_POSIX_SPAWN

( 
)

SS

_POSIX_SPORADIC_SERVER

(
) (
)

TCT

_POSIX_THREAD_CPUTIME


( 
)

TEF

_POSIX_TRACE_EVENT_FILTER

_POSIX_THREADS

TMO

_POSIX_TIMEOUTS

 ( 
)

TMR

_POSIX_TIMERS

(
)

TPI

_POSIX_THREAD_PRIO_INHERIT


( )

THR

62

2. UNIX

2.5 ()

SUS

TPP

_POSIX_THREAD_PRIO_PROTECT

(
)

TPS

_POSIX_THREAD_PRIORITY_SCHE 
DULING
( 
)

TRC

_POSIX_TRACE

( 
)

TRI

_POSIX_TRACE_INHERIT

TRL

_POSIX_TRACE_LOG

TSA

_POSIX_THREAD_ATTR_STACKADDR

TSF

_POSIX_THREAD_SAFE_FUNCTIONS ,

TSH

_POSIX_THREAD_PROCESS_SHARED , 

TSP

TSS

_POSIX_THREAD_SPORADIC_SERVER (
) ( 
)

TYM
XSI
XSR

_POSIX_THREAD_ATTR_STACKSIZE
_POSIX_TYPED_MEMORY_OBJECTS

(
)

_XOPEN_UNIX

X/Open

_XOPEN_STREAMS

XSI STREAMS

POSIX.1 . 
, ,
POSIX.1 
. UNIX, 
, 
. 
.
, 
. PO
SIX.1 , Austin
Group (http://www.opengroup.org/austin). 
, .

2.2. UNIX

63

2.2.3. Single UNIX Specification


Single Unix Specification ( UNIX)
POSIX.1 
, 
POSIX.1. 
X/Open System Interface (XSI). POSIX.1, 
XSI, 
_XOPEN_UNIX.
XSI POSIX.1, 
,
XSI. , 
, , . 2.5
SUS. XSI 
UNIX.
UNIX The Open Group, 
UNIX , 
, UNIX.
UNIX, 
.

, XSI,
, .

:

: _XOPEN_CRYPT

:
_XOPEN_REALTIME


: _XO
PEN_REALTIME_THREADS

XSI STREAMS: _XOPEN_STREAMS

: 
_XOPEN_LEGACY

UNIX (SUS) The Open Group, 


1996 X/Open Open Software Foundation
(OSF). X/Open X/Open Portability Guide (
X/Open ), 
, 
. 
,
.

64

2. UNIX

Single UNIX Specification X/Open 1994 .


Spec 1170,
1170 . Common Open
Software Environment (COSE ),
, 
UNIX. COSE Sun, IBM,
HP, Novell/USL OSF
. , 
. 1170
, , X/Open Common Application Environ
ment, Issue 4 (CAE , XPG4,
X/Open
Portability Guide), System V Interface Definition, Issue 3 (SVID
System V) OSF Application Environment Specification (AES
).
Single UNIX Specification The Open Group
1997 . , 
, 64 ,
.
Single UNIX Specification ( SUSv3) 
The Open Group 2001 . SUSv3 ,
IEEE Standard 1003.12001, 
: , , 
. SUSv3 X/Open
Curses Issue 4, Version 2, POSIX.1.
2002 
ISO/IEC 9945:2002. 2003 The Open
Group 1003.1, 
, ISO ISO/IEC 9945:2003. 
2004 The Open Group Single UNIX Specification, Ver
sion 3, 2004 Edition. 
.

2.2.4. FIPS
FIPS Federal Information Processing Standard (
).
,
. FIPS 1511 ( 1989 ) IEEE Std.
1003.11988 ANSI C. FIPS 1512
( 1993 ) IEEE Standard 1003.11990. FIPS 1512
, POSIX.1 
. PO
SIX.12001.
, POSIX.1
,

2.3. UNIX

65

POSIX.1. 
POSIX.1 FIPS , 
.

2.3. UNIX
ISO C, IEEE POSIX Single UNIX
Specification , .
. 
? 
. ,
.
1.1 [McKusick et al. 1996] ( 
) UNIX. 6
(1976) 7 (1979) UNIX TimeSharing System PDP11 (
Version 6 Version 7). , 
Bell Laboratories.
UNIX:
1. AT&T; System III System V ( 
UNIX).
2. ;
4.xBSD.
3. UNIX, 
(Comput
ing Science Research Center) AT&T Bell Laboratories 
UNIX TimeShared System 8 9 
10 1990 .

2.3.1. UNIX System V Release 4


UNIX System V Release 4 (SVR4)
AT&T UNIX System Laboratories (USL, UNIX Software Operation).
SVR4 AT&T UNIX System Release 3.2
(SVR3.2), SunOS Sun Microsystems, 4.3BSD, 
, Xenix 
Microsoft . (
Xenix 7
, System V.) SVR4 
1989 , 
1990 . SVR4 POSIX
1003.1, X/Open Portability Guide, Issue 3 (XPG3).
AT&T System V Interface Definition
(SVID, System V) [AT&T 1989]. 3 SVID 
, 
, 

66

2. UNIX

, System V Release 4. POSIX.1, SVID


, . SVID 
. 
, 
SVR4 [AT&T 1990e].

2.3.2. 4.4BSD
Berkeley Software Distribution (BSD) 
Computer Systems Research Group (CSRG) 
.
4.2BSD 1983, 4.3BSD 1986 . 
VAX. , 4.3BSD Tahoe, 
1988
Tahoe. ( (Leffler) . [1989]
4.3BSD Tahoe.) 1990 4.3BSD Reno,
, 
POSIX.1.
BSD ,
AT&T, AT&T. 
BSD, AT&T UNIX. 
,
AT&T 
; , 
, .
1989 4.3BSD Tahoe ,
AT&T, 
BSD Networking Software, Release 1.0. , 1991 ,
BSD Networking Software (Release 2.0), 
4.3BSD Reno. ,
4.4BSD 
AT&T, .
4.4BSDLite CSRG. 
 USL.
1994 ,
4.4BSDLite, , ,
,  
UNIX. , 1995 , CSRG , 
. 4.4BSDLite 
BSD CSRG. ( BSD  [1996].)
UNIX PDP11, 
VAX
. 90 
,
80386, 386BSD. 
(Bill Jolitz)

2.3. UNIX

67

Dr. Dobbs Journal 1991 .


BSD Networking Software, Release 2.0.

2.3.3. FreeBSD
FreeBSD 4.4BSDLite. FreeBSD
BSD ,
BSD
UNIX, 386BSD .
, FreeBSD, 
, ,
. FreeBSD 5.2.1 
, .
, BSD. 
NetBSD (http://www.netbsd.org) FreeBSD,
. 
OpenBSD (http://www.openbsd.org) FreeBSD, 
.

2.3.4. Linux
Linux , 
UNIX
GNU (GNU Public License). Linux
. Linux 
, 
.
Linux (Linus Torvalds) 1991
MINIX. , 

.
Linux Mandrake 9.2 , 
.
Linux 2.4.22.

2.3.5. Mac OS X
Mac OS X , 
.
Darwin Mach ([Accetta et
al. 1986]) FreeBSD. Darwin 
, FreeBSD Linux.
Mac OS X 10.3 (Darwin 7.4.0)
.

68

2. UNIX

2.3.6. Solaris
Solaris UNIX, Sun Microsystems. 
System V Release 4, Sun
Microsystems 10 . 
SVR4, UNIX.
( UNIX
http://www.opengroup.org/certification/idx/unix.html.)
Solaris 9
.

2.3.7. UNIX
,
UNIX, :
AIX, UNIX IBM
HPUX, UNIX HewlettPackard
IRIX, UNIX, Silicon Graphics
UnixWare, UNIX, SVR4 
SCO

2.4.

. 
: FreeBSD 5.2.1, Linux 2.4.22, Mac OS X 10.3
Solaris 9. , Solaris UNIX
, , UNIX.
POSIX
, ,
POSIX.1,
POSIX
. , 
, . SUSv3 
POSIX.1, ,
SUSv3, POSIX.1.
, 
,
SVR3.2 4.3BSD. , Solaris 
 (O_NONBLOCK) POSIX.1,
System V (O_NDELAY). 
, POSIX.1,
, 
. , SVR3.2, 4.3BSD
,
POSIX.1. 10 POSIX.1.

2.5.

69

2.5.
.
, 
.
, 
,
.
:
1. (, ,
short int).
2. (,
).
,
. 
, , 
.
, 

. ,

.
. System V SVR4 
14 , BSD
255 . UNIX 
,
,
, 
. ,
14 ,
255 .
:
1. ( ).
2. ,
( sysconf).
3. ,
( pathconf fpathconf).
, 
, 
. 
, conf (
), .

70

2. UNIX

2.5.1. ISO C
, ISO C,
. . 2.6 , 
C <limits.h>. 
. 
, ISO C.
16 
(onescomplement). 
Linux, 32 
(twoscomplement).
, 
, 0. 64
long 
long long.
2.6. <limits.h>

CHAR_BIT

CHAR_MAX


char

(. )

127

CHAR_MIN


char

(. )

128

SCHAR_MAX 
signed
char

127

127

SCHAR_MIN 
signed
char

127

128

UCHAR_MAX 

un
signed char

255

255

INT_MAX


int

32 767

2 147 483 647

INT_MIN


int

32 767

2 147 483 648

UINT_MAX


unsigned
int

65 535

4 294 967 295

SHRT_MAX


short

32 767

32 767

SHRT_MIN


short

32 767

32 768

71

2.5.

USHRT_MAX 
unsig
ned short

65 535

65 535

LONG_MAX


long

2 147 483 647

2 147 483 647

LONG_MIN


long

2 147 483 647

2 147 483 648

ULONG_MAX 
unsig
ned long

4 294 967 295

4 294 967 295

LLONG_MAX  9 223 372 036 854 775 807 9 223 372 036 854 775 807
long long
LLONG_MIN  9 223 372 036 854 775 807 9 223 372 036 854 775 808
long long
ULLONG_MAX  18 446 744 073 709 551 615 18 446 744 073 709 551 615
unsig
ned long long
MB_LEN_MAX 



16

, , ,
char . 
. 2.6 , char
. CHAR_MIN SCHAR_MIN, CHAR_MAX 
SCHAR_MAX. char 
, , CHAR_MIN 0, CHAR_MAX UCHAR_MAX.

<float.h> . ,
, 
.
ISO C, , FOPEN_MAX.

, .
<stdio.h>
8. POSIX.1 STREAM_MAX,
, .
<stdio.h> ISO C TMP_MAX. 
, 
tmpnam. 5.13.

72

2. UNIX

. 2.7 FOPEN_MAX TMP_MAX 


, .
2.7. , ISO

FreeBSD 5.2.1

Linux 2.4.22

Mac OS X 10.3

Solaris 9

FOPEN_MAX

20

16

20

20

TMP_MAX

308 915 776

238 328

308 915 776

17 576

ISO C FILENAME_MAX, 
,
.

2.5.2. POSIX
POSIX.1 , 
. , 
POSIX.1. POSIX.1
,
, POSIX.1. 
:
1. : 19 ,
. 2.8.
2. SSIZE_MAX.
3. , : CHAR
CLASS_NAME_MAX, COLL_WEIGHTS_MAX, LINE_MAX, NGROUPS_MAX RE_DUP_MAX.
4. , , 
: ARG_MAX, CHILD_MAX, HOST_NAME_MAX, LOGIN_NAME_MAX, OPEN_MAX, PAGESIZE,
RE_DUP_MAX, STREAM_MAX, SYMLOOP_MAX, TTY_NAME_MAX TZNAME_MAX.
5. , , 
: FILESIZEBITS, LINK_MAX, MAX_CANON, MAX_INPUT, NAME_MAX, PATH_MAX,
PIPE_BUF, SYMLINK_MAX.
44
<limits.h>, 
. ,
, 2.5.4, 
sysconf, pathconf fpathconf.
. 2.8.

. , 
. , 
POSIX,
. ,
MAX. ,
, , ,

73

2.5.

.
, .
2.8. <limits.h>,
POSIX.1

_POSIX_ARG_MAX

exec

4 096

_POSIX_CHILD_MAX

25

_POSIX_HOST_NAME_MAX ,
gethostname
_POSIX_LINK_MAX

_POSIX_LOGIN_NAME_MAX

255
8
9

_POSIX_MAX_CANON

255

_POSIX_MAX_INPUT

255

_POSIX_NAME_MAX

14

_POSIX_NGROUPS_MAX

_POSIX_OPEN_MAX

20

_POSIX_PATH_MAX

256

_POSIX_PIPE_BUF

512

_POSIX_RE_DUP_MAX


,
regexec regcomp,
\{m,n\}

255

_POSIX_SSIZE_MAX

,
ssize_t

32 767

_POSIX_STREAM_MAX

_POSIX_SYMLINK_MAX

255

_POSIX_SYMLOOP_MAX

_POSIX_TTY_NAME_MAX

_POSIX_TZNAME_MAX

74

2. UNIX

, POSIX, POSIX
. , 
IEEE Standard 1003.12001. , ,
POSIX ,
, 
, , . 2.8.

,
, . , 
UNIX
20 . 255 _POSIX
_PATH_MAX . 
, , _POSIX_OP
EN_MAX _POSIX_PATH_MAX .
19 ,
. 2.8, , ,
_POSIX_. _POSIX_
, 
. ( 19 ,
, 25 , : 
, , 
, ,
, .)
, 19 , ,
<limits.h>.
, 
, 
. 
,
. POSIX.1 sys
conf, pathconf fpathconf,
. 
: POSIX.1
(, ). , 
. Linux, ,
iovec, readv writev, 
. IOV_MAX Linux
. 2.5.5.

2.5.3. XSI
XSI ,
. :
1. : ,
. 2.9.
2. : LONG_BIT WORD_BIT.

75

2.5.

3. , , 
: ATEXIT_MAX, IOV_MAX PAGE_SIZE.
. 2.9.
. 
, , 
POSIX.1, (, , 
POSIX 
), Single UNIX Specification 
XSI
.
2.9. <limits.h>,
XSI

NL_ARGMAX

 9
printf scanf

NL_LANGMAX

 14
LANG

14

NL_MSGMAX

32 767

NL_NMAX




NL_SETMAX

255

255

NL_TEXTMAX

_POSIX2_LINE_MAX

2 048

NZERO

20

20

_XOPEN_IOV
_MAX

iovec, 16

readv writev

16

32 767

_XOPEN_NAME  255
_MAX

255

_XOPEN_PATH  1 024
_MAX

1 024

2.5.4. sysconf, pathconf fpathconf


, 
, ,
? , 
,
. ,
, ,
, . 
.

76

2. UNIX

#include <unistd.h>
long sysconf(int name);
long pathconf(const char *pathname, int name);
long fpathconf(int filedes, int name);

, 1 (. )

,
, 
.
. 2.10 name, 
sysconf .
, _SC_.
. 2.11 name pathconf
fpathconf.
, _PC_.
2.10. name sysconf

ARG_MAX

 _SC_ARG_MAX
exec ( )

A name

ATEXIT_MAX

, _SC_ATEXIT_MAX

atexit

CHILD_MAX

_SC_CHILD_MAX

 _SC_CLK_TCK


COLL_WEIGHTS_MAX  _SC_COLL_WEIGHTS_MAX
LC_COLLATE

HOST_NAME_MAX

,  _SC_HOST_NAME_MAX
gethostname

IOV_MAX

iovec,  _SC_IOV_MAX
readv writev

LINE_MAX

,  _SC_LINE_MAX

LOGIN_NAME_MAX

_SC_LOGIN_NAME_MAX

NGROUPS_MAX

_SC_NGROUPS_MAX

77

2.5.

A name

OPEN_MAX

_SC_OPEN_MAX

PAGESIZE

_SC_PAGESIZE

PAGE_SIZE

_SC_PAGE_SIZE

RE_DUP_MAX

_SC_RE_DUP_MAX

, regexec
regcomp,
\{m, n\}

STREAM_MAX

 _SC_STREAM_MAX
 
; , 
, FOPEN_MAX

SYMLOOP_MAX

 _SC_SYMLOOP_MAX
,

TTY_NAME_MAX

_SC_TTY_NAME_MAX
,

TZNAME_MAX

_SC_TZNAME_MAX

2.11. name
pathconf fpathconf

A name

FILESIZEBITS

,

, ,

_PC_FILESIZEBITS

LINK_MAX

_PC_LINK_MAX

MAX_CANON

_PC_MAX_CANON

MAX_INPUT

_PC_MAX_INPUT

NAME_MAX


( )

_PC_NAME_MAX

PATH_MAX

, _PC_PATH_MAX

PIPE_BUF

, _PC_PIPE_BUF

SYMLINK_MAX

_PC_SYMLINK_MAX

78

2. UNIX

,
.
1. 1 EINVAL 
errno, name .
. 2.10 . 2.11 ,
.
2.
(0),
1, errno .
3. _SC_CLK_TCK 
; 
, times ( 8.16).
, pathname
pathconf fileldes fpathconf. 
, 
.
1. , _PC_MAX_CANON _PC_MAX_INPUT, 
.
2. , _PC_LINK_MAX,
, . , 
, , 
.
3. , _PC_FILESIZEBITS _PC_NAME_MAX,
.
.
4. , _PC_PATH_MAX, 
. 
, .
( ,
, .
2.5.5.)
5. , _PC_PIPE_BUF, 
, .
. 

, .
6. , _PC_SYMLINK_MAX, 
. ,
.

2.5.

79

awk(1), 2.1, 
C, 
pathconf sysconf.
2.1. C,

BEGIN {
printf("#include \"apue.h\"\n")
printf("#include <errno.h>\n")
printf("#include <limits.h>\n")
printf("\n")
printf("static void pr_sysconf(char *, int);\n")
printf("static void pr_pathconf(char *, char *, int);\n")
printf("\n")
printf("int\n")
printf("main(int argc, char *argv[])\n")
printf("{\n")
printf("\tif (argc != 2)\n")
printf("\t\terr_quit(\": a.out <>\");\n\n")
FS="\t+"
while (getline <"sysconf.sym" > 0) {
printf("#ifdef %s\n", $1)
printf("\tprintf(\"%s %%d\\n\", %s+0);\n", $1, $1)
printf("#else\n")
printf("\tprintf(\" %s \\n\");\n", $1)
printf("#endif\n")
printf("#ifdef %s\n", $2)
printf("\tpr_sysconf(\"%s =\", %s);\n", $1, $2)
printf("#else\n")
printf("\tprintf(\" %s \\n\");\n", $2)
printf("#endif\n")
}
close("sysconf.sym")
while (getline <"pathconf.sym" > 0) {
printf("#ifdef %s\n", $1)
printf("\tprintf(\"%s %%d\\n\", %s+0);\n", $1, $1)
printf("#else\n")
printf("\tprintf(\" %s \\n\");\n", $1)
printf("#endif\n")
printf("#ifdef %s\n", $2)
printf("\tpr_pathconf(\"%s =\", argv[1], %s);\n", $1, $2)
printf("#else\n")
printf("\tprintf(\" %s \\n\");\n", $2)
printf("#endif\n")
}
close("pathconf.sym")
exit
}
END {

80

2. UNIX
printf("\texit(0);\n")
printf("}\n\n")
printf("static void\n")
printf("pr_sysconf(char *mesg, int name)\n")
printf("{\n")
printf("\tlong val;\n\n")
printf("\tfputs(mesg, stdout);\n")
printf("\terrno = 0;\n")
printf("\tif ((val = sysconf(name)) < 0) {\n")
printf("\t\tif (errno != 0) {\n")
printf("\t\t\tif (errno == EINVAL)\n")
printf("\t\t\t\tfputs(\" ( )\\n\", stdout);\n")
printf("\t\t\telse\n")
printf("\t\t\t\terr_sys(\" sysconf\");\n")
printf("\t\t} else {\n")
printf("\t\t\tfputs(\" ( )\\n\", stdout);\n")
printf("\t\t}\n")
printf("\t} else {\n")
printf("\t\tprintf(\" %%ld\\n\", val);\n")
printf("\t}\n")
printf("}\n\n")
printf("static void\n")
printf("pr_pathconf(char *mesg, char *path, int name)\n")
printf("{\n")
printf("\tlong val;\n")
printf("\n")
printf("\tfputs(mesg, stdout);\n")
printf("\terrno = 0;\n")
printf("\tif ((val = pathconf(path, name)) < 0) {\n")
printf("\t\tif (errno != 0) {\n")
printf("\t\t\tif (errno == EINVAL)\n")
printf("\t\t\t\tfputs(\" ( )\\n\", stdout);\n")
printf("\t\t\telse\n")
printf("\t\t\t\terr_sys(\" pathconf, path = %%s\", path);\n")
printf("\t\t} else {\n")
printf("\t\t\tfputs(\" ( )\\n\", stdout);\n")
printf("\t\t}\n")
printf("\t} else {\n")
printf("\t\tprintf(\" %%ld\\n\", val);\n")
printf("\t}\n")
printf("}\n")
}

awk pathconf.sym sys


conf.sym, , 
.
, awk
pathconf sysconf #ifdef.
, awk ,
:
NAME_MAX

_PC_NAME_MAX

2.5.

81

C:
#ifdef NAME_MAX
printf("NAME_MAX %d\n", NAME_MAX+0);
#else
printf(" NAME_MAX \n");
#endif
#ifdef _PC_NAME_MAX
pr_pathconf("NAME_MAX =", argv[1], _PC_NAME_MAX);
#else
printf(" _PC_NAME_MAX \n");
#endif

, 2.2, 
. , 
, .
2.2. sysconf pathconf
#include "apue.h"
#include <errno.h>
#include <limits.h>
static void pr_sysconf(char *, int);
static void pr_pathconf(char *, char *, int);
int
main(int argc, char *argv[])
{
if (argc != 2)
err_quit(": a.out <>");
#ifdef ARG_MAX
printf("ARG_MAX %d\n", ARG_MAX+0);
#else
printf(" ARG_MAX \n");
#endif
#ifdef _SC_ARG_MAX
pr_sysconf("ARG_MAX =", _SC_ARG_MAX);
#else
printf(" _SC_ARG_MAX \n");
#endif
/* */
/* sysconf... */
#ifdef MAX_CANON
printf("MAX_CANON %d\n", MAX_CANON+0);
#else
printf(" MAX_CANON \n");
#endif
#ifdef _PC_MAX_CANON
pr_pathconf("MAX_CANON =", argv[1], _PC_MAX_CANON);
#else
printf(" _PC_MAX_CANON \n");
#endif
/* */

82

2. UNIX
/* pathconf... */
exit(0);
}
static void
pr_sysconf(char *mesg, int name)
{
long val;
fputs(mesg, stdout);
errno = 0;
if ((val = sysconf(name)) < 0) {
if (errno != 0) {
if (errno == EINVAL)
fputs(" ( )\n", stdout);
else
err_sys(" sysconf");
} else {
fputs(" ( )\n", stdout);
}
} else {
printf(" %ld\n", val);
}
}
static void
pr_pathconf(char *mesg, char *path, int name)
{
long val;
fputs(mesg, stdout);
errno = 0;
if ((val = pathconf(path, name)) < 0) {
if (errno != 0) {
if (errno == EINVAL)
fputs(" ( )\n", stdout);
else
err_sys(" pathconf, path = %s", path);
} else {
fputs(" ( )\n", stdout);
}
} else {
printf(" %ld\n", val);
}
}

. 2.12 ,
2.2, , .
, 
_SC _PC,
. 
. 
, ,

83

2.5.

pathconf sysconf. ,
, , .
2.12.

FreeBSD
5.2.1

Linux
2.4.22

Mac OS X
10.3

Solaris 9

UFS PCFS

ARG_MAX

65 536

131 072

262 144

1 048,320

ATEXIT_MAX

32

2 147 483 647   

CHARCLASS_NAME  2 048
_MAX

1 048 320

 14

14

867

999

100

7 877

7 877

128


100

100

100

100

255

10

10

CHILD_MAX

COLL_WEIGHTS
_MAX

FILESIZEBITS

 64

HOST_NAME_MAX

255

   

IOV_MAX

1 024

 16

16

LINE_MAX

2 048

2 048

2 048

2 048

2 048

LINK_MAX

32 768

32 000

32 768

32 768

256

 9

LOGIN_NAME_MAX 17

 41

MAX_CANON

255

255

255

256

256

MAX_INPUT

255

255

255

512

512

NAME_MAX

255

255

765

255

NGROUPS_MAX

16

32

16

16

16

OPEN_MAX

1 735

1 024

256

256

256

PAGESIZE

4 096

4 096

4 096

8 192

8 192

PAGE_SIZE

4 096

4 096

 8 192

8 192

PATH_MAX

1 024

4 096

1 024

1 024

1 024

PIPE_BUF

512

4 096

512

5 120

5 120

RE_DUP_MAX

255

32 767

255

255

255

84

2. UNIX

2.12 ()

FreeBSD
5.2.1

Linux
2.4.22

Mac OS X
10.3

Solaris 9

UFS PCFS

STREAM_MAX

1 735

16

20

256

SYMLINK_MAX

 

  

SYMLOOP_MAX

32

  

TTY_NAME_MAX

255

32

 128

TZNAME_MAX

255

255

256

128

 

4.14 , UFS Berkeley fast file system


SVR4, PCFS MSDOS FAT So
laris.

2.5.5.
, . 
, , <lim
its.h>, . , ,
!
: 
.



. ;
(
), 256, 512, 1024
BUFSIZ. 4.3BSD MAXPATHLEN,
<sys/param.h>, ,
, 4.3BSD, .
POSIX.1 PATH_MAX,
. 2.3
, 
, .
PATH_MAX <limits.h>,
. , pathconf. , 
, 
, 
. ,

2.5.

85

.
pathconf , PATH_MAX ,
.
, SUSv3, ,
PATH_MAX . 

, 
.

, .
getcwd, ,
( 4.22), ,
, errno
ERANGE. , 
, realloc ( 7.8 4.16),
. 
, getcwd .
2.3.
#include "apue.h"
#include <errno.h>
#include <limits.h>
#ifdef PATH_MAX
static int pathmax = PATH_MAX;
#else
static int pathmax = 0;
#endif
#define SUSV3 200112L
static long posix_version = 0;
/* PATH_MAX , , */
/* */
#define PATH_MAX_GUESS 1024
char *
path_alloc(int *sizep) /* , */
/* */
{
char *ptr;
int size;
if (posix_version == 0)
posix_version = sysconf(_SC_VERSION);
if (pathmax == 0) { /* */
errno = 0;
if ((pathmax = pathconf("/", _PC_PATH_MAX)) < 0) {
if (errno == 0)

86

2. UNIX
pathmax = PATH_MAX_GUESS; /* */
else
err_sys(" pathconf _PC_PATH_MAX");
} else {
pathmax++;
/* 1, .. */
}
}
if (posix_version < SUSV3)
size = pathmax + 1;
else
size = pathmax;
if ((ptr = malloc(size)) == NULL)
err_sys(" malloc");
if (sizep != NULL)
*sizep = size;
return(ptr);
}


, , , 
, 
. 
, ,
<sys/param.h> NOFILE:
#include <sys/param.h>
for (i = 0; i < NOFILE; i++)
close(i);

_NFILE,
<stdio.h> .
20.
OPEN_MAX,
POSIX.1, ,
, . ,
OPEN_MAX 
, sysconf 1:
#include <unistd.h>
for (i = 0; i < sysconf(_SC_OPEN_MAX); i++)
close(i);

, , 
, 256.
,
, , . 
2.4.

2.5.

87

2.4.
#include "apue.h"
#include <errno.h>
#include <limits.h>
#ifdef OPEN_MAX
static long openmax = OPEN_MAX;
#else
static long openmax = 0;
#endif
/*
* OPEN_MAX ,
* .
*/
#define OPEN_MAX_GUESS 256
long
open_max(void)
{
if (openmax == 0) { /* */
errno = 0;
if ((openmax = sysconf(_SC_OPEN_MAX)) < 0) {
if (errno == 0)
openmax = OPEN_MAX_GUESS; /* */
else
err_sys(" sysconf _SC_OPEN_MAX");
}
}
return(openmax);
}

close , 
, , EBADF,
close, , 
.
, , 10 
, 9 , 
9 10 . , 
dup ( 3.12) ,
OPEN_MAX, 
.
LONG_MAX ,
.
ATEXIT_MAX Linux (. 2.12).
, 
.
, ulimit, 
Bourneagain shell, ,

88

2. UNIX

. ,
, 
.
, sysconf
LONG_MAX OPEN_MAX. , 
, 2.4, 
2 147 483 647 
, .
, XSI Single UNIX
Specification, getrlimit(2) ( 7.11).

. , 
, .
OPEN_MAX POSIX 
. , 
. ,
XSI, setrlimit(2) ( 7.11).
( limit 
C shell ulimit Bourne, Bourneagain Korn
shell.) ,
, 2.4, , sysconf
, .

2.6.
, 
POSIX.1, . 2.5 XSI 
2.2.3. ,
, 
, .
(. 2.5), Single UNIX Specification
:
1. , <unistd.h>.
2. , 
sysconf.
3. , ,
pathconf
fpathconf.

. 2.5, ,
. 2.13 2.14. ,
sysconf, pathconf fpathconf, , 
. 
name ,
_POSIX _SC _PC. , _XOPEN,

89

2.6.

name , 
_SC _PC. , _POSIX_THREADS
. , , 
POSIX, sysconf, 
name _SC_THREADS. , _XOPEN_UNIX
, , 
XSI, sysconf,
name _SC_XOPEN_UNIX.
, 
:
1. 1, ,
.
2. , ,
.
3. , ,
sysconf, pathconf fpathconf, 
, .
. 2.13
, sysconf,
. 2.5.
2.13.
sysconf

_POSIX_JOB_CONTROL ,

name
_SC_JOB_CONTROL

_POSIX_READER_
WRITER_LOCKS

,


_POSIX_SAVED_IDS

,  _SC_SAVED_IDS

_POSIX_SHELL

,
POSIX

_SC_SHELL

_POSIX_VERSION

POSIX.1

_SC_VERSION

_XOPEN_CRYPT

,
XSI

_SC_XOPEN_CRYPT

_XOPEN_LEGACY

,
XSI,

_SC_XOPEN_LEGACY

_XOPEN_REALTIME

,
XSI

_SC_XOPEN_REALTIME

_XOPEN_REALTIME_
THREADS

,  _SC_XOPEN_REALTIME
XSI _THREADS

_XOPEN_VERSION

XSI

_SC_READER_WRITER
_LOCKS

_SC_XOPEN_VERSION

90

2. UNIX

. 2.14 , 
pathconf fpathconf.
, , 
.
2.14.
pathconf fpathconf

name

_POSIX_CHOWN
_RESTRICTED

, _PC_CHOWN_RESTRICTED
chown

_POSIX_NO_TRUNC

,  _PC_NO_TRUNC
NAME_MAX

_POSIX_VDISABLE

,  _PC_VDISABLE

_POSIX_ASYNC_IO

,  _PC_ASYNC_IO


_POSIX_PRIO_IO

, _PC_PRIO_IO


_POSIX_SYNC_IO

, _PC_SYNC_IO
 

1. _SC_VERSION ( ) (
) .
198808L, 199009L, 199506L . ,
3 Single UNIX Specification 200112L.
2. _SC_XOPEN_VERSION XSI, 
. Single UNIX Specification 
600.
3. _SC_JOB_CONTROL, _SC_SAVED_IDS _PC_VDISABLE 
,
3 Single UNIX Specification 
, 
.
4. _PC_CHOWN_RESTRICTED _PC_NO_TRUNC 
1 errno, 
pathname filedes.
5. , _PC_CHOWN_RESTRICTED,
, . , 
.
6. , _PC_NO_TRUNC, 
. 
.

91

2.6.

7. , _PC_VDISABLE,
.
. 2.15 
, .
, 
Single UNIX Specification. , , Mac OS X 10.3 
POSIX,
#define _POSIX_THREADS

. Single UNIX
Specification 3
1, 0 200112.
2.15.
FreeBSD
5.2.1

Linux
2.4.22

Mac OS X
10.3

Solaris 9

UFS PCFS

_POSIX_JOB_CONTROL 1

_POSIX_NO_TRUNC

_POSIX_SAVED_IDS

_POSIX_THREADS

200112

200112

_POSIX_VDISABLE

255

255

_POSIX_VERSION

200112

200112

198808

199506

199506

_XOPEN_UNIX

_XOPEN_VERSION

500

_POSIX_CHOWN_
RESTRICTED

, ,
,

_PC _SC. , , 
,  ,
_POSIX_THREADS. ,
1
0, sysconf pathconf 1.
, pathconf Solaris 9
1 _PC_NO_TRUNC,
, PCFS. 

92

2. UNIX

DOS ( )
8.3, DOS.

2.7.

POSIX.1 XSI 
.
, 
POSIX.1 XSI. 
, POSIX
, , 
_POSIX_C_SOURCE. 
POSIX.1
.
POSIX.1 _POSIX_SOURCE. 
_POSIX_C_SOURCE POSIX.1 2001 .

_POSIX_C_SOURCE _POSIX_SOURCE
.
. 
cc,
cc D_POSIX_C_SOURCE=200112 file.c

, 
C  . 
POSIX.1, 

:
#define _POSIX_C_SOURCE 200112

, 
3 Single UNIX Specification, 
_XOPEN_SOURCE 600. ,
_POSIX_C_SOURCE 200112L, 
, POSIX.1.
Single UNIX Specification c99 
C.
:
c99 D_XOPEN_SOURCE=600 file.c o file

gcc 1999 ISO C,


std=c99, :
gcc D_XOPEN_SOURCE=600 std=c99 file.c o file

, __STDC__, 
C, ISO C.

2.8.

93

,
ISO C, ,
. , 
ISO C, ,
:
#ifdef _ _STDC_ _
void *myfunc(const char *, int);
#else
void *myfunc();
#endif

C 
ISO C,
__STDC__.

2.8.
C
UNIX. , 
16 , 8 
8 .

256 , 
. (, Solaris 32 
14 18
.)
<sys/types.h>
,
. , 
. type
def. _t. . 2.16
, 
.
2.16.

caddr_t

( 14.9)

clock_t

( ) ( 1.10)

comp_t

( 8.14)

dev_t

( ) ( 4.23)

fd_set

( 14.5.1)

fpos_t

( 5.10)

gid_t

94

2. UNIX

2.16 ()

ino_t

(inode) ( 4.14)

mode_t

, ( 4.5)

nlink_t

( 4.14)

off_t

( ) (lseek, 3.6)

pid_t


( ) ( 8.2 9.4)

ptrdiff_t

( )

rlim_t

( 7.11)

sig_atomic_t ,
( 10.15)
sigset_t

( 10.11)

size_t

(, ) ( ) ( 3.7)

ssize_t

,
( ) (read, write, 3.7)

time_t

( 1.10)

uid_t

wchar_t

, 

, . ,
, .

2.9.
, 
. 
ISO C POSIX.1, SUSv3
POSIX.1. .
ISO C clock,
, . 
clock_t. ,
CLOCKS_PER_SEC, 
<time.h>. POSIX.1 times, 
(
, ), .
clock_t. sysconf 

clock_t . , 

2.10.

95

ISO C
POSIX.1 . ,
(clock_t) . 
Solaris, clock
(, CLOCKS_PER_SEC
1 000 000), sysconf 100 (
).
, ISO C
, , POSIX.1.
, , , 
POSIX ( ), ISO C (
). 
POSIX
ISO C .
signal. signal
Solaris ( ,
ISO C UNIX), , 
, sigaction,
POSIX.1. signal 10.

2.10.
UNIX
.
ISO C, POSIX Single UNIX Specification 
UNIX, : FreeBSD, Linux, Mac OS X So
laris.
, , 
, .
.

2.1. 2.8, 
.
, , FreeBSD 5.2.1 size_t 26
. 26 , 
ISO C
, , .
2.2. 
,
.
2.3. 2.4 , 
, sysconf LONG_MAX
OPEN_MAX.

3

3.1.
UNIX ,
, , . . 
 UNIX 
: open, read, write, lseek close. 
,
read write.
, ,
; 
, 5. ;
, 
.  
ISO C, POSIX.1
Single UNIX Specification.
, 
,
. 
 open. 
,
. 
dup, fcntl, sync, fsync ioctl.

3.2.
. 
. 
, 
. ,

3.3. open

97

read write ,
open creat.
UNIX 
0 
, 1 2
.
, 
UNIX. ,
.
POSIX 0, 1 2
STDIN_FILENO, STDOUT_FILENO STDERR_FILENO.
<unistd.h>.
0 OPEN_MAX.
( . 2.10.) UNIX 
19, 
20 , 
63.
FreeBSD 5.2.1, Mac OS X 10.3 Solaris 9 
, 
, 
. Linux 2.4.22
1 048 576.

3.3. open
open.
#include <fcntl.h>
int open(const char *pathname, int oflag, ... /* mode_t mode */);
, 1

(...), ISO
C , 
. 
, .
.
pathname , 
. , 
oflag.
(OR) , 
<fcntl.h> :
O_RDONLY

98

3. -

O_WRONLY

O_RDWR

, .


O_RDONLY 0, O_WRONLY 1
O_RDWR 2.

. 
, oflag 
:
O_APPEND

. 
, 3.11.

O_CREAT

, .
open (mode), 
. ( 4.5,
, , 
mode umask .)

O_EXCL

,
O_CREAT.
, . 
3.11.

O_TRUNC


, .

O_NOCTTY

pathname ,

. 9.6.

O_NONBLOCK pathname (FIFO), 


, 

. 14.2.

System V O_NDELAY. O_NONBLOCK,


, read.
O_NODELAY , read 
0
, 0, 
. , SVR4, 
O_NODELAY ,
O_NONBLOCK.

.

, Single UNIX Specification ( POSIX.1):
O_DSYNC

write
, , , 
.

3.3. open

99

O_RSYNC

read , 

.

O_SYNC

write
, . 
3.14.

O_DSYNC O_SYNC ,   .
O_DSYNC , ,
(, , 
). O_SYNC
. , 
O_DSYNC, 
. , O_SYNC, 
write ,
.
Solaris 9 , FreeBSD 5.2.1 MacOS X 10.3
(O_FSYNC), , O_SYNC.
, FreeBSD 5.2.1
( Mac OS X 10.3 O_SYNC). FreeBSD 5.2.1,
Mac OS X 10.3 O_DSYNC O_RSYNC. Linux 2.4.22
, O_SYNC.

open ,

. 
,
. , 
( 1)
, , 1.
3.12 
dup2.


, NAME_MAX
14 ,
15 ? System V,
SVR2, , 14 .
BSD ENAMETOOLONG 
errno. , 
. , NAME_MAX
14 14 
, , pathname, open
stat,
, , , .
_POSIX_NO_TRUNC, 
POSIX.1, ,

100

3. -

.
2,
.
, 
. , , , SVR4,
S5. UFS 
.
(. . 2.15): Solaris
UFS, PCFS, DOS,
, 8.3.
BSD Linux .

_POSIX_NO_TRUNC
PATH_MAX 
NAME_MAX, 
errno ENAMETOOLONG.

3.4. creat
creat.
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
,
, 1

:
open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);

UNIX open 
: 0, 1 2. . 
, .
O_CREAT O_TRUNC open 
, creat .

mode 4.5,
.
creat : .
open,
, ,
creat, close open.
open :
open(pathname, O_RDWR | O_CREAT | O_TRUNC, mode);

101

3.5. close

3.5. close
close.
#include <unistd.h>
int close(int filedes);
0 , 1

, 
. 14.3.

. 
. , 
1.2.

3.6. lseek
,
. , , 
. ( ,
, .)

, 
. 
0, O_APPEND.

lseek.
#include <unistd.h>
off_t lseek(int filedes, off_t offset, int whence);

, 1

offset whence.
whence SEEK_SET, offset
.
whence SEEK_CUR, offset
. offset
, .
whence SEEK_END, offset
. offset
, .

102

3. -

lseek 
, offset 0, 
:
off_t currpos;
currpos = lseek(fd, 0, SEEK_CUR);

, , 
. 

, lseek 1 er
rno ESPIPE.
SEEK_SET, SEEK_CUR SEEK_END System V.
whence 0 ( ), 1
( ) 2 ( ).
.
l lseek long integer ( ). 
off_t offset long. 
lseek Version 7, C
. ( Version 6 , 
seek tell.)

, 3.1, 
.
3.1.

#include "apue.h"
int
main(void)
{
if (lseek(STDIN_FILENO, 0, SEEK_CUR) == 1)
printf(" \n");
else
printf(" \n");
exit(0);
}

,
$ ./a.out < /etc/motd

$ cat < /etc/motd | ./a.out

$ ./a.out < /var/spool/cron/FIFO


. 

3.6. lseek

103

.
.  
, lseek
1, , .
FreeBSD Intel x86 /dev/kmem 
.
off_t (. 2.16), 
. , off_t 32
, 2311 .

lseek

. 
.
. 
. 
. , 
, .
. 

, .

3.2 .
3.2.
#include "apue.h"
#include <fcntl.h>
char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";
int
main(void)
{
int fd;
if ((fd = creat("file.hole", FILE_MODE)) < 0)
err_sys(" creat");
if (write(fd, buf1, 10) != 10)
err_sys(" buf1");
/* = 10 */
if (lseek(fd, 16384, SEEK_SET) == 1)
err_sys(" lseek");
/* = 16384 */
if (write(fd, buf2, 10) != 10)
err_sys(" buf2");

104

3. -
/* = 16394 */
exit(0);

,
$ ./a.out
$ ls l file.hole

rwrr 1 sar
16394 Nov 25 01:01 file.hole
$ od c file.hole

0000000 a b c d e f g h i j \0 \0 \0 \0 \0 \0
0000020 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
*
0040000 A B C D E F G H I J
0040012

, od(1).
c , 
. , , , 
.
.
, , 
, :
$ ls ls file.hole file.nohole

8 rwrr 1 sar
16394 Nov 25 01:01 file.hole
20 rwrr 1 sar
16394 Nov 25 01:03 file.nohole

, , 
20 , 8.
write ( 3.8). 
4.12.
lseek
off_t, , 
.
: 32 64
.
Single UNIX Specification 
sysconf ( 2.5.4) , 
. . 3.1 ,
sysconf.
c99 , 
getconf(1).

.
, , .
, 2 3 Single UNIX Specification.

105

3.7. read

, _FILE_OFF
SET_BITS 64. off_t 64 
. _FILE_OFFSET_BITS 32, 32
. 32, 64
, , ,
_FILE_OFFSET_BITS 
.
3.1. ,
sysconf


name

_POSIX_V6_ILP32_OFF32 int, long, off_t  _SC_V6_ILP32_OFF32


32
_POSIX_V6_ILP32_OFFBIG int, long _SC_V6_ILP32_OFFBIG
32 , off_t 
64
_POSIX_V6_LP64_OFF64

int 32 , long, _SC_V6_LP64_OFF64


off_t 64

_POSIX_V6_LP64_OFFBIG int 32 , long, _SC_V6_LP64_OFFBIG


off_t
64

: 64 , 
2 (2311 ) 
.

3.7. read
read.
#include <unistd.h>
ssize_t read(int filedes, void *buf, size_t nbytes);
,
0 , 1

read .
, 0.
, 
, :

, ,
. ,
30 , 100 , read 
30. 0 ( ).

106

3. -

. 
. ( 18 , .)

.
, ,
.

.
, , read
, .

c , 
.
, .

,
. 
10.5.

. 
.
POSIX.1 read. 
:
int read(int filedes, char *buf, unsigned nbytes);

, (char*) void* 
ISO C: void* 
.

,
(ssize_t), (
), 0 ( ) 1 (
).

, ,
16 65534
. POSIX.1 1990 
: ssize_t 
size_t, ,
. ( SSIZE_MAX 2.5.2.)

3.8. write
write.
#include <unistd.h>
ssize_t write(int filedes, const void *buf, size_t nbytes);

, 1

3.9. -

107

nbytes,
. 
, ,
(
7.11 10.11).
.
O_APPEND, 
. 

.

3.9. 
3.3 ,
read write. 
.
,
, ,
. 
UNIX, , 

( ) . 

.
3.3.
#include "apue.h"
#define BUFFSIZE 4096
int
main(void)
{
int n;
char buf[BUFFSIZE];
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys(" ");
if (n < 0)
err_sys(" ");
exit(0);
}

, 
0, 1.
STDIN_FILENO STDOUT_FILENO,
<unistd.h>.

108

3. -

. 
UNIX ,
.

, 
, 
.

, :
BUFFSIZE. , 
BUFFSIZE. . 3.2
103 316 352 
20 .
3.2.
Linux
BUFFSIZE
()


()
()

124,89

161,65

288,64

103 316 352

63,10

80,96

145,81

51 658 176

31,84

40,00

72,75

25 829 088

15,17

21,01

36,85

12 914 544

16

7,86

10,27

18,76

6 457 272

32

4,13

5,01

9,76

3 228 636

64

2,11

2,48

6,76

1 614 318

128

1,01

1,27

6,82

807 159

256

0,56

0,62

6,80

403 579

512

0,27

0,41

7,03

201 789

1 024

0,17

0,23

7,84

100 894

2 048

0,05

0,19

6,82

50 447

4 096

0,03

0,16

6,86

25 223

8 192

0,01

0,18

6,67

12 611

16 384

0,02

0,18

6,87

6 305

32 768

0,00

0,16

6,70

3 152

65 536

0,02

0,19

6,92

1 576

131 072

0,00

0,16

6,84

788

262 144

0,01

0,25

7,30

394

524 288

0,00

0,22

7,35

198

3.10.

109

3.3 
/dev/null.
Linux ext2 4096 . (
st_blksize, 4.12, 4096.) 
,
BUFFSIZE.
.

. 
, ,
, , 
. . 3.2 ,
ext2  128 .
. 3.14 
, 5.8

.
, 
, .
(incore),
, ,
. , 

, . ( incore .

( core). core dump ( ) 
, .)
, . 3.2, 
, . 
,
( 512 ).

3.10.
UNIX 
. ,
dup. 
,
.
, ,
. System V
[Bach 1986]. [McKusick et al. 1996] 
4.4BSD. [McKusick and NevilleNeil 2005] FreeBSD 5.2. 
Solaris [Mauro and McDougall 2001].

110

3. -


, 
.
1. .

, ,
. 
:
. ( closeonexec (exec),
. . 3.1 3.14).
b. .
2. . 
:
. , , ,
, ,
( 3.14).
b. .
c. (vnode).
3.
(vnode),
, .
vnode (inode) .
, 
. (inode) , 
, , ,
. (
4.14
UNIX.)
Linux (vnode).
(inode). ,
. 
, .

,
. , 
, .
: 
,
. 
.
. 3.1 , 
, ( 0) 
( 1). 
UNIX [Thompson 1978], 

111

3.10.

fd 0:
fd 1:
fd 2:

...

. 3.1.


.
,
.
(vnode) ,

. (Peter Weinberger)
Bell Labaratories (Bill Joy) Sun Microsystems. Sun 
Virtual File System ( ), 
(inode), , 
(vnode) [Kleiman 1986]. 
UNIX Network File System (NFS
) Sun. , 
, 4.3BSD Reno, NFS.
SVR4 SVR3. Solaris, 
SVR4, .
, Linux 
, , 
, .

, ,
. 3.2. ,
3,
4. , , 
, 
.
,
.
, , 
, .

112

3. -

fd 0:
fd 1:
fd 2:
fd 3:

...

fd 0:
fd 1:
fd 2:
fd 3:
fd 4:

...

. 3.2.


. 
,
, 
( , , 
).
O_APPEND, 
. 

.
.

lseek,
.
( : ,
O_APPEND, 3.11.)
lseek 
.  .

3.11.

113

,
; 
3.12 dup.
fork,

( 8.3).
, 
. 
, ,
,
.
fcntl 3.14, ,
.
,
.

. 
,
. 
, .

3.11.

, .
UNIX O_APPEND open,
:
if (lseek(fd, 0L, 2) < 0)
/* */
err_sys(" lseek");
if (write(fd, buf, 100) != 100)
/* */
err_sys(" write");

, 
,
. ( 
, ,
.)
, A B, 
. 
, O_APPEND. . 3.2. 
,
. 
, A lseek 
1500 ( ). 
A B,

114

3. -

lseek 
1500 ( ).
B write,
1600. , 
(1600) . 
A. 
A write, ,
A,
1500. , 
B.
,
( 
). 1 
. ,
, , 
, 
( ).
UNIX 
, O_APPEND . 
, 
.
, lseek 
write.

pread pwrite
Single UNIX Specification XSI, 

.
pread pwrite.
#include <unistd.h>
ssize_t pread(int filedes, void *buf, size_t nbytes, off_t offset);
,
0 1
ssize_t pwrite(int filedes, const void *buf, size_t nbytes, off_t offset);
1

pread 
lseek read :

pread

. . .

3.12. dup dup2

115

pwrite 
lseek write .



O_CREAT O_EXCL open.
open , .
,
. ,
:
if ((fd = open(pathname, O_WRONLY)) < 0) {
if (errno == ENOENT) {
if ((fd = creat(pathname, mode)) < 0)
err_sys(" creat");
} else {
err_sys(" open");
}
}

,
open creat. 

, ,
creat.
.
, ,
. ,
,
. 
. , 
link ( 4.15) 
( 14.3).

3.12. dup dup2



:
#include <unistd.h>
int dup(int filedes);
int dup2(int filedes, int filedes2);
1

116

3. -

dup , 
. dup2
filedes2. 
filedes2 , 
. filedes filedes2 
, dup2 filedes2, .
, ,
, filedes. 
. 3.3.

fd 0:
fd 1:
fd 2:
fd 3:
...

. 3.3. dup(1)

,
newfd = dup(1);

, 3 (
, 
0, 1 2).
,
, , , 
.

. , dup 
closeonexec (exec) .
fcntl, 
3.14.
dup(filedes);


fcntl(filedes, F_DUPFD, 0);


dup2(filedes, filedes2);

3.13. sync, fsync fdatasync

117


close(filedes2);
fcntl(filedes, F_DUPFD, filedes2);

dup2 
close fcntl. 
:
1. dup2 , 
.
, close
fcntl ,
. ( 10.)
2. , er
rno dup2 fcntl.
dup2 Version 7 BSD. 
fcntl System III
System V. SVR3.2 dup2, 4.2BSD
fcntl F_DUPFD. POSIX.1
dup2, fcntl F_DUPFD.

3.13. sync, fsync fdatasync


UNIX
,
. , , 
, , 
. ;
. ( 3 [Bach 1986] 
.)
, 
. 

sync, fsync fdatasync.
#include <unistd.h>
int fsync(int filedes);
int fdatasync(int filedes);
0 , 1
void sync(void);

sync 
, 
.

118

3. -

sync, , ( 30 
) , update. 
. sync(1)
sync.
fsync ,
filedes, , 
, .
fsync , ,
.
fdatasync fsync, 
. ( fsync
.)
, , sync fsync.
fdatasync FreeBSD 5.2.1 Mac OS X 10.3.

3.14. fcntl
fcntl .
#include <fcntl.h>
int fcntl(int filedes, int cmd, ... /* int arg */);

cmd (. ) , 1



. 14.3 
.
fcntl .
1. (cmd = F_DUPFD).
2. / (cmd = F_GETFD F_SETFD).
3. / (cmd = F_GETFL F_SETFL).
4. / 
(cmd = F_GETOWN F_SETOWN).
5. / (cmd =
F_GETLK, F_SETLK F_SETLKW).
cmd 
. ( , , 
14.3.) . 3.1,
, 
, 
, .

119

3.14. fcntl

F_DUPFD filedes. 
.
,
( ). 
, filedes (. 3.3).
,
FD_CLOEXEC . ( , 
exec, 8.)
F_GETFD filedes 
.
FD_CLOEXEC.
F_SETFD filedes.
( ).

, , 
, FD_CLOEXEC. 0
( FD_CLOEXEC) 1 ( FD_CLOEXEC).
F_GETFL filedes
. ,
open. . 3.3.

3.3. , fcntl

O_RDONLY

O_WRONLY

O_RDWR

O_APPEND

O_NONBLOCK

O_SYNC

(
)

O_DSYNC

( )

O_RSYNC

O_FSYNC

(
FreeBSD Mac OS X)

O_ASYNC

 ( FreeBSD
Mac OS X)

, , O_RDONLY, O_WRONLY O_RDWR, 


, , 
. ( ,
0, 1 2 . ,

.) O_ACCMODE,
, 
.

120
F_SETFL

3. -

.
( ). 
O_APPEND, O_NONBLOCK, O_SYNC, O_DSYNC, O_RSYNC, O_FSYNC O_ASYNC.

F_GETOWN , 
SIGURG SIGIO.
 14.6.2.
F_SETOWN ,
SIGIO SIGURG. arg
, 
, 
arg.

fcntl .
1
. _F_DUPFD, F_GETFD, F_GETFL F_GET
OWN . 
, 
( ), 
( ).

, 3.4, 
, , 
.
3.4.
#include "apue.h"
#include <fcntl.h>
int
main(int argc, char *argv[])
{
int val;
if (argc != 2)
err_quit(": a.out <_>");
if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
err_sys(" fcntl %d", atoi(argv[1]));
switch (val & O_ACCMODE) {
case O_RDONLY:
printf(" ");
break;
case O_WRONLY:
printf(" ");
break;
case O_RDWR:
printf(" ");
break;

3.14. fcntl

121

default:
err_dump(" ");
}
if (val & O_APPEND)
printf(", ");
if (val & O_NONBLOCK)
printf(", ");
#if defined(O_SYNC)
if (val & O_SYNC)
printf(", ");
#endif
#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC)
if (val & O_FSYNC)
printf(", ");
#endif
putchar(\n);
exit(0);
}

: 
_POSIX_C_SOURCE
, POSIX.1. 
bash (Bourneagain
shell). 
.
$ ./a.out 0 < /dev/tty

$ ./a.out 1 > temp.foo
$ cat temp.foo

$ ./a.out 2 2>>temp.foo
,
$ ./a.out 5 5<>temp.foo

5<>temp.foo temp.foo
5.

, 
,
. 
F_SETFD F_SETFL,
, .
3.5 ,
.

122

3. -

3.5.
#include "apue.h"
#include <fcntl.h>
void
set_fl(int fd, int flags) /* flags , */
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
err_sys(" F_GETFL fcntl");
val |= flags;

/* */

if (fcntl(fd, F_SETFL, val) < 0)


err_sys(" F_SETFL fcntl");
}


val &= flags;

/* */

clr_fl, 
. (AND) 
val
flags.
, 3.3,
set_fl(STDOUT_FILENO, O_SYNC);

. , 
write 
, . UNIX write
,
. O_SYNC
, ,

.
, O_SYNC
. , 
3.3. 98,5 

, O_SYNC. ,
Linux ext2, . 3.4.
BUFFSIZE, 
4096. , . 3.2,
/dev/null, 
. . 3.4
. 
. 3.4 .

123

3.14. fcntl

, 
, , 
, . ,
,
. ,

.
3.4.
Linux ext2


()
()
()

. 3.2 0,03
BUFFSIZE=4096

0,16

6,86

0,02

0,30

6,87

 0,03
O_SYNC

0,30

6,83

0,03
fdatasync

0,42

18,28

0,03
fsync

0,37

17,95

 0,05
O_SYNC 
fsync

0,44

17,95

,
. , 
, .
, ext2 Linux O_SYNC.
: ,
, 
fsync, , 
fsync ( 
). , fsync 
.
. 3.5 Mac
OS X. ,
: 
, fsync
. 
, fsync 

. , , ,

124

3. -

,
fsync .
3.5.
Mac OS X


()
()
()

/dev/null

0,06

0,79

4,33

0,05

3,56

14,40

 0,13
O_FSYNC

9,53

22,48

0,11
fsync

3,31

14,12

 0,17
O_FSYNC 
fsync

9,14

22,12

fsync fdatasync, 
, O_SYNC,
.
, fcntl.
( ), 
, .
O_SYNC ,
. fcntl 
, . 
fcntl, 
 
( 15.2),
.

3.15. ioctl
ioctl .
, , 
, , ioctl. 
. (
18, , POSIX.1 
 .)

125

3.15. ioctl

#include <unistd.h>
/* System V */
#include <sys/ioctl.h> /* BSD Linux */
#include <stropts.h> /* XSI STREAMS */
int ioctl(int filedes, int request, ...);
1 ,

ioctl Single UNIX Specification 


STREAMS [Rago 1993].
UNIX .

.

POSIX.1.
FreeBSD 5.2.1 Mac OS X 10.3
unsigned long. , 
,
.
ISO C 
. 
,
.
, 
ioctl. , , 

. , ioctl 
, POSIX.1, 
<termios.h>.

ioctl. 
ioctl . 
ioctl, FreeBSD,
. 3.6.
3.6. ioctl FreeBSD

ioctl

DIOxxx

<sys/disklabel.h>

FIOxxx

<sys/filio.h>

MTIOxxx

<sys/mtio.h>

11

SIOxxx

<sys/sockio.h>

60

TIOxxx

<sys/ttycom.h>

44

126

3. -


, , 
.

, (read, write, lseek . .). ,

ioctl.
ioctl STREAMS 
14.4, 18.12, 
, 19.7, 
.

3.16. /dev/fd
/dev/fd,
0, 1, 2 . . /dev/fd/n 
n, n 
.
/dev/fd (Tom Duff)
8 Research UNIX System.
,
: FreeBSD 5.2.1, Linux 2.4.22, Mac OS X 10.3 Solaris 9.
POSIX.1.


fd = open("/dev/fd/0", mode);

mode, , 
, , 
( 
).
fd = dup(0);

0 fd 
(. 3.3). , 0
, fd . 

fd = open("/dev/fd/0", O_RDWR);

,
fd.
, /dev/fd pathname
creat, open O_CREAT.
, creat, , 
pathname, , /dev/fd/1.

3.17.

127

/dev/stdin, /dev/stdout /dev/stderr,


/dev/fd/0, /dev/fd/1 /dev/fd/2 .
/dev/fd 
. , , 
,
. , cat(1)
,
"":
filter file2 | cat file1  file3 | lpr

cat file1, 
( filter, file2)
file3. /dev/fd,
 :
filter file2 | cat file1 /dev/fd/0 file3 | lpr


,
. , 
, 
. /dev/fd .

3.17.
, 
UNIX.
, read write
. , 
 , .

.
,
.
, 
.
.
fcntl ioctl. 
14, ioctl  STREAMS,
fcntl .

3.1. , 
, ? .
3.2. dup2, 
, dup2, 3.12, 

128

3. -

fcntl.
.
3.3. , :
fd1 = open(pathname, oflags);
fd2 = dup(fd1);
fd3 = open(pathname, oflags);

, , . 3.3. 
fcntl, 
fd1 F_SETFD?
fcntl, fd1 F_SETFL?
3.4. 
.
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
if (fd > 2)
close(fd);

, if, 
, fd 1, , 
, 

dup2. , 
, fd 3.
3.5. Bourne shell, Bourneagain shell Korn shell 
:
digit1>&digit2

, digit1
, digit2.
:
./a.out > outfile 2>&1
./a.out 2>&1 > outfile

(: 
.)
3.6. O_APPEND, 
lseek?
lseek 
? , 
.

4

4.1.
,
.
 : ,
.
. stat,
stat, 
: , .
, 
. ,
UNIX .
,
.

4.2. stat, fstat lstat



stat , .
#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *restrict pathname, struct stat restrict buf);
0 , 1

stat , 
pathname. fstat 
, filedes. lstat

130

4.

stat, ,
, , 
. ( 4.21 ,
.
4.16.)
, buf, ,
.
, :
struct stat {
mode_t st_mode; /* ( ) */
ino_t st_ino;
/* */
dev_t st_dev;
/* ( ) */
dev_t st_rdev;
/* */
nlink_t st_nlink; /* */
uid_t st_uid;
/* */
gid_t st_gid;
/* */
off_t st_size;
/* , */
time_t st_atime; /* */
time_t st_mtime; /* */
time_t st_ctime; /* */
blksize_t st_blksize; /*  */
blkcnt_t st_blocks; /* */
};

POSIX.1 st_rdev, st_blksize st_blocks. 


XSI Single UNIX Specification.

, 
( 2.8). ,
.
, stat ls l,
.

4.3.
: . 
UNIX , 
, . :
1. , 
. UNIX
.
, 
.
.
, . 
, ,
.

131

4.3.

2. . 
. ,
, , 
. , 
, .
3. .
 , 
.
4. . 

.
, .
5. FIFO, . 
.
15.5.
6. . 
. 

.
16.
7. .
. 
4.16.
st_mode stat.
, . 4.1.
st_mode 
stat.
4.1. <sys/stat.h>

S_ISREG()

S_ISDIR()

S_ISCHR()

S_ISBLK()

S_ISFIFO()

( )

S_ISLNK()

S_ISSOCK

POSIX.1 
(IPC), ,
. . 4.2
IPC stat. , 

132

4.

. 4.1, ,
stat, st_mode.
4.2. IPC <sys/stat.h>

S_TYPEISMQ()

S_TYPEISSEM()

S_TYPEISSHM()

, 
15. , 
, .

, 4.1,
.
4.1.
#include "apue.h"
int
main(int argc, char *argv[])
{
int i;
struct stat buf;
char *ptr;
for (i = 1; i < argc; i++) {
printf("%s: ", argv[i]);
if (lstat(argv[i], &buf) < 0) {
err_ret(" lstat");
continue;
}
if (S_ISREG(buf.st_mode))
ptr = " ";
else if (S_ISDIR(buf.st_mode))
ptr = "";
else if (S_ISCHR(buf.st_mode))
ptr = " ";
else if (S_ISBLK(buf.st_mode))
ptr = " ";
else if (S_ISFIFO(buf.st_mode))
ptr = "fifo";
else if (S_ISLNK(buf.st_mode))
ptr = " ";
else if (S_ISSOCK(buf.st_mode))
ptr = "";
else

133

4.3.
ptr = "** **";
printf("%s\n", ptr);
}
exit(0);
}

4.1:
$ ./a.out /etc/passwd /etc /dev/initctl /dev/log /dev/tty \
> /dev/scsi/host0/bus0/target0/lun0/cd /dev/cdrom
/etc/passwd:
/etc:
/dev/initctl: fifo
/dev/log:
/dev/tty:
/dev/scsi/host0/bus0/target0/lun0/cd:
/dev/cdrom:

( 
, . 

>.) lstat stat, 
. stat, 
.
Linux 
_GNU_SOURCE,
S_ISSOCK.
UNIX S_ISxxx. 
(AND) st_mode 
S_IFMT S_IFxxx.

<sys/stat.h>. , , 
S_ISDIR
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)

, 
, , 
. . 4.3 
Linux,
. 
, 4.21.
4.3.

226 856

82,22%

23 017

8,95

6 442

2,51

134

4.

4.3 ()

447

0,17

312

0,12

69

0,03

FIFO

0,00

4.4. setuserID setgroupID


. 
. 4.4.
4.4. ,


,
exec

,
.
. 
, , 
, , 8.11.

,
. (
1.8.)

,
. 
, setuid 8.11.

POSIX.1 2001 . POSIX 
.
_POSIX_SAVED_IDS sysconf
_SC_SAVED_IDS , ,
.

4.5.

135


,
.

. st_uid
stat, st_gid.
, 
, 
. 
st_mode,
:

(st_uid). st_mode ,

(st_gid). st_mode 
set;user;ID set;group;ID .
,
setuserID,
. 
, , 
. , UNIX, 
, passwd(1), 
setuserID. , 
( /etc/passwd
/etc/shadow), 
. ,
, , 
.
8.
setuserID setgroupID st_mode stat, 
. S_ISUID
S_ISGID.

4.5.
st_mode 
. .
, 
. ,
.
, 
. . 4.5.

136

4.

4.5. <sys/stat.h>
st_mode
S_IRUSR

userread

S_IWUSR

userwrite

S_IXUSR

userexecute

S_IRGRP

groupread

S_IWGRP

groupwrite

S_IXGRP

groupexecute

S_IROTH

otherread

S_IWOTH

otherwrite

S_IXOTH

otherexecute

chmod(1),
, : u
user (, ), g group () o other ().
owner (),
group () world ( ), 
, chmod o owner (),
other (). user (
), group () other (),
chmod.
. 4.5 , 
. 
,
.
: ,
,
, . 
.
, /usr/include/stdio.h,
/, /usr /usr/include. 

,
, . .
/usr/include, 
stdio.h,
. 
, .
./stdio.h.
, 
.
, , .

4.5.

137

,
, . (
, ).

PATH ( 8.10).  
, ,
.
, 
( O_RDONLY O_RDWR, open).
, 
( O_WRONLY O_RDWR, open).
O_TRUNC open, 
.

.
, 
, .
.

exec ( 8.10), .
, .

,
, , , 
, (st_uid st_gid), 
( 
) 
, . 
,

. .
1. , 0
(), .
.
2. , 
(
), , 
.
.
: , 
userread, ,
userwrite, 
, userexecute.
3.

138

4.

, ,
. .
4. ,
, .
.
: ( 2),

, .
, , 
, 
.

4.6.
3 
open creat, ,
.
, 4.20
mkdir. 
.
() 
.
PO
SIX.1 .
1.
.
2.
, .
FreeBSD 5.2.1 Mac OS X 10.3 
.
ext2 ext3 Linux
mount(1). 
Linux 2.4.22 ( mount)
Solaris 9 , 
setgroupID , . 
,
, .


, , ,
, .

. , 
/var/spool/mail Linux.

139

4.7. access

,
FreeBSD 5.2.1 Mac OS X 10.3, Linux So
laris . Linux 2.4.22
Solaris 9, setgroupID, mkdir
. (
4.20.)

4.7. access
, 
, 
. 

. ,
setuserID setgroupID.
setuserID ,

. access
,
. (
, 4.5.)
#include <unistd.h>
int access(const char *pathname, int mode);
0 , 1

mode . 4.6, 
(OR).
4.6. , mode access
mode

mode

R_OK

X_OK

W_OK

F_OK

, 4.2, 
access.
4.2. access
#include "apue.h"
#include <fcntl.h>
int
main(int argc, char *argv[])
{

140

4.
if (argc != 2)
err_quit(": a.out <_>");
if (access(argv[1], R_OK) < 0)
err_ret(" access %s", argv[1]);
else
printf(" \n");
if (open(argv[1], O_RDONLY) < 0)
err_ret(" open %s", argv[1]);
else
printf(" \n");
exit(0);

:
$ ls l a.out
rwxrwxrx 1 sar
15945 Nov 30 12:10 a.out
$ ./a.out a.out


$ ls l /etc/shadow
r 1 root
1315 Jul 17 2002 /etc/shadow
$ ./a.out /etc/shadow
access /etc/shadow: Permission denied
open /etc/shadow: Permission denied
$ su

Password:

# chown root a.out

# chmod u+s a.out
set;user;ID
# ls l a.out
SUID
rwsrwxrx
1 root
15945 Nov 30 12:10 a.out
# exit

$ ./a.out /etc/shadow
access /etc/shadow: Permission denied

, setuserID, 
, , 
open .
8 ,
. 
, 
.

4.8. umask
, , ,
, .
umask
. ( ,
.)

141

4.8. umask

#include <sys/stat.h>
mode_t umask(mode_t cmask);

cmask . 4.5 (S_IRUSR,


S_IWUSR . .), (OR).

. ( 3.3 3.4, 
open creat. mode,
.)
4.20. , ;
, .

, 4.3, : 
, , ,
.
4.3. umask
#include "apue.h"
#include <fcntl.h>
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
int
main(void)
{
umask(0);
if (creat("foo", RWRWRW) < 0)
err_sys(" creat foo");
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (creat("bar", RWRWRW) < 0)
err_sys(" creat bar");
exit(0);
}

, ,
.
$ umask
002
$ ./a.out
$ ls l foo bar
rw
1 sar
rwrwrw
1 sar
$ umask
002

0 Dec 7 21:20 bar


0 Dec 7 21:20 foo
,

UNIX .
,

142

4.

, . ,
,
,
. ,
, 0.

, .
umask 
. 
, 
( ). 
umask,
.
umask 
. 
,
, , . 4.7.
. 
002 ( 
, ), 022 ( 
) 027 ( ,
, ).
4.7

0400

userread

0010

groupexecute

0200

userwrite

0004

otherread

0100

userexecute

0002

otherwrite

0040

groupread

0001

otherexecute

0020

groupwrite

Single UNIX Specification , 


. 
,
, ( ), ,
( ).
umask:
$ umask
002
$ umask S
u=rwx,g=rwx,o=rx
$ umask 027
$ umask S
u=rwx,g=rx,o=

143

4.9. chmod fchmod

4.9. chmod fchmod


.
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int filedes, mode_t mode);
0 , 1

chmod , , fchmod
, .
, 

.
mode . 4.8, 
(OR).
4.8. chmod,
<sys/stat.h>
mode

S_ISUID

setuserID

S_ISGID

setgroupID

S_ISVTX

savedtext ( sticky)

S_IRWXU

, ()

S_IRUSR

()

S_IWUSR

()

S_IXUSR

()

S_IRWXG

S_IRGRP

S_IWGRP

S_IXGRP

S_IRWXO

S_IROTH

S_IWOTH

S_IXOTH

: . 4.8 
. 4.5. setID (S_ISUID
S_ISGID), savedtext (S_ISVTX)
(S_IRWXU, S_IRWXG S_IRWXO).

144

4.

savedtext (S_ISVTX) POSIX.1. 


XSI Single UNIX Specification.
.

foo bar,
4.3, umask:
$ ls l foo bar
rw 1 sar
rwrwrw 1 sar

0 Dec 7 21:20 bar


0 Dec 7 21:20 foo

, 4.4,
.
4.4. r chmod
#include "apue.h"
int
main(void)
{
struct stat

statbuf;

/* setgroupID groupexecute */
if (stat("foo", &statbuf) < 0)
err_sys(" stat foo");
if (chmod("foo", (statbuf.st_mode & S_IXGRP) | S_ISGID) < 0)
err_sys(" chmod foo");
/* "rwrr" */
if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0)
err_sys(" chmod bar");
exit(0);
}

4.4 ,
:
$ ls l foo bar
rwrr
1 sar
rwrwSrw
1 sar

0 Dec 7 21:20 bar


0 Dec 7 21:20 foo


bar, . 
foo , , 
. 
stat .
setgroupID groupexecute. :
ls groupexecute S, 
, setgroupID groupexecute.

4.9. chmod fchmod

145

Solaris S ls l, ,
.
, 
14.3.

, , , 
ls, 4.4. 
, 4.18, , chmod
(inode). ls 
.
chmod 
:
, Solaris, sticky
. sticky (S_ISVTX)
, 
, mode . (
sticky .) , 
. ,
S_ISVTX 
.
FreeBSD 5.2.1, Mac OS X 10.3 Solaris 9 
sticky . Linux 2.4.22 
, Linux 
. , FreeBSD 5.2.1 Mac OS X 10.3 
, 
.

,
, . 
4.6 , ,
, . 
, 


, setgroupID 
.
, .
FreeBSD 5.2.1, Mac OS X 10.3, Linux 2.4.22 Solaris 9
, 
. , , ,
, setuserID setgroupID .

setuserID setgroupID, 
.

146

4.

4.10. sticky
S_ISVTX. UNIX, 
,
sticky bit (). 
,
. ( 
.) ,
,
,
,
. sticky
, C. 
, ,
,
. sticky () ,

. UNIX
saved;text bit ( ),
S_ISVTX. UNIX 

, .
sticky .
Single UNIX Specification sticky .
sticky ,
, 
, 
.
, , ,
sticky /tmp /var/spool/uucppublic.
. ,
,
.
savedtext POSIX.1. 
Single UNIX Specification XSI 
FreeBSD 5.2.1, Mac OS X 10.3, Solaris 9 Linux 2.4.22.
Solaris 9 sticky .
sticky ,
.

4.11. chown, fchown lchown


chown 
.

4.11. chown, fchown lchown

147

#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int filedes, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group);
0 , 1

, ,
. 
lchown ,
, .
lchown XSI, Single UNIX
Specification. UNIX .

, owner group, 1, 
.
, BSD

.

.
POSIX.1 
_POSIX_CHOWN_RESTRICTED.
Solaris 9 ,
.
FreeBSD 5.2.1, Linux 2.4.22 Mac OS X 10.3
.

2.6 , _POSIX_CHOWN_RESTRICTED
<unistd.h>,
pathconf fpathconf.
; , 

.
_POSIX_CHOWN_RESTRICTED ,
, , 
<unistd.h> .
_POSIX_CHOWN_RESTRICTED ,
1. , , 
.
2. , ,
,
(
), owner
1

148

4.

group
.
, _POSIX_CHOWN_RESTRICTED ,
() . 

,
, .
,
,
setuserID setgroupID.

4.12.
st_size stat . 
, .
Solaris ,
. 15.2.

, . 
.
,
16 512. 4.21.

. , 7
usr/lib:
lrwxrwxrwx 1 root

7 Sep 25 07:14 lib > usr/lib

( :
C , , 
st_size .)
UNIX st_blksize st_blocks.

, 512 , 
. 3.9 , 
, st_blksize.
, 5,
 st_blksize
, .
UNIX, st_blocks 512
. .


3.6 , 
. 3.2.

4.13.

149


. :
$ ls l core
rwrr 1 sar 8483248 Nov 18 12:18 core
$ du s core
272 core

core 8 , du ,
272 512 (139 264 ). ( du 
, BSD, 1024
, Solaris 512 .) ,
.
3.6, read 0
, .
, ,  
, :
$ wc c core
8483248 core

wc(1) c () .

, , cat(1),
0:
$ cat core > core.copy
$ ls l core*
rwrr 1 sar 8483248 Nov 18 12:18 core
rwrwr 1 sar 8483248 Nov 18 12:27 core.copy
$ du s core*
272 core
16592 core.copy

8 495 104 (. . 51216 592)


. , ls,
,
.
, , 
, 4.2 [Bach 1986], 7.2 7.3
[McKusick 1996] ( 8.2 8.3 [McKusick and NevilleNeil
2005]) 14.2 [Mauro and McDougall 2001].

4.13.
,
. ,
O_TRUNC open, 
.

150

4.

#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int filedes, off_t length);
0 , 1

, 
length. 
length, , ,
. length,
, XSI
. ,
, , 
( , , ).
ftruncate POSIX.1. truncate XSI
POSIX.1, Single
UNIX Specification.
BSD, 4.4BSD, truncate
.
Solaris fcntl (F_FREESP),
, , .

ftruncate 13.2,
.

4.14.
,
UNIX. 
(inode)
, .
UNIX.
, Solaris 
: BSD UNIX File System (UFS), DOS
PCFS , 
 HSFS.
. 2.15. UFS 
Berkeley fast file system, .
, . 
, . 4.1.
,
.
, 
, ,
. 4.2.

151

4.14.

...

()

...

. 4.1. ,

. 4.2 :

,
. 
; ,
. ,
0, ( ,
, ). 
(unlink)
, (delete).

. 4.2.

152

4.

unlink (),
delete (). stat
st_nlink. nlink_t. 
. , 2.5.2
LINK_MAX,
.
.
, ,
, . 

lib, 7 usr/lib.
S_IFLNK, 
.
lrwxrwxrwx 1 root 7 Sep 25 07:14 lib > usr/lib

: , 
, ,
. stat 
. ,
, : 
. , 
, .
, , ino_t.

, , 
,
. ln(1) ( 
, ) 
,
. link .
/ 
.
, , , 
, 
. . ,
/usr/lib/foo /usr/foo, 
foo, /usr /usr/lib 
. mv(1).
,
? , 
:
$ mkdir testdir

. 4.3 . 
: (
)  ( ).

153

4.15. link, unlink, remove rename

1267

2549
2549

1267

..

.
1267

..

2549

testdir

. 4.3. testdir

2549 ,
2. ( 
) 2,
: ,
testdir, , 
. 1267
, 3 . ,
3,
. 3 ,
( ),
() testdir (). ,

.
UNIX, 
4 [Bach 1986]. 
, Berkeley fast file system, 7
[McKusik 1996] 8 [McKusik and NevilleNeil 2005].
UFS 14 [Mauro and Mc
Dougall 2001].

4.15. link, unlink, remove rename


,
. 
link.

154

4.

#include <unistd.h>
int link(const char *existingpath, const char *newpath);
0 , 1

newpath, 
existingpath.
newpath , .
newpath, 
.

. ( 
3.11.)
,
, POSIX.1
, .
, 
. 
, 
,
.
( 4.16 , 
.) 
.
unlink.
#include <unistd.h>
int unlink(const char *pathname);
0 , 1


pathname. ,
 .
.
, ,
, 
. , 4.10 ,
sticky,
, ,
.
,
0. , ,
 .
, .

4.15. link, unlink, remove rename

155

,
, ,
.

, 4.5, ,
( unlink). 
15 .
4.5. ,
#include "apue.h"
#include <fcntl.h>
int
main(void)
{
if (open("tempfile", O_RDWR) < 0)
err_sys(" open");
if (unlink("tempfile") < 0)
err_sys(" unlink");
printf(" \n");
sleep(15);
printf("\n");
exit(0);
}

:
$ ls l tempfile
rwr 1 sar
$ df /home
Filesystem 1Kblocks
/dev/hda4
11021440
$ ./a.out &
1364
$
ls l tempfile
ls: tempfile: No such
$ df /home
Filesystem 1Kblocks
/dev/hda4
11021440
$
df /home
Filesystem 1Kblocks
/dev/hda4
11021440


413265408 Jan 21 07:14 tempfile

Used Available Use% Mounted on
1956332
9065108 18% /home
4.5


,
file or directory

,
Used Available Use% Mounted on
1956332
9065108 18% /home
,

Used Available Use% Mounted on
1552352
9469088 15% /home
394.1 M

unlink 
, 
. open creat,
unlink. ,

156

4.

.
, ,
, .
pathname ,
, , 
, .
, ,
unlink ,
rmdir, 4.20.

remove. remove
unlink, rmdir.
#include <stdio.h>
int remove(const char *pathname);
0 , 1

ISO C remove .
UNIX unlink , 
, ISO C,
.

rename.
#include <stdio.h>
int rename(const char *oldname, const char *newname);
0 , 1

ISO C rename . (ISO C


.) POSIX.1 ,
.

, oldname
, .
, , newname .
1. oldname , 
, .
newname , .
newname , ,
oldname newname.
, newname oldname, 
.
2. oldname , 
. newname , 

4.16.

157

, . (
, :
.) newname ,
, oldname newname. 
, newname
oldname. , ,
/usr/foo /usr/foo/testdir,
(/usr/foo) .
3. oldname newname 
, , , 
.
4. , oldname newname
, , 
.
newname , 
, . ,
, oldname
, newname,
.

4.16.
, 
, 
.
, .
, 



, 
, 
.
.
4.2BSD 
SVR4.

, , 
, .
, ,
.
, ,
. . 4.9
, .
mkdir, mkfifo, mknod rmdir

158

4.

,
. , , 
, fstat fchmod, ,

, ( , open).
chown , 
.
Linux ( 2.1.81) chown 
. 2.1.81 chown . 
FreeBSD 5.2.1 Mac OS X 10.3 chown 
. ( , 4.4BSD, chown 
, 4.4.BSD.) Solaris 9
chown . 
lchown .

, . 4.9, open
O_CREAT O_EXCL.
pathname , 
EEXIST.

.
4.9.

access

chdir

chmod
chown

creat

exec
lchown

link
lstat

open

opendir

pathconf

readlink

remove

rename

stat

truncate

unlink

4.16.

159


. , , 
, errno ELOOP. 
:
$ mkdir foo

$ touch foo/a

$ ln s ../foo foo/testdir
$ ls l foo
total 0
rwr 1 sar
0 Jan 22 00:16 a
lrwxrwxrwx 1 sar
6 Jan 22 00:16 testdir > ../foo

foo,
a foo. . 4.4 ,
,
. ,
ftw(3) 
, Solaris 9, :
foo
foo/a
foo/testdir
foo/testdir/a
foo/testdir/testdir
foo/testdir/testdir/a
foo/testdir/testdir/testdir
foo/testdir/testdir/testdir/a
( , ELOOP)

4.21 ftw,
lstat stat, 
.
: Linux ftw lstat,
.

.
unlink, foo/testdir,
unlink . ,

foo

testdir

. 4.4. testdir

160

4.

,
. link 
.

. 
, fsck(1). 
clri(8) dcheck(8).
.
mkdir .

open
, , 
. , , ,
open , 
. ,
, :
$ ln s /no/such/file myfile

$ ls myfile
myfile
ls ,
$ cat myfile

cat: myfile: No such file or directory
$ ls l myfile
l
lrwxrwxrwx 1 sar
13 Jan 22 00:26 myfile > /no/such/file

myfile , cat ,
myfile , , 
, . ls l : 
, ls l, 
(link), , >
. ls (F), 
@,
l.

4.17. symlink readlink


symlink.
#include <unistd.h>
int symlink(const char *actualpath, const char *sympath);
0 , 1

sympath,
actualpath. actualpath
. (
.) , ,
actualpath sympath .

161

4.18.

open , 
, 
, , .
readlink.
#include <unistd.h>
ssize_t readlink(const char *restrict pathname, char *restrict buf,
size_t bufsize);

, 1

open, read close.


, buf. ,
buf, .

4.18.
.
. 4.10.
4.10. ,

st_atime

 read

ls(1)
u

st_mtime

 write

st_ctime

 chmod, chown

c


(st_mtime) 
(st_ctime).
, . 

. 
, , 
: ,
(), .
, 

, .
, 
. access stat, ,
.

162

4.


, 
. a.out core,
.
find(1).

, 
,
.
ls
. l t 
. u 
, c 
.
. 4.11 
. 4.14 ,
, ,
. ,
, 
. . 4.11
, ,
. , 
, 
, , . 

. ( mkdir rmdir
4.20. utime 
. exec 
8.10. mkfifo pipe 15.)

4.19. utime
utime 
.
#include <utime.h>
int utime(const char *pathname, const struct utimbuf *times);
0 , 1

:
struct utimbuf {
time_t actime;
time_t modtime;
}

/* */
/* */

163

4.19. utime

4.11.
,



a
m
c
a
m

chmod,
fchmod

4.9

chown,
fchown

4.11

creat

creat
exec

3.4


(O_CREAT)

3.4


(O_TRUNC)

8.10

lchown

4.11

link

4.15

mkdir

4.20

mkfifo

15.5

open

3.3


(O_CREAT)

3.3


(O_TRUNC)

15.2

open
pipe

read

3.7

remove
remove

rename
rmdir
truncate,
ftruncate

write

4.15

remove = unlink

4.15

remove = rmdir

4.15

4.20

4.19

3.8

unlink
utime

4.13

4.15

, 
, , 1.10.
, , 
, times .

164

4.

times (NULL), 

. 

, .
times , 
, 
times. 
, ,
.

: 
,
utime.
UNIX touch(1) . 
, tar(1) cpio(1)
utime
.

, 4.6,
, open O_TRUNC,
, 
. ,
stat,

utime.
4.6. utime
#include "apue.h"
#include <fcntl.h>
#include <utime.h>
int
main(int argc, char *argv[])
{
int i, fd;
struct stat statbuf;
struct utimbuf timebuf;
for (i = 1; i < argc; i++) {
if (stat(argv[i], &statbuf) < 0) { /* */
err_ret("%s: stat", argv[i]);
continue;
}
if ((fd = open(argv[i], O_RDWR | O_TRUNC)) < 0) { /* */
err_ret("%s: open", argv[i]);
continue;

165

4.20. mkdir rmdir


}
close(fd);
timebuf.actime = statbuf.st_atime;
timebuf.modtime = statbuf.st_mtime;
if (utime(argv[i], &timebuf) < 0) { /* */
err_ret("%s: utime", argv[i]);
continue;
}
}
exit(0);
}

4.6 
.
$ ls l changemod times
rwxrwxrx 1 sar 15019 Nov
rwxrwxrx 1 sar 16172 Nov
$ ls lu changemod times
rwxrwxrx 1 sar 15019 Nov
rwxrwxrx 1 sar 16172 Nov
$ date
Thu Jan 22 06:55:17 EST 2004
$ ./a.out changemod times
$ ls l changemod times
rwxrwxrx 1 sar
0 Nov
rwxrwxrx 1 sar
0 Nov
$ ls lu changemod times
rwxrwxrx 1 sar
0 Nov
rwxrwxrx 1 sar
0 Nov
$ ls lc changemod times
rwxrwxrx 1 sar
rwxrwxrx 1 sar

18
19
18
19

18
19
18
19

0 Jan 22
0 Jan 22



18:53 changemod
20:05 times

18:53 changemod
20:05 times

4.6

18:53 changemod
20:05 times

18:53 changemod
20:05 times


06:55 changemod
06:55 times

,
. 

.

4.20. mkdir rmdir


mkdir,
rmdir.
#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
0 , 1

166

4.

. 
. , 
mode, .
, mode 
: . 
, , , 
, , 
( 4.16).

, 4.6.
Solaris 9 Linux 2.4.22 setgro
upID . , , 
. Linux
. , ext2 ext3
mount(1). 
UFS Linux : setgroupID 
, BSD,
.
, BSD, setgroupID
. Free
BSD 5.2.1 Mac OS X 10.3 4.4BSD, set
groupID.
setgro
upID.
UNIX mkdir. 4.2BSD SVR3.
, ,
mknod. ,
.  , 
mkdir(1) setuserID
root. ,
mkdir(1) system(3).

rmdir. 
, , 
: .
#include <unistd.h>
int rmdir(const char *pathname);
0 , 1


,
, , .
, 
0,
. ,

167

4.21.

. 
, . (
,  ,
rmdir .)

4.21.
,
. ,
. 4.5
,
,
.
UNIX 
. UNIX, Version 7,
: 
16 14 2 
. 4.2BSD 
, . ,
, ,
. 
, , 
POSIX.1. 
read,
, 
.
#include <dirent.h>
DIR *opendir(const char *pathname);

NULL
struct dirent *readdir(DIR *dp);
, NULL

void rewinddir(DIR *dp);
int closedir(DIR *dp);
0 1
long telldir(DIR *dp);

, dp
void seekdir(DIR *dp, long loc);

168

4.

telldir seekdir POSIX.1. 


XSI Single UNIX Specification , 
, UNIX, 
.
,
1.1,
ls.
dirent <dirent.h> 
. UNIX 
:
struct dirent {
ino_t d_ino;
/* */
char d_name[NAME_MAX + 1]; /* , */
/* */
}

d_ino POSIX.1,
, XSI
POSIX.1. POSIX.1 d_name .

: NAME_MAX Sola
ris 9 , 
, , , fpathconf. 
NAME_MAX, 255 ( . 2.12).
,
, d_name ,
.
DIR ,
.
DIR FILE, 
, 5.
DIR, opendir,
. opendir
, read
dir .
, , 
.


, .
,
. 4.3. , 4.7, 

. Solaris ftw(3), 

4.21.

169

,
. :
stat , 
. , 
, 
/lib, /usr/lib,
/usr/lib . 
, Solaris nftw(3),
. 
nftw,  
, 
.
, ftw nftw, Single UNIX Specification 
XSI POSIX.1. 
Solaris 9 Linux 2.4.22. , BSD,
fts(3) . 
FreeBSD 5.2.1, Mac OS X 10.3 Linux 2.4.22.
4.7.

#include "apue.h"
#include <dirent.h>
#include <limits.h>
/* , */
typedef int Myfunc(const char *, const struct stat *, int);
static Myfunc myfunc;
static int
myftw(char *, Myfunc *);
static int
dopath(Myfunc *);
static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;
int
main(int argc, char *argv[])
{
int ret;
if (argc != 2)
err_quit(": ftw <_>");
ret = myftw(argv[1], myfunc); /* */
ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;
if (ntot == 0)
ntot = 1;/* 0; 0 */
printf(" = %7ld, %5.2f %%\n", nreg,
nreg*100.0/ntot);
printf(" = %7ld, %5.2f %%\n", ndir,
ndir*100.0/ntot);
printf(" = %7ld, %5.2f %%\n", nblk,

170

4.
nblk*100.0/ntot);
printf(" = %7ld, %5.2f %%\n", nchr,
nchr*100.0/ntot);
printf("FIFO = %7ld, %5.2f %%\n", nfifo,
nfifo*100.0/ntot);
printf(" = %7ld, %5.2f %%\n", nslink,
nslink*100.0/ntot);
printf(" = %7ld, %5.2f %%\n", nsock,
nsock*100.0/ntot);
exit(ret);

}
/*
* , "pathname".
* func() .
*/
#define
#define
#define
#define

FTW_F
FTW_D
FTW_DNR
FTW_NS

1
2
3
4

/*
/*
/*
/*
/*

, */
*/
, */
, */
stat */

static char *fullpath; /* */


static int
/* , func() */
myftw(char *pathname, Myfunc *func)
{
int len;
fullpath = path_alloc(&len); /* PATH_MAX+1 */
/* ( 2.3) */
strncpy(fullpath, pathname, len); /* */
fullpath[len1] = 0;
/* */
return(dopath(func));
}
/*
* , "fullpath". "fullpath"
* , lstat(), func() .
* .
*/
static int
/* , func() */
dopath(Myfunc* func)
{
struct stat
statbuf;
struct dirent *dirp;
DIR
*dp;
int
ret;
char
*ptr;
if (lstat(fullpath, &statbuf) < 0) /* stat */
return(func(fullpath, &statbuf, FTW_NS));

171

4.21.
if (S_ISDIR(statbuf.st_mode) == 0) /* */
return(func(fullpath, &statbuf, FTW_F));
/*
* . func(),
* .
*/
if ((ret = func(fullpath, &statbuf, FTW_D)) != 0)
return(ret);
ptr = fullpath + strlen(fullpath); /* */
/* fullpath */
*ptr++ = /;
*ptr = 0;
if ((dp = opendir(fullpath)) == NULL) /* */
return(func(fullpath, &statbuf, FTW_DNR));
while ((dirp = readdir(dp)) != NULL) {
if (strcmp(dirp>d_name, ".") == 0 ||
strcmp(dirp>d_name, "..") == 0)
continue;
/* "." ".." */
strcpy(ptr, dirp>d_name);

/* */

if ((ret = dopath(func)) != 0) /* */
break;
/* */
}
ptr[1] = 0; /* */
if (closedir(dp) < 0)
err_ret(" %s", fullpath);
return(ret);
}
static int
myfunc(const char *pathname, const struct stat *statptr, int type)
{
switch (type) {
case FTW_F:
switch (statptr>st_mode & S_IFMT) {
case S_IFREG: nreg++; break;
case S_IFBLK: nblk++; break;
case S_IFCHR: nchr++; break;
case S_IFIFO: nfifo++; break;
case S_IFLNK: nslink++; break;
case S_IFSOCK: nsock++; break;
case S_IFDIR:
err_dump(" S_IFDIR %s", pathname);
/* = FTW_D */
}
break;
case FTW_D:

172

4.
ndir++;
break;
case FTW_DNR:
err_ret(" %s", pathname);
break;
case FTW_NS:
err_ret(" stat %s", pathname);
break;
default:
err_dump(" %d %s", type, pathname);
}
return(0);

, 
. ftw. ,
myfunc 0, , 
, .

UNIX find, ls, tar 
[Fowler, Korn and Vo 1989].

4.22. chdir, fchdir getcwd


.
( ,
). , 
,
/etc/passwd, . 
,
.

chdir fchdir.
#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int filedes);
0 , 1

pathname,
.
fchdir POSIX.1.
XSI Single UNIX Specification. , 
, fchdir.

4.22. chdir, fchdir getcwd

173

, 
chdir
. ( 
8.) , ,
4.8, , .
4.8. chdir
#include "apue.h"
int
main(void)
{
if (chdir("/tmp") < 0)
err_sys(" chdir");
printf(" /tmp \n");
exit(0);
}


(mycd ):
$ pwd
/usr/lib
$ mycd
/tmp
$ pwd
/usr/lib

, 
mycd, .
. 
,
chdir .
chdir , 
cd.
,
. , 
, ,
(vnode) .
,
, ,
() ,
. 
, 
, . 
, ,
.
, .

174

4.

#include <unistd.h>
char *getcwd(char *buf, size_t size);
buf , NULL

buf .
, 
. ( 

2.5.5.)
UNIX
NULL.
size malloc. 
POSIX.1 Single UNIX Specification, 
.

, 4.9, 
, getcwd
. :
$ ./a.out
cwd = /var/spool/uucppublic
$ ls l /usr/spool
lrwxrwxrwx 1 root 12 Jan 31 07:57 /usr/spool > ../var/spool

4.9. getcwd
#include "apue.h"
int
main(void)
{
char *ptr;
int size;
if (chdir("/usr/spool/uucppublic") < 0)
err_sys(" chdir");
ptr = path_alloc(&size);
/* */
if (getcwd(ptr, size) == NULL)
err_sys(" ");
printf("cwd = %s\n", ptr);
exit(0);
}

: getcwd ,
. 4.9, ,
/var/spool /usr/spool. 
.

4.23.

175

getcwd , 
.
getcwd 
.
chdir .
fchdir 
. getcwd , 
.
,
fchdir.

4.23.
st_dev st_rdev. 
18.9 ttyname. 
.


,
dev_t.
,
. 
. . 4.1 ,
. 
, ,
, .


, : major minor.
, , 
dev_t.
UNIX 16
, 8 8
. FreeBSD 5.2.1 Mac OS X 10.3
32 ,
8 , 24 . 32 Solaris 9
32 , 14 ,
18 . 64 Solaris 9 64
, 32 . Linux 2.4.22, 
, dev_t 64 , 
8 .
POSIX.1 dev_t,
.
major minor, ,
, . BSD 
<sys/types.h>. Solaris <sys/mkdev.h>, Li
nux <sys/sysmacros.h>, <sys/types.h>.

176

4.

st_dev
, 
.
st_rdev 
.
, .

, 4.10,
. , 
, 
st_rdev.
4.10. st_dev st_rdev
#include "apue.h"
#ifdef SOLARIS
#include <sys/mkdev.h>
#endif
int
main(int argc, char *argv[])
{
int i;
struct stat buf;
for (i = 1; i < argc; i++) {
printf("%s: ", argv[i]);
if (stat(argv[i], &buf) < 0) {
err_ret(" stat");
continue;
}
printf("dev = %d/%d", major(buf.st_dev), minor(buf.st_dev));
if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {
printf(" (%s) rdev = %d/%d",
(S_ISCHR(buf.st_mode)) ? ". ." : " .",
major(buf.st_rdev), minor(buf.st_rdev));
}
printf("\n");
}
exit(0);
}

:
$ ./a.out / /home/sar /dev/tty[01]
/: dev = 3/3
/home/sar: dev = 3/4
/dev/tty0: dev = 0/7 (. .) rdev = 4/0
/dev/tty1: dev = 0/7 (. .) rdev = 4/1
$ mount
?

4.24.

177

/dev/hda3 on / type ext2 (rw,noatime)


/dev/hda4 on /home type ext2 (rw,noatime)
$ ls lL /dev/tty[01] /dev/hda[34]
brw 1 root

3,

3 Dec 31 1969 /dev/hda3

brw 1 root

3,

4 Dec 31 1969 /dev/hda4

crw 1 root

4,

0 Dec 31 1969 /dev/tty0

crw 1 root

4,

1 Jan 18 15:36 /dev/tty1

(/ /home/sar),
/dev/tty[01]. ( 
,
.
/dev/tty[01] /dev/tty0 /dev/tty1.)
, 
. , /
/home/sar , , 
. mount(1).
ls, 
, mount, .

,
. ( , 

, , CDROM.
UNIX
, .)
: 
(st_dev) 0/7,
devfs, /dev,
4/0 4/1.

4.24.
, 
. . 4.12 

.
, :
S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR
S_IRWXG = S_IRGRP | S_IWGRP | S_IXGRP
S_IRWXO = S_IROTH | S_IWOTH | S_IXOTH

178

4.

4.12.

S_ISUID

setuserID

( )

S_ISGID

setgroupID

groupexe
cute, 

, 



( )



,
, 



S_ISVTX

sticky


(
)





S_IRUSR

userread

S_IWUSR

userwrite

S_IXUSR

userexecute

S_IRGRP

groupread




S_IWGRP

groupwrite

S_IXGRP

groupexecute

S_IROTH

otherread

S_IWOTH

otherwrite

S_IXOTH

otherexecute


4.25.

179

4.25.
stat. 
stat. , , 
UNIX . 
, 
, UNIX.

4.1. , 4.1, ,
lstat stat. 
, 
?
4.2. , 777
( )?
umask.
4.3. , userread 
.
4.4. , 4.3,
foo bar. ?
4.5. 4.12 ,
. , st_size 
. 
?
4.6. , cp(1),
, 0 .
4.7. ls 4.12: core core.copy
. , 
, ,
umask .
4.8. 4.5
df(1).
du(1)?
4.9. 4.11 , unlink
. ?
4.10. 
myftw 4.21?
4.11. myftw .
, ,
, chdir 
, lstat ,
. chdir("..").
.

180

4.

4.12. ,

.
chroot.
. ?
4.13. utime
?
4.14. finger(1) "New mail re
ceived ..." "unread since ...", 
.
?
4.15. , cpio(1)
tar(1). ( 5 UNIX Pro
grammers Manual.)
?
?
4.16. UNIX
? , , 

. ,
PATH_MAX.
getcwd , 
? UNIX 
?
tar cpio?
4.17. 3.16 /dev/fd/. 
,
rwrwrw. 
,
, 
. :
unlink(path);
if ((fd = creat(path, FILE_MODE)) < 0)
err_sys(...);

, path /dev/fd/1?

5

5.1.
. 
ISO C,
, UNIX. Single
UNIX Specification 
ISO C.
 
 ,

( 3.9). , 
, 
.

1975 . Portable I/O library
(Mike Lesk). , 
30 .

5.2. FILE
, 3, 
. , 
.

. ( (stream) 
 STREAMS, System V
XSI STREAMS Single UNIX
Specification.)
, , .

182

5. -

ASCII . 

. 
, (wide 
) . ,
. 
, , . 
 
(<wchar.h>), 
. 
,
. 
. freopen (
) ,
fwide .
#include <stdio.h>
#include <wchar.h>
int fwide(FILE *fp, int mode);
,
, ,
, 0,

fwide
mode.

mode , fwide 
.

mode , fwide
.

mode 0, fwide 
, , .
: fwide 
. , .
, , errno
fwide
.
, .
fopen
FILE. , , , 
, 
: , 
, , ,
, , 
. .

5.3. ,

183

FILE . 
, FILE
.
FILE, FILE *, .
 
UNIX. , 
.
, ,
UNIX.

5.3. ,


: , 
. , 
STDIN_FILENO, STDOUT_FILENO STDERR_FILENO,
3.2.

stdin, stdout stderr. 
<stdio.h>.

5.4.
, , 
, 
read write. ( . 3.2
 .) , 
 , 
. 
, 
, .
:
1. .  
, 
. 
, . , ,
 
malloc ( 7.8) .
 
flush ().
, , 
fflush. , UNIX flush
. 

184

5. -

. 
, tcflush ( 18),
.
2. .  
, .
( 
fputc), , 
, . 
,
, .

. , ,
 , ,
 ,
, 
. , , 
 () ,
() , 
,
. () , 

. () ,
.
3. .  
. 15 (
, fputs), , 15 
, ,
write ( 3.8).
, , 
. ,
, .
ISO C .

,
, 
.


.

, 

, ,

. 
.

5.4.

185

,
,
.
, , : 
, , 
, , 
.

 
5.12 5.3.

 , .
#include <stdio.h>
void setbuf(FILE *restrict fp, char *restrict buf );
int setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);
0 ,

, 
( , 
), 
, .
setbuf .
, buf
BUFSIZ (,
<stdio.h>). , 
, 
. ,
buf NULL.
setvbuf 
. mode:
_IOFBF
_IOLBF
_IONBF

, buf size 
. , 
buf size .
buf NULL, 
. ( 
BUFSIZ).
C st_blksize
stat ( 4.2), 
. , GNU C .

186

5. -

. 5.1 ,
.
5.1. setbuf setvbuf
mode

buf

setbuf


BUFSIZ

NULL

size

NULL

size

NULL

_IOFBF

setvbuf
_IOLBF

_IONBF ()

,  
, 
. ( 
7.8.) ,
, , , 
, .
, 
. 
 ,
.
.
#include <stdio.h>
int fflush(FILE *fp);
0 , EOF

.
, fp NULL, 
.

5.5.
.

187

5.5.

#include <stdio.h>
FILE *fopen(const char *restrict pathname, const char *restrict type);
FILE *freopen(const char *restrict pathname, const char *restrict type,
FILE *restrict fp);
FILE *fdopen(int filedes, const char *type);

, NULL

.
1. fopen .
2. freopen
, , .
, . 
,
,
.
3. fdopen ,
open, dup, dup2, fcntl, pipe, socket, socketpair accept, 
. 
, 
. 
fopen,
, , 
, fdopen.
, fopen freopen, ISO C. fdopen 
POSIX.1, ISO C .

ISO C 15 type.
. 5.2.
5.2. type
type

r rb

w wb

a ab

r+, r+b, rb+

w+, w+b, wb+

a+, a+b, ab+

188

5. -

b type 
 . UNIX 
, b .
fdopen type .
, 
. ( , 
, open,
O_TRUNC. fdopen ,
.) ,
( 
).
,
.
,  
.
fopen , 4.4BSD, ,
177 [Kernighan Ritchie 1988],
. lseek
. , 
, O_APPEND, 
3.3. lseek 
; 3.11.

( + type),
:


fflush, fseek, fsetpos rewind.

fseek, fset
pos rewind , .
, 
. 5.2, .
5.3. ;

r+

w+

a+

: type a w, 
, ,
open creat 3.

5.6.

189

, , 
, , 
. 
,  
setbuf setvbuf, 
.
fclose.
#include <stdio.h>
int fclose(FILE *fp);
0 , EOF

, , 
. , , .
, 
.
,
exit main,
, .

5.6.

:
1. .
, 
, .
2. . 
, fgets fputs. 
, fgets 
, .
5.7.
3. . 
fread fwrite. 
, . 
, 
.
5.9.
 ISO C : 
,  ,  
.

190

5. -


.
#include <stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
, EOF

getchar getc(stdin). 
, getc
, fgetc . .
1. getc 
.
2. fgetc ,
. fgetc 
.
3. fgetc ,
getc, , 
.
unsigned char, 
int. ,
, 
1. int ,

. EOF, <stdio.h>, 
. 1. ,

EOF.
: 
, . 
, ferror feof.
#include <stdio.h>
int ferror(FILE *fp);
int feof(FILE *fp);
(),
, 0 (),
void clearerr(FILE *fp);

5.6.

191

FILE 
:

clearerr.

ungetc.
#include <stdio.h>
int ungetc(int c, FILE *fp);
, EOF

, ,
, . 
, ISO C
, 
.
.

. (EOF). 
.
,
EOF. , ungetc
.
, 
.
, , 
. ,
getc. 
 , 
, ,
, , .
ungetc,
. 
 .


.
, putchar(c)
putc(c, stdout), putc ,
fputc .

192

5. -

#include <stdio.h>
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);
c
, EOF

5.7. 
.
#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *buf);
buf ,
NULL


. gets , fgets
.
fgets , n.
, 
, n1 .
. ,
, n1 , ,
.
fgets .
gets.
, . 
,
,
. , 
 1988 ,
Communications of the ACM 1989 (vol. 32 no. 6).
gets fgets , gets 
, fgets.
UNIX.
Version 7 (1979) : gets ,
fgets , .

5.8. -

193

ISO C ,
gets, fgets.
puts fputs.
#include <stdio.h>
int fputs(const char *restrict str, FILE *restrict fp);
int puts(const char *str);

, EOF

fputs , , 
. . ,
, 

. 
, .
puts , , 
. ,
.
puts , gets.
,
, . 
fgets fputs, ,
.

5.8.

, 
. ,
5.1, , 3.1

getc putc. 
.
5.1.
getc putc
#include "apue.h"
int
main(void)
{
int c;
while ((c = getc(stdin)) != EOF)

194

5. -
if (putc(c, stdout) == EOF)
err_sys(" ");
if (ferror(stdin))
err_sys(" ");
exit(0);


fgetc fputc, , .
( , 
.)
,
( 5.2).
5.2.
fgets fputs
#include "apue.h"
int
main(void)
{
char buf[MAXLINE];
while (fgets(buf, MAXLINE, stdin) != NULL)
if (fputs(buf, stdout) == EOF)
err_sys(" ");
if (ferror(stdin))
err_sys(" ");
exit(0);
}

: 5.1 5.2
 . , exit 
. ( 
8.5.) , 
, . 3.2.
. 5.4 ( 
98,5 , 3 ).
, 
, ,
. 3.2, 100
, 
3 144 984 . ,
read, 12 611 ( 8 192 ). 

, .

195

5.8. -

5.4.
;

  
()
() () ()

0,01
. 3.2

0,18

6,67

fgets, fputs

2,59

0,19

7,15

139

getc, putc

10,84

0,27

12,07

120

fgetc, fputc

10,44

0,27

11,42

120

161,65

288,64


124,89
. 3.2, 
1

, 
. : 
 , 

. ,  
,
fgets, , .
. 5.4 ,
C. , 
fgetc/fputc , getc/putc.
getc putc ,
GNU C .

, . fgets
fputs getc putc ( 7.7 [Kernighan
and Ritchie 1988]), , 
getc. 
, 
6 200 
. , ,

memccpy(3). memccpy
C, .
, ,
fgetc , 
3.1 BUFFSIZE=1.
200 , 
fgetc 12
,

196

5. -

25 . ,
open 200 ,
200 .
fgetc 200 ,
25222 . 
, .
: , 
, . 
,
UNIX.

. 3.9, 
,  ,
read write. 
, 
getc putc 0,11 
. 
, 
.

5.9. 
5.6 , 5.7
. 
.
getc putc,
, . 
, 
fputs , ,
. fgets
,
.  
.
#include <stdio.h>
size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
size_t fwrite(const void *restrict ptr, size_t size, size_t nobj,
FILE *restrict fp);

:
1. . , 2
5
:

5.9. -

197

float data[10];
if (fwrite(&data[2], sizeof(float), 4, fp) != 4)
err_sys(" fwrite");

size ,
nobj .
2. . :
struct {
short count;
long total;
char name[NAMESIZE];
} item;
if (fwrite(&item, sizeof(item), 1, fp) != 1)
err_sys(" fwrite");

size , nobj 
().

. size (
sizeof), nobj 
.

. fread nobj
, . 
ferror feof. fwrite 
, nobj,
.
,  
, ,
, . ,
UNIX PDP11, , 
. 
.
:
1.
 . 


, , 
. ,

.
2. 
.

198

5. -

,
16. 

. , 
, 8.2 [Rago 1993]
5.18 [Stevens, Fenner, & Rudoff 2004].
fread 8.14,
.

5.10.
:
1. ftell fseek, Version 7.
,
.
2. ftello fseeko. Single
UNIX Specification , 
.
3. fgetpos fsetpos.
ISO C.
fops_t. , 
.
, 
, UNIX, fget
pos fsetpos.
#include <stdio.h>
long ftell(FILE *fp);

, 1L
int fseek(FILE *fp, long offset, int whence);
0 ,

void rewind(FILE *fp);


. , ftell 
, .
fseek, offset
, . whence
, lseek ( 3.6): SEEK_SET 
, SEEK_CUR
SEEK_END . ISO C , 

199

5.11. -

SEEK_END ,
,
. UNIX 
SEEK_END .

. 
, UNIX, 
. , 
whence SEEK_SET, offset 
0, ,
, ftell .
, rewind.
ftello ftell, fseeko
fseek, , long, off_t.
#include <stdio.h>
off_t ftello(FILE *fp);

, (off_t)1
int fseeko(FILE *fp, off_t offset, int whence);
0 ,

off_t 3.6.
off_t , 32 .
, fgetpos fsetpos 
ISO C.
#include <stdio.h>
int fgetpos(FILE *restrict fp, fpos_t *restrict pos);
int fsetpos(FILE *fp, const fpos_t *pos);
0 ,

fgetpos , 
pos. 
fsetpos .

5.11. 


printf.

200

5. -

#include <stdio.h>
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict fp, const char *restrict format, ...);

,
int sprintf(char *restrict buf, const char *restrict format, ...);
int snprintf(char *restrict buf, size_t n, const char *restrict format, ...);
, ,
,

printf , fprintf
, sprintf buf.
sprintf ,
.
: sprintf
, buf. ,

. , 
, snprintf. 
,
. snprintf
, ,
. sprintf, 
. snprintf 
, n, 
, . 
, snprintf .

. 
, 
(%). , , 
. 
, :
%[flags][fldwidth][precision][lenmodifier]convtype

flags . 5.5.
fldwidth 
. 
, . 
(*).
precision 
, ,

5.11. -

201

, 
. precision 
(.),
.
5.5. flags

(,
0x )

fldwidth precision . 

. , 
.
lenmodifier .
. 5.6.
5.6. lenmodifier

hh

signed char unsigned char

signed short unsigned short

signed long, unsigned long

ll

signed long long unsigned long long

intmax_t uintmax_t

size_t

ptrdiff_t

long double

convtype .
. . 5.7.
5.7. convtype

d, i

202

5. -

5.7 ()

x, X

f, F

e, E

g, G

f, F, e E, 

a, A

( l )

( l )

void

( XSI, lc)

( XSI, ls)

printf 
, (...) 
arg.
#include <stdarg.h>
#include <stdio.h>
int vprintf(const char *restrict format, va_list arg);
int vfprintf(FILE *restrict fp, const char *restrict format, va_list arg);

,
int vsprintf(char *restrict buf, const char *restrict format, va_list arg);
int vsnprintf(char *restrict buf, size_t n,
const char *restrict format, va_list arg);
,
,

vsnprintf 
( B).

ISO C 7.3 [Kernighan and Rit
chie 1988]. , 

5.11. -

203

, ISO C,
<stdarg.h> <varargs.h>,
UNIX.


scanf.
#include <stdio.h>
int scanf(const char *restrict format, ...);
int fscanf(FILE *restrict fp, const char *restrict format, ...);
int sscanf(const char *restrict buf, const char *restrict format, ...);

EOF,


scanf 
.
, , ,
.
. 
(%) .
, ,
.  
, ,
.
,
:
%[*][fldwidth][lenmodifier]convtype

(*),
.
,
.
fldwidth .
lenmodifier , 
. scanf 
(lenmodifier), printf (. 5.6).
convtype
printf, .
, ,
, . ,
1 4294967295
. . 5.8 , 
scanf.

204

5. -

5.8. convtype

, 10

( )

, 10 (
)

( )

a, , e, E, f, F, g, G
c

( l )

( l )

void

( XSI, lc)

( XSI, ls)

,
, ]

[^

, ,
]

printf scanf , 
,
<stdarg.h>.
#include <stdarg.h>
#include <stdio.h>
int vscanf(const char *restrict format, va_list arg);
int vfscanf(FILE *restrict fp, const char *restrict format,
va_list arg);
int vsscanf(const char *restrict buf, const char *restrict format,
va_list arg);
EOF,


scanf
UNIX.

5.12.

205

5.12.
,  
, 3. 
 , ,
fileno.
: fileno ISO C 
, POSIX.1.
#include <stdio.h>
int fileno(FILE *fp);
,

, , , 
dup fcntl.
,  
, <stdio.h>. 
FILE, 
, getc, . 8.5
[Kernighan and Ritchie 1988] ,
UNIX. 12 [Plauger 1992]

. ,
 GNU.

, 5.3, 
 ,
.
5.3. ;
#include "apue.h"
void pr_stdio(const char *, FILE *);
int
main(void)
{
FILE *fp;
fputs(" \n", stdout);
if (getchar() == EOF)
err_sys(" getchar");
fputs(" \n",
stderr);
pr_stdio("stdin", stdin);

206

5. -
pr_stdio("stdout", stdout);
pr_stdio("stderr", stderr);
if ((fp = fopen("/etc/motd", "r")) == NULL)
err_sys(" fopen");
if (getc(fp) == EOF)
err_sys(" getc");
pr_stdio("/etc/motd", fp);
exit(0);

}
void
pr_stdio(const char *name, FILE *fp)
{
printf(" = %s, ", name);
/*
* .
*/
if (fp>_IO_file_flags & _IO_UNBUFFERED)
printf(" ");
else if (fp>_IO_file_flags & _IO_LINE_BUF)
printf(" ");
else /* */
printf(" ");
printf(", = %d\n", fp>_IO_buf_end  fp>_IO_buf_base);
}

: , 
, ,

. FILE _IO_file_flags, _IO_buf_base, _IO_buf_end
_IO_UNBUFFERED _IO_LINE_BUFFERED 
GNU, Linux. , 
 UNIX.
,
 , , 
, :
$ ./a.out

stdin, stdout stderr



= stdin, , = 1024
= stdout, , = 1024
= stderr, , = 1
= /etc/motd, , = 4096
$ ./a.out < /etc/termcap > std.out 2> std.err


$ cat std.err

5.13.

207

$ cat std.out

= stdin, , = 4096
= stdout, , = 4096
= stderr, , = 1
= /etc/motd, , = 4096

, 
, .
1024 . ,
1024 
. 2048 
write. 
, 
, 
( st_blksize stat) .
, 
, ,
.

5.13.
ISO C , 
.
#include <stdio.h>
char *tmpnam(char *ptr);

FILE *tmpfile(void);
, NULL

tmpnam ,
. 
TMP_MAX .
TMP_MAX <stdio.h>.
ISO C , 
25. Single UNIX Specification , XSI
TMP_MAX , , 10000. 
(00009999) 
, UNIX
.

ptr NULL, 

. tmpnam
. ( , tmpnam

208

5. -

, , 
, .) 
ptr , , 
L_tmpnam . ( L_tmpnam
<stdio.h>.)
, ptr.
tmpfile (wb+), 
. UNIX
, .

, 5.4,
.
5.4. tmpnam tmpfile
#include "apue.h"
int
main(void)
{
char name[L_tmpnam], line[MAXLINE];
FILE *fp;
printf("%s\n", tmpnam(NULL));
tmpnam(name);
printf("%s\n", name);

/* */
/* */

if ((fp = tmpfile()) == NULL)


err_sys("
fputs(" \n", fp);
rewind(fp);

/* */
tmpfile");
/* */
/* */

if (fgets(line, sizeof(line), fp) == NULL)


err_sys(" fgets");
fputs(line, stdout);
/* */
exit(0);
}

5.4, :
$ ./a.out
/tmp/fileC1Icwc
/tmp/filemSkHSe

, tmpfile : 
tmpnam,
, unlink. 4.15
, unlink
. 
.

5.13.

209

Single UNIX Specification XSI


.
tempnam.
#include <stdio.h>
char *tempnam(const char *directory, const char *prefix);

tempnam tmpnam, 

. ,
.
1. TMPDIR, 
. ( 
7.9.)
2. directory ,
.
3. <stdio.h> P_tmpdir, 
.
4. , /tmp.
prefix , 
, 
.

malloc.
. ( malloc free 
7.8.)

, 5.5,
tempnam.
5.5. tempnam
#include "apue.h"
int
main(int argc, char *argv[])
{
if (argc != 3)
err_quit(": a.out <> <>");
printf("%s\n", tempnam(argv[1][0] != ? argv[1] : NULL,
argv[2][0] != ? argv[2] : NULL));
exit(0);
}

210

5. -

: ( 
) , 
NULL. 
:
$ ./a.out /home/sar TEMP
/home/sar/TEMPsf00zi
$ ./a.out " " PFX
: P_tmpdir
/tmp/PFXfBw7Gi
$ TMPDIR=/var/tmp ./a.out /usr/tmp " "
,
/var/tmp/file8fVYNi
,

$ TMPDIR=/no/such/dir ./a.out /home/sar/tmp QQQ
/home/sar/tmp/QQQ98s8Ui

, ,
, , , . 
(, /no/such/dir), 
. ,
P_tmpdir /tmp.
, 
, TMPDIR , 
Bourne shell, Korn shell bash.
, XSI, mkstemp.
tmpfile, , 
.
#include <stdlib.h>
int mkstemp(char *template);
, 1

.
template,

XXXXXX. ,
. mkstemp
template, .
tmpfile, mkstemp 
. ,
.
tmpnam tempnam : ,
, ,
, .
.

5.14. -

211

tempfile mkstemp, 
.
mktemp, mkstemp, ,
. mktemp ,
, tmpnam tempnam. Single
UNIX Specification mktemp . 
,
.

5.14.

 . [Korn and Vo
1991] ,
, 
.
,
, , 
. 
, fgets fputs,
:  ( 
read write)  
.  (fio(3) [AT&T 1990a])
, , , 
, 
. [Hume 1988] , 
grep(1).
[Korn and Vo 1991] 
 sfio.
fio , 
. , sfio 
, :  
, ,
 
, .
[Krieger, Stumm, and Unrau 1992]
, mmap
( 14.9). ASI, Alloc Stream
Interface ( ).
, UNIX (malloc,
realloc free, 7.8). sfio, ASI

.
, 
, 

212

5. -

. 
, ,
. 
uClibc ( 
http://www.uclibc.org) newlibc (http://sourc;
es.redhat.com/newlib).

5.15.
 
UNIX. , 
, 
. 
,
.

5.1. setbuf set


vbuf.
5.2. 5.8,
 (fgets fputs), ,
MAXLINE 4. ,
, 4 
? .
5.3. 0, printf?
5.4.
. ?
#include <stdio.h>
int
main(void)
{
char c;
while ((c = getchar()) != EOF)
putchar(c);
}

5.5. tempnam 
?
5.6. fsync ( 3.13) 
?
5.7. 1.5 1.8
, fflush.
?

6

6.1.
UNIX 
. /etc/passwd /etc/group
. ,
, 
 ls l.

ASCII, 
. 
.
, ASCII,
,
.
. , ,
, .

6.2.
UNIX, POSIX.1 
, , . 6.1. 
passwd, <pwd.h>.
: POSIX.1 
passwd. . 
, BSD, .

/etc/passwd
ASCII. 
(. . 6.1), . 
/etc/passwd Linux:

214

6.

root:x:0:0:root:/root:/bin/bash
squid:x:23:23::/var/spool/squid:/dev/null
nobody:x:65534:65534:Nobody:/home:/bin/sh
sar:x:205:105:Stephen Rago:/home/sar:/bin/bash

6.1. /etc/passwd

POSIX.1 FreeBSD Linux Mac OS X Sola


passwd
5.2.1
2.4.22 10.3
ris 9
char *pw_name

char *pw_passwd

 uid_t pw_uid

 gid_t pw_gid

char *pw_gecos

char *pw_dir


char *pw_shell

char *pw_class

time_t pw_change

time_t pw_expire

,
root. 0 (
).


. UNIX .
,
, ,
.
, 
.

. , 
, , ( 
). squid
. .

6.2.

215


,
. ,
/bin/sh. , squid
/dev/null.
,
squid .
, ,
( 13). , squid
,  squid.

/dev/null 
.
/bin/false .
( );
.
/bin/true.
( ). 
nologin. 
, .
nobody 
, 65534 
65534, .
, 
. ( 
, 65534 
65534.)
, finger(1), 
. 

, ,
. , 
(&) ( ).
:
sar:x:205:105:Steve Rago, SF 5121, 5551111, 5552222:/home/sar:/bin/sh

finger 
Steve Rago:
$ finger p sar
Login: sar
Name: Steve Rago
Directory: /home/sar
Shell: /bin/sh
Office: SF 5121, 5551111
Home Phone: 5552222
On since Mon Jan 19 03:57 (EST) on ttyv0 (messages off)
No Mail.

216

6.

finger,
,
.
vipw, 
. vipw 

, . 

.
POSIX.1 , 
.

.
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
, NULL

getpwuid ls(1) 
, , 
. getpwnam login(1),
.
passwd.
, 
;
.
POSIX.1 , 

, 
. .
#include <pwd.h>
struct passwd *getpwent(void);
,
NULL
void setpwent(void);
void endpwent(void);

POSIX.1. 
XSI Single UNIX Specification. , , 
UNIX .

217

6.3.

getpwent 
. , getpwent 
passwd. 
.
. , ,
,
/etc/passwd.
setpwent
, endpwent . get
pwent endpwent.
getpwent ,
( ), ,
.

6.1 getpwnam.
6.1. getpwnam
#include <pwd.h>
#include <stddef.h>
#include <string.h>
struct passwd *
getpwnam(const char *name)
{
struct passwd *ptr;
setpwent();
while ((ptr = getpwent()) != NULL)
if (strcmp(name, ptr>pw_name) == 0)
break; /* */
endpwent();
return(ptr);

/* ptr NULL, */

setpwent ;
, 
getpwent. endp
went , getpwnam,
getpwuid .

6.3.
, 
. 
, , 
.

218

6.

(. [Morris and Thompson 1979])


13 64 [azAZ09./].
MD5,
31 . ( 
, 

.) 
, , 
.
, ,
. ( 
, 
Password:.) ,
, 

. 
, . 
,
, 
. ,
. ( 4 [Garfinkel et al.
2003]
, UNIX.)
,
, ;
(shadow password file).
.
, (. 6.2).
6.2. /etc/shadow

spwd
char *sp_namp

char *sp_pwdp

, int sp_lstchg

int sp_min

int sp_max

int sp_warn

int sp_inact

int sp_expire

unsigned int sp_flag

219

6.4.


. ,
.
.
, login(1) pass
wd(1). ,
setuserID.
, /etc/passwd, .
Linux 2.4.22 Solaris 9 
, , 
.
#include <shadow.h>
struct spwd *getspnam(const char *name);
struct spwd *getspent(void);
, NULL
void setspent(void);
void endspent(void);

FreeBSD 5.2.1 Mac OS X 10.3 1,


(. 6.1).

6.4.
UNIX, POSIX.1 ,
, . 6.3. 
group, <grp.h>.
6.3. /etc/group

POSIX.1 FreeBSD Linux Mac OS X Sola


group
5.2.1
2.4.22 10.3
ris 9
char *gr_name

char *gr_passwd

 int gr_gid

char **gr_mem


BSD /etc/mas
ter.passwd. passwd,
. . 6.6. . . .

220

6.

gr_mem ,
. .

POSIX.1 .
#include <grp.h>
struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);
, NULL

, 
, 
.
, 
. , 
.
#include <grp.h>
struct group *getgrent(void);
,
NULL
void setgrent(void);
void endgrent(void);

POSIX.1. 
XSI Single UNIX Specification UNIX.

setgrent , , 
. getgrent
, , .
endgrent .

6.5.
UNIX
. , Version 7
. 
, 
.

newgrp(1). newgrp ( 

), 
,

6.5.

221

. 
, newgrp .
,
4.2BSD ( 1983 .). 4.2BSD 
. 
,
, 16 .
, 
, 
.

POSIX.1. ( POSIX.1 
.) NGROUPS_MAX (. 2.8)
. 16 (. 2.12).

, 
. 
(,
).

.
#include <unistd.h>
int getgroups(int gidsetsize, gid_t grouplist[]);

, 1
#include <grp.h>
/* Linux */
#include <unistd.h> /* FreeBSD, Mac OS X Solaris */
int setgroups(int ngroups, const gid_t grouplist[]);
#include <grp.h>
/* Linux Solaris */
#include <unistd.h> /* FreeBSD Mac OS X */
int initgroups(const char *username, gid_t basegid);
0 , 1

getgroups POSIX.1.
setgroups initgroups , 
. ,
, .
Mac OS X 10.3 basegid int.

getgroups grouplist 
. gidsetsize .
, , 
.

222

6.

gidsetsize 0, 
. grouplist . ( 
grouplist
.)
setgroups 

: grouplist ,
ngroups . ngroups 
NGROUPS_MAX.
setgroups 
initgroups, getgrent,
setgrent endgrent , username.
setgroups, 
.
initgroups, ,
setgroups. 
, username, initgroups
basegid, basegid
, username .
initgroups , 
login(1), initgroups,
.

6.6.
,
Linux Solaris. FreeBSD Mac OS X
. . 6.4 , , 
, .
6.4.

FreeBSD 5.2.1

Linux 2.4.22 Mac OS X 10.3 Solaris 9

/etc/passwd

/etc/passwd

netinfo

/etc/master.passwd /etc/shadow

netinfo

/etc/shadow

/etc/group

netinfo

/etc/group

/etc/group

/etc/passwd

FreeBSD /etc/master.passwd.
, 
/etc/passwd
. , : /etc/pwd.db
/etc/passwd /etc/spwd.db 

6.7.

223

/etc/master.passwd. 
.
Mac OS X /etc/passwd /etc/master.passwd
( 
; ,
). , . . 
, 
netinfo.
Linux Solaris 
, 
. , Solaris . 6.2 
int, Linux long int. , 
, . So
laris ,
, Linux , 
.

Network Information Service (NIS
).

. 
. NIS+ Lightweight Directory
Access Protocol (LDAP ) 
. 

/etc/nsswitch.conf.

6.7.
:
. UNIX 
. ,
BSD /etc/services (
, ), /etc/protocols ( 
) /etc/networks ( ). ,
,
.

:
1. get , 
. .
, . 
get , 
, , 
.

224

6.

2. set , , 
. ,  
.
3. end . ,
.
,
, ,
. , :
getpwnam , getpwuid
.
. 6.5 ,
UNIX. , 
,
, .
get, set end , .
6.5.

 

/etc/passwd

<pwd.h>

passwd

getpwnam, getpwuid

/etc/group

<grp.h>

group

getgrnam, getgrgid

/etc/shadow

<shadow.h>

spwd

getspnam

/etc/hosts

<netdb.h>

hostent

gethostbyname, gethostbyaddr
getnetbyname, getnetbyaddr

/etc/networks <netdb.h>

netent

/etc/protocols <netdb.h>

protoent getprotobyname, getprotobynumber

/etc/services <netdb.h>

servent

getservbyame, getservbyprot

Solaris . 6.5
, /etc/inet. 
UNIX , ,

.

6.8.
UNIX : utmp, 
, wtmp, 

. Version 7 
, :
struct utmp {
char ut_line[8]; /* : "ttyh0", "ttyd0", "ttyp0", ... */

225

6.9.
char ut_name[8]; /* */
long ut_time;
/* */
};

login 
utmp, 
wtmp. init
utmp, , wtmp 
. , , ut_name
. ,
wtmp .
who(1) utmp 
. UNIX last(1),
wtmp .
UNIX utmp wtmp, ,
, . , 20
, Version 7, 36 SVR2,
SVR4 utmp 350 !
Solaris 
utmpx(4). Solaris 9 /var/adm.
Solaris , 
getutx(3).
utmp(5) Linux 2.4.22, FreeBSD 5.2.1 Mac OS X
10.3 . 
/var/run/utmp /var/log/wtmp.

6.9.
POSIX.1 uname,
.
#include <sys/utsname.h>
int uname(struct utsname *name);
, 1

utsname, 
. POSIX.1
, , 
.
.
struct utsname {
char sysname[];
char nodename[];
char release[];
char version[];

/*
/*
/*
/*

*/
*/
*/
*/

226

6.
char machine[]; /* */

};

. . 6.6
,
. , utsname,
uname(1).
POSIX.1 , nodename 
. System V,
, UUCP.
, ,
POSIX.1. _POSIX_VER
SION ( 2.6).
, ;
POSIX.1 .

, BSD, get
hostname, . , 
TCP/IP.
#include <unistd.h>
int gethostname(char *name, int namelen);
0 , 1

namelen name. 
, name 
. , 
, .
gethostname POSIX.1,
, HOST_NAME_
MAX. 
. 6.6.
6.6.

name
FreeBSD 5.2.1

Linux 2.4.22

Mac OS X 10.3

Solaris 9

uname

256

65

256

257

gethostname

256

64

256

256

TCP/IP, 
(fully qualified domain name).
, hostname(1),
. ( 
sethostname.) , 

227

6.10.

, 
/etc/rc init.

6.10.
UNIX 
, 00:00:00 1 1970 
(UTC). 1.10 ,
time_t ;
.
, . UNIX
, () UTC, , () 
, , () 
.
time .
#include <time.h>
time_t time(time_t *calptr);
, 1

.
calptr ,
.
, .
, , System V, stime(2),
, BSD, settimeofday(2).
Single UNIX Specification ,
.

gettimeofday , time
( ). .
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
0

Single UNIX Specification 


XSI. tzp NULL;
. 
tzp,
Single UNIX
Specification.

228

6.

gettimeofday , 
, tp.
timeval, :
struct timeval {
time_t tv_sec; /* */
long tv_usec; /* */
};

, 
, , 
, .
. 6.1 
.


as

im

ct

ft

im

r
st

(, )

struct tm

mktime

localtime

gmtime

ctime

time_t

( )

time

. 6.1.

( , 
, localtime, mktime, ctime strftime 
TZ, .)
, localtime gmtime, 
tm, :
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;

/*
/*
/*
/*
/*
/*
/*
/*
/*

, */
: [0  60] */
: [0  59] */
: [0  23] */
: [1  31] */
: [0  11] */
1900 */
: [0  6] */
(1 ): [0  365] */

229

6.10.
int tm_isdst; /* : <0, 0, >0 */
};

59,
. ,
, , 0.
, , 0
, .
Single UNIX Specification 
. , tm_sec 061. 
UTC ,
060.
#include <time.h>
struct tm *gmtime(const time_t *calptr);
struct tm *localtime(const time_t *calptr);
tm

localtime gmtime , 
,
, UTC .
mktime tm
time_t.
#include <time.h>
time_t mktime(struct tm *tmptr);
, 1

asctime ctime 26 , 
date(1):
Tue Feb 10 18:27:38 2004\n\0
#include <time.h>
char *asctime(const struct tm *tmptr);
char *ctime(const time_t *calptr);
,

asctime tm,
ctime .
, strftime.
printf .

230

6.

#include <time.h>
size_t strftime(char *restrict buf, size_t maxsize,
const char *restrict format,
const struct tm *restrict tmptr);
, ,
, 0

tm, 
, .
buf, 
maxsize.
, , ,

. 0.
format . 
printf, 
, .
format . ,
, .
printf,

. . 6.7 37 , 
ISO C. 
strftime Linux, Tue Feb 10 18:27:38 EST 2004.
6.7. strftime


%a

Tue

%A

Tuesday

%b

Feb

%B

February

%c

Tue Feb 10
18:27:38 2004

%C

20

%d

: [0131]

10

%D

: [MM/DD/YY]

02/10/04

%e

( 0 ): [131] 10

%F

ISO 8601: [YYYYMMDD]

%g

ISO 8601, 04
: [0099]

20040210

231

6.10.


%G

ISO 8601,

2004

%h

, %b

Feb

%H

( 24 ): [0023]

18

%I

( 12 ): [0012]

06

%j

: [001366]

041

%m

: [0112]

02

%M

: [0059]

27

%n

%p

AM PM ( )

PM

%r

12

06:27:38 PM

%R

, %H:%M

18:27

%S

: [0060]

38

%t

%T

, %H:%M:%S

%u

ISO 8601 [=1, 2


17]

%U

, : 06
[0153]

%V

ISO 8601: [0153]

07

%w

[=0, 06]

%W

,  06
: [0053]

%x

02/10/04

%X

18:27:38

%y

: [0099]

04

%Y

2004

%z

UTC

0500

%Z

EST

%%

18:27:38

, : %U, %V %W. 
%U , , 
. %W 
, , 
. %V . 
, 1 , 4 ,

232

6.

, 
. 
.
printf, strftime
. O E 
,
.
,
strftime.

, , . 6.1
, TZ
localtime, mktime, ctime strftime. 
, 
. , TZ=,
UTC.
TZ=EST5EDT, POSIX.1
. 
TZ Environment Variables
Single UNIX Specification [Open Group 2004].
,
gettimeofday, ISO C. TZ 
POSIX.1. FreeBSD 5.2.1, Linux 2.4.22 Mac OS X 10.3 

tzset(3). Solaris 9 environ(5).

6.11.
UNIX .
. 
, 
.
. ,
,
. POSIX.1 
, 
, . ,

ISO C Single UNIX Specification.

6.11.

233

6.1. , 
. 
?
6.2. , 
,
.
6.3. , uname 
utsname. 
, uname(1).
6.4. ,
time_t. , 
?
6.5. , 
strftime ,
, date(1) . 
TZ , .

7

7.1.
, 
,
. ,
main , 
, ,
, 
.
longjmp setjmp . , 
.

7.2. main
C main. 
:
int main(int argc, char *argv[]);

argc , argv 
. 7.4.
C (
exec, 8.10), 
main .

. ,
C.
, 
main.

7.3.

235

7.3.
.
:
1. main.
2. exit.
3. _exit _Exit.
4. ( 11.5).
5. pthread_exit ( 11.5) .
:
6. abort ( 10.17).
7. ( 10.2).
8. ( 11.5 12.7).
, , 11
12, .

, 
, , exit,
main. C
( ), main
:
exit(main(argc, argv));

exit
:
_exit _Exit, , exit,

.
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);

8.5 , 
, .
,
_exit _Exit ISO C, exit 
POSIX.1.

236

7.

exit 
, fclose . 
5.5 , (
).

, . 
UNIX .
, ()
, () main
return () main
. main, 
, 
( ), 
0.
ISO C 1999 .
, main
return exit.

main
exit . ,
exit(0);

,
return(0);

main.

7.1 , !
7.1. C
#include <stdio.h>
main()
{
printf(", !\n");
}

, , 
.
, , ,

main:
$ cc hello.c
$ ./a.out
, !
$ echo $?
13

7.3.

237

, 
1999 ISO C, , :
$ cc std=c99 hello.c
1999 ISO C gcc
hello.c:4: warning: return type defaults to `int
$ ./a.out
, !
$ echo $?

0

, 
1999 ISO C. ,
main .
, . ,
( Wall), 
, : control reaches end
of nonvoid function ( , ).
main 
exit return 
lint(1).
, main exit , 
return. , 
, 
return exit. , , 

grep. main 
void int exit.
, (
) , , 
, , main 
. main
, ISO C POSIX.1.

. : GNU C 
, ,
.

,
, .

atexit
ISO C
32 , exit.

atexit.
#include <stdlib.h>
int atexit(void (*func)(void));
0 ,

238

7.

, atexit 
. 
, .
exit , 
. ,
.
ANSI C 1989 . ,
, SVR3 BSD4.3, 
.
ISO C ,
32 . 
sysconf (. 2.10).

ISO C POSIX.1, exit 



( fclose). POSIX.1 
ISO C, , 
, exec.
. 7.1 , , 
C.
: 
exec. 

main

_exit

_Exit

_exit

_Exit

( e
x
it




)
exit
(
)

it
ex )


(

exit

_exit

_Exit


. . .

exec

. 7.1. , C

7.3.

239

_exit _Exit,
( exit). 
( . 7.1).

, 7.2,
atexit.
7.2.
#include "apue.h"
static void my_exit1(void);
static void my_exit2(void);
int
main(void)
{
if (atexit(my_exit2) != 0)
err_sys(" my_exit2");
if (atexit(my_exit1) !=
err_sys("
if (atexit(my_exit1) !=
err_sys("

0)
my_exit1");
0)
my_exit1");

printf(" main \n");


return(0);
}
static void
my_exit1(void)
{
printf(" \n");
}
static void
my_exit2(void)
{
printf(" \n");
}

:
$ ./a.out
main


, 
. 7.2
, . ,
exit , return.

240

7.

7.4.
, exec, 
.
UNIX, 
.

, 7.3, 
. :
echo(1) .
7.3.
#include "apue.h"
int
main(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++) /* */
printf("argv[%d]: %s\n", i, argv[i]);
exit(0);
}

echo
arg, :
$ ./echoarg arg1 TEST foo
argv[0]: ./echoarg
argv[1]: arg1
argv[2]: TEST
argv[3]: foo

ISO C POSIX.1, argv[argc]


. ,
:
for (i = 0; argv[i] != NULL; i++)

7.5.
, , 
.
, 
, ,
. 
environ:
extern char **environ;

241

7.6. C


HOME=/home/sar\0

environ:

PATH=:/bin:/usr/bin\0
SHELL=/bin/bash\0
USER=sar\0
LOGNAME=sar\0
NULL

. 7.2. ,

, , ,
, . 7.2. 
, . environ ;
, ;
, , , .

(. 7.2):
name=value


, .
UNIX main 
, :
int main(int argc, char *argv[], char *envp[]);

ISO C main,

environ.
POSIX.1 , 
main, 
environ ( ). 
getenv
putenv, 7.9, 
environ.
environ.

7.6. C
C :
, , 
. ,

242

7.


, , C,
. , 
,
.
, 
. , 
. ,

int maxcount = 99;

 ,

.
,
bss. ,
block started by symbol (, 
).

.
long sum[1000];

, 

.
(stack), 
, ,
.

, . 

. 
C . , 
, ,

.
(heap), . 

.

. 7.3 .
, ; 
.
, 
. Linux Intel x86 
0x8048000, 
0xC0000000 ( 

243

7.7.

(bss)

exec


exec

. 7.3.

). 
.
a.out ,
, , 
. 
, .

, . 7.3
.
, . , 
, 
.
size(1) ( ) , bss.
:
$ size /usr/bin/cc /bin/sh
text
data
bss
dec
hex
79606
1536
916 82058 1408a
619234 21120 18260 658614 a0cb6

filename
/usr/bin/cc
/bin/sh

7.7.
UNIX 
. [Arnold 1986] 
System V, [Gingel et al. 1987] SunOS.

244

7.


; 
, . 
, , 

.
,
, 
. ( , 
.)
, , 
.
cc(1) ld(1) . , 
hello.c
:
$ cc static hello1.c

$ ls l a.out
rwxrwxrx 1 sar
475570 Feb 18 23:17 a.out
$ size a.out
text
data
bss
dec
hex
filename
375657
3780 3220 382657 5d6c1
a.out


, :
$ cc hello1.c
gcc
$ ls l a.out
rwxrwxrx 1 sar 11410 Feb 18 23:19 a.out
$ size a.out
text
data
bss
dec
hex
filename
872
256
4 1132
46c
a.out

7.8.
ISO C ,
:
1. malloc .
.
2. calloc 
. 
.
3. realloc , 
. 
.
, , 
, .

245

7.8.

#include <stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);

, NULL
void free(void *ptr);

, 
, . 
, ,
double , 8, 
, , , 8.
void*, ,
<stdlib.h> ( 
), 
.
free ,
ptr. , ,

.
realloc 
. ( 
.) , 512 
, 
512 ,
realloc. , 
, realloc 
,
, . ,
,
realloc 
512 ,
.
, 
. 4.16 ,
realloc getcwd,
. 17.28 
realloc ,
.
, realloc 
, 
. , ptr , re
alloc malloc newsize.

246

7.

realloc
, free mal
loc, realloc calloc. Version 7
, malloc .
Solaris , .
.


sbrk(2). ( ) 
() (. 7.3).
malloc free 8.7 [Kernighan and Ritchie 1988].
sbrk(2) , 
, malloc free 
. 
, ,
malloc.
, 
, , 
: ,
. 
, 
.
,
. , 
,
.

. 
.
,
.
, 
, ,
free ,
. malloc,
free,
; . 
free, 
, , 
, . 

.
, 
,
, 
. 

7.8.

247

. , 
,
,
.
FreeBSD, Mac OS X Linux 
. , Free
BSD /etc/
malloc.conf.


,
malloc free. , 
. 
, 
,
. .

libmalloc
, SVR4, Solaris,
libmalloc, , 
ISO C. lib
malloc mallopt, 
,
. , mallinfo,

.

vmalloc
[Vo 1996] , 

. , vmalloc 
, 
ISO C.

quickfit

(bestfit),
(firstfit). quickfit ( ) 
, . [Wein
stock and Wulf 1988] ,

. 
free malloc quickfit 
FTP.

248

7.

alloca
, . alloca 
, malloc, 
,
. ,

. alloca
. , 
, 
. 
, .
, , alloca.

7.9.
, 

name=value

UNIX ; 
. , ,
. 
, HOME USER,
, . 

. , , 
MAILPATH, Bourne shell,
GNU Bourneagain shell Korn shell ,
.
ISO C ,
, ,
.
#include <stdlib.h>
char *getenv(const char *name);

name NULL,

,
value name=value. 
, getenv
environ.
Single UNIX Specification 
POSIX.1, , 

249

7.9.

XSI. . 7.1
, Single UNIX Specification, ,
. , 
POSIX.1, , 
XSI. , , 
. 
, ISO C .
7.1. ,
Single UNIX Specification
 POSIX.1 FreeBSD Linux Mac OS Sola

5.2.1
2.4.22 X 10.3 ris 9
COLUMNS

DATEMSK

XSI


getdate(3)

HOME

LANG

(
)

LC_ALL

(
)

LC_COLLATE

(
)

LC_CTYPE

(
) 

LC_MESSAGES

(
) 

LC_MONETARY

(
) 

LC_NUMERIC

(
) 

LC_TIME

(
) 

LINES

LOGNAME

MSGVERB

XSI


, 
fmtmsg(3)

250

7.

7.1 ()
 POSIX.1 FreeBSD Linux Mac OS Sola

5.2.1
2.4.22 X 10.3 ris 9
XSI

PATH

,


PWD

SHELL

TERM

TMPDIR

TZ

NLSPATH

,
. (
, 
. 
, 
. 
.) ,
. . 7.2 , 
.
7.2.

ISO C POSIX.1 FreeBSD 5.2.1 Linux 2.4.22

putenv

XSI

setenv

unsetenv

clearenv

Mac OS X 10.3 Solaris 9

getenv

clearenv Single UNIX Specification.


.

,
. 7.2.

251

7.9.

#include <stdlib.h>
int putenv(char *str);
int setenv(const char *name, const char *value, int rewrite);
int unsetenv(const char *name);
0 ,

putenv name=value
. name 
, .

setenv name value. 


name , : ()
rewrite , 
; () rewrite , 
, value
.
unsetenv name.
, .

putenv setenv. setenv


, name=value , putenv 

. Linux Solaris putenv , 
, 
. , ,
, 
.

,
. . 7.3:
name=value,

. ;

. 
.
,
;
, ,
.
1. name:
. value ,
.

252

7.

. value , 
malloc, 

.
2. , .
malloc, 
name=value .
. , , 
malloc . 
,
, , 
. , environ
. : 
(. 7.3),
( ). 

, .
. ,
, . ,
realloc, 
, name=value ( 
) .

7.10. setjump longjump


C ( goto) ,
. 
setjmp longjmp. ,
, 
.
 7.4.
, 
do_line.
get_token, 
. , 
, switch , .
cmd_add.
7.4
, ,
, . . 7.4 , 
cmd_add.
7.4.
#include "apue.h"
#define TOK_ADD 5

253

7.10. setjump longjump



main


do_line


cmd_add

. 7.4. cmd_add
void do_line(char *);
void cmd_add(void);
int get_token(void);
int
main(void)
{
char line[MAXLINE];
while (fgets(line, MAXLINE, stdin) != NULL)
do_line(line);
exit(0);
}
char *tok_ptr;

/* get_token() */

void
do_line(char *ptr) /* */
{
int cmd;
tok_ptr = ptr;
while ((cmd = get_token()) > 0) {
switch (cmd) {
/* case */
case TOK_ADD:
cmd_add();
break;
}
}
}
void
cmd_add(void)
{
int token;
token = get_token();
/* */

254

7.

}
int
get_token(void)
{
/* , tok_ptr */
}


. line
main, cmd
do_line, token cmd_add.
, ,
.
. , 
, C
.
, 7.4,
, . ,
cmd_add , ,
,
main, 
.
, C . (
cmd_add
main, , , 
.) 
,
, .

: setjmp longjmp. ,
C, 
, 
.
#include <setjmp.h>
int setjmp(jmp_buf env);
0, , ,
longjmp
void longjmp(jmp_buf env, int val);

setjmp , ;
main. setjmp 
0, . 
env setjmp jmp_buf.
, ,

7.10. setjump longjump

255

,
longjmp. env ,
.
, , cmd_add, longjmp
. env,
setjmp, val, , , 
setjmp. 
longjmp setjmp. , 
longjmp cmd_add 
val, 1, get_token val, 2.
setjmp main 1, 2,
, cmd_add get_token.
. 7.5
cmd_add main. ( , do_line get_token, 
.)
7.5. setjmp longjmp
#include "apue.h"
#include <setjmp.h>
#define TOK_ADD 5
jmp_buf jmpbuffer;
int
main(void)
{
char line[MAXLINE];
if (setjmp(jmpbuffer) != 0)
printf("");
while (fgets(line, MAXLINE, stdin) != NULL)
do_line(line);
exit(0);
}
...
void
cmd_add(void)
{
int token;
token = get_token();
if (token < 0) /* */
longjmp(jmpbuffer, 1);
/* */
}

main, setjmp
jmpbuffer 
0. do_line,

256

7.



main

. 7.5. longjmp

cmd_add. , 
. longjmp cmd_add , 
. 7.4. longjmp
main, ,
cmd_add do_line (. 7.5). longjmp
setjmp main,
1 ( longjmp).

register,
automatic volatile
, longjmp.
, ,
main? 
longjmp main, 
, setjmp (
),
do_line ( cmd_add,
longjmp)? ,
: .
, 
, .
,
, volatile. longjmp
.

, 7.6, 
, , , volatile
, longjmp.
7.6. longjmp

#include "apue.h"
#include <setjmp.h>

7.10. setjump longjump

257

static void f1(int, int, int, int);


static void f2(void);
static jmp_buf jmpbuffer;
static int globval;
int
main(void)
{
int autoval;
register int regival;
volatile int volaval;
static int statval;
globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5;
if (setjmp(jmpbuffer) != 0) {
printf(" longjmp:\n");
printf("globval = %d, autoval = %d, regival = %d,"
" volaval = %d, statval = %d\n",
globval, autoval, regival, volaval, statval);
exit(0);
}
/*
* setjmp, longjmp.
*/
globval = 95; autoval = 96; regival = 97; volaval = 98;
statval = 99;
f1(autoval, regival, volaval, statval); /* */
/* */
exit(0);
}
static void
f1(int i, int j, int k, int l)
{
printf(" f1():\n");
printf("globval = %d, autoval = %d, regival = %d,"
" volaval = %d, statval = %d\n", globval, i, j, k, l);
f2();
}
static void
f2(void)
{
longjmp(jmpbuffer, 1);
}


, :
$ cc testjmp.c
$ ./a.out

258

7.

f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval
longjmp:
globval = 95, autoval = 96, regival = 97, volaval = 98, statval
$ cc O testjmp.c
$ ./a.out
f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval
longjmp:
globval = 95, autoval = 2, regival = 3, volaval = 98, statval =

= 99
= 99

= 99
99

: 
, , 
volatile; longjmp 
. setjmp(3)
, , ,
, longjmp, ,

, , 
setjmp. ,
7.6. 
, ( register
regival ). , 
autoval regival ( ,
register), ,
volatile, .
, 
, volatile.
, .
7.6,
printf, , . 
printf, 
, ISO C, 

"string1" "string2"


"string1string2"

setjmp longjmp 10, 


:
sigsetjmp siglongjmp.



,
,

7.11. getrlimit setrlimit

259

. 
, ,
, . 
UNIX.
7.7 open_data, 
.
7.7.
#include <stdio.h>
#define DATAFILE "datafile"
FILE *
open_data(void)
{
FILE *fp;
char databuf[BUFSIZ]; /*setvbuf */
if ((fp = fopen(DATAFILE, "r")) == NULL)
return(NULL);
if (setvbuf(fp, databuf, _IOLBF, BUFSIZ) != 0)
return(NULL);
return(fp); /* */
}

, , open_data , 
, , 
. 
 
. . , 
databuf , (static extern)
( ).

7.11. getrlimit setrlimit


. 

getrlimit setrlimit.
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlptr);
int setrlimit(int resource, const struct rlimit *rlptr);
0 ,

Single UNIX Specification XSI.



0 
. 
.

260

7.

(re
source) :
struct rlimit {
rlim_t rlim_cur; /* : */
rlim_t rlim_max; /* : rlim_cur */
};


:
1. , ,
.
2.
.
.
3. , ,
.
RLIM_INFINITY.
resource .
RLIMIT_AS

( ).
sbrk ( 1.11) mmap (
14.9).

RLIMIT_CORE

(core). 0 
core.

RLIMIT_CPU

. 
SIGXCPU.

RLIMIT_DATA

: 
, 
(. 7.3).

RLIMIT_FSIZE

.
SIGXFSZ.

RLIMIT_LOCKS

, 
. (
, (leases),
Linux.
fcntl(2) Linux.)

RLIMIT_MEMLOCK ,
mlock(2), .
RLIMIT_NOFILE . 
, 
sysconf _SC_OPEN_MAX ( 2.5.4 2.4).
RLIMIT_NPROC


.
, sysconf _SC_CHILD_MAX
( 2.5.4).

261

7.11. getrlimit setrlimit

RLIMIT_RSS

, 
, . 
, 
, .

RLIMIT_SBSIZE , 
, .
RLIMIT_STACK

(. 7.3).

RLIMIT_VMEM

RLIMIT_AS.

. 7.3 ,
Single UNIX Specification 
.
7.3.

XSI

FreeBSD 5.2.1

Linux 2.4.22

Mac OS X 10.3

Solaris 9

RLIMIT_AS

RLIMIT_CORE

RLIMIT_CPU

RLIMIT_DATA

RLIMIT_FSIZE

RLIMIT_LOCKS

RLIMIT_NPROC

RLIMIT_RSS

RLIMIT_SBSIZE

RLIMIT_MEMLOCK
RLIMIT_NOFILE

RLIMIT_STACK
RLIMIT_VMEM


. ,

, , .
, Bourne shell, GNU Bourneagain
shell Korn shell ulimit, 
C shell limit. ( umask chdir 
.)

, 7.8, 
, .

262

7.

UNIX,

,
. , printf
, 
rlim_t unsigned long long unsig
ned long.
7.8.
#include "apue.h"
#if defined(BSD) || defined(MACOS)
#include <sys/time.h>
#define FMT "%10lld "
#else
#define FMT "%10ld "
#endif
#include <sys/resource.h>
#define doit(name) pr_limits(#name, name)
static void pr_limits(char *, int);
int
main(void)
{
#ifdef RLIMIT_AS
doit(RLIMIT_AS);
#endif
doit(RLIMIT_CORE);
doit(RLIMIT_CPU);
doit(RLIMIT_DATA);
doit(RLIMIT_FSIZE);
#ifdef RLIMIT_LOCKS
doit(RLIMIT_LOCKS);
#endif
#ifdef RLIMIT_MEMLOCK
doit(RLIMIT_MEMLOCK);
#endif
doit(RLIMIT_NOFILE);
#ifdef RLIMIT_NPROC
doit(RLIMIT_NPROC);
#endif
#ifdef RLIMIT_RSS
doit(RLIMIT_RSS);
#endif
#ifdef RLIMIT_SBSIZE
doit(RLIMIT_SBSIZE);
#endif
doit(RLIMIT_STACK);
#ifdef RLIMIT_VMEM
doit(RLIMIT_VMEM);

263

7.11. getrlimit setrlimit


#endif
exit(0);
}
static void
pr_limits(char *name, int resource)
{
struct rlimit limit;
if (getrlimit(resource, &limit) < 0)
err_sys(" getrlimit %s", name);
printf("%19s ", name);
if (limit.rlim_cur == RLIM_INFINITY)
printf("()");
else
printf(FMT, limit.rlim_cur);
if (limit.rlim_max == RLIM_INFINITY)
printf("()");
else
printf(FMT, limit.rlim_max);
putchar((int)\n);
}

, doit ,
, (#),
ISO C. ,
doit(RLIMIT_CORE)

C
pr_limits("RLIMIT_CORE", RLIMIT_CORE);

FreeBSD, :
$ ./a.out
RLIMIT_CORE
RLIMIT_CPU
RLIMIT_DATA
RLIMIT_FSIZE
RLIMIT_MEMLOCK
RLIMIT_NOFILE
RLIMIT_NPROC
RLIMIT_RSS
RLIMIT_SBSIZE
RLIMIT_STACK
RLIMIT_VMEM

()
()
536870912
()
()
1735
867
()
()
67108864
()

()
()
536870912
()
()
1735
867
()
()
67108864
()

()
()
()

()
()
()

Solaris:
$ ./a.out
RLIMIT_AS
RLIMIT_CORE
RLIMIT_CPU

264
RLIMIT_DATA
RLIMIT_FSIZE
RLIMIT_NOFILE
RLIMIT_STACK
RLIMIT_VMEM

7.
()
()
256
8388608
()

()
()
65536
()
()


10.11.

7.12.
UNIX, C, 
UNIX.
, ,

. ,
, ,
exec .
,
C, 
. ,
. setjmp
longjmp, 
. ,
.

7.1. FreeBSD Linux 


x86 , !, 
exit return 
main, 13 ( 
). ?
7.2. ,
printf 7.2?
7.3. 
, main, , () 
argc argv
()
.
7.4. UNIX 
. ?
7.5. typedef Exitfunc
 . atexit
.

7.12.

265

7.6. long cal


loc, 
?
calloc,
?
7.7. 7.6 
size?
7.8. 7.7 (475570 11410)
?
7.9. 7.7 

?
7.10. 7.10 ,

. , ?
int
f1(int val)
{
int *ptr;
if (val == 0) {
int val;
val = 5;
ptr = &val;
}
return(*ptr + 1);
}

8

8.1.
UNIX. 
, .
, 
,

.
system. , 
UNIX . 
.

8.2.
,
.
, 
, 
. , 
, 
.

.
.
UNIX , 
,
,
. , 

.

8.2.

267

, 
. 0 , , 
, swapper ( ). 
, 
. 1
init, 
. UNIX
/etc/init, /sbin/init. 
. init 
/etc/rc* /etc/inittab,
, /etc/init.d, 
, . init 
. ,
, swapper, 
. , init
.
UNIX , 
. , 
UNIX 2 pagedaemon.

.
, 
. , 
:
#include <unistd.h>
pid_t getpid(void);

pid_t getppid(void);

uid_t getuid(void);


uid_t geteuid(void);


gid_t getgid(void);


gid_t getegid(void);

268

8.

,
. ,
fork.
4.4.

8.3. fork
,
fork.
#include <unistd.h>
pid_t fork(void);
0 ,
, 1

, fork, ;
, ;. , 
,
0, 
. , 
,
,
. fork 0, 

getppid. (
0 , 0 
.)
, 
, fork. 
. ,
, 
. , ;
. 
( 7.6).
UNIX 
, ,
fork exec. ,
(copy;on;write, COW).
,
. 
,
; .
9.2 [Bach 1986] 
5.6 5.7 [McKusik et al. 1996].

8.3. fork

269

fork.
, , vfork(2),
.
, Linux 2.4.22 
clone(2). fork,
, 
.
FreeBSD 5.2.1 rfork(2),
clone Linux Plan 9 ([Pike et al. 1995]).
Solaris 9 :
POSIX (pthreads) Solaris. fork 
. POSIX fork , 
, Solaris , 
. , 
POSIX, Solaris fork1, 
,
, . 
11 12.

, 8.1, 
fork , 
.
8.1. fork
#include "apue.h"
int glob = 6; /* */
char buf[] = " stdout\n";
int
main(void)
{
int var; /* , */
pid_t pid;
var = 88;
if (write(STDOUT_FILENO, buf, sizeof(buf)1) != sizeof(buf)1)
err_sys(" write");
printf(" fork\n"); /* */
/* stdout */
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) {
/* */
glob++;
/* */
var++;
} else {
sleep(2);
/* */
}
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);

270

8.
exit(0);

:
$ ./a.out
stdout
fork
pid = 430, glob = 7, var =
pid = 429, glob = 6, var =
$ ./a.out > temp.out
$ cat temp.out
stdout
fork
pid = 432, glob = 7, var =
fork
pid = 431, glob = 6, var =

89
88

89
88

, , 
fork .
, .

, .
8.1 
2 , 
. , 
. 
8.9, . 10.6 
,
fork.
, 1 buf,
. ,
strlen
, sizeof ,
. : strlen 
, sizeof 
, 
.
, fork 8.1
. 3 ,
write . write 
fork, . 
,  . 
5.12 ,
, , 
.
, ,
printf, ,
. 

8.3. fork

271

, .
fork printf ,
fork .

. , 
,
. printf, 
exit, 
. 
.


8.1 
, 
. 
, fork ,
, 
. , 
,
dup. 

( . 3.3).
, : ,
. 
fork , 
. 8.1.
, , 
. ,
. ,
.

(, ), , 
,
, .

, .

, , 
, . 
, 
, 
.
, 
 , ,
, 

272

fd 0:
fd 1:
fd 2:
...

8.

fd 0:
fd 1:
fd 2:
...

. 8.1.
fork

( fork).
. 8.1, 
.

fork.
1. , .

. , 
, 
, .
2. ,
. fork
, , 
. , 
. 
.

, :
, 
, , 
.

8.3. fork

273

.
.
.
.
setuserID setgroupID.
.
.
.
.
closeonexec .
.
.
.
.


:
fork .
.
:

, 
.
tms_utime, tms_stime, tms_cutime tms_cstime
0.
, , 
.
, , .
, , .
;
.
fork : ()
, 
, ()

. . 2.10 , 

CHILD_MAX.
, fork:
1. , 


274

8.

. . 
,
fork , 
.
2. . 
.
exec ( 8.10), 
fork .
fork
exec , spawn. UNIX 
, 
fork exec. , 
fork exec
, , 
, , . . 
, , 15.
, Single UNIX Specification spawn 
. fork exec.
, 
fork, , 
.

8.4. vfork
vfork fork ,
.
vfork 2.9BSD.
UNIX, , ,
. vfork 4.4BSD,
BSD , 4.4BSD, 
. Single UNIX Specification vfork 
.

vfork ,
exec
( 2 ). 1.5
. vfork
, fork,
, 
exec
( exit) , vfork . ,
exec exit 
.
UNIX. ( 
, fork exec
,

8.4. vfork

275

,
.)
vfork , 
, 
exec exit.
, . ( 
, 
, 
.)

, 8.2, 
8.1. fork vfork 
.
sleep, vfork 
, ,
exec exit.
8.2. vfork
#include "apue.h"
int glob = 6; /* */
int
main(void)
{
int var; /* */
pid_t pid;
var = 88;
printf(" vfork\n"); /* stdout */
if ((pid = vfork()) < 0) {
err_sys(" vfork");
} else if (pid == 0) {
/* */
glob++;
/* */
var++;
_exit(0);
/* */
}
/*
* .
*/
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
}

:
$ ./a.out
vfork
pid = 29039, glob = 7, var = 89

276

8.

, ,
. , 
, 
. , 
fork.
, 8.2 exit 
_exit. 7.3, _exit
. exit, 
.
 ,
, printf .
exit,
 . 
, ,
_exit. ,
, , 
FILE , .

,
printf, (1). 
, STDOUT_FILENO
, 
(. 8.1).
exit 
. , 
, .
.

fork vfork
[McKusik et al. 1996], 5.6. vfork
8.1 8.2.

8.5. exit
7.3
:
1. main. 7.3, 
exit.
2. exit. ISO C, 
 ,
atexit, . 
ISO C , 
( ) , 
UNIX .

8.5. exit

277

3. _exit _Exit. ISO C


_Exit 
.
,  .
UNIX _exit _Exit , 
. _exit
exit , UNIX. _exit 
POSIX.1.
UNIX exit(3) ,
_exit(2) .

4. .

.
, 0.
5. pthread_exit . 
, 0,
pthread_exit .
11.5.
:
1. abort. ,
SIGABRT.
2. . ( 
10.)
(, abort),
. ,
, 
, .
3. .
: 
,  
. 11.5 12.7.
, ,
.
, . .
,
, 
. (exit, _exit _Exit)
. 
,
. 
wait waitpid (
).

278

8.

, 

main, . 
, _exit (. 7.1). . 8.1 
, 
.
, .
fork, , 
fork. 
. 
, ? :
,
, init. ,
init. 
, , 
 . ,
, , 
1 ( init).
.
,
.
,
, .
, 
, wait waitpid. 
,
,
. , , 
. UNIX , 
, , . 
ps(1)  Z.
, 
, , 
.
; 300
10.7 , .

, , , 
init. ? , init 
, , , init 
wait, .
init .
init , 
init (, getty, 9.2),
, .

279

8.6. wait waitpid

8.6. wait waitpid


, ,
SIGCHLD. 
(
), 
, .
,
.
. 
10. , wait waitpid,
, :
, 
.
, 
, 
.
,
.
wait SIGCHLD,
. wait
, 
.
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);

, 1

:
wait , 
,
waitpid .
waitpid
, .
,
wait
.
, . 
, wait 
, . 
, , 
.

280

8.

statloc
. , 
.
, .
, ,
.
( ),
( ), ,
( core), . . POSIX.1
<sys/wait.h> ,
. , 
, , 
WIF. , 
, ,
, . 
. 8.1.
8.1. ,
wait waitpid

WIFEXITED (status)

true, status 
. 
8 , exit,
_exit _Exit, :
WEXITSTATUS(status)

WIFSIGNALED (status) true, status 


() , 
, . 
, 
, :
WTERMSIG(status)
, ( Single UNIX
Specification)
WCOREDUMP(status)
true, 
(core)
WIFSTOPPED (status)

true, status 
. 
, , 

WSTOPSIG(status)

WIFCONTINUED (status) true, status 


, (
XSI POSIX.1 waitpid)

8.6. wait waitpid

281

9.8, , ,
.

pr_exit, 8.3,
. 8.1 , . 
. :
WCOREDUMP, .
8.3. ,
#include "apue.h"
#include <sys/wait.h>
void
pr_exit(int status)
{
if (WIFEXITED(status))
printf(" , = %d\n",
WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf(" , = %d%s\n",
WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? " ( core)" : "");
#else
"");
#endif
else if (WIFSTOPPED(status))
printf(" , = %d\n",
WSTOPSIG(status));
}

FreeBSD 5.2.1, Linux 2.4.22, Mac OS X 10.3 Solaris 9


WCOREDUMP.

8.4 
pr_exit. 
, :
$ ./a.out
, = 7
, = 6 ( core)
, = 8 ( core)

,
, WTERMSIG, . ( 
10.21.) , 
SIGABRT 6, SIGFPE 8, 
<signal.h>.

282

8.

, 
, wait
. , 
( , )? 
UNIX wait 
, .
, , 

wait.
, .
, 
, 
, wait. ,
, . 
( ) waitpid, 
POSIX.1.
8.4.
#include "apue.h"
#include <sys/wait.h>
int
main(void)
{
pid_t pid;
int status;
if ((pid = fork()) < 0)
err_sys(" fork");
else if (pid == 0)
/* */
exit(7);
if (wait(&status) != pid)
/* */
err_sys(" wait");
pr_exit(status);
/* */
if ((pid = fork()) < 0)
err_sys(" fork");
else if (pid == 0)
/* */
abort();
/* SIGABRT */
if (wait(&status) != pid)
/* */
err_sys(" wait");
pr_exit(status);
/* */
if ((pid = fork()) < 0)
err_sys(" fork");
else if (pid == 0)
/* */
status /= 0;
/* 0 SIGFPE */
if (wait(&status) != pid)
/* */
err_sys(" wait");

283

8.6. wait waitpid


pr_exit(status);

/* */

exit(0);
}

waitpid pid :
pid == 1 . 
waitpid wait.
pid > 0

pid.

pid == 0

,
, ( 
9.4).

pid < 1

,
pid.

waitpid
,
statloc. wait , 
. ( ,
.
10.) waitpid, , ,

.
options waitpid. 
0 , 
(OR) , . 8.2.
8.2. options waitpid

WCONTINUED

, wait
pid , pid, 

( XSI POSIX.1).

WNOHANG

waitpid , 
, pid, .
0.

WUNTRACED

, wait
pid , 
pid,
. WIFSTOPPED 
, 
.

waitpid , 
wait.

284

8.

1. waitpid ,
, wait 
, . 
, 
popen.
2. waitpid
, ,
, .
3. waitpid 
WUNTRACED WCONTINUED.

 8.5. , 
, fork, 
 
, ,
fork . 
, 8.5.
8.5.
fork
#include "apue.h"
#include <sys/wait.h>
int
main(void)
{
pid_t pid;
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) {
/* */
if ((pid = fork()) < 0)
err_sys(" fork");
else if (pid > 0)
exit(0);
/* , */
/* */
/*
* ,
* init,
* exit() .
* , ,
* ,
* init.
*/
sleep(2);
printf(" , = %d\n",
getppid());
exit(0);

285

8.7. waitid
}
if (waitpid(pid, NULL, 0) != pid) /* */
err_sys(" waitpid");
/*
* () ,
*
* .
*/
exit(0);
}

, 
, , 
. fork 
, ,
, .
fork 
, , printf,
, init.
8.5
$ ./a.out
$ , = 1

: ( $),
, ,
.

8.7. waitid
XSI Single UNIX Specification 
, .
waitid waitpid,
.
#include <sys/wait.h>
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
0 , 1

waitpid, waitid , 
. 

,
waitid . id 
idtype.
. 8.3.

286

8.

8.3 idtype waitid



P_PID

. id 
.

P_PGID

, 
. id
.

P_ALL

. 
id .

options ,
(OR) , . 8.4.
,
.
8.4. options waitid

WCONTINUED , 
.
WEXITED

WNOHANG


, .

WNOWAIT

,
wait, waitpid waitid.

WSTOPPED

, 
.

infop siginfo. 
, 
. siginfo 10.14.
, , Solaris
waitid.

8.8. wait3 wait4


UNIX 
: wait3 wait4. BSD. 
wait, waitid waitpid
, , 
, 
.

287

8.9.

#include
#include
#include
#include

<sys/types.h>
<sys/wait.h>
<sys/time.h>
<sys/resource.h>

pid_t wait3(int *statloc, int options, struct rusage *rusage);


pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);

, 0 1

, 
( ), 
, 
. 
getrusage(2). ( 
, 7.11.) . 8.5
, 
wait.
8.5. , wait

pid

options

rusage

POSIX.1 FreeBSD Linux


5.2.1
2.4.22

wait
waitid

XSI

waitpid

wait3
wait4

Mac OS X Solaris
10.3
9

wait3 Single UNIX Specification.


,
.

8.9.
,
, 
, ,
, 
. fork
, , 
,
. , 
. ,

288

8.

, 
, .

8.5, 
.
, . 

, , 
init. sleep, 
, , 
. ,

, .
,
.
, ,
wait.
, 8.5,
:
while (getppid() != 1)
sleep(1);

, (polling), 
. , 
,
, .
, 
. 
, 10.16.

(interprocess communication IPC).
15 17.

.
fork , , 
. , 
, 
. ,


, .
:
#include "apue.h"
TELL_WAIT(); /* TELL_xxx WAIT_xxx */

289

8.9.
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) {
/* */
/* ... */
TELL_PARENT(getppid()); /* */
/* */
WAIT_PARENT();
/* */
/* ... */
exit(0);
}
/* ... */
TELL_CHILD(pid);
WAIT_CHILD();

/* */
/* */
/* */

/* ... */
exit(0);

, 
apue.h. TELL_WAIT, TELL_PARENT,
TELL_CHILD, WAIT_PARENT WAIT_CHILD 
.
TELL WAIT 
: 10.16
, 15.3 .
, .

, 8.6, : 
, . 
,
, .
8.6. ,
#include "apue.h"
static void charatatime(char *);
int
main(void)
{
pid_t pid;
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) {
charatatime(" \n");

290

8.
} else {
charatatime(" \n");
}
exit(0);

}
static void
charatatime(char *str)
{
char *ptr;
int c;
setbuf(stdout, NULL); /* */
for (ptr = str; (c = *ptr++) != 0; )
putc(c, stdout);
}

,
write.
, 
, . 
. ( , , , 
, . ,
, ; ,
.) ,
:
$ ./a.out


$ ./a.out


$ ./a.out

8.6 ,
TELL WAIT. 8.7. 
+.
8.7. 8.6,

#include "apue.h"
static void charatatime(char *);
int
main(void)
{
pid_t pid;
+

TELL_WAIT();

8.10. exec

291

if ((pid = fork()) < 0) {


err_sys(" fork");
} else if (pid == 0) {
WAIT_PARENT(); /* */
charatatime(" \n");
} else {
charatatime(" \n");
TELL_CHILD(pid);
}
exit(0);

}
static void
charatatime(char *str)
{
char *ptr;
int c;
setbuf(stdout, NULL); /* */
for (ptr = str; (c = *ptr++) != 0; )
putc(c, stdout);
}

, , , 
, .
8.7 .
, ,
, fork:
} else if (pid == 0) {
charatatime(" \n");
TELL_PARENT(getppid());
} else {
WAIT_CHILD(); /* */
charatatime(" \n");
}

8.3 .

8.10. exec
8.3, fork
, 
exec.
exe, ,
main. 
, exec 
, , 
, 
.

292

8.

exec,
exec, .
UNIX,
. fork ,
exec . exit
wait 
. ,
. 
, popen system.
#include <unistd.h>
int execl(const char *pathname, const char *arg0, ... /* (char *)0 */ );
int execv(const char *pathname, char *const argv[]);
int execle(const char *pathname, const char *arg0, ...
/* (char *)0, char *const envp[] */ );
int execve(const char *pathname, char *const argv[], char *const envp[]);
int execlp(const char *filename, const char *arg0, ... /* (char *)0 */ );
int execvp(const char *filename, char *const argv[]);
1 ,

,
,
. filename
:
filename ,
.

, PATH.
PATH , 
; . ,
name=value
PATH=/bin:/usr/bin:/usr/local/bin/:.

, 
. . (
. ,
value.)
, , 
PATH. [Garfinkel et al. 2003].

execlp execvp ,
, 

8.10. exec

293

, , ,

/bin/sh .
(l 
(list), v , (vector)). ,

.
. (execv, execvp execve) 

.
ISO C 
, execl, execlp execle,
:
char *arg0, char *arg1, ..., char *argn, (char *)0

, 
. 0,
; ,
. 
char *,
exec .

. , e (execle execve),
.

environ . ( 
7.9 . 7.2. 
, setenv putenv, 

, .)

,
. 
login, . 
login 

.
ISO C, execle
:
char *pathname, char *arg0, ..., char *argn, (char *)0, char *envp[]

, 
. 
ISO C , ,
envp (...).

294

8.

exec 
. . p 
, filename 
PATH, . l , 
, v ,
() argv[]. , e ,
envp[] . . 8.6
.
8.6. exec

pathname

filename

argv[] environ

execl

execlp
execle

execv

execvp
execve

envp[]


. 2.5.2
. 2.8 , ARG_MAX.
POSIX.1
4096 . 
. 
,
grep getrlimit /usr/share/man/*/*


Argument list too long

.
System V 5120 . BSD
20480 . . (.
2.2, . 2.12.)

, 
xargs(1), 
. , getrlimit 
,
:
find /usr/share/man type f print | xargs grep getrlimit

, 
:

8.10. exec

295

find /usr/share/man type f print | xargs bzgrep getrlimit

type f find,
, grep 
,
.
, 
exec. ,
:





,




,

tms_utime, tms_stime, tms_cutime tms_cstime
closeonexec (
exec) . . 3.1 
FD_CLOEXEC 3.14. ,
closeonexec. ,
exec. 
. exec 
, closeonexec
fcntl.
POSIX.1 , (
opendir 4.21) exec.
opendir, fcntl,
closeonexec , 
.
,
exec,
setuserID set
groupID . setuserID ,


296

8.

execlp

execl

argv
execvp


PATH

execle

argv
execv

environ

argv
execve
( )

. 8.2. exec

.
( 
).
.
UNIX , execve,
.
, 
. . 8.2 
exec.
, execlp execvp 
PATH ,
filename.

, 8.8, 
exec.
8.8. exec
#include "apue.h"
#include <sys/wait.h>
char *env_init[] = { "USER=unknown", "PATH=/tmp", NULL };
int
main(void)
{
pid_t pid;
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) { /* */
if (execle("/home/sar/bin/echoall", "echoall", "myarg1",
"MY ARG2", (char *)0, env_init) < 0)
err_sys(" execle");
}
if (waitpid(pid, NULL, 0) < 0)
err_sys(" wait");
if ((pid = fork()) < 0) {

8.10. exec

297

err_sys(" fork");
} else if (pid == 0) { /* , */
if (execlp("echoall", "echoall", "only 1 arg", (char *)0) < 0)
err_sys(" execlp");
}
exit(0);
}

execle,
. execlp, 
, 
. ex
eclp ,
/home/sar/bin PATH. , ,
(argv[0])
.
. , 
argv[0] . login
, . login
argv[0] , 
, .
, 
.
echoall, 8.8, 
8.9. , 
.
8.9.

#include "apue.h"
int
main(int argc, char *argv[])
{
int i;
char **ptr;
extern char **environ;
for (i = 0; i < argc; i++) /* */
printf("argv[%d]: %s\n", i, argv[i]);
for (ptr = environ; *ptr != 0; ptr++) /* */
printf("%s\n", *ptr);
exit(0);
}

8.9 
:
$ ./a.out
argv[0]: echoall

298

8.

argv[1]: myarg1
argv[2]: MY ARG2
USER=unknown
PATH=/tmp
$ argv[0]: echoall
argv[1]: only 1 arg
USER=sar
LOGNAME=sar
SHELL=/bin/bash
47
HOME=/home/sar

,
argv[0] exec.
, , 
.

8.11.

UNIX ( 
) (,
) .
,
, ,
,
. ,
,

,
.

. , 
,
. , 
,
.

setuid. 
setgid.
#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
0 , 1

8.11.

299

, 
. . ( 
.)
1. , setuid
,
uid.
2. ,
uid 
, setuid .
.
3. , setuid 1
errno EPERM.
, _POSIX_SAVED_IDS
true. 
, 
.
POSIX.1
2001 . POSIX 
. , , 
_POSIX_SAVED_IDS 
sysconf _SC_SAVED_IDS .


.
1. ,
. ,
login(1)
. login 
, , 
setuid .
2.
exec ,
setuserID. , exec
.
setuid, 
. ,
,
.
3. exec 
.
setuserID, , exec

.
. 8.7 
.

300

8.

8.7.


exec
setuid(uid)
setuser
setuserID  
ID



uid





 uid
uid

  
 

uid

, getuid geteuid,
8.2, 
.
.

, 
, , .
man(1), 
. , man set
userID setgroupID, 
, . 
man , 
, , , 
( /etc/man.con
fig /etc/manpath.config), .
man
, . 

, man 
: , , 
man. :
1. , man setuser
ID man. exec 
, :
= ,

8.11.

301

= man
= man

2. man
. 
man, 
man, .
3.  , 
man setuid(getuid()). man
, 
. :
= ,

( )
= ,

= man ( )

man 
, , . 
, , 
.
. man 
 .
4.  man setuid(euid),
euid man. ( 
man geteuid.) , 
setuid 
. ( .)
:
= ,

( )
= man
= man ( )

5. man , 

man.

,
setuserID. 
.

302

8.

, , ,

, .
, , man .
( fork exec.) 
man 
( 3),
. 
exec 
. , 
, exec, 
.
setuid man
, 
, setuid
. , ,
setuid .

setreuid setregid
BSD 

setreuid.
#include <unistd.h>
int setreuid(uid_t ruid, uid_t euid);
int setregid(gid_t rgid, gid_t egid);
0 , 1

1 , , 
.
:

. setuserID

. 
POSIX.1 ,
, 

.
, setreuid setregid, XSI Single UNIX
Specifications. , , UNIX 
.

303

8.11.

4.3BSD , 
. setreuid setregid. 

. , ,
, exec
.
, 
( setreuid), , 
, setreuid 
.
, exec
.

seteuid setegid
POSIX.1 : seteuid setegid.
setuid setgid, 
.
#include <unistd.h>
int seteuid(uid_t uid);
int setegid(gid_t gid);
0 , 1


.
8.3 ,
.

setreuid(ruid, euid )
eui


setuid(uid)

ruid

uid

uid


seteuid(uid)
uid

uid


setreuid


setreuid



set$user$ID

setuid seteuid

setuid seteuid

. 8.3. ,

304

8.


, , 
. setgid, setregid setegid 
.

8.12.
UNIX .
,
#! pathname [optionalargument]

pathname 
.
#!/bin/sh

pathname
,
( PATH ). 

exec.
, , pathname
. 
, ,
#!, , ,
.
,
. 
#!, pathname, ,
.
FreeBSD 5.2.1 128 , Mac OS X 10.3
512 , Linux 2.4.22 127 , Solaris 9 1023 .

,
exec,
. , 
8.10, .
8.10. ,
#include "apue.h"
#include <sys/wait.h>
int
main(void)
{

305

8.12.
pid_t pid;
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) {
/* */
if (execl("/home/sar/bin/testinterp",
"testinterp", "myarg1", "MY ARG2", (char *)0) < 0)
err_sys(" execl");
}
if (waitpid(pid, NULL, 0) < 0)
err_sys("waitpid error");

/* */

exit(0);
}

, 
8.10, .
$ cat /home/sar/bin/testinterp
#!/home/sar/bin/echoarg foo
$ ./a.out
argv[0]: /home/sar/bin/echoarg
argv[1]: foo
argv[2]: /home/sar/bin/testinterp
argv[3]: myarg1
argv[4]: MY ARG2

echoarg () , 
( 7.3). 
, , argv[0]
, argv[1] 
, , argv[2] 
(/home/sar/bin/testinterp), argv[3]
argv[4] execl (myarg1 MY ARG2).
execl, argv[1] argv[2], 
. : pathname
execl (testinterp) ,
pathname , .

,
, f , 
. , , awk(1)
awk f myfile

, awk
myfile.
, System V, awk. 
awk old awk ( awk) 

306

8.

, Version 7. , nawk (new


awk awk) , 
[Aho, Kernighan, and Weinberger 1988]. 
. Solaris 9 .
awk , POSIX 1003.2 (
POSIX.1 Single UNIX Specification). 
, [Aho, Kernighan, and Weinberger 1988].
awk Mac OS X 10.3 Bell Laboratories,
Lucent . FreeBSD 5.2.1 Linux 2.4.22
GNU awk, gawk. awk
gawk. gawk POSIX,
. awk Bell Labora
tories gawk , 
nawk awk. ( awk Bell Labaratories 
http://cm.belllabs.com/cm/cs/awkbook/index.html.)

f :
#!/bin/awk f
( awk)

, 8.11
/usr/local/bin/awkexample.
8.11. awk
#!/bin/awk f
BEGIN {
for (i = 0; i < ARGC; i++)
printf "ARGV[%d] = %s\n", i, ARGV[i]
exit
}

/usr/local/bin PATH,
8.11 ( ,
) :
$ awkexample file1 FILENAME2 f3
ARGV[0] = awk
ARGV[1] = file1
ARGV[2] = FILENAME2
ARGV[3] = f3

/bin/awk
:
/bin/awk f /usr/local/bin/awkexample file1 FILENAME2 f3

(/usr/
local/bin/awkexample). ( 
) , , 
( /bin/awk) 
, PATH. awk

8.12.

307

, , awk
# .

:
$ /bin/su

Password:

# mv /bin/awk /bin/awk.save

# cp /home/sar/bin/echoarg /bin/awk

# suspend

[1] + Stopped
/bin/su
$ awkexample file1 FILENAME2 f3
argv[0]: /bin/awk
argv[1]: f
argv[2]: /usr/local/bin/awkexample
argv[3]: file1
argv[4]: FILENAME2
argv[5]: f3
$ fg

/bin/su
# mv /bin/awk.save /bin/awk

# exit

f .
, awk , 
awk. , 
. 
, 
. , 

/bin/awk /usr/local/bin/awkexample file1 FILENAME2 f3

awk /usr/local/bin/awkexam
ple awk.
( 
f), 
.
? 
. ,
(
).
.
1. ,
. , , 
8.11 :
awkexample 

308

8.

, 
awk, 

awk f awkexample 

2. .
. ,
awk, :
awk BEGIN {
for (i = 0; i < ARGC; i++)
printf "ARGV[%d] = %s\n", i, ARGV[i]
exit
} $*

. 

execlp.
, ,
execlp ,
( ). 
/bin/sh, .
, awk, 
fork, exec wait. , 

.
3.
, /bin/sh. execlp 
, ,
, /bin/sh. ,

,
#!/bin/csh
( C shell)

, /bin/
sh, ,
.
,
awk # .

8.13. system
system
. , 
. ,
6.10:
time, tm localtime,

309

8.13. system

strftime
. :
system("date > file");

system ISO C,
. POSIX.1 
system, ISO C, 
POSIX.
#include <stdlib.h>
int system(const char *cmdstring);
: .

cmdstring , system 
, 
. , 
system . UNIX .
system fork, exec wait
pid, .
1. fork waitpid
, EINTR, system 1.
2. exec , ,
, system ,
exit(127).
3. fork, exec waitpid 
, system
, waitpid.
system EINTR,
waitpid .
, POSIX
, system
. ( 10.5.)

8.12 system. 
. 
10.18.
8.12. system
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
int
system(const char *cmdstring) /* */
{
pid_t pid;

310

8.
int status;
if (cmdstring == NULL)
return(1);
/* UNIX */
if ((pid = fork()) < 0) {
status = 1;
/* , */
} else if (pid == 0) {
/* */
execl("/bin/sh", "sh", "c", cmdstring, (char *)0);
_exit(127);
/* execl */
} else {
/* */
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = 1; /* waitpid , EINTR */
break;
}
}
}
return(status);

c ,
, .
. cmdstring
. , 
 < >.
, 
, .
execlp execl, 
PATH . 
, 
execlp. , 
.
, exit _exit.
, 

fork.
system 
, 8.13. ( pr_exit
8.3.)
8.13. system
#include "apue.h"
#include <sys/wait.h>
int
main(void)
{
int status;

311

8.13. system
if ((status = system("date")) < 0)
err_sys(" system()");
pr_exit(status);
if ((status = system("nosuchcommand")) < 0)
err_sys(" system()");
pr_exit(status);
if ((status = system("who; exit 44")) < 0)
err_sys(" system()");
pr_exit(status);
exit(0);
}

8.13 :
$ ./a.out
Sun Mar 21 18:41:32 EST 2004
, = 0
sh: nosuchcommand: command not found
, = 127
sar :0 Mar 18 19:45
sar pts/0 Mar 18 19:45 (:0)
sar pts/1 Mar 18 19:45 (:0)
sar pts/2 Mar 18 19:45 (:0)
sar pts/3 Mar 18 19:45 (:0)
, = 44

date
nosuchcommand

exit

system 
fork exec ,
, (
, 10.18) .
UNIX, SVR3.2 4.3BSD, waitpid.

:
while ((lastpid = wait(&status)) != pid && lastpid != 1)
;

,
, system. 
while , 
, system,  
, , , 
pid, 
while. wait
, POSIX.1 Rationale
waitpid. 15.3 ,
popen pclose,
waitpid.

312

8.

setuserID
, system 
setuserID? 
, . 8.14 
, system 
.
8.14.
system
#include "apue.h"
int
main(int argc, char *argv[])
{
int status;
if (argc < 2)
err_quit(" ");
if ((status = system(argv[1])) < 0)
err_sys(" system()");
pr_exit(status);
exit(0);
}

tsys.
8.15 ,
.
8.15.
#include "apue.h"
int
main(void)
{
printf(" uid = %d, uid = %d\n", getuid(), geteuid());
exit(0);
}

printuids.
:
$ tsys printuids

uid = 205, uid = 205
, = 0
$ su

Password:

# chown root tsys

# chmod u+s tsys
set;user;ID
# ls l tsys

rwsrwxrx 1 root
16361 Mar 16 16:59 tsys
# exit

313

8.14.
$ tsys printuids
uid = 205, uid = 0
, = 0

, tsys, 
fork exec, system.
/bin/sh bash 2,
, bash 
, .

, 
setuserID setgroupID 
,
fork exec,
fork exec. system 
set
userID setgroupID.
, system 
,
IFS .

. 
IFS system .

8.14.
UNIX 
. , 
, . 
, 
, , 
, .
, 
,
fread 5.9.

. , 
. ,  Solaris 9 ,
FreeBSD 5.2.1 Mac OS X 10.3 , 
, . 
, Linux 2.4.22 .
,
. , Solaris ,
runacct(1m) acctcom(1), FreeBSD
sa(8).


acct.

314

8.

accton(8) (, ,
). ,
accton , 
. 
. /var/account/acct FreeBSD Mac
OS X, /var/account/pacct Linux /var/adm/pacct Solaris. 
, accton .

<sys/acct.h> :
typedef u_short comp_t;
struct acct
{
char ac_flag;
/*
char ac_stat;
/*
/*
uid_t ac_uid;
/*
gid_t ac_gid;
/*
dev_t ac_tty;
/*
time_t ac_btime; /*
comp_t ac_utime; /*
comp_t ac_stime; /*
comp_t ac_etime; /*
comp_t ac_mem; /*
comp_t ac_io;
/*
/*
comp_t ac_rw;
/*
/*
char ac_comm[8]; /*
/*
};

/* 3, 8, ; 13 */

(. 8.8) */
( */
core) ( Solaris) */
*/
*/
*/
*/
( ) */
( ) */
( ) */
*/
( read write) */
"" BSD */
*/
( BSD) */
: [8] Solaris, */
[10] Mac OS X, [16] FreeBSD [17] Linux */

ac_flag , 
. . 8.8.
8.8. ac_flag acct
ac_flag
AFORK

fork,
exec

ASU

FreeBSD Linux Mac OS X Sola


5.2.1
2.4.22 10.3
ris 9

ACOMPAT 

ACORE


(core)

AXSIG

AEXPND

315

8.14.

, 
, 

fork. 
. , 
, .
, 
.
,
( 1.10), 
. ,
( 60 128 ). 
; , , 
. , , 
, ,

, .
, 
. 
fork, , 
. exec ,
AFORK. 
, A B, B C C 
, 
.
C, 
, .

, 
, .

for
sleep(2)
k
for
exit(2)
sleep(4)
k
for
abort()
k
for
sleep(8)
k
exit(0)
execl

sleep(6)
kill()

/bin/dd

. 8.4. ,

316

8.

8.16. 
fork . 
.
8.16.
#include "apue.h"
int
main(void)
{
pid_t pid;
if ((pid = fork()) < 0)
err_sys(" fork");
else if (pid != 0) {
/* */
sleep(2);
exit(2);
/* 2 */
}
/* */
if ((pid = fork()) < 0)
err_sys(" fork");
else if (pid != 0) {
sleep(4);
abort();
/* core */
}
/* */
if ((pid = fork()) < 0)
err_sys(" fork");
else if (pid != 0) {
execl("/bin/dd", "dd", "if=/etc/termcap", "of=/dev/null", NULL);
exit(7);
/* */
}
/* third child */
if ((pid = fork()) < 0)
err_sys(" fork");
else if (pid != 0) {
sleep(8);
exit(0);
/* */
}
/* */
sleep(6);
kill(getpid(), SIGKILL); /* core */
exit(6);

/* */

Solaris
8.17.
8.17.
#include "apue.h"
#include <sys/acct.h>

8.14.

#ifdef HAS_SA_STAT
#define FMT "%*.*s e = %6ld, chars = %7ld, stat = %3u: %c %c %c %c\n"
#else
#define FMT "%*.*s e = %6ld, chars = %7ld, %c %c %c %c\n"
#endif
#ifndef HAS_ACORE
#define ACORE 0
#endif
#ifndef HAS_AXSIG
#define AXSIG 0
#endif
static unsigned long
compt2ulong(comp_t comptime) /* comp_t unsigned long */
{
unsigned long val;
int exp;
val = comptime & 0x1fff;
/* 13 */
exp = (comptime >> 13) & 7; /* 3 (07) */
while (exp > 0)
val *= 8;
return(val);
}
int
main(int argc, char *argv[])
{
struct acct acdata;
*fp;
FILE
if (argc != 2)
err_quit(": pracct _");
if ((fp = fopen(argv[1], "r")) == NULL)
err_sys(" %s", argv[1]);
while (fread(&acdata, sizeof(acdata), 1, fp) == 1) {
printf(FMT, (int)sizeof(acdata.ac_comm),
(int)sizeof(acdata.ac_comm), acdata.ac_comm,
compt2ulong(acdata.ac_etime), compt2ulong(acdata.ac_io),
#ifdef HAS_SA_STAT
(unsigned char) acdata.ac_stat,
#endif
acdata.ac_flag & ACORE ? D : ,
acdata.ac_flag & AXSIG ? X : ,
acdata.ac_flag & AFORK ? F : ,
acdata.ac_flag & ASU ? S : );
}
if (ferror(fp))
err_sys(" read");
exit(0);
}

317

318

8.

, BSD, ac_flag acct 


, HAS_SA_STAT ,
. , 
,


. 

#if defined(BSD) || defined(MACOS)


.
, ,
ACORE AXSIG.
, Linux enum,
#ifdef.
:
1. , 
accton. , 
, accton , 
;
.
2. 
8.16.
: 
, 
,
, .

execl. .
3. 
. accton
, 
, .
4. 8.17, ,
.
, 4. 
(
).
accton
sh
dd
a.out
a.out

e
e
e
e
e

=
=
=
=
=

6,
2106,
8,
202,
407,

chars
chars
chars
chars
chars

=
0, stat =
0:
= 15632, stat =
0:
= 273344, stat =
0:
=
921, stat =
0:
=
0, stat = 134:

S
S


F

319

8.14.
a.out
a.out

e =
e =

600, chars =
801, chars =

0, stat =
0, stat =

9:
0:

F
F


. (. 2.12) 
100 . , sleep(2) 
202 . 
sleep(4) 407 . 
, , sleep,
. ( 10.) 
fork exit .
, ac_stat 
, ,
8.6. ,
( )
core ( ), . 
, 
.
128+6, 128 core, 6 SIGABRT
, abort. 9
SIGKILL. 
,
( exit) 2,
exit 0.
/etc/termcap, dd
, 136 663 . 
, 136 663
136 663 . , 
, .
ac_flag . F
, ,
execl. F , 
, , fork, 
exec a.out. abort,
SIGABRT, core. 
, D X, 
Solaris; , 
, ac_stat. 
, SIGKILL 
core, .
: 
, core.
, , 
core, .

320

8.

8.15.

.
, . 
getpwuid(getuid()), ,
, 
? (
,
.) ,
, ( 6.8), 
getlogin.
#include <unistd.h>
char *getlogin(void);

, NULL

,
, .
. 13.
, getpwnam 
, , , 
.
, UNIX
ttyname ( 18.9)
utmp ( 6.8). FreeBSD Mac OS X 
, , 
.
System V cuserid, 
. getlogin , , get
pwuid(getuid()). IEEE 1003.11988 cuserid, 
,
. cuserid POSIX.1
1990 .
login(1)
LOGNAME, .
, 
, .
getlogin.

8.16.
1.10 , 
: , 

8.16.

321

. times,
.
#include <sys/times.h>
clock_t times(struct tms *buf);

, 1

tms,
buf:
struct tms {
clock_t tms_utime; /* */
clock_t tms_stime; /* */
clock_t tms_cutime; /* */
/* */
clock_t tms_cstime; /* */
};

: .
.
,
, 
. , times
.  
times . 
,
times. ( , , 
, . 1.6.)

, , 
wait, waitid waitpid.
clock_t, , 

_SC_CLK_TCK, sysconf
( 2.5.4).
getrusage(2). 
14 ,
. BSD, ,
BSD , , 
, .

, 8.18, ,
,
tms.

322

8.

8.18.
#include "apue.h"
#include <sys/times.h>
static void pr_times(clock_t, struct tms *, struct tms *);
static void do_cmd(char *);
int
main(int argc, char *argv[])
{
int i;
setbuf(stdout, NULL);
for (i = 1; i < argc; i++)
do_cmd(argv[i]); /* */
exit(0);
}
static void
do_cmd(char *cmd)
/* "cmd" */
{
struct tms tmsstart, tmsend;
clock_t start, end;
int status;
printf("\n: %s\n", cmd);
if ((start = times(&tmsstart)) == 1) /* */
err_sys(" times");
if ((status = system(cmd)) < 0)
/* */
err_sys(" system()");
if ((end = times(&tmsend)) == 1)
/* */
err_sys(" times");
pr_times(endstart, &tmsstart, &tmsend);
pr_exit(status);
}
static void
pr_times(clock_t real, struct tms *tmsstart, struct tms *tmsend)
{
static long clktck = 0;
if (clktck == 0)
/*
if ((clktck = sysconf(_SC_CLK_TCK)) < 0)
err_sys(" sysconf");
printf(" real: %7.2f\n", real / (double) clktck);
printf(" user: %7.2f\n",
(tmsend>tms_utime  tmsstart>tms_utime) /
printf(" sys: %7.2f\n",
(tmsend>tms_stime  tmsstart>tms_stime) /
printf(" child user: %7.2f\n",
(tmsend>tms_cutime  tmsstart>tms_cutime)
printf(" child sys: %7.2f\n",
(tmsend>tms_cstime  tmsstart>tms_cstime)
}

. */

(double) clktck);
(double) clktck);
/ (double) clktck);
/ (double) clktck);

8.17.

323

, :
$ ./a.out "sleep 5" "date"
: sleep 5
real: 5.02
user: 0.00
sys: 0.00
child user: 0.01
child sys: 0.00
, = 0
: date
Mon Mar 22 00:43:58 EST 2004
real: 0.01
user: 0.00
sys: 0.00
child user: 0.01
child sys: 0.00
, = 0


, , 
.

8.17.
UNIX 
.
: fork, 
exec, _exit, wait waitpid. 
. , fork
.
system 
.
exec 
, .
,

setuserID.

, 
. 10 
.

8.1. 8.2 , 
_exit exit,

324

8.

printf
1. , ,
. , ?
8.2. ,
. 7.3.
, vfork 
,
, vfork 
main, ,
vfork? 

.
8.3. 8.7 :
$ ./a.out

.
:
$ ./a.out ; ./a.out ; ./a.out





. ?
? ,
?
8.4. 8.10 execl, 
.
execlp, testinterp,
/home/sar/bin PATH,
argv[2]?
8.5. 
?
8.6. ,  
system ps(1), , 
.
8.7. 8.10, POSIX.1 ,
exec.
:
opendir, DIR
closeonexec.
open 
closeonexec.

9

9.1.
, 
. , (

). , 
. 
, waitpid ( 8.6),
.
, 
, POSIX.1. 
, 
, ,
.

, ,
, .
UNIX, , ,
10.

9.2.
,
UNIX. UNIX,
Version 7, ,
.
( ), 
( ).
. 
, PDP11

326

9.

DH11 DZ11. ,
,
.
, 
, ,
. 
 ,
,
( ).

, .
, , 
(
).
, , 
UNIX . 
 , 
,  
, .

BSD
30 .
, /etc/ttys,
. 
, get
ty , (baud rate). 
1, init,
. init
/etc/ttys getty
fork exec. , . 9.1.

1
init

fork

init
exec


getty

getty

. 9.1. , init,

9.2.

327

, . 9.1,
0 ( 
). , init getty 
.
getty open
. ,
open ,
.
, 0, 1 2. 
getty , login:, 
.
, getty 
, 
. getty
(gettytab), , 
.
getty 
login, :
execle("/bin/login", "login", "p", username, (char *)0, envp);

( gettytab ,
login.) init 
getty , getty login (
envp) ( TERM=foo,
foo , gettytab) 
, gettytab. p 
login, 
, . . 9.2
login.

1
init
fork

/etc/ttys,

,

init
exec
getty
exec


( 0, 1, 2),
,

login

. 9.2. login

328

9.

, . 9.2, 
. , 
exec . ,
, init, 
1.
login .
, getpwnam, 
. login 
getpass(3), Password: 
( , , 
). crypt(3),
, pw_passwd 
. 
( ), login exit
1. login 
(init), fork exec
getty .
, UNIX. 
UNIX
. , FreeBSD, Linux, MacOS X Solaris 
, PAM (Pluggable Authentication Modu
les ). 

, PAM.

,
, , 
PAM. PAM , 

, 
.
, login:
(chdir)
(chown)
,

setgid initgroups
, 
login: (HOME), 
(SHELL), (USER LOGNAME) 
(PATH)
(setuid)

execl("/bin/sh", "sh", (char *)0);

9.2.

329

 argv[0] ,
. , 
, , .

login ,
. , , 
, 
. , .
8.11, setuid, ,
, , 
, 
. setgid, login
, .
, .
init ( 1), , 
, init (
SIGCHLD) .
0, 1 2
. . 9.3.
(.profile
Bourne shell Korn shell; .bash_profile, .bash_login .profile Bour
neagain shell .cshrc .login C shell). 
.
, 
(PATH) (TERM).
, 
.

1
init
getty login


fd 0, 1, 2

. 9.3.

330

9.

Mac OS X
Mac OS X , BSD,
Mac OS X FreeBSD,
.

Linux
Linux
BSD. , login Linux 
login 4.3BSD.
Linux BSD , 
.
, ,
getty, Linux 
/etc/inittab, , System V.
getty, 
( getty), /etc/gettydefs (
mgetty).

Solaris
Solaris : ()
getty, BSD, () ttymon
, SVR4. , 
getty, ttymon.
ttymon , 
SAF Service Access Facility ( ). 
SAF ,
, . ( 
6 [Rago 1993].)
,
. 9.3, init 
. init
sac (service access controller ), 
fork exec ttymon, 
. ttymon
, , 
. 
exec login, 
. , login
, , . 9.3.

ttymon, getty
init.

9.3.

331

9.3.
, 
,
,
. login , 
, FTP SMTP.
, , init ,
, getty .

(, Ethernet) 
, . , 
,
.

, , 
, .
, 
. ( 19
.)

BSD
BSD 
inetd, Internet
superserver. ,
BSD .

[Stevens, Fenner, and Rudoff 2004].
init 
, /etc/rc. ,
, inetd.
inetd init. inetd 
TCP/IP.
, inetd fork exec 
.
, TELNET TCP
. TELNET , 
TCP. , (
) , 
, TELNET:
telnet hostname

TCP hostname,
, TELNET. 
TELNET.

332

9.

, , 
. (, ,
.) . 9.4
, TELNET telnetd.

1
init


TELNET

/bin/sh,
/etc/rc

inetd
fork


TELNET

inetd
exec
telnetd

. 9.4. , TELNET

telnetd
fork . 
,
login. .
exec 
0, 1 2 .
login , 9.2: 
, 
. 
login
exec. . 9.5 .
, 
. 19,
.
, , 
(. 9.3) (. 9.5),
,
,
, . 
,
POSIX.1, 
.

9.4.

333

1
init
inetd, telnetd login


fd 0, 1, 2


telnetd telnet

. 9.5.

Mac OS X
Mac OS X
, BSD, Mac OS X
FreeBSD.

Linux
Linux ,
BSD, , inetd
xinetd (extended Internet services daemon 
). xinetd
inetd.

Solaris
Solaris 
BSD Linux. Solaris, BSD, 
inetd. Solaris
SAF,
. inetd
init. , . 9.5.

9.4.
, 
. 
10.

334

9.

,
(
9.8),
. 
. 
: ,
pid_t. getpgrp 
.
#include <unistd.h>
pid_t getpgrp(void);

BSD getpgrp pid 


. Single UNIX
Specification XSI getpgid, 
.
#include <unistd.h>
pid_t getpgid(pid_t pid);

, 1

pid 0,
. ,
getpgid(0);


getpgrp();

. 
.
, ,
.
, , 
, .
,
, .
, 
.

setpgid. ( ,
setsid .)

335

9.5.

#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
0 , 1

pid 
pgid. ,
, pid,
. pid 0, 
.
pgid 0, 
pid.

. 
, 
exec.
, 
, setpgid fork, 
,

. , , ,
,
.
, ,
.
, 
( ) ( 
). waitpid

.

9.5.
. 
, . 9.6.
.

. , ,
. 9.6, :
proc1 | proc2 &
proc3 | proc4 | proc5

setsid.

336

9.

#include <unistd.h>
pid_t setsid(void);

, 1

, 
. .
1. . ( ,
.)
.
2. .

.
3. . ( 
.)
setsid, .
,
. ,
fork, , 
. ,
,
,
. , ,

.
Single UNIX Specification
, . , 
, 
, ,

proc1

proc2

proc3

proc4


proc5

. 9.6.

337

9.6.

.
SVR4. BSD
, . getsid 
.
Single UNIX Specification XSI.
, Solaris, Single UNIX Specification,
; 
. ,
.
#include <unistd.h>
pid_t getsid(pid_t pid);

, 1

pid 0, getsid
, 
.

, pid 
, , .

9.6.
.

.
( ) 
( 
), .

, 
, .


;
.

,
,
.

(
DELETE ControlC),
.

(
Control\), 
.

338

9.


, ( ) ,
.

. 9.7.

.
POSIX.1
. 19.4.
, System V,
, ,
. , , open,
O_NOCTTY ( 3.3).
, BSD, ,
ioctl, request TIOCSCTTY
( ). , 
. ( ioctl
setsid , 
.) O_NOCTTY open BSD, 
, .

,
,
 . 
, open /dev/tty.

proc1

proc2

proc3

proc4


proc5

. 9.7. ,

9.7. tcgetpgrp, tcsetpgrp tcgetsid

339

.
, ,
.
getpass(3), , 
(,
). crypt(1) 
. ,
crypt < salaries | lpr

salaries 
. crypt ,
, 
. , crypt , 

( ).
, , 
crypt. 
[Garfinkel et al. 2003].

9.7. tcgetpgrp, tcsetpgrp tcgetsid


,
, ,
(. 9.7).
#include <unistd.h>
pid_t tcgetpgrp(int filedes);

, 1
int tcsetpgrp(int filedes, pid_t pgrpid);
0 , 1

tcgetpgrp
, filedes.
,
tcsetpgrp,
pgrpid . pgrpid 
, 
filedes .
.
, 
.
Single UNIX Specification XSI
tcgetsid, 

340

9.


.
#include <termios.h>
pid_t tcgetsid(int filedes);

, 1

, 
, tcgetsid, 
, 
( ).

9.8.
BSD 1980 .
( ) 
, , 
. 
, :
1. .
2. 
.
3. , 
.
SVR3 ,
(shell layers). POSIX.1 
, BSD; 
. 
, POSIX.1 , POSIX
.

, 
.
, . ,
vi main.c

, .
pr *.c | lpr &
make all &

. ,
, .
, , 
, . 

9.8.

341

, 
. , C shell 
, Bourne shell , Korn shell , 
.
C shell ,
(, System V), SVR4

Bourne shell, jsh sh. 
Korn shell ,
. Bourneagain shell 
.
, ,
, , 
.


. , Korn shell:
$ make all > Make.out &
[1]
1475
$ pr *.c | lpr &
[2]
1490
$

[2] + Done
pr *.c | lpr &
[1] + Done
make all > Make.out &

1 make,
1475. 2 
, 1490. 
, , 
, .

, , 
. 
. ,
,
.
, 
, , 
( ControlZ).
SIGTSTP . ,
, . 

.
( DELETE ControlC)
SIGINT.
( Control\) SIGQUIT.

342

9.

( ControlZ) SIGTSTP.

18 , 

.
,
.
, ,
, . 
. 
, 
, SIGTTIN .
,
, ,
, :
$ cat > temp.foo &

[1] 1681
$

[1] + Stopped (SIGTTIN)
cat > temp.foo &
$ fg %1
1
cat > temp.foo
,

hello, world

D
EOF ( )
$ cat temp.foo
,
hello, world

cat, 
( ).
, ,
SIGTTIN. 
( wait waitpid 8.6)
, . 
fg .
( , 
fg bg, 
.) 

(tcsetpgrp) (SIGCONT). 
,
.
, 
? ,
stty(1). ( 18 , 
.) :
$ cat temp.foo &

9.9.

343

[1] 1719
$ hello, world



[1] + Done
cat temp.foo &
$ stty tostop

$ cat temp.foo &

[1] 1721
$
,
[1] + Stopped(SIGTTOU)
cat temp.foo &
$ fg %1

cat temp.foo
,

hello, world


, cat
, ,
, SIGTTOU. 
, fg , 
.
. 9.8 , .
, 
, ,
. ,
SIGTTOU, , 
.
?

,
. , 

. 
, ,
, .
, , 
, . ,
, 
POSIX.1.

9.9.
,
, 
. ps.
,
Bourne shell So
laris.

344

9.

init inetd

getty
telnetd
exec setsid,

login
exec

SIGI

NT,S

I
G


QUIT
,S
IT
ST
P

U
TO
GT
SI


IN

GTT

SI






),

()




tp

gi

d

se



id

pg

e

s

tcsetpgrp, ,

. 9.8.

ps o pid,ppid,pgid,sid,comm

:
PID PPID PGID
949 947 949
1774 949 949

SID COMMAND
949 sh
949 ps

9.9.

345

, ps 
. , ps

(949). , 949 
, ,
, .
ps 
, . 
TPGID. , ps
UNIX. , Solaris 9 . FreeBSD 5.2.1
Mac OS X 10.3
ps o pid,ppid,pgid,sess,tpgid,command

Linux 2.4.22
ps o pid,ppid,pgrp,session,tpgid,comm

, .
:
( TPGID terminal process group ID).
, .
, . 
, . , 
.
tcset
pgrp, . 9.8.
, . , ps
TPGID, . , 
, ps 1.

:
ps o pid,ppid,pgid,sid,comm &

, :
PID PPID PGID
949 947 949
1812 949 949

SID COMMAND
949 sh
949 ps

,

.
, Bourne shell . 

ps o pid,ppid,pgid,sid,comm | cat1

:
PID PPID PGID SID COMMAND
949 947 949 949 sh

346
1823 949
1824 1823

9.
949
949

949 cat1
949 ps

( cat1 cat,
. cat cat2,
.
cat .) 
: 
,
. ,
,
.
:
ps o pid,ppid,pgid,sid,comm | cat1 &

. 
, 
949,
.
, 
? , , 
:
cat > temp.foo &

, , 
,
, SIGTTIN.


/dev/null, .
/dev/null .
, cat
.
,
, , 
/dev/tty
? : , , ,
, . ,
crypt < salaries | lpr &

. ,
crypt /dev/tty,
( ), 
.
, Password:,
, 

9.9.

347

.
, ,
, 
. 
,
, . 
, , 
.
Bourne shell, 
, :
ps o pid,ppid,pgid,sid,comm | cat1 | cat2

:
PID
949
1988
1989
1990

PPID
947
949
1988
1988

PGID
949
949
949
949

SID
949
949
949
949

COMMAND
sh
cat2
ps
cat1

, .
:
PID PPID PGID SID COMMAND
949 947 949 949 sh
1831 949 949 949 sh
1832 1831 949 949 ps
1833 1831 949 949 sh

, ps 
, cat fork exec. ,
, ex
ec, ps .


, 
. . 9.9 . 
(cat2) 
, .
, Linux
, .
, 
. Bourneagain shell; 
.
ps o pid,ppid,pgrp,session,tpgid,comm

:
PID PPID PGRP SESS TPGID COMMAND
2837 2818 2837 2837 5796 bash
5796 2837 5796 2837 5796 ps

348

9.

rk

sh
(1989)

exec

ps
(1989)

fo

sh
(949)

fork

sh
(1988)

fo

rk

sh
(1990)

exec

cat1
(1990)

exec

cat2
(1988)

. 9.9. ps | cat1 | cat2, Bourne shell

(
.) Bourne shell. 
Bourneagain shell (ps)
(5796). ps 
.
, ,
. ps
. 
, , 2837 5796, 
. , 
.
:
ps o pid,ppid,pgrp,session,tpgid,comm &


PID PPID PGRP SESS TPGID COMMAND
2837 2818 2837 2837 2837 bash
5797 2837 5797 2837 2837 ps

ps ,
(5797) 
. . TPGID (2837)
, 
.
:
ps o pid,ppid,pgrp,session,tpgid,comm | cat1

9.10.
PID
2837
5799
5800

PPID
2818
2837
2837

PGRP
2837
5799
5799

349

SESS TPGID COMMAND


2837 5799 bash
2837 5799 ps
2837 5799 cat1

, ps cat1,
(5799), .
Bourne shell.
Bourne shell 
,
.
Bourneagain shell.
:
ps o pid,ppid,pgrp,session,tpgid,comm | cat1 &

, ps cat1
:
PID
2837
5801
5802

PPID
2818
2837
2837

PGRP
2837
5801
5801

SESS TPGID COMMAND


2837 2837 bash
2837 2837 ps
2837 2837 cat1

, , , 
.

9.10.
, , ,
init. ,
, 
, POSIX.1 .

, 
. ( ),
, , ( 
), ?
,
? . 9.10: 
, , 
.
, , 9.1.
. ,
, 
. ,
( 

350

9.

2837

(PID 2837)
fork/exec
C

(PID 6099)
fo
rk

(PID 6100)
6099

. 9.10.

6099), (2837). 
. , 
fork
5 . (
) 
, .
SIGHUP. 
, SIGHUP .
( 10.)
kill
SIGTSTP.
, 
(ControlZ).
,
init 
1.
;
. POSIX.1 
, 
, ,
. ,
, , 
, .
, , 
, , 
, . 
(,
6100 1).

9.10.

351

, 
,
( ) SIGHUP
SIGCONT, POSIX.1.
, 
SIGHUP. 
, ,
. ,
printf sig_hup,
pr_ids.

9.1:
$ ./a.out
: pid = 6099, ppid = 2837, pgrp = 6099, tpgrp = 6099
: pid = 6100, ppid = 6099, pgrp = 6099, tpgrp = 6099
$ SIGHUP, pid = 6100
: pid = 6100, ppid = 1, pgrp = 6099, tpgrp = 2837
TTY, errno = 5

,
, . ,

. ,
1.
9.1.
#include "apue.h"
#include <errno.h>
static void
sig_hup(int signo)
{
printf(" SIGHUP, pid = %d\n", getpid());
}
static void
pr_ids(char *name)
{
printf("%s: pid = %d, ppid = %d, pgrp = %d, tpgrp = %d\n",
name, getpid(), getppid(), getpgrp(), tcgetpgrp(STDIN_FILENO));
fflush(stdout);
}
int
main(void)
{
char c;
pid_t pid;
pr_ids("");
if ((pid = fork()) < 0) {

352

9.
err_sys(" fork");
} else if (pid > 0) {
/* */
sleep(5); /* , */
exit(0); /* */
} else {
/* */
pr_ids("");
signal(SIGHUP, sig_hup); /* */
kill(getpid(), SIGTSTP); /* */
pr_ids("");
/* , */
/* */
if (read(STDIN_FILENO, &c, 1) != 1)
printf(" TTY, errno = %d\n",
errno);
exit(0);
}

pr_ids
. , 

, SIGTTIN.
; 
, , , 
. POSIX.1 , read
EIO errno ( 
5).
, , 
, ,

.
19.5 , 
pty.

9.11. FreeBSD
, , 
, , ,
.
FreeBSD. SVR4
[Williams 1989]. . 9.11 , 
FreeBSD.
, session.
session (
, , setsid).
s_count . 
, , , .
s_leader proc .

353

9.11. FreeBSD

session
s_count

tty

s_leader
s_ttyvp
t_session
t_pgrp
t_termios

s_ttyp

C vnode

s_sid
pgrp

t_winsize

pg_id
pg_session
c

pg_members

proc

proc

proc

p_pglist

p_pglist

p_pglist

p_pid

p_pid

p_pid

p_pptr

p_pptr

p_pptr

p_pgrp

p_pgrp

p_pgrp

. 9.11. FreeBSD

s_ttyvp vnode .
s_ttyp tty .

s_sid . ,
Single UNIX Specification.

setsid 
session. s_count 1, s_leader
proc , s_sid
s_ttyvp s_ttyp 
, .
tty.
.
( 19.)

354

9.

t_session session, 
. ( , tty
session, .) 
SIGHUP , 
(. 9.7).
t_pgrp pgrp .

. , 
( , 
).
t_termios , 
, 
, ( 
) . 18.
t_winsize winsize,
.
SIGWINCH. 18.12 
, .

, 
session. s_ttyp,
tty ,
t_pgrp pgrp . 
pgrp
.
pg_id .
pg_session session , 
.
pg_members proc, 
, .
p_pglist, proc, 
proc, 
.
proc .
p_pid .
p_pptr proc .
p_pgrp pgrp , 
.
p_pglist , 
.
, vnode.
. 
/dev/tty vnode.
(inode) (vnode).

9.12.

355

9.12.

, . 
UNIX, 
, ,
. 
.
, 
. 
, 
UNIX.

9.1. utmp wtmp 6.8 


: init?

?
9.2. , fork
, .
,
.

10

10.1.
. 
. 
, 
, , 
.
UNIX, ,
, Version 7, 
. ,
. 
4.3BSD SVR3,
. , 
AT&T, . ,
POSIX.1 ,
.
, 
. ,
. ,
, .
, ,
.

10.2.
, .
SIG. , SIGABRT 
, , abort.
SIGALRM , , alarm,
. Version 7 15

10.2.

357

, SVR4 4.4BSD 31 . FreeBSD 5.2.1, Linux 2.4.22


Mac OS X 10.3 31 , Solaris 9 38 
. , Linux Solaris , 
(
POSIX , 
[Gallmeister 1995]).

( ) <signal.h>.
,
<signal.h>. , 
, 
. , ,
, , 
. , FreeBSD 5.2.1
Mac OS X 10.3 <sys/signal.h>. Linux 2.4.22 
<bits/signum.h>, Solaris 9 <sys/iso/signal_iso.h>.

0. 10.9 ,
kill 0 . POSIX.1 
null signal ( ).
.
, , , 
. 
DELETE ( ControlC )
(SIGINT).
,  . ( 18 ,
.)
0,
. 
, .

, . , 
SIGSEGV 
.
kill(2) 
. , 
: , 
, .
kill(1) .
kill.

.
, ,
,
. (, , 

358

10.

0), .
SIGURG (, 
(outofband) ), SIGPIPE (
,
, ) SIGALRM ( 
).
.
.
, , 
(, , errno),
:  .

. , ,
.
1. . ,
, SIGKILL SIGSTOP, . 
, , 
, 
. ,
,
( 0 
), .
2. . 
, .
,
. , 
, , , 
, ,
, . SIGCHLD, 
, , 
, waitpid, 
. :
, 
SIGTERM ( , kill
), . 
: SIGKILL SIGSTOP .
3. . 
( . 10.1).
, 
.
. 10.1 ,
.
SUS (Single UNIX Specification) , ,
POSIX.1, 
XSI, XSI.

359

10.2.

10.1. UNIX

SIGABRT


(abort)

SIGALRM
SIGBUS

ISO C SUS FreeBSD Linux Mac OS Sola


5.2.1
2.4.22 X 10.3 ris 9

+core


(alarm)

+core

SIGCANCEL

threads
SIGCHLD




SIGCONT





/

SIGEMT

+core

SIGFPE

+core

SIGFREEZE 

SIGHUP

SIGILL

SIGINFO

SIGINT




SIGIO

+core

/


SIGIOT

+core

SIGKILL

SIGLWP

threads

360

10.

10.1 ()

ISO C SUS FreeBSD Linux Mac OS Sola


5.2.1
2.4.22 X 10.3 ris 9

SIGPIPE

,


SIGPOLL


(poll)

XSI

SIGPROF



(seti
timer)

XSI

SIGPWR


/

SIGQUIT




SIGSEGV

/


+core

+core

SIGSTKFLT , 


SIGSTOP

SIGSYS

XSI

+core

SIGTERM

SIGTHAW

SIGTRAP

SIGTSTP

XSI

+core




SIGTTIN




SIGTTOU




361

10.2.

SIGURG


()

SIGUSR1

SIGUSR2

XSI

SIGVTALRM

(seti
timer)

ISO C SUS FreeBSD Linux Mac OS Sola


5.2.1
2.4.22 X 10.3 ris 9

SIGWAIT
ING

threads
SIGWINCH 


SIGXCPU

(setr
limit)

XSI

+core/

SIGXFSZ



(setr
limit)

XSI

+core/

SIGXRES





+core,
, core 
. ( core , 
UNIX.) 
, 
.
core , 
UNIX. POSIX.1, 
XSI Single UNIX Specification , 
.

362

10.

core . FreeBSD 5.2.1, ,


core cmdname.core, cmdname ,
, . Mac OS X 10.3 core core.pid,
pid , . ( 
core sysctl.)
core 
, Mac OS X core /cores.

core , ()
setuserID, , ()
setgroupID,
, ()
, ()
, () (
RLIMIT_CORE 7.11). core ( )
, Mac OS X
.
. 10.1 
. 
UNIX PDP11.
, 
.
.
SIGABRT

abort ( 10.17).
.

SIGALRM

, 
alarm ( 10.10). , 
setitimer(2).

SIGBUS

, .
, 
, 14.9.

SIGCANCEL threads Solaris. 


.
SIGCHLD

,
SIGCHLD. , 
, 
. , 
, wait,
.
System V SIGCLD ( H). 
,
SVR2
. ( , SVR3 SVR4
.)
SIGCHLD, , UNIX SIGCLD,
SIGCHLD, .

10.2.

363

SIGCLD 
, .
10.7.
SIGCONT

,
. 
, , 
. , ,
, 
. 
10.20.

SIGEMT

, .

EMT PDP11 emulator trap ( ).


. Linux, , 
, SPARC, MIPS
PARISC.
SIGFPE

, 
0 .

SIGFREEZE Solaris. 
, 
, ,
.
SIGHUP

( ), 
, 
. . 9.11 , ,
s_leader session.
, CLOCAL. ( CLOCAL 
.
, .
18 , .)
, , ,
(. 9.7). 
, (, 
), .
.

.
 (
13) .
SIGHUP,
, ,
, .

SIGILL

, 
.

4.3BSD abort.
SIGABRT.

364

10.

SIGINFO

BSD 
( ControlT).
(. 9.8).

.

Linux SIGINFO, Alpha,


, SIFPWR.
SIGINT


( DELETE ControlC). 
. (. 9.8).
 ,
.

SIGIO

.
14.6.2.

. 10.1 , SIGIO 
. , 
. System V SIGIO SIGPOLL, 
. BSD .
Linux 2.4.22 Solaris 9 SIGIO , SIGPOLL,
. FreeBSD 5.2.1
Mac OS X 10.3 .
, .

SIGIOT

IOT PDP11 input/output TRAP (


). System V
abort. SIGABRT.
FreeBSD 5.2.1, Linux 2.4.22, Mac OS X 10.3 Solaris 9 SIGIOT
, SIGABRT.
SIGKILL

, 
. 
.

SIGLWP

threads Solaris
.

SIGPIPE

,
, , , 
. 15.2. 
SOCK_STREAM, 
. 16.

SIGPOLL


. 
poll 14.5.2. SIGPOLL SVR3
SIGIO SIGURG BSD.

Linux Solaris SIGPOLL , SIGIO.

10.2.

365

SIGPROF


, setitimer(2).

SIGPWR

.
, (UPS).


. ,
. 

,
, 1530 
, . 
SIGPWR. , 
SIGPWR
init, init .

Linux 2.4.22 Solaris 9


inittab powerfail powerwait ( powerokwait).
. 10.1 , SIGPWR
. , 
. Linux , Solaris .
SIGQUIT


( Control\).
(. 9.8). 
( SIGINT),
core.

SIGSEGV

, 
.

SEGV segmentation violation ( 


).
SIGSTKFLT Linux.
Linux ,
.
, .
SIGSTOP

. SIGTSTP, 
,
.

SIGSYS

.  
,
, 
. ,
, ,

, .

SIGTERM

, kill(1)
.

366

10.

SIGTHAW

Solaris
, 
.

SIGTRAP

, .

PDP11 TRAP (). 


.
SIGTSTP


( ControlZ) .
(. 9.8).

, . 
, 
. , , 
ControlS ControlQ 
. ,
, SIGTSTP, 
, .
SIGTTIN

,
(
9.8). () , , 
() , 
, ,
;
errno EIO.

SIGTTOU

,
( 9.8). 
SIGTTIN,
.
18.
, , 
SIGTTIN, : () 
() 
. 
;
errno EIO. , 
,
SIGTTOU:
tcsetattr, tcsendbreak, tcdrain, tcflush, tcflow tcsetpgrp. 
18.

SIGURG

, .
(outofband) 
.

SIGUSR1

SIGUSR2

, . SIGU
SR1, .

367

10.3. signal

SIGVTALRM ,
setitimer(2).
SIGWAITING
threads Solaris.
SIGWINCH

, 
.
ioctl, 18.12.
setwindowsize
ioctl, SIGWINCH
.

SIGXCPU

Single UNIX Specification XSI


( 7.11).
, 
SIGXCPU.

. 10.1 , SIGXCPU
. , 
. Linux 2.4.22 Solaris 9 
core, FreeBSD 5.2.1 Mac OS X 10.3 
. Single UNIX Specification ,
. core, 
.
SIGXFSZ

,
( 7.11).

SIGXCPU, 
. Linux 2.4.22 Solaris 9 
core, FreeBSD 5.2.1 Mac OS X 10.3
. Single UNIX Specification , 
. core,
.
SIGXRES

Solaris. 
, 
. So
laris , 
.

10.3. signal
signal UNIX.
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);

(. ) , SIG_ERR

368

10.

signal ISO C, 
, ,  .
UNIX.
, System V, signal, 
(
10.4). 
, . 
.
4.4BSD signal,
sigaction ( 10.14) , 
signal 4.4BSD . FreeBSD
5.2.1 Mac OS X 10.3 .
Solaris 9 System V, BSD, signal 
, System V.
Linux 2.4.22 signal System V
BSD, C
.
signal ,
sigaction. sigaction 
10.14 signal sigaction. 
signal, 10.12.

signo . 10.1. func


() SIG_IGN, () SIG_DFL,
() , .
SIG_IGN, ,
. ( , , SIGKILL SIGSTOP,
.) SIG_DFL, 
( . 10.1).
, 
, . ;
.
signal , 
,
(void). signal, signo,
. ,
. ,
signal, 
( (int)). , 
( ),
. signal , 
, 
. signal
.
,
, . 10.14.

369

10.3. signal

signal,
,
typedef [Plauger 1992]:
typedef void Sigfunc(int);

signal :
Sigfunc *signal(int, Sigfunc *);

apue.h ( B)
.
<signal.h>, 
:
#define SIG_ERR (void (*)())1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1

, 

signal .
1, 0 1.
, . 
, .

10.1 , 
, , .
pause 10.10, 
, .
10.1. ,
SIGUSR1 SIGUSR2
#include "apue.h"
static void sig_usr(int); /* */
int
main(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
err_sys(" SIGUSR1");
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
err_sys(" SIGUSR2");
for ( ; ; )
pause();
}
static void
sig_usr(int signo)
{

/* */

370

10.
if (signo == SIGUSR1)
printf(" SIGUSR1\n");
else if (signo == SIGUSR2)
printf(" SIGUSR2\n");
else
err_dump(" %d\n", signo);


kill(1) . , kill (
) UNIX 
. kill(1) kill(2)
.
, ,
.
$ ./a.out &
[1]
7216




SIGUSR1

$ kill USR1 7216


SIGUSR1
$ kill USR2 7216
SIGUSR2
SIGUSR2
$ kill 7216
SIGTERM
[1]+ Terminated
./a.out

SIGTERM, , 
, 
.


,
. 
, , exec, 
 . exec
, , 
. ( ,
, , 
exec, 
,  
.)
,
SIGINT SIGQUIT .
,
,
cc main.c &


SIG_IGN. ,

10.4.

371

.
,
, .
, ,
, :
void sig_int(int), sig_quit(int);
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, sig_int);
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
signal(SIGQUIT, sig_quit);

, 
.
signal 

. ,
sigaction.


fork, 
. , 
,
 .

10.4.
UNIX ( Version 7) .
, ; ,
. , 
: 
, . 
, , 
, .
4.2BSD,
. , 
, SVR3. POSIX.1 
BSD.

, , ,

. ( , 
10.1, ,
.) , 
UNIX, 
:

372

10.

int sig_int();

/*  */

...
signal(SIGINT, sig_int);
...

/*  */

sig_int()
{
signal(SIGINT, sig_int); /*  */
...
/* ... */
}

(
, UNIX void
ISO C.)
. , 

signal , SIGINT
. 
, .
, ,
, , .
UNIX ,
, 
. , 
: , 
, . , 
, , 
, :
int sig_int_flag;

/* , */

main()
{
int sig_int();
/*  */
...
signal(SIGINT, sig_int); /*  */
...
while (sig_int_flag == 0)
pause();
/* */
...
}
sig_int()
{
signal(SIGINT, sig_int); /*  */
sig_int_flag = 1; /* */
}

pause, , 
. 
sig_int_flag .

10.5.

373

,
.
,
, . 
sig_int_flag pause,
( ,
). . ,
.
.

10.5.
UNIX : , 
, , 
. 
EINTR errno.
, , 
,  , 
.

. , 
.

,
.
, . 
:
,
(, 
).
,
, 
.
,
,
( ,
).
pause (
) wait.
ioctl.
( 15).

 . , 

(

374

10.

, ), 
 
.
, ,
,
.

, .
read write 
POSIX.1 2001 . 
, , 
. read 
,
, , EINTR

, . , 

, EINTR 

. , ,
System V, , ,
BSD,
. 2001 POSIX.1 
BSD .

,
.
( , 
, 
) :
again:
if ((n = read(fd, buf, BUFFSIZE)) < 0) {
if (errno == EINTR)
goto again; /* */
/* */
}


, 4.2BSD 
. ,
, ioctl, read, readv,
write, writev, wait waitpid. ,
,
. wait waitpid 
.
, , 
, 4.3BSD 
.

375

10.5.

POSIX.1 ,
. Single UNIX Specification 
XSI SA_RESTART sigaction, 
.
System V . ,
BSD , . FreeBSD 5.2.1,
Linux 2.4.22 Mac OS X 10.3 , 
. Solaris 9 (EINTR).

, 4.2BSD 
, , , 
 . ,
, , ,
, 
. , , 
,

EINTR .
. 10.2 , 
, .
10.2. ,


 



signal

ISO C, POSIX.1

V7, SVR2, SVR3,


SVR4, Solaris

sigset

sigvec

4.2BSD

4.3BSD,
4.4BSD,
FreeBSD,
Linux,
Mac OS X

XSI

SVR3, SVR4, Sola


ris, Linux

4.2BSD

4.3BSD,
4.4BSD,
FreeBSD, Mac OS X

sigaction POSIX.1
XSI, 4.4BSD, SVR4,
FreeBSD, Mac OS X,
Linux, Solaris

sigset sigvec.
sigaction .

376

10.

signal, ,
sigaction.

, UNIX 
, . , sigaction
SunOS 4.1.2 
, , .
10.12 signal, 
( 
SIGALRM). , signal_intr,
10.13, .
14.5,
select poll.

10.6.
, 

. ,
.
( , , exit longjmp),
, 
. ( ,
.) ,
, , 
. malloc, 
, malloc?
, getpwnam ( 6.2),
,
? malloc 
, 
malloc 
, ,
. getpwnam 
, , 
, .
Single UNIX Specification ,
(
). . 10.3.
10.3. ,

accept

fchmod

lseek

sendto

stat

access

fchown

lstat

setgid

symlink

aio_error

fcntl

mkdir

setpgid

sysconf

377

10.6.

aio_return

fdatasync

mkfifo

setsid

tcdrain

aio_suspend

fork

open

setsockopt

tcflow

alarm

fpathconf

pathconf

setuid

tcflush

bind

fstat

pause

shutdown

tcgetattr

cfgetispeed

fsync

pipe

sigaction

tcgetpgrp

cfgetospeed

ftruncate

poll

sigaddset

tcsendbreak

cfsetispeed

getegid

posix_trace_event

sigdelset

tcsetattr

cfsetospeed

geteuid

pselect

sigemptyset

tcsetpgrp

chdir

getgid

raise

sigfillset

time

chmod

getgroups

read

sigismember

timer_getoverrun

chown

getpeername

readlink

signal

timer_gettime

clock_gettime

getpgrp

recv

sigpause

timer_settime

close

getpid

recvfrom

sigpending

times

connect

getppid

recvmsg

sigprocmask

umask

creat

getsockname

rename

sigqueue

uname

dup

getsockopt

rmdir

sigset

unlink

dup2

getuid

select

sigsuspend

utime

execle

kill

sem_post

sleep

wait

execve

link

send

socket

waitpid

_Exit _exit

listen

sendmsg

socketpair

write

, . 10.3, 
, () , ,
, () malloc free,
() .

, .
, printf
, ,
,
printf, .
, , 
. 10.3, ,
errno (
1.7), . , 
,
errno . 
, , read, 
, , .
, ,

378

10.

. 10.3, , 
errno
. ( SIGCHLD 
wait,
errno.)
: longjmp ( 7.10) siglongjmp ( 10.15)
. 10.3,
,
. 
, 
siglongjmp.  
, 
, sigsetjmp, 
.

10.2 , 
getpwnam ,
. alarm 10.10.
SIGALRM .
10.2.
#include "apue.h"
#include <pwd.h>
static void
my_alarm(int signo)
{
struct passwd *rootptr;
printf(" \n");
if ((rootptr = getpwnam("root")) == NULL)
err_sys(" getpwnam(root)");
alarm(1);
}
int
main(void)
{
struct passwd *ptr;
signal(SIGALRM, my_alarm);
alarm(1);
for ( ; ; ) {
if ((ptr = getpwnam("sar")) == NULL)
err_sys(" getpwnam");
if (strcmp(ptr>pw_name, "sar") != 0)
printf(" !, pw_name = %s\n",
ptr>pw_name);
}
}

10.7. SIGCLD

379

, 
. SIG
SEGV, 
. core , main
getpwnam, 
.
,
SIGSEGV. main 
, getpwnam
, . Mac OS X 
malloc, 
, malloc.
, 
.

10.7. SIGCLD
,
SIGCLD SIGCHLD. , SIGCLD ( H) ,
System V. BSD
SIGCHLD. POSIX.1 
SIGCHLD.
SIGCHLD . 
, SIGCHLD,
wait, ,
.
System V SIGCLD , 
. , SVR4, 
( ) , 
signal sigset ( SVR3
, ). 
SIGCLD .
1. SIG_IGN,
. :
SIG_DFL, 
. 10.1 , .

. wait,
,
, wait 1
ECHILD errno. (
, , 
SIG_IGN. 
SIG_IGN.)

380

10.

POSIX.1 , SIGCHLD
, . Single UNIX
Specification XSI, ,
SIGCHLD.
4.4BSD, SIGCHLD , .
, wait
. FreeBSD 5.2.1 4.4BSD. Mac OS X 10.3
, SIGCHLD .
SVR4 signal sigset,
SIGCHLD SIG_IGN, . Solaris 9
Linux 2.4.22 SVR4.
sigaction SA_NOCLDWAIT
(. 10.5), .
: FreeBSD 5.2.1, Linux 2.4.22, Mac OS X 10.3 Solaris 9.

2. SIGCLD ,

SIGCLD, .
2 ,
.

10.4, ,

signal. ( , 

.) 10.3. 
. 
System V, Open
Server 5 UnixWare 7,
SIGCLD received ( SIGCLD), , , 
, .
FreeBSD 5.2.1 Mac OS X 10.3 , ,
BSD, System V SIGCLD.
Linux 2.4.22 , 
SIGCHLD , SIGCLD
SIGCHLD . , Solaris 9 
, 
, .

, (, UnixWare), 
.
10.3. SIGCLD System V,
#include "apue.h"
#include <sys/wait.h>

381

10.7. SIGCLD
static void sig_cld(int);
int
main()
{
pid_t pid;
if (signal(SIGCLD, sig_cld) == SIG_ERR)
perror(" signal");
if ((pid = fork()) < 0) {
perror(" fork");
} else if (pid == 0) {
/* */
sleep(2);
_exit(0);
}
pause();
/* */
exit(0);
}
static void
sig_cld(int signo)
{
pid_t pid;
int status;

/* pause() */

printf(" SIGCLD\n");
if (signal(SIGCLD, sig_cld) == SIG_ERR) /* */
perror(" signal");
if ((pid = wait(&status)) < 0) /* */
perror(" wait");
printf("pid = %d\n", pid);
}

, signal
, , 
( ,
SIGCLD), 
. 
signal, .
, signal
wait. signal 
, 
,
.
POSIX.1 ,
, SIGCHLD 
, . 
, . POSIX.1

( ,
POSIX.1 sigaction), , 
SIGCHLD .

382

10.

SIGCHLD .
,
#define SIGCHLD SIGCLD, .
,
, 
, , .
, , SIGCLD
SIGCHLD.

10.8. .

, 
. ,
( ) , . 
(, 0),
(, , 
), , ,
kill. , , ,
.
, , ,
.
.
.
, , 
, ,
, ()
() SIG_IGN.
, , 
. ,
. 
sigpending.
, 
, ? POSIX.1
, .
, 
, . UNIX
POSIX.1
, .
SVR2 , SIGCLD ,
SIGCLD. ,
, 
. , 
10.7. SVR3 

383

10.9. kill raise

: , SIGCLD 
. SVR4 
, SIGCLD, ,
 .
SVR4 sigaction(2) , 
SA_SIGINFO.
. , 
, SVR4. , SVID
.

,
? POSIX.1 .
POSIX.1 Rationale 
, ( 
SIGSEGV).
,
.
, . 
, 
. sig
procmask, 10.12.
, 
, POSIX.1 
sigset_t . 10.11
, 
.

10.9. kill raise


kill .
raise .
raise ISO C. POSIX.1
, ISO C,
(
12.8). ISO C
, kill,
.
#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
0 , 1

raise(signo);

384

10.


kill(getpid(), signo);

pid kill
.
pid > 0

pid.

pid == 0


, ,
. 
,
. UNIX 
init ( 1).

pid < 0


, pid,
. 
.

pid == 1 , 
.
.

, ,
. ,
.

, , 
, 
. _POSIX_SAVED_IDS (
),
.
: SIGCONT 
, .
POSIX.1 0 .
signo 0, kill 
, . 
, , . 
, kill
1 ESRCH errno.
, 
, 
, , 
.
, 
. , kill
, , 
.

385

10.10. alarm pause

kill 
,
signo,
, kill . (
, 12.8.)

10.10. alarm pause


alarm ,
SIGALRM. 
, .
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
0
,

seconds ,
. , 
.
UNIX , 
( ). POSIX.1 .

. 
alarm , ,
, 
.
se
conds 0, , 
, 
.
SIGALRM 
, . 
, 
.
SIGALRM, 
, alarm.
alarm 
, .
pause ,
.
#include <unistd.h>
int pause(void);
1 EINTR errno

386

10.

pause , 
 . 1
EINTR errno.

alarm pause 
. sleep1
10.4 , ,
.
10.4. , sleep
#include <signal.h>
#include <unistd.h>
static void
sig_alrm(int signo)
{
/* , */
}
unsigned int
sleep1(unsigned int nsecs)
{
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
return(nsecs);
alarm(nsecs);
/* , */
/* */
return(alarm(0)); /* , */
/* */
}

sleep, 
10.19, .
1. ,
alarm. 
, .
, nsecs,
. ,
nsecs, , nsecs
, ,
.
2. SIGALRM. 
, 

. ,
signal .
3. alarm pause 
. 

10.10. alarm pause

387

,  
pause. , 
pause (, 
,  ).
sleep ,
1 2 , . 
.
setjmp, .
sigprocmask sigsuspend, 
10.19.

SVR2 sleep 
setjmp longjmp ( 7.10).
, sleep2, 10.5. (
, 1 2.)
10.5. () sleep
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
static jmp_buf env_alrm;
static void
sig_alrm(int signo)
{
longjmp(env_alrm, 1);
}
unsigned int
sleep2(unsigned int nsecs)
{
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
return(nsecs);
if (setjmp(env_alrm) == 0) {
alarm(nsecs); /* */
pause();
/* */
/* */
}
return(alarm(0)); /* , */
/* */
}

sleep2
. pause , sleep2
SIGALRM.
, 
. SIGALRM

388

10.

 ,
longjmp . 
10.6 . 
SIGINT , ,
, 5 .
, , 
sleep2. k vola
tile, , 
. 10.6 
:
$ ./a.out
?

sig_int
sleep2 : 0

, longjmp sleep2 
(sig_int), . ,
sleep (
10.3).
10.6. sleep2 ,

#include "apue.h"
unsigned int sleep2(unsigned int);
static void sig_int(int);
int
main(void)
{
unsigned int unslept;
if (signal(SIGINT, sig_int) == SIG_ERR)
err_sys(" signal(SIGINT)");
unslept = sleep2(5);
printf(" sleep2 : %u\n", unslept);
exit(0);
}
static void
sig_int(int signo)
{
int i, j;
volatile int k;
/*
* ,
* 5 , .
*/
printf("\n sig_int \n");
for (i = 0; i < 300000; i++)
for (j = 0; j < 4000; j++)

10.10. alarm pause

389

k += i * j;
printf(" sig_int \n");
}

sleep1 sleep2 , 
. 
, 
,
.

alarm pause ,
, 
. ,
( 10.5), 
,
read . 10.7
,
.
10.7. read ;
#include "apue.h"
static void sig_alrm(int);
int
main(void)
{
int n;
char line[MAXLINE];
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
err_sys(" signal(SIGALRM)");
alarm(10);
if ((n = read(STDIN_FILENO, line, MAXLINE)) < 0)
err_sys(" read");
alarm(0);
write(STDOUT_FILENO, line, n);
exit(0);
}
static void
sig_alrm(int signo)
{
/* , read */
}


UNIX, .
1. 10.7 , 
10.4: 

390

10.

alarm read.

, , 
read. 
, 
, , ,
.
2. ,
read SIG
ALRM.  .

, 
longjmp.
.
10.8. read ;
longjmp
#include "apue.h"
#include <setjmp.h>
static void sig_alrm(int);
static jmp_buf env_alrm;
int
main(void)
{
int n;
char line[MAXLINE];
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
err_sys(" signal(SIGALRM)");
if (setjmp(env_alrm) != 0)
err_quit(" read ");
alarm(10);
if ((n = read(STDIN_FILENO, line, MAXLINE)) < 0)
err_sys(" read");
alarm(0);
write(STDOUT_FILENO, line, n);
exit(0);
}
static void
sig_alrm(int signo)
{
longjmp(env_alrm, 1);
}

, , , 
. ,

391

10.11.

,
.
,
longjmp, ,
.

select poll, 14.5.1
14.5.2.

10.11.

. , sigproc
mask ( ), 
, . , 

, int
, 
. POSIX.1
sigset_t,
.
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
0 , 1
int sigismember(const sigset_t *set, int signo);
1 (), 0 (), 1

sigemptyset ,
set. sigfillset 
, .
sigemptyset sigfillset
, , 
, C, 
.
,
.
sigaddset,
sigdelset. , , 
.

392

10.

, 
, 
.
, 31 
, 32 . 
, sigemptyset , sigfillset 
.
<signal.h>:
#define sigemptyset(ptr) (*(ptr) = 0)
#define sigfillset(ptr) (*(ptr) = (sigset_t)0, 0)

: sigfillset
0, 
C , 
, .
sigaddset , sigdelset 
. sigismember 
. 0 , 
1. 10.9
.
10.9. sigaddset, sigdelset sigismember
#include <signal.h>
#include <errno.h>
/*
* <signal.h> NSIG,
* 0.
*/
#define SIGBAD(signo) ((signo) <= 0 || (signo) >= NSIG)
int
sigaddset(sigset_t *set, int signo)
{
if (SIGBAD(signo)) { errno = EINVAL; return(1); }
*set |= 1 << (signo  1);
return(0);

/* */

}
int
sigdelset(sigset_t *set, int signo)
{
if (SIGBAD(signo)) { errno = EINVAL; return(1); }
*set &= (1 << (signo  1)); /* */
return(0);
}
int

393

10.12. sigprocmask
sigismember(const sigset_t *set, int signo)
{
if (SIGBAD(signo)) { errno = EINVAL; return(1); }
return((*set & (1 << (signo  1))) != 0);
}


<signal.h>, POSIX.1
, 
errno.
, .

10.12. sigprocmask
10.8 , ,
,
. ,
.
#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
0 , 1

, oset ,
.
, set , 
how , . . 10.4
how. SIG_BLOCK 
, SIG_SETMASK
. , SIGKILL SIGSTOP
.
10.4.
sigprocmask
how

SIG_BLOCK


, set. 
, set ,
.

SIG_UNBLOCK


, set. 
, set , 
.

SIG_SETMASK

, set, 
.

394

10.

set ,
how .
sigprocmask,  
, ,
.
sigprocmask .

. 12.8.

10.10 , ,
. 
10.14 10.15.
10.10.
#include "apue.h"
#include <errno.h>
void
pr_mask(const char *str)
{
sigset_t sigset;
int errno_save;
errno_save = errno;/* */
if (sigprocmask(0, NULL, &sigset) < 0)
err_sys(" sigprocmask");
printf("%s", str);
if (sigismember(&sigset,
if (sigismember(&sigset,
if (sigismember(&sigset,
if (sigismember(&sigset,

SIGINT)) printf("SIGINT ");


SIGQUIT)) printf("SIGQUIT ");
SIGUSR1)) printf("SIGUSR1 ");
SIGALRM)) printf("SIGALRM ");

/* */
printf("\n");
errno = errno_save;
}

,
. 10.1 (. 10.9).

10.13. sigpending
sigpending , 
. 
set.

395

10.13. sigpending

#include <signal.h>
int sigpending(sigset_t *set);
0 , 1

, 10.11, 
.
10.11. sigprocmask
#include "apue.h"
static void sig_quit(int);
int
main(void)
{
sigset_t newmask, oldmask, pendmask;
if (signal(SIGQUIT, sig_quit) == SIG_ERR)
err_sys(" SIGQUIT");
/*
* SIGQUIT .
*/
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys(" sigprocmask SIG_BLOCK");
sleep(5); /* SIGQUIT */
if (sigpending(&pendmask) < 0)
err_sys(" sigpending");
if (sigismember(&pendmask, SIGQUIT))
printf("\n SIGQUIT \n");
/*
* , SIGQUIT.
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys(" sigprocmask SIG_SETMASK");
printf(" SIGQUIT \n");
sleep(5); /* SIGQUIT core */
exit(0);
}
static void
sig_quit(int signo)
{
printf(" SIGQUIT\n");
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)

396

10.
err_sys(" SIGQUIT");

SIGQUIT, 
,
5 . SIGQUIT, 
, ,
. 5
SIGQUIT,
.
: , 
. ,
SIG_SETMASK, 
. , 
SIG_UNBLOCK. ,
,
, 
, SIG_UNBLOCK 
. SET_SIGMASK
, ,

. system 10.18.
SIGQUIT , 

sigprocmask. ,
printf , ,
printf, sigprocmask.
5 . SIGQUIT 
, , 

. ^\ ,
Control\ 
.
$ ./a.out
\
SIGQUIT
SIGQUIT
SIGQUIT
\Quit(coredump)
$ ./a.out
\\\\\\\\\\
SIGQUIT
SIGQUIT
SIGQUIT
\Quit(coredump)

SIGQUIT
( 5; )


sigprocmask
SIGQUIT
SIGQUIT 10
( 5; )

SIGQUIT

397

10.14. sigaction

Quit(coredump) , 
. , ,
, SIGQUIT,
, .
, .

10.14. sigaction
sigaction , 
, .
signal UNIX. 
signal sigaction.
#include <signal.h>
int sigaction(int signo, const struct sigaction *restrict act,
struct sigaction *restrict oact);
0 , 1

signo ,
. act
, . oact 
, 
, oact . 
:
struct sigaction {
void
(*sa_handler)(int);
sigset_t sa_mask;
int
sa_flags;

/*
/*
/*
/*

 , */
SIG_IGN, SIG_DFL */
*/
, .10.5 */

/* */
void
(*sa_sigaction)(int, siginfo_t *, void *);
};

sa_handler
 ( SIG_IGN SIG_DEL), sa_mask
, 
. 

. 
. 
, ,
, 
. 10.8 ,
. 
, 
,  .

398

10.

,
sigaction. 
UNIX , POSIX.1 ,
, 
.
sa_flags act
. . 10.5
. SUS ,
POSIX.1.
XSI, XSI.
10.5. (sa_flags)

SUS FreeBSD Linux Mac OS Sola


5.2.1
2.4.22 X 10.3 ris 9

SA_INTERRUPT

SIGCHLD 

. 
, 

(
SA_NOCLDWAIT 
). ,
SIGCHLD 


.

SA_NOCLDWAIT XSI

SIGCHLD 


.

wait, 
, 

, wait 
1 ECHLD 
errno ( 10.7).

XSI



(, ,
sa_mask).

SA_NOCLDSTOP

SA_NODEFER

,
, 
( XSI
sigaction). 

10.5.

399

10.14. sigaction

SUS FreeBSD Linux Mac OS Sola


5.2.1
2.4.22 X 10.3 ris 9
: 

UNIX.
XSI


,

sigaltstack(2).

SA_RESETHAND XSI



SIG_DFL
SA_SIGINFO. :


UNIX.
SIGILL SIG
TRAP 
. 
sigacti
on ,
SA_NODEFER.

SA_RESTART

XSI


,

( 10.5).

SA_SIGINFO



: 
siginfo .

SA_ONSTACK

sa_sigaction 
SA_SIGINFO.
sa_handler sa_sigaction
, .
 :
void handler(int signo);

SA_SIGINFO, 
:
void handler(int signo, siginfo_t *info, void *context);

siginfo_t .
. POSIX
si_signo
si_code. XSI
:

400

10.

struct siginfo {
int
si_signo; /* */
int
si_errno; /* 0, errno <errno.h> */
int
si_code;
/* ( ) */
pid_t si_pid;
/*  */
uid_t si_uid; /*  */
void *si_addr;
/* , */
int
si_status; /* */
long si_band;
/* SIGPOLL */
/* */
};

. 10.6 si_code ,
Single UNIX Specification. ,
.
10.6. siginfo_t

SIGILL

SIGFPE

ILL_ILLOPN

ILL_ILLADR

ILL_ILLTRP

ILL_PRVOPC

ILL_PRVREG

ILL_COPROC

ILL_BADSTK

FPE_INTDIV

FPE_INTOVF

FPE_FLTDIV

FPE_FLTOVF

FPE_FLTUND

FPE_FLTRES

FPE_FLTINV

FPE_FLTSUB

SIGSEGV SEGV_MAPPER

SIGBUS

ILL_ILLOPC

SEGV_ACCERR

BUS_ADRALN

BUS_ADRERR

BUS_OBJERR

SIGTRAP TRAP_BRKPT

401

10.14. sigaction

TRAP_TRACE

CLD_EXITED

CLD_KILLED

( core)

SIGCHLD CLD_DUMPED

core

CLD_TRAPPED

CLD_STOPPED

CLD_CONTINUED
POLL_IN

POLL_OUT

SIGPOLL POLL_MSG

POLL_ERR

POLL_PRI

POLL_HUP

SI_USER

kill

SI_QUEUE

sigqueue ( 
)

SI_TIMER

, timer_set
time ( )

SI_ASYNCIO


 ( )

SI_MESGQ

(
)

SIGCHLD si_pid, si_status


si_uid. SIGILL SIGSEGV si_addr , 
, . 
SIGPOLL si_band
STREAMS, POLL_IN, POLL_OUT
POLL_MSG ( [Rago 1993]).
si_errno , , 
, .
context, , 
, struct ucon
text_t, .
,
SA_SIGINFO ,
.
. siginfo 
, sigqueue. 
. [Gallmeister 1995].

402

10.

signal
signal sigaction.
(POSIX.1 Ratio
nale , POSIX). 
,
signal, 
. 
(, 
), signal
sigaction. ( ,
, sigac
tion SA_RESETHAND SA_NODEFER.) ,
signal, , 
10.12.
10.12. signal sigaction
#include "apue.h"
/* signal() sigaction() */
/* POSIX. */
Sigfunc *
signal(int signo, Sigfunc *func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
} else {
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}

: sa_mask 
sigemptyset. ,
act.sa_mask = 0;

.
SA_RESTART ,
SIGALRM, 

10.15. sigsetjmp siglongjmp

403

, . SIGALRM
, 
 ( 10.7).
, SunOS, SA_INTERRUPT.

, 
. XSI 
Single UNIX Specification , sigaction
,
SA_RESTART.

signal_intr
10.13 signal, 
.
10.13. signal_intr
#include "apue.h"
Sigfunc *
signal_intr(int signo, Sigfunc *func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}

, 
SA_INTERRUPT,
.

10.15. sigsetjmp siglongjmp


7.10 setjmp longjmp, 
, , .
longjmp , 
, 
. 10.5 10.8.
longjmp . 
, 
.

404

10.

. ,
, (long
jmp) ?
FreeBSD 5.2.1 Mac OS X 10.3 setjmp longjmp 
. Linux 2.4.22 Solaris 9 . FreeBSD
5.2.1 Mac OS X 10.3 _setjmp _longjmp, 
.

POSIX.1 setjmp longjmp


, sigsetjmp
siglongjmp.
.
#include <setjmp.h>
int sigsetjmp(sigjmp_buf env, int savemask);
0, , ,
siglongjmp
void siglongjmp(sigjmp_buf env, int val);

setjmp longjmp ,
sigsetjmp . 
savemask , sigsetjmp
env. siglongjmp,
env sigsetjmp save
mask, .

, 10.14, , 

. sig
setjmp siglongjmp.
10.14. sigsetjmp
siglongjmp
#include "apue.h"
#include <setjmp.h>
#include <time.h>
static void
static sigjmp_buf
static volatile sig_atomic_t

sig_usr1(int), sig_alrm(int);
jmpbuf;
canjump;

int
main(void)
{
if (signal(SIGUSR1, sig_usr1) == SIG_ERR)
err_sys(" signal(SIGUSR1)");

10.15. sigsetjmp siglongjmp

405

if (signal(SIGALRM, sig_alrm) == SIG_ERR)


err_sys(" signal(SIGALRM)");
pr_mask(" main: ");
/* 10.10 */
if (sigsetjmp(jmpbuf, 1)) {
pr_mask(" main: ");
exit(0);
}
canjump = 1;
/* */
for ( ; ; )
pause();
}
static void
sig_usr1(int signo)
{
time_t starttime;
if (canjump == 0)
return;

/* , */

pr_mask(" sig_usr1: ");


alarm(3);
/* SIGALRM 3 */
starttime = time(NULL);
for ( ; ; )
/* 5 */
if (time(NULL) > starttime + 5)
break;
pr_mask(" sig_usr1: ");
canjump = 0;
siglongjmp(jmpbuf, 1);

/* main */

}
static void
sig_alrm(int signo)
{
pr_mask(" sig_alrm: ");
}

, 
, siglongjmp
. canjump ,
, sigsetjmp.
, siglongjmp
, canjump . 
, 
sigsetjmp. (
siglongjmp,

siglongjmp.)
longjmp C ( 
). , , 

406

10.

, 
.
sig_atomic_t, 
ISO C , .
, ,
, 
. , 
volatile ,

main . . 10.1
.
main
signal()
signal()
pr_mask()
sigsetjmp()
pause()
SIGUSR1

sig_usr1
pr_mask()
alarm()
time()
time()
time()
SIGALRM

sigsetjmp()
pr_mask()
exit()

sig_alrm
pr_mask()
return()

pr_mask()
siglongjmp()

. 10.1. ,

10.1 :
main, sig_usr1 
sig_alrm. ,
( ).
SIGUSR1. 
SIGUSR1 SIGALRM.
, 10.14 :
$ ./a.out &

main:
[1]
531

$ kill USR1 531
SIGUSR1
sig_usr1: SIGUSR1

407

10.16. sigsuspend
$ sig_alrm: SIGUSR1 SIGALRM
sig_usr1: SIGUSR1
main:

[1] + Done

./a.out &

,
.
. , siglongjmp 
, sigsetjmp.
10.14 sigsetjmp siglongjmp
setjmp longjmp Linux ( _setjmp _longjmp FreeBSD),
, ,
main: SIGUSR1

, longjmp main
SIGUSR1, , .

10.16. sigsuspend
,
.

, .
pause 
? , SIGINT,
:
sigset_t newmask, oldmask;
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
/* SIGINT */
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys(" SIG_BLOCK");
/* */
/* , SIGINT */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys(" SIG_SETMASK");
/* , */
pause(); /* */
/* */

, ,
,
. , 

408

10.

pause ( 
, ). 


pause, . ,
, , pause 
,
. , .
, , 

. sigsuspend.
#include <signal.h>
int sigsuspend(const sigset_t *sigmask);
1 errno EINTR

, sigmask, 
. ,
 . 
,  
, sigsuspend 
, 
.
: 
EINTR errno ( , 
).

10.15 
.
10.15.
#include "apue.h"
static void sig_int(int);
int
main(void)
{
sigset_t newmask, oldmask, waitmask;
pr_mask(" : ");
if (signal(SIGINT, sig_int) == SIG_ERR)
err_sys(" signal(SIGINT)");
sigemptyset(&waitmask);
sigaddset(&waitmask, SIGUSR1);
sigemptyset(&newmask);

409

10.16. sigsuspend
sigaddset(&newmask, SIGINT);
/*
* SIGINT .
*/
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys(" SIG_BLOCK");
/*
* .
*/
pr_mask(" : ");
/*
* , ,
* SIGUSR1.
*/
if (sigsuspend(&waitmask) != 1)
err_sys(" sigsuspend");
pr_mask(" sigsuspend: ");
/*
* , SIGINT.
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys(" SIG_SETMASK");
/*
* ...
*/
pr_mask(" : ");
exit(0);
}
static void
sig_int(int signo)
{
pr_mask("\n sig_int: ");
}

: sigsuspend ,
, .
SIGINT 
. , 
, (oldmask).
10.15 :
$ ./a.out
:
: SIGINT
?
sig_int: SIGUSR1

410

10.

sigsuspend: SIGINT
:

sigsuspend
SIGUSR1. , , 
. , sigsuspend ,
.

sigsuspend , 
, 
. , 10.16,
, SIGINT SIGQUIT,
SIGQIUIT.
10.16. sigsuspend ,

#include "apue.h"
volatile sig_atomic_t quitflag; /*
/*
static void
sig_int(int signo)
/*
{
if (signo == SIGINT)
printf("\n\n");
else if (signo == SIGQUIT)
quitflag = 1;
/*
}

*/
*/
SIGINT SIGQUIT */

*/

int
main(void)
{
sigset_t newmask, oldmask, zeromask;
if (signal(SIGINT, sig_int) == SIG_ERR)
err_sys(" signal(SIGINT)");
if (signal(SIGQUIT, sig_int) == SIG_ERR)
err_sys(" signal(SIGQUIT)");
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
/*
* SIGQUIT .
*/
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys(" SIG_BLOCK");
while (quitflag == 0)
sigsuspend(&zeromask);

10.16. sigsuspend

411

/*
* SIGQUIT .
*/
quitflag = 0;
/*
* , SIGQUIT .
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys(" SIG_SETMASK");
exit(0);
}

:
$ ./a.out
?

\ $

POSIX.1 ,
POSIX, ISO C, 
: 
sig_atomic_t. POSIX.1 
,
(. 10.3), , , 
, POSIX.

, 
. 
10.17 TELL_WAIT, TELL_PARENT,
TELL_CHILD, WAIT_PARENT WAIT_CHILD 8.9.
10.17.

#include "apue.h"
static volatile sig_atomic_t sigflag; /* */

412

10.

/* */
static sigset_t newmask, oldmask, zeromask;
static void
sig_usr(int signo) /* SIGUSR1 SIGUSR2 */
{
sigflag = 1;
}
void
TELL_WAIT(void)
{
if (signal(SIGUSR1,
err_sys("
if (signal(SIGUSR2,
err_sys("

sig_usr) == SIG_ERR)
signal(SIGUSR1)");
sig_usr) == SIG_ERR)
signal(SIGUSR2)");

sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGUSR1);
sigaddset(&newmask, SIGUSR2);
/*
* SIGUSR1 SIGUSR2,
* .
*/
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys(" SIG_BLOCK");
}
void
TELL_PARENT(pid_t pid)
{
kill(pid, SIGUSR2); /* , */
}
void
WAIT_PARENT(void)
{
while (sigflag == 0)
sigsuspend(&zeromask); /* */
sigflag = 0;
/*
* .
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys(" SIG_SETMASK");
}
void
TELL_CHILD(pid_t pid)
{
kill(pid, SIGUSR1); /* , */

10.16. sigsuspend

413

}
void
WAIT_CHILD(void)
{
while (sigflag == 0)
sigsuspend(&zeromask); /* */
sigflag = 0;
/*
* .
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys(" SIG_SETMASK");
}

, :
SIGUSR1 , SIGUSR2
. 15.3
.
sigsuspend ,
, (
),
? 
, ,
,
, 12.8.
, , 

. , 
SIGINT SIGALRM 
signal_intr,
. 
select ( 14.5.1),
. (
SIGALRM,
.) , , 
:
if (intr_flag) /* SIGINT */
handle_intr();
if (alrm_flag) /* SIGALRM */
handle_alrm();
/* , , */
while (select( ... ) < 0) {
if (errno == EINTR) {
if (alrm_flag)
handle_alrm();
else if (intr_flag)

414

10.
handle_intr();
} else {
/* */
}


select , 
. ,

select. , ,
, . , 
, , 
, select (, , 
).
:
1. SIGINT SIGALRM.
2. , ,
 , 
.
3. select ( , read) 
.
sigsuspend , 3 
pause.

10.17. abort
, abort
.
#include <stdlib.h>
void abort(void);

SIGABRT . (
.) ISO C , 
abort 
raise(SIGABRT).
ISO C , abort 
, , SIGABRT.
,

exit, _exit, _Exit, longjmp siglongjmp. ( longjmp
siglongjmp 10.15.) , POSIX.1

10.17. abort

415

, abort ,
SIGABRT.
SIGABRT,
.
, POSIX.1 , abort
, .
ISO C 
 ( 5.13). 
POSIX.1 , abort,
, 
, fclose.
System V abort SIGIOT. ,
.
, , abort
.
4.3BSD SIGILL, abort 
SIG_DFL ( 
core). 
.
abort 
. ,
 ,
abort. err_dump ( B), 
.
UNIX tmpfile un
link, ,
ISO C, .

10.18 abort,
POSIX.1.
10.18. abort,
POSIX.1
#include
#include
#include
#include

<signal.h>
<stdio.h>
<stdlib.h>
<unistd.h>

void
abort(void) /* abort() POSIX */
{
sigset_t mask;
struct sigaction action;
/*
* SIGABRT,
* .

416

10.
*/
sigaction(SIGABRT, NULL, &action);
if (action.sa_handler == SIG_IGN) {
action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &action, NULL);
}
if (action.sa_handler == SIG_DFL)
fflush(NULL); /*  */
/*
* SIGABRT;
* , .
*/
sigfillset(&mask);
sigdelset(&mask, SIGABRT); /* SIGABRT */
sigprocmask(SIG_SETMASK, &mask, NULL);
kill(getpid(), SIGABRT);
/* */
/*
* , , SIGABRT
* .
*/
fflush(NULL);
/* */
action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &action, NULL);
/* */
/* */
sigprocmask(SIG_SETMASK, &mask, NULL); /* ... */
kill(getpid(), SIGABRT);
/* */
exit(1);
/* ... */

,
, 
. fclose (
, ),
, .
, 
, 
. , , _exit
_Exit . ,
, . ,
.
10.9 , kill 

( 10.18), (
, )
kill. 
, SIGABRT, 
, kill , , 
.

10.18. system

417

10.18. system
8.13 system.
. POSIX.1 ,
system SIGINT SIGQUIT SIGCHLD.
, ,
, .

, 10.19,
system 8.13 ed(1). (
UNIX.
, SIGINT SIGQUIT. 
ed 
, ?. , ed
SIGQUIT SIG_IGN.)
10.19 SIGINT SIGCHLD. ,
:
$ ./a.out
a


.

1,$p
,


w temp.foo

23
, 23
q

SIGCHLD

, 
(a.out) SIGCHLD.
. , 
, . 

system, POSIX.1. , 
system, ,
. 
wait, 
.
10.19. ed system
#include "apue.h"
static void
sig_int(int signo)
{
printf(" SIGINT\n");

418

10.

}
static void
sig_chld(int signo)
{
printf(" SIGCHLD\n");
}
int
main(void)
{
if (signal(SIGINT, sig_int) == SIG_ERR)
err_sys(" signal(SIGINT)");
if (signal(SIGCHLD, sig_chld) == SIG_ERR)
err_sys(" signal(SIGCHLD)");
if (system("/bin/ed") < 0)
err_sys(" system()");
exit(0);
}

SIGINT, 
:
$ ./a.out
a

,
.

1,$p

,
w temp.foo
12
?
?
SIGINT
q
SIGCHLD


, 12



9.6 , 
SIGINT .
. 10.2 .

fork
exec

a.out

fork
exec

/bin/sh

fork
exec

. 10.2.

/bin/ed

419

10.18. system

SIGINT 
. ( .) ,
, a.out , . 
system, ,
,
SIGINT SIGQUIT.
.
, system, (
ed ), , system, 
, , 
, . 
POSIX.1 , system
, .

10.20 system, 
.
10.20. system,
POSIX.1
#include
#include
#include
#include

<sys/wait.h>
<errno.h>
<signal.h>
<unistd.h>

int
system(const char *cmdstring) /* */
{
pid_t pid;
int status;
struct sigaction ignore, saveintr, savequit;
sigset_t chldmask, savemask;
if (cmdstring == NULL)
return(1); /* UNIX */
ignore.sa_handler = SIG_IGN; /* SIGINT SIGQUIT */
sigemptyset(&ignore.sa_mask);
ignore.sa_flags = 0;
if (sigaction(SIGINT, &ignore, &saveintr) < 0)
return(1);
if (sigaction(SIGQUIT, &ignore, &savequit) < 0)
return(1);
sigemptyset(&chldmask);
/* SIGCHLD */
sigaddset(&chldmask, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0)
return(1);
if ((pid = fork()) < 0) {
status = 1;

/* , */

420

10.
/* */
} else if (pid == 0) {
/* */
/* */
sigaction(SIGINT, &saveintr, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &savemask, NULL);
execl("/bin/sh", "sh", "c", cmdstring, (char *)0);
_exit(127);
/* exec */
} else {
/* */
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR) {
status = 1;
/* , EINTR */
break;
}
}
/* */
if (sigaction(SIGINT, &saveintr, NULL) < 0)
return(1);
if (sigaction(SIGQUIT, &savequit, NULL) < 0)
return(1);
if (sigprocmask(SIG_SETMASK, &savemask, NULL) < 0)
return(1);
return(status);

10.19 system,
.
1. SIGINT SIGQUIT, 
.
2. SIGCHLD 
. , 
sigprocmask , 
waitpid .
POSIX.1 , wait waitpid 
, SIGCHLD , 
SIGCHLD ,
. 
. SIGCHLD
, system waitpid.
, . wait
sig_chld 10.19, ECHILD,
system.

, 
SIGINT SIGQUIT, :
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) {

421

10.18. system
/* */
execl(...);
_exit(127);
}
/* */
old_intr = signal(SIGINT, SIG_IGN);
old_quit = signal(SIGQUIT, SIG_IGN);
waitpid(pid, &status, 0)
signal(SIGINT, old_intr);
signal(SIGQUIT, old_quit);

, ,
fork
. ,
, , 
.
10.20
fork.
: 
execl. execl

, 8.10.

system
system. 
, 
. 8.13 , 
: 
, date, 0. exit 44
44. ,
?
8.14 
:
$ tsys "sleep 30"
? , = 130
$ tsys "sleep 30"
\sh: 946 Quit
, = 131


(Control;C)

sleep SIGINT, pr_exit (


8.3) . 
, sleep SIGQUIT. , 
Bourne shell 
128 ,
.
.

422

10.

$ sh
, Bourne shell
$ sh c "sleep 30"
?

$ echo $?

130
$ sh c "sleep 30"
\sh: 962 Quit  core dumped
$ echo $?

131
$ exit
Bourne shell

, SIGINT 2, SIGQUIT 3, 
130 131 .
, 
, system:
$ tsys "sleep 30" &
9257
$ ps f
UID PID PPID
sar 9260 949
sar 9258 9257
sar 949 947
sar 9257 949
sar 9259 9258
$ kill KILL 9258
,



TIME CMD
0:00 ps f
0:00 sh c sleep 60
0:01 /bin/sh
0:00 tsys sleep 60
0:00 sleep 60

= 9
TTY
pts/5
pts/5
pts/5
pts/5
pts/5

, system
, 
. fork, exec wait, 

system.

10.19. sleep
sleep 
10.4 10.5; ,
.
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
0 ,


,
1. .

10.19. sleep

423

2. .
0.
 , ( ),
, 
(
, ).
alarm, sleep
, , .
sleep alarm ( 10.10),
. ,
sleep alarm,
. POSIX.1
. , , alarm(10), 
, 3 , sleep(5)? sleep
5 (, 
), SIGALRM 2 
? .
Solaris 9 sleep alarm.
sleep(3) Solaris , SIGALRM
. , sleep
SIGALRM
( 2 ) sleep 0.
(, sleep SIGALRM
.) , 
alarm(6) 3 sleep(5), sleep 
3 ( SIGALRM), 5.
2 ( ,
).
, FreeBSD 5.2.1, Linux 2.4.22 Mac OS X 10.3
: nanosleep(2). 
, Single UNIX Specification, 
. 
sleep, .
 
sleep,
sleep , ,
.

10.21 POSIX.1 sleep.


10.4, 
, 
. 
, alarm .
( , POSIX.1 
.)

424

10.

10.21. sleep
#include "apue.h"
static void
sig_alrm(int signo)
{
/* , ,
* sigsuspend()
*/
}
unsigned int
sleep(unsigned int nsecs)
{
struct sigaction newact, oldact;
sigset_t newmask, oldmask, suspmask;
unsigned int unslept;
/* , */
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, &newact, &oldact);
/* SIGALRM */
sigemptyset(&newmask);
sigaddset(&newmask, SIGALRM);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
alarm(nsecs);
suspmask = oldmask;
sigdelset(&suspmask, SIGALRM);/* , SIGALRM */
sigsuspend(&suspmask);
/* , */
/*  */
/* , SIGALRM */
unslept = alarm(0);
sigaction(SIGALRM, &oldact, NULL); /* */
/* , SIGALRM */
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return(unslept);
}

,
, 10.4.
( 10.5, ) 
, 
SIGALRM.

10.20.
, . 10.1, POSIX.1 
.

10.20.

425

SIGCHLD

SIGCONT

SIGSTOP

( ).

SIGTSTP

SIGTTIN


.

SIGTTOU


.

, 
SIGCHLD.
. 
( ControlZ), 
SIGTSTP.
,
SIGCONT. , SIGTTIN
SIGTTOU, , ,
, .
, , 
vi(1). , 
, ,
. , ,
vi, 
. 
, , vi, .

. , 
(SIGSTOP, SIGTSTP, SIGTTIN SIGTTOU), 
SIGCONT . 
, SIGCONT, 
.
: SIGCONT 
, , 
. 
. SIGCONT, 
, 
.

, 10.22, 
, 
.
; , 
, .

426

10.

SIGTSTP
, SIG_DFL.
, , 
(, /bin/sh),
SIG_IGN. 
(SIGTSTP, SIGTTIN
SIGTTOU) SIG_IGN, init,
. 
, , 
SIG_DFL.
, SIGTSTP
. 
, : 
, .
, 
SIG_DFL. 
,
, 
. 
. SIGCONT (
fg).
SIGCONT.
, , 
kill .
SIGTSTP 
(, ).
10.22. SIGTSTP
#include "apue.h"
#define BUFFSIZE 1024
static void sig_tstp(int);
int
main(void)
{
int n;
char buf[BUFFSIZE];
/*
* SIGTSTP ,
* .
*/
if (signal(SIGTSTP, SIG_IGN) == SIG_DFL)
signal(SIGTSTP, sig_tstp);
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys(" write");
if (n < 0)

10.21.

427

err_sys(" read");
exit(0);
}
static void
sig_tstp(int signo) /* SIGTSTP */
{
sigset_t mask;
/* ... , ... */
/*
* SIGTSTP, .
*/
sigemptyset(&mask);
sigaddset(&mask, SIGTSTP);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
signal(SIGTSTP, SIG_DFL); /* SIG_DFL */
kill(getpid(), SIGTSTP); /* */
/*
* kill ,
* .
*/
signal(SIGTSTP, sig_tstp); /* */
/* ... , ... */
}

10.21.

, .



extern char *sys_siglist[];


.
FreeBSD 5.2.1, Linux 2.4.22 Mac OS X 10.3. Solaris 9
, _sys_siglist.

, psignal.
#include <signal.h>
void psignal(int signo, const char *msg);


( ), , , 

428

10.

. perror
( 1.7).
strsignal.
strerror ( 1.7).
#include <string.h>
char *strsignal(int signo);


. 
.
psignal strsig
nal, . Solaris 9 strsignal 
, , Free
BSD 5.2.1, Linux 2.4.22 Mac OS X 10.3 
, . , psignal
Solaris 9, <siginfo.h>.


Solaris 
.
#include <signal.h>
int sig2str(int signo, char *str);
int str2sig(const char *str, int *signop);
0 , 1

,
.
sig2str
, str. 

, .
Solaris <signal.h> 
SIG2STR_MAX, , 
sig2str.
SIG. , SIGKILL,
KILL , str.
str2sig . 
, 
signop.
SIG, (, 9).

10.22.

429

10.22.
. 
, , 
UNIX. 
UNIX. 
, ,
, .
POSIX.1 . 
, abort, system sleep.
, 
.

10.1. 10.1 for(;;). ?


10.2. sig2str, 10.21.
10.3. , 
10.6.
10.4. 10.8
setjmp longjmp,
.
:
signal(SIGALRM, sig_alrm);
alarm(60);
if (setjmp(env_alrm) != 0) {
/*  */
...
}
...

, .
10.5. ( alarm, setitim
er ), , 

.
10.6. ,

10.17. 
0. fork, 
, 
. 
,
.

430

10.

10.7. 10.18 
SIGABRT kill
, .
_exit?
10.8. , siginfo ( 10.14)
si_uid , 
?
10.9. 10.10 , 
. 10.1.
,
.
10.10. , sleep(60)
. (. . 5 ) 

tm_sec. 
. , , 
, cron BSD?
10.11. 3.3 : () 
BUFFSIZE 100, () SIGXFSZ
signal_intr,
() ,
write, . 
RLIMIT_FSIZE ( 7.11), 
1024, 
, 1024 . ( 
.
, setrlimit .) 
, . 
?
10.12. , fwrite 
( ). 
fwrite alarm, 
. 
, , 
. fwrite ? ,
?

11

11.1.
. 
UNIX,
.

, ( 
(threads)) 
.
, .


. 
, 
, 
.

11.2.
UNIX

.
, 
,
. .
,
, . 
, 
, 
.

432

11.


, 
, 
, ( 15
17). , ,
.

,
. 
, , 
, 
.
.
, 
.

, 
,
, 
.


. 
, . 
, 
,
. , ,

, 
, 
, 
.
, 
. ;
, , 
, , , , errno (
1.7) , ( 12.6).
, , 
, ,
.
, ,
POSIX.12001. , pthreads ( POSIX
threads), 
, POSIX.12001. POSIX
_POSIX_THREADS. 
,
#ifdef, ,
sysconf _SC_THREADS.

433

11.3.

11.3.
,
. , 
,
, .
, pid_t 
. 
pthread_t.
pthread_t, , 
, . 
, 
.
#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
,
, 0

pthread_t Linux 2.4.22 long int, Solaris 9


unsigned int, FreeBSD 5.2.1 Mac OS X 10.3 pthread_t
pthread.

pthread_t ,
. 
, , ,
. 
, 
.
,
pthread_self.
#include <pthread.h>
pthread_t pthread_self(void);

pthread_equal,
. ,

, ,
. . 11.1.
, 
. ,
, ,
, .

434

11.

TID 1

TID 3

TID 2

TID 3

. 11.1.

, 
.

11.4.
UNIX
. , 
, . 
pthreads ,
. 
, 
.
pthread_create.
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp,
const pthread_attr_t *restrict attr,
void *(*start_rtn)(void), void *restrict arg);
0 ,

tid ,
, pthread_create 
. atr 
. 12.3,
(NULL), 
.

11.4.

435

start_rtn. 
, arg,
. start_rtn
,
arg.
, 
,
pthread_create. 

, , 
, .
: pthread, ,
. errno 
POSIX. errno

, . , 
, 
,
, .

,
, 
, , 
. , 
11.1,
.
11.1
#include "apue.h"
#include <pthread.h>
pthread_t ntid;
void
printids(const char *s)
{
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid,
(unsigned int)tid, (unsigned int)tid);
}
void *
thr_fn(void *arg)
{

436

11.
printids(" : ");
return((void *)0);

}
int
main(void)
{
int err;
err = pthread_create(&ntid, NULL, thr_fn, NULL);
if (err != 0)
err_quit(" : %s\n", strerror(err));
printids(" :");
sleep(1);
exit(0);
}

,
. (

.) . 
, 
,
.
.
,
pthread_self, 
.
pthread_create ,
tidp. 
ntid, . 
, , pthre
ad_create , 
ntid.
11.1 Solaris,
:
$ ./a.out
: pid 7225 tid 1 (0x1)
: pid 7225 tid 4 (0x4)

,
, .
11.1 FreeBSD :
$ ./a.out
: pid 14954 tid 134529024 (0x804c000)
: pid 14954 tid 134530048 (0x804c400)

.
,

11.5.

437

,
, .
, FreeBSD 
.
Mac OS X , 
, pthre
ad_create, .
$ ./a.out
: pid 779 tid 2684396012 (0xa000a1ec)
: pid 779 tid 25166336 (0x1800200)

Linux :
$ ./a.out
: pid 6628 tid 1026 (0x402)
: pid 6626 tid 1024 (0x400)

Linux ,
. 
Linux, pthread_create clone.
,

.
, , ,
Linux, . ,
,
.

11.5.
exit, _exit _Exit, 
. , ,
, 
( 
12.8).
, 
, .
1. .
.
2. 
.
3. pthread_exit.
#include <pthread.h>
void pthread_exit(void *rval_ptr);

438

11.

rval_ptr , 
, .
, pthread_join.
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
0 ,

,
pthread_exit,
. 
, rval_ptr
. , 
rval_ptr PTHREAD_CANCELED.
pthread_join
( ), 
. , , 
pthread_join, EINVAL.
, 
rval_ptr. 
pthread_join ,
.

11.2 ,
.
11.2.
#include "apue.h"
#include <pthread.h>
void *
thr_fn1(void *arg)
{
printf(" 1: \n");
return((void *)1);
}
void *
thr_fn2(void *arg)
{
printf(" 2: \n");
pthread_exit((void *)2);
}
int
main(void)
{

11.5.

439

int err;
pthread_t tid1, tid2;
void *tret;
err = pthread_create(&tid1, NULL, thr_fn1, NULL);
if (err != 0)
err_quit(" 1: %s\n", strerror(err));
err = pthread_create(&tid2, NULL, thr_fn2, NULL);
if (err != 0)
err_quit(" 2: %s\n", strerror(err));
err = pthread_join(tid1, &tret);
if (err != 0)
err_quit(" 1: %s\n", strerror(err));
printf(" 1: %d\n", (int)tret);
err = pthread_join(tid2, &tret);
if (err != 0)
err_quit(" 2: %s\n", strerror(err));
printf(" 2: %d\n", (int)tret);
exit(0);
}

11.2, :
$ ./a.out
1:
2:
1: 1
2: 2

, pthread_exit
, 
pthread_join.
, pthread_create pth
read_exit, .
, 
. , 
. , ,
, 
, .
pthre
ad_exit, , , 
, ,
, pthread_join, .

, 11.3, , 

( ) pthread_exit.

440

11.

11.3. pthread_exit
#include "apue.h"
#include <pthread.h>
struct foo {
int a, b, c, d;
};
void
printfoo(const char *s, const struct foo *fp)
{
printf(s);
printf(" 0x%x\n", (unsigned)fp);
printf(" foo.a = %d\n", fp>a);
printf(" foo.b = %d\n", fp>b);
printf(" foo.c = %d\n", fp>c);
printf(" foo.d = %d\n", fp>d);
}
void *
thr_fn1(void *arg)
{
struct foo foo = {1, 2, 3, 4};
printfoo(" 1:\n", &foo);
pthread_exit((void *)&foo);
}
void *
thr_fn2(void *arg)
{
printf(" 2:  %d\n", pthread_self());
pthread_exit((void *)0);
}
int
main(void)
{
int err;
pthread_t tid1, tid2;
struct foo *fp;
err = pthread_create(&tid1, NULL, thr_fn1, NULL);
if (err != 0)
err_quit(" 1: %s\n", strerror(err));
err = pthread_join(tid1, (void *)&fp);
if (err != 0)
err_quit(" 1: %s\n", strerror(err));
sleep(1);
printf(" \n");
err = pthread_create(&tid2, NULL, thr_fn2, NULL);
if (err != 0)
err_quit(" 2: %s\n", strerror(err));

11.5.

441

sleep(1);
printfoo(" :\n", fp);
exit(0);
}

Linux, :
$ ./a.out
1:
0x409a2abc
foo.a = 1
foo.b = 2
foo.c = 3
foo.d = 4

2:  32770
:
0x409a2abc
foo.a = 0
foo.b = 32770
foo.c = 1075430560
foo.d = 1073937284

, , 
. FreeBSD
:
$ ./a.out
1:
0xbfafefc0
foo.a = 1
foo.b = 2
foo.c = 3
foo.d = 4

2:  134534144
:
0xbfafefc0
foo.a = 0
foo.b = 134534144
foo.c = 3
foo.d = 67164259

, ( tid1) 
, . 
, (tid2) 
. , 
, malloc.

, pthread_cancel.

442

11.

#include <pthread.h>
int pthread_cancel(pthread_t tid);
0 ,

pthread_cancel
, pthread_exit
PTHREAD_CANCELED. 
. 12.7.
, pthread_cancel .
.
, 
, , 
atexit ( 7.3), , 
. ;
.
. ,
, .
#include <pthread.h>
void pthread_cleanup_push(void (*rtn)(void *), void *arg);
void pthread_cleanup_pop(int execute);

pthread_cleanup_push rtn, 
arg, :
pthread_exit

pthread_cleanup_pop execute
execute 0,
. pthread_cleanup_pop
,
pthread_cleanup_push.
, , , 

, . 
pthread_cleanup_push {,
} pthread_
cleanup_pop.

11.4
. , 
. : 
pthread_cleanup_pop,

11.5.

443

 pthread_cleanup_push pthre
ad_cleanup_pop , 
.
11.4.
#include "apue.h"
#include <pthread.h>
void
cleanup(void *arg)
{
printf(": %s\n", (char *)arg);
}
void *
thr_fn1(void *arg)
{
printf(" 1\n");
pthread_cleanup_push(cleanup, " 1, ");
pthread_cleanup_push(cleanup, " 1, ");
printf(" 1, \n");
if (arg)
return((void *)1);
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return((void *)1);
}
void *
thr_fn2(void *arg)
{
printf(" 2\n");
pthread_cleanup_push(cleanup, " 2, ");
pthread_cleanup_push(cleanup, " 2, ");
printf(" 1, \n");
if (arg)
pthread_exit((void *)2);
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
pthread_exit((void *)2);
}
int
main(void)
{
int err;
pthread_t tid1, tid2;
void *tret;
err = pthread_create(&tid1, NULL, thr_fn1, (void *)1);
if (err != 0)
err_quit(" 1: %s\n", strerror(err));
err = pthread_create(&tid2, NULL, thr_fn2, (void *)1);
if (err != 0)

444

11.
err_quit(" 2: %s\n", strerror(err));
err = pthread_join(tid1, &tret);
if (err != 0)
err_quit(" 1: %s\n", strerror(err));
printf(" 1: %d\n", (int)tret);
err = pthread_join(tid2, &tret);
if (err != 0)
err_quit(" 2: %s\n", strerror(err));
printf(" 2: %d\n", (int)tret);
exit(0);

11.4 :
$ ./a.out
1
1,
2
2,
: 2,
: 2,
1: 1
2: 2

,
,
. , , 
,
. , 
, , 
.

. . 11.1
.
11.1.

fork

pthread_create

exit

pthread_exit

waitpid

pthread_join

atexit

pthread_cleanup
_push

getpid

pthread_self

abort

pthread_cancel

, 
pthread_join.

11.6.

445

, ;
. , pthread_join 
,
EINVAL. pthread_detach.
#include <pthread.h>
int pthread_detach(pthread_t tid);
0 ,

, 
, , 
, pthread_create.

11.6.
, 
, ,
.
, , 
. ,
, 
. , 
, 
, , 
, 
.
,
,
. ,
, , 
. , 
,
, 
.
. 11.2 ,

. A 
, 
. B 
, .
, 

. . 11.3 . B 
, . 
, A ,

446

11.

. 11.2.

. , B
, A .
,
. 
, 1 (. 11.4).
() .
1. .
2. .
3. .

, , 
.
1 2 ,

. 11.3.

447

11.6.

.
1 , 3,
, , 1 
, 
.
, 
. , 
, 
. ,
.
,
, 
. 
, 
,

.

, . : A
, B 
, 2 : B
, A 
A


i
(=5)


(=6)


i
(=5)


i
(=6)


(=6)


i
(=6)

. 11.4.

448

11.

, 2. 
.
,
. 
, ,
, 
. , 
, ,
.


(mutual
exclusion) pthreads. (mutex) ,
()
()
. , ,
, , .
, , 
, ,
, . ,
 , .
, .

,
.
. 
, , 
, 
.
 pthread_mutex_t.
,
, PTHREAD_MUTEX_INITIALIZER ( 
) pthread_mutex_init.
(,
malloc), ,
pthread_mutex_destroy.
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
0 ,

11.6.

449

,
NULL attr.
12.4.
pthread_mutex_lock.
, ,
. pthread_mutex_unlock.
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
0 ,

, 
pthread_mutex_trylock.
, 
0. pthread_mutex_trylock EBUSY.

11.5 
. ,
,
, ,
.
11.5.
#include <stdlib.h>
#include <pthread.h>
struct foo {
int f_count;
pthread_mutex_t f_lock;
/* ... ... */
};
struct foo *
foo_alloc(void) /* */
{
struct foo *fp;
if ((fp = malloc(sizeof(struct foo))) != NULL) {
fp>f_count = 1;
if (pthread_mutex_init(&fp>f_lock, NULL) != 0) {
free(fp);
return(NULL);
}
/* ... ... */

450

11.
}
return(fp);

}
void
foo_hold(struct foo *fp) /* */
{
pthread_mutex_lock(&fp>f_lock);
fp>f_count++;
pthread_mutex_unlock(&fp>f_lock);
}
void
foo_rele(struct foo *fp) /* */
{
pthread_mutex_lock(&fp>f_lock);
if (fp>f_count == 0) { /* */
pthread_mutex_unlock(&fp>f_lock);
pthread_mutex_destroy(&fp>f_lock);
free(fp);
} else {
pthread_mutex_unlock(&fp>f_lock);
}
}


.
1 foo_alloc 
, , ,
. , 
, 
.
, 
.
. , , ,
.


(deadlock), 
, .
, , 

,

.
, 
, , .
, ,
. . ,

11.6.

451

, A B, . 
A, B,
. ,
B, A, 
.
,
.

. 
, , ,
,
. , 
.
pth
read_mutex_trylock. pthread_mu
tex_trylock, . ,
, ,
.

10.10, 
. 
,
,
.  foo. 
, hashlock  fh f_next 
foo. foo 
f_lock.
11.6.
#include <stdlib.h>
#include <pthread.h>
#define NHASH 29
#define HASH(fp) (((unsigned long)fp)%NHASH)
struct foo *fh[NHASH];
pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER;
struct foo {
int f_count;
pthread_mutex_t f_lock;
struct foo *f_next; /* hashlock */
int f_id;
/* ... ... */
};
struct foo *

452

11.

foo_alloc(void) /* */
{
struct foo *fp;
int idx;
if ((fp = malloc(sizeof(struct foo))) != NULL) {
fp>f_count = 1;
if (pthread_mutex_init(&fp>f_lock, NULL) != 0) {
free(fp);
return(NULL);
}
idx = HASH(fp);
pthread_mutex_lock(&hashlock);
fp>f_next = fh[idx];
fh[idx] = fp>f_next;
pthread_mutex_lock(&fp>f_lock);
pthread_mutex_unlock(&hashlock);
/* ... ... */
pthread_mutex_unlock(&fp>f_lock);
}
return(fp);
}
void
foo_hold(struct foo *fp) /* */
{
pthread_mutex_lock(&fp>f_lock);
fp>f_count++;
pthread_mutex_unlock(&fp>f_lock);
}
struct foo *
foo_find(int id)
{
struct foo *fp;
int idx;

/* */

idx = HASH(fp);
pthread_mutex_lock(&hashlock);
for (fp = fh[idx]; fp != NULL; fp = fp>f_next) {
if (fp>f_id == id) {
foo_hold(fp);
break;
}
}
pthread_mutex_unlock(&hashlock);
return(fp);
}
void
foo_rele(struct foo *fp) /* */
{
struct foo *tfp;

11.6.

453

int idx;
pthread_mutex_lock(&fp>f_lock);
if (fp>f_count == 1) {
/* */
pthread_mutex_unlock(&fp>f_lock);
pthread_mutex_lock(&hashlock);
pthread_mutex_lock(&fp>f_lock);
/* */
if (fp>f_count != 1) {
fp>f_count;
pthread_mutex_unlock(&fp>f_lock);
pthread_mutex_unlock(&hashlock);
return;
}
/* */
idx = HASH(fp);
tfp = fh[idx];
if (tfp == fp) {
fh[idx] = fp>f_next;
} else {
while (tfp>f_next != fp)
tfp = tfp>f_next;
tfp>f_next = fp>f_next;
}
pthread_mutex_unlock(&hashlock);
pthread_mutex_unlock(&fp>f_lock);
pthread_mutex_destroy(&fp>f_lock);
free(fp);
} else {
fp>f_count;
pthread_mutex_unlock(&fp>f_lock);
}
}

11.6 11.5, ,

, , 
.
, ,
, 
.
foo_find 
. , 
. ,
, hashlock ,
foo_hold f_lock.
foo_rele,
. ,
f_lock, hashlock, 
.

454

11.

f_lock. , 
, 
. 
, 
,
, .
,
. , hashlock 
. f_lock 
foo. 11.7.
11.7.
#include <stdlib.h>
#include <pthread.h>
#define NHASH 29
#define HASH(fp) (((unsigned long)fp)%NHASH)
struct foo *fh[NHASH];
pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER;
struct foo {
int f_count;
/* hashlock */
pthread_mutex_t f_lock;
struct foo *f_next; /* hashlock */
int f_id;
/* ... ... */
};
struct foo *
foo_alloc(void)
/* */
{
struct foo *fp;
int idx;
if ((fp = malloc(sizeof(struct foo))) != NULL) {
fp>f_count = 1;
if (pthread_mutex_init(&fp>f_lock, NULL) != 0) {
free(fp);
return(NULL);
}
idx = HASH(fp);
pthread_mutex_lock(&hashlock);
fp>f_next = fh[idx];
fh[idx] = fp>f_next;
pthread_mutex_lock(&fp>f_lock);
pthread_mutex_unlock(&hashlock);
/* ... ... */
}
return(fp);
}
void

455

11.6.
foo_hold(struct foo *fp) /* */
{
pthread_mutex_lock(&hashlock);
fp>f_count++;
pthread_mutex_unlock(&hashlock);
}
struct foo *
foo_find(int id)
{
struct foo *fp;
int idx;

/* */

idx = HASH(fp);
pthread_mutex_lock(&hashlock);
for (fp = fh[idx]; fp != NULL; fp = fp>f_next) {
if (fp>f_id == id) {
fp>f_count++;
break;
}
}
pthread_mutex_unlock(&hashlock);
return(fp);
}
void
foo_rele(struct foo *fp) /* */
{
struct foo *tfp;
int idx;
pthread_mutex_lock(&hashlock);
if (fp>f_count == 0) { /* , */
idx = HASH(fp);
tfp = fh[idx];
if (tfp == fp) {
fh[idx] = fp>f_next;
} else {
while (tfp>f_next != fp)
tfp = tfp>f_next;
tfp>f_next = fp>f_next;
}
pthread_mutex_unlock(&hashlock);
pthread_mutex_destroy(&fp>f_lock);
free(fp);
} else {
pthread_mutex_unlock(&hashlock);
}
}

, 
11.6. 
 , 

456

11.

.
. 
, 
, 

. ,
,  
.

, .


 , ,
.
, ,
. 
: , 
.
,
.
 
, , ,
, . 
 , ,
, 
,  
, ,
. 
 , ,
,
, ,
, . 

.
 ,
, . 
, 
,
.  
,
, 
.
  
.  ,
, .

11.6.

457

 , 
, .
,  

.
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
0 ,

pthread_rwlock_init .
attr , 
. 
12.4.
, ,
pthread_rwlock_destroy, 
. pthread_rwlock_init
, pthread_rwlock_destroy
. , ,
pthread_rwlock_destroy, 
, , .
,
pthread_rwlock_rdlock.
, pthread_rwlock_wrlock.
, , 
pthread_rwlock_unlock.
#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
0 ,

, 
,
, pthread_rwlock_rdlock. 
pthread_rwlock_wrlock pthread_rwlock_unlock ,
,
. 
, 

458

11.


.
Single UNIX Specification 
,
.
#include <pthread.h>
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
0 ,

, 
0. EBUSY. 
, 
, 
, .

, 11.8, 
. 
.
, . 11.1,
, .
11.8. ;
#include <stdlib.h>
#include <pthread.h>
struct job {
struct job *j_next;
struct job *j_prev;
pthread_t j_id; /* , */
/* ... ... */
};
struct queue {
struct job *q_head;
struct job *q_tail;
pthread_rwlock_t q_lock;
};
/*
* .
*/
int
queue_init(struct queue *qp)
{
int err;

11.6.
qp>q_head = NULL;
qp>q_tail = NULL;
err = pthread_rwlock_init(&qp>q_lock, NULL);
if (err != 0)
return(err);
/* ... ... */
return(0);
}
/*
* .
*/
void
job_insert(struct queue *qp, struct job *jp)
{
pthread_rwlock_wrlock(&qp>q_lock);
jp>j_next = qp>q_head;
jp>j_prev = NULL;
if (qp>q_head != NULL)
qp>q_head>j_prev = jp;
else
qp>q_tail = jp; /* */
qp>q_head = jp;
pthread_rwlock_unlock(&qp>q_lock);
}
/*
* .
*/
void
job_append(struct queue *qp, struct job *jp)
{
pthread_rwlock_wrlock(&qp>q_lock);
jp>j_next = NULL;
jp>j_prev = qp>q_tail;
if (qp>q_tail != NULL)
qp>q_tail>j_next = jp;
else
qp>q_head = jp; /* */
qp>q_tail = jp;
pthread_rwlock_unlock(&qp>q_lock);
}
/*
* .
*/
void
job_remove(struct queue *qp, struct job *jp)
{
pthread_rwlock_wrlock(&qp>q_lock);
if (jp == qp>q_head) {
qp>q_head = jp>j_next;

459

460

11.
if (qp>q_tail == jp)
qp>q_tail = NULL;
} else if (jp == qp>q_tail) {
qp>q_tail = jp>j_prev;
if (qp>q_head == jp)
qp>q_head = NULL;
} else {
jp>j_prev>j_next = jp>j_next;
jp>j_next>j_prev = jp>j_prev;
}
pthread_rwlock_unlock(&qp>q_lock);

}
/*
* .
*/
struct job *
job_find(struct queue *qp, pthread_t id)
{
struct job *jp;
if (pthread_rwlock_rdlock(&qp>q_lock) != 0)
return(NULL);
for (jp = qp>q_head; jp != NULL; jp = jp>j_next)
if (pthread_equal(jp>j_id, id))
break;
pthread_rwlock_unlock(&qp>q_lock);
return(jp);
}

 
, 
. 
, , 

. 
.
, 
. 
, 
.


. 
.

, .
.
, .

11.6.

461

, 
, 
.
, pthread_cond_t,
. 
PTHREAD_COND_INITIALIZER,
, 
pthread_cond_init.

pthread_cond_destroy.
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,
pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
0 ,

attr ,
.
12.4.
pthread_cond_wait , 
. 
, e pthread_cond_timedwait.
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict timeout);
0 ,

, pthread_cond_wait, 
.
, 
, , .
,
, 
. pthre
ad_cond_wait , .
pthread_cond_timedwait , 
.
timeout ,

462

11.

.  timespec,
. 
:
struct timespec {
time_t tv_sec; /* */
long tv_nsec; /* */
};

,
. ,
3 , 3 
, + 3.
gettimeofday ( 6.10), 
timeval, 
timespec.
timeout, :
void
maketimeout(struct timespec *tsp, long minutes)
{
struct timeval now;
/* */
gettimeofday(&now);
tsp>tv_sec = now.tv_sec;
tsp>tv_nsec = now.tv_usec * 1000; /* usec to nsec */
/*  */
tsp>tv_sec += minutes * 60;
}

 , pthread_
cont_timedwait ETIMEDOUT. 
pthread_cont_wait pthread_cont_timedwait ,
,
.
.
pthread_cond_signal ,
, pthread_cond_broadcast ,
.
c POSIX , pthread_cond_sig

nal .
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
0 ,

11.6.

463

pthread_cond_signal, , 
. , 

.

11.9 
.
11.9.
#include <pthread.h>
struct msg {
struct msg *m_next;
/* ... ... */
};
struct msg *workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;
void
process_msg(void)
{
struct msg *mp;
for (;;) {
pthread_mutex_lock(&qlock);
while (workq == NULL)
pthread_cond_wait(&qready, &qlock);
mp = workq;
workq = mp>m_next;
pthread_mutex_unlock(&qlock);
/* mp */
}
}
void
enqueue_msg(struct msg *mp)
{
pthread_mutex_lock(&qlock);
mp>m_next = workq;
workq = mp;
pthread_mutex_unlock(&qlock);
pthread_cond_signal(&qready);
}

.
, 
while. ,
, 

464

11.

, . , 
, ,
 . 
, 
: , , ,
. 
, pthread_cond_signal,
.

11.7.
POSIX.1
. . 

,  
.

11.1. 11.3 , 
.
11.2. 11.8 , 
( ), 
?
job_remove?
11.3. , 11.9,
(. 11.1 11.3) .
queue_init 
job_insert job_append ,
.
?
11.4. ?
1. (pthread_mutex_lock).
2. , .
3. (pthread_cond_broadcast).
4. (pthread_mutex_unlock).

1. (pthread_mutex_lock).
2. , .
3. (pthread_mutex_unlock).
4. (pthread_cond_broadcast).

12

12.1.
11 , , 
. 
. 
, , 
.
,
. 
.

12.2.
2.5.4 sysconf. Single UNIX Spe
cification , ,
. 2.10. , 
sysconf.
. 12.1.
, sysconf,

. , 
, 
, , , 
,
.
12.2 
.
sysconf (
_SC_), .
, 

466

12.

, , 
. , sysconf 
, .
12.1.
name sysconf

name

PTHREAD_DESTRUCTOR_ITE  _SC_THREAD_DESTRUCTOR_ITE
RATIONS
 RATIONS

( 12.6)
PTHREAD_KEYS_MAX

 _SC_THREAD_KEYS_MAX
, 
( 12.6)

PTHREAD_STACK_MIN

, _SC_THREAD_STACK_MIN

( 12.3)

PTHREAD_STACK_MAX

, _SC_THREAD_STACK_MAX

( 12.3)

, 
, , .
,
sysconf.
12.2.

FreeBSD 5.2.1 Linux 2.4.22

Mac OS X 10.3 Solaris 9

PTHREAD_DESTRUC
TOR_ITERATIONS
PTHREAD_KEYS_MAX
PTHREAD_STACK_MIN 4096
PTHREAD_STACK_MAX

12.3.
11, pthread_create,
NULL pthread_attr_t.
pthread_attr_t ,
.
pthread_attr_t
pthread_init_attr. pthread_attr_t
,
. 
, .

467

12.3.

#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
0 ,

pthread_attr_t pthread_
attr_destroy. pthread_attr_init ,
 ,
pthread_attr_destroy . , pthread_attr_destroy
, pthread_create 
.
pthread_attr_t . ,
,
. 
, POSIX.1 
.
, POSIX.1, . 12.3.
, POSIX.1
, . . 12.3
, 
. ,
.
12.3. POSIX.1

detachstate 

FreeBSD 5.2.1 Linux 2.4.22 Mac OS X 10.3 Solaris 9

guardsize

stackaddr

stacksize

11.5 . 
, 
pthread_detach,
, , .
, ,
, 
detachstate pthread_attr_t. 
pthread_attr_setdetachstate,

468

12.

PTHREAD_CREATE_DETACHED, 
, PTHREAD_CREATE_JOINABLE,
, 
.
#include <pthread.h>
int pthread_attr_getdetachstate(const pthread_attr_t *restrict attr,
int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
0 ,

detachstate, 
pthread_attr_getdetachstate. ,
, :
PTHREAD_CREATE_DETACHED PTHREAD_CREATE_JOINABLE, 
pthread_attr_t.

12.1 ,
.
12.1.
#include "apue.h"
#include <pthread.h>
int
makethread(void *(*fn)(void *), void *arg)
{
int err;
pthread_t tid;
pthread_attr_t attr;
err = pthread_attr_init(&attr);
if (err != 0)
return(err);
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (err == 0)
err = pthread_create(&tid, &attr, fn, arg);
pthread_attr_destroy(&attr);
return(err);
}

, ,
pthread_attr_destroy. 
, pthread_attr_destroy 
. , , 
:
, 

12.3.

469

. ,
pthre
ad_attr_destroy, , , 
, pthread_attr_init. ,
pthread_attr_init , pthread_attr_destroy ,
,
. 
 pthread_at
tr_destroy, .
, , 
POSIX , 
, XSI.
,
_POSIX_THREAD_ATTR_STACKADDR _POSIX_THREAD_ATTR_STACKSIZE.
 , 
. 
sysconf,
_SC_THREAD_ATTR_STACKADDR _SC_THREAD_ATTR_STACKSIZE.
POSIX.1 
. , pthread_attr_getstackaddr pthre
ad_attr_setstackaddr, Single UNIX
Specification,  
pthreads. 
pthread_attr_getstack pthre
ad_attr_setstack. , 
.
#include <pthread.h>
int pthread_attr_getstack(const pthread_attr_t *restrict attr,
void **restrict stackaddr,
size_t *restrict stacksize);
int pthread_attr_setstack(const pthread_attr_t *attr,
void *stackaddr, size_t *stacksize);
0 ,


stackaddr stacksize.
.
,
.
.
, 
, ,

. ,

470

12.

, 
, , , , 
.

malloc mmap ( 14.9) 
, pthread_attr_setstack,
. stackaddr,
, 
, 
.
stackaddr , 
. () . 

, stackaddr () ,
().
pthread_attr_getstackaddr pthread_attr_setstackaddr 
stackaddr. 
, , 
. , , ,
, ,
. pthread_attr_getstack pthread_attr_setstack 
.


stacksize pthread_attr_getstacksize pthread_attr_set
stacksize.
#include <pthread.h>
int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
size_t *restrict stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
0 ,

pthread_attr_setstacksize , 
, 
.
guardsize ,
, . 
PAGESIZE. 
guardsize 0, 
. , stackaddr,
, 
, 
0 guardsize.

471

12.3.

#include <pthread.h>
int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
size_t *restrict guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
0 ,

guardsize , , , 
, . 
, 
, .
Single UNIX Specification 
,
.


,
pthread_attr_t:

( 12.7)

( 12.7)

(concurrency level)
, . 

, 
,
. ,

, 
. 
pthread_setconcurrency.
#include <pthread.h>
int pthread_getconcurrency(void);

int pthread_setconcurrency(int level);
0 ,

pthread_getconcurrency 
. (
pthread_setconcurrency),
pthread_getconcurrency 0.

472

12.

pthread_
setconcurrency. , 
. , 
, level
0. 
pthread_setconcurrency level.

12.4.
, .
, 
.


pthread_mutexattr_t
pthread_mutexattr_init, pthread_mutexattr_destroy.
#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
0 ,

pthread_mutexattr_init pthread_mutex
attr_t . 
: processshared type. POSIX.1
processshared 
, _POSIX_THRE
AD_PROCESS_SHARED. 
sysconf, _SC_THREAD_PROCESS_SHARED.
POSIX , 
Single UNIX Specification 
, XSI.

. ,
11. processshared
PTHREAD_PROCESS_PRIVATE.
14 15, , 

. , 
, ,
.
processshared PTHREAD_PROCESS_SHARED,
, ,
,
.

12.4.

473

processshared pthread_mutexattr_t
pthread_mutexattr_getpshared. 
, pthread_mutexattr_set
pshared.
#include <pthread.h>
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr,
int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
0 ,

processshared pthread 
,
PTHREAD_PROCESS_PRIVATE, 
. 
, 
.
type . POSIX.1 
. PTHREAD_MUTEX_NORMAL , 

. PTHREAD_MUTEX_ERRORCHECK 
.
PTHREAD_MUTEX_RECURSIVE
, . 
, . 
,
. , , 
, , 
, .
, , PTHREAD_MUTEX_DEFAULT
. 
, 
. , , Linux 
PTHREAD_MUTEX_NORMAL.
. 12.4.
, 
, . 
, 
,
.
type, pthre
ad_mutexattr_gettype, pthread_mutexattr_set
type.

474

12.

#include <pthread.h>
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,
int *restrict type);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
0 ,

12.4.

PTHREAD_MUTEX_NORMAL

PTHREAD_MUTEX_ERROR
CHECK

PTHREAD_MUTEX_RECUR
SIVE

PTHREAD_MUTEX_DE
FAULT

11.6 ,
. , pthre
ad_cond_wait pthread_cond_timedwait ,
. ,
, 
. 
, 
. , 
pthread_cond_wait, ,
, , pthread_cond_wait .
, 
, 
, 
.
, ,
.

. 12.1 , 
, , 
. , func1 func2 
,
 
, .

475

12.4.

main

func1(x)

func1
pthread_mutex_lock(x>lock)

func2(x)

pthread_mutex_unlock(x>lock)
func2(x)

func2
pthread_mutex_lock(x>lock)

pthread_mutex_unlock(x>lock)

. 12.1.

,
, (x) 
. , 
, 
( , 
).
, 
, . 
, ,
.


, 
, func1 func2 
. func1 func2,

. 
, func2 func1 
func2,
, 
. 
, .
. 12.2
.
func1 func2 

476

12.

main

func1(x)

func1
pthread_mutex_lock(x>lock)

func2_locked(x)

pthread_mutex_unlock(x>lock)
func2(x)

func2
pthread_mutex_lock(x>lock)
func2_locked(x)

func2_locked

pthread_mutex_unlock(x>lock)

. 12.2.


func2 func2_locked. func2_locked , 
, , 
. func2_locked func2,
func2 , func2_locked
.

, 
, , 
. , 
, , 
.

. 
(,
, , 
) 
, .

, 12.2, 
, .
timeout,
. , 
, 

477

12.4.

.
.
,
. 
, 
.
12.2.
#include
#include
#include
#include

"apue.h"
<pthread.h>
<time.h>
<sys/time.h>

extern int makethread(void *(*)(void *), void *);


struct to_info {
void (*to_fn)(void *);
void *to_arg;
struct timespec to_wait;
};
#define SECTONSEC 1000000000
#define USECTONSEC 1000

/* */
/* */
/* */
/* */
/* */

void *
timeout_helper(void *arg)
{
struct to_info *tip;
tip = (struct to_info *)arg;
nanosleep(&tip>to_wait, NULL);
(*tip>to_fn)(tip>to_arg);
return(0);
}
void
timeout(const struct timespec *when, void (*func)(void *), void *arg)
{
struct timespec now;
struct timeval tv;
struct to_info *tip;
int err;
gettimeofday(&tv, NULL);
now.tv_sec = tv.tv_sec;
now.tv_nsec = tv.tv_usec * USECTONSEC;
if ((when>tv_sec > now.tv_sec) ||
(when>tv_sec == now.tv_sec && when>tv_nsec > now.tv_nsec)) {
tip = malloc(sizeof(struct to_info));
if (tip != NULL) {
tip>to_fn = func;
tip>to_arg = arg;
tip>to_wait.tv_sec = when>tv_sec  now.tv_sec;
if (when>tv_nsec >= now.tv_nsec) {
tip>to_wait.tv_nsec = when>tv_nsec  now.tv_nsec;

478

12.
} else {
tip>to_wait.tv_sec;
tip>to_wait.tv_nsec = SECTONSEC  now.tv_nsec +
when>tv_nsec;
}
err = makethread(timeout_helper, (void *)tip);
if (err == 0)
return;
}
}
/*
* , () when <= now
* () malloc
* () ,
* .
*/
(*func)(arg);

}
pthread_mutexattr_t attr;
pthread_mutex_t mutex;
void
retry(void *arg)
{
pthread_mutex_lock(&mutex);
/* , ... */
pthread_mutex_unlock(&mutex);
}
int
main(void)
{
int err, condition, arg;
struct timespec when;
if ((err = pthread_mutexattr_init(&attr)) != 0)
err_exit(err, " pthread_mutexattr_init");
if ((err = pthread_mutexattr_settype(&attr,
PTHREAD_MUTEX_RECURSIVE)) != 0)
err_exit(err, " ");
if ((err = pthread_mutex_init(&mutex, &attr)) != 0)
err_exit(err, " ");
/* ... */
pthread_mutex_lock(&mutex);
/* ... */
if (condition) {
/* "when" */
timeout(&when, retry, (void *)arg);
}
/* ... */
pthread_mutex_unlock(&mutex);
/* ... */

12.4.

479

exit(0);
}


makethread 12.1.
, .
sleep,
.
, 
, nanosleep(2), 
.
, nanosleep
, Single UNIX Specification, 
, .

, timeout, 
retry, 
. retry
. ,
retry timeout .


, , .
pthread_rwlockattr_t
pthread_rwlockattr_init, pthread_rwlockattr_
destroy.
#include <pthread.h>
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
0 ,

, ,
processshared,
. , pro
cessshared  : pthre
ad_rwlockattr_getpshared pthread_rwlockattr_setpshared.
#include <pthread.h>
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict attr,
int *restrict pshared);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared);
0 ,

480

12.

POSIX 
,
.


.
, 
.
#include <pthread.h>
int pthread_condattr_init(pthread_condattr_t *attr);
int pthread_condattr_destroy(pthread_condattr_t *attr);
0 ,

, 
processshared.
#include <pthread.h>
int pthread_condattr_getpshared(const pthread_condattr_t *restrict attr,
int *restrict pshared);
int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared);
0 ,

12.5.
10.6 
.  ,
. , 
,
.
, 
, (thread;safe).
, Single UNIX Specification, 
,
. 12.5. , ctermid tmpnam 
, 
. , wcrtomb wcsrtombs 
,
mbstate_t .
,
, <unistd.h> _POSIX_THREAD_
SAFE_FUNCTIONS. ,
sysconf 

481

12.5.

_SC_THREAD_SAFE_FUNCTIONS. , XSI,
.
12.5. ,

asctime

ecvt

gethostent

getutxline

putc_unlocked

basename

encrypt

getlogin

gmtime

putchar_unlocked

catgets

endgrent

getnetbyaddr

hcreate

putenv

crypt

endpwent

getnetbyname

hdestroy

pututxline

ctime

endutxent

getnetent

hsearch

rand

dbm_clearerr

fcvt

getopt

inet_ntoa

readdir

dbm_close

ftw

getprotobyname

l64a

dbm_delete

gcvt

getprotobynumber lgamma

setgrent

dbm_error

getc_unlocked

getprotoent

lgammaf

setkey

dbm_fetch

getchar_unlocked getpwent

lgammal

setpwent

dbm_firstkey

getdate

getpwnam

localeconv

setutxent

dbm_nextkey

getenv

getpwuid

localtime

strerror

dbm_open

getgrent

getservbyname

lrand48

strtok

dbm_store

getgrgid

getservbyport

mrand48

ttyname

dirname

getgrnam

getservent

nftw

unsetenv

dlerror

gethostbyaddr

getutxent

nl_langinfo

wcstombs

drand48

gethostbyname

getutxid

ptsname

wctomb

setenv

, , 
, 
POSIX.1.
. 12.6. ,
, .
, 
.
, . 12.6, , 
, _r
, .
,
. 
, 
. 
,
. , 
, . 10.3 
( 10.6).

482

12.

12.6. ,

acstime_r

gmtime_r

ctime_r

localtime_r

getgrgid_r

rand_r

getgrnam_r

readdir_r

getlogin_r

strerror_r

getpwnam_r

strtok_r

getpwuid_r

ttyname_r

, . 12.6, POSIX.1 
, 
FILE .
FILE, flockfile
ftrylockfile. : 
, . 
, ,
, FILE, 
, flockfile funlockfile.
#include <stdio.h>
int ftrylockfile(FILE *fp);
0 ,

void flockfile(FILE *fp);
void funlockfile(FILE *fp);

 
,
( ),
, 
.
. , 
FILE 
.

,
.

. ,
, 
.

483

12.5.

#include <stdio.h>
int getchar_unlocked(void);
int getc_unlocked(FILE *fp);

, EOF
int putchar_unlocked(int c);
int putc_unlocked(int c, FILE *fp);

, EOF

flockfile
( ftrylockfile) funlockfile. 
( ,
).
FILE 
. 

.

12.3 getenv
( 7.9). . 
, 
,
, ,
getenv.
12.3. getenv
#include <limits.h>
#include <string.h>
static char envbuf[ARG_MAX];
extern char **environ;
char *
getenv(const char *name)
{
int i, len;
len = strlen(name);
for (i = 0; environ[i] != NULL; i++) {
if ((strncmp(name, environ[i], len) == 0) &&
(environ[i][len] == =)) {
strcpy(envbuf, &environ[i][len+1]);
return(envbuf);
}

484

12.
}
return(NULL);

12.4 getenv,
getenv_r. pthread_once (
12.6), , 
thread_init .
12.4. ( )
getenv
#include
#include
#include
#include

<string.h>
<errno.h>
<pthread.h>
<stdlib.h>

extern char **environ;


pthread_mutex_t env_mutex;
static pthread_once_t init_done = PTHREAD_ONCE_INIT;
static void
thread_init(void)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&env_mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
int
getenv_r(const char *name, char *buf, int buflen)
{
int i, len, olen;
pthread_once(&init_done, thread_init);
len = strlen(name);
pthread_mutex_lock(&env_mutex);
for (i = 0; environ[i] != NULL; i++) {
if ((strncmp(name, environ[i], len) == 0) &&
(environ[i][len] == =)) {
olen = strlen(&environ[i][len+1]);
if (olen >= buflen) {
pthread_mutex_unlock(&env_mutex);
return(ENOSPC);
}
strcpy(buf, &environ[i][len+1]);
pthread_mutex_unlock(&env_mutex);
return(0);
}
}
pthread_mutex_unlock(&env_mutex);

12.6.

485

return(ENOENT);
}

getenv_r , 
, 
.
, . 
, getenv_r 
. ,
, 
.
getenv_r putenv .
, 
getenv_r 
, , , 
. , ,

. , putenv getenv
, , ,
.
getenv_r ,
, 
. 
, getenv_r
. ,
getenv_r env_mutex ,
, 
. , 

, .
, ,
pthreads
, 
, .

12.6.
, 
.
, ,
,
.

. , 
,
? .

486

12.

, 
, .
,
,
,
. ,
, .
,

. 
errno ( 1.7). (
) errno 
. 

.
, errno 
. , ,
, errno,
.
,
. 
,
. .
,
,
,
.
,
.
.
pthread_key_create.
#include <pthread.h>
int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *));
0 ,

keyp. 
, 
.

NULL.
, pthread_key_create
. 
, ,

12.6.

487


. destructor , ,
. 
pthread_exit 
, .
exit, _exit, _Exit, abort ,
.
, 
malloc.  
. ,
.
.
. 
, , 
.

, (PTHREAD_KEYS_MAX . 12.1).

. ,
. 
,  
, 
, .
,

PTHREAD_DESTRUCTOR_ITERATIONS (. 12.1).
,
pthread_key_delete.
#include <pthread.h>
int pthread_key_delete(pthread_key_t *key);
0 ,

, pthread_key_delete 
, . ,
,
.
, , 
. , 
, , pthread_key_create
:
void destructor(void *);
pthread_key_t key;

488

12.

int init_done = 0;
int
threadfunc(void *arg)
{
if (!init_done) {
init_done = 1;
err = pthread_key_create(&key, destructor);
}
...
}

, , 
, . 
pthread_once.
#include <pthread.h>
pthread_once_t initflag = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *initflag, void (*initfn)(void));
0 ,

initflag ,
PTHREAD_ONCE_INIT.
, initfn
pthread_once,
, pthread_once. , 
:
void destructor(void *);
pthread_key_t key;
pthread_once_t init_done = PTHREAD_ONCE_INIT;
void
thread_init(void)
{
err = pthread_key_create(&key, destructor);
}
int
threadfunc(void *arg)
{
pthread_once(&init_done, thread_init);
...
}

, 
pthread_setspecific. 

, pthread_getspecific.

12.6.

489

#include <pthread.h>
void *pthread_getspecific(pthread_key_t key);

NULL,
int pthread_setspecific(pthread_key_t key, const void *value);
0 ,

, 
pthread_getspecific NULL. 
, ,
pthread_setspecific.

12.3
getenv. , 12.4,
, .
, ,
? 
,
. 12.5.
12.5. getenv,
#include
#include
#include
#include

<limits.h>
<string.h>
<pthread.h>
<stdlib.h>

static pthread_key_t key;


static pthread_once_t init_done = PTHREAD_ONCE_INIT;
pthread_mutex_t env_mutex = PTHREAD_MUTEX_INITIALIZER;
extern char **environ;
static void
thread_init(void)
{
pthread_key_create(&key, free);
}
char *
getenv(const char *name)
{
int i, len;
char *envbuf;
pthread_once(&init_done, thread_init);
pthread_mutex_lock(&env_mutex);
envbuf = (char *)pthread_getspecific(key);
if (envbuf == NULL) {

490

12.
envbuf = malloc(ARG_MAX);
if (envbuf == NULL) {
pthread_mutex_unlock(&env_mutex);
return(NULL);
}
pthread_setspecific(key, envbuf);
}
len = strlen(name);
for (i = 0; environ[i] != NULL; i++) {
if ((strncmp(name, environ[i], len) == 0) &&
(environ[i][len] == =)) {
strcpy(envbuf, &environ[i][len+1]);
pthread_mutex_unlock(&env_mutex);
return(envbuf);
}
}
pthread_mutex_unlock(&env_mutex);
return(NULL);

pthread_once, 
, 
. pthread_getspecific , 
. 
, pthread_getspecific.
free, , 
. , 

.
: getenv 
,
. , 
,
malloc, 
.

12.7.
, pthread_attr_t,
(cancelability
state) (cancelability type).
pthread_
cancel ( 11.5).
cancelability state PTHREAD_CANCEL_ENABLE
PTHREAD_CANCEL_DISABLE. 
pthread_setcancelstate.

491

12.7.

#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
0 ,

pthread_setcancelstate 
cancelability state
state ,
oldstate.
11.5 , pthread_cancel ,
. 
, . 
, 
. POSIX.1 ,
. 12.7.
12.7. , POSIX.1
accept

mq_timedsend

putpmsg

sigsuspend

aio_suspend

msgrcv

pwrite

sigtimedwait

clock_nanosleep

msgsnd

read

sigwait

close

msync

readv

sigwaitinfo

connect

nanosleep

recv

sleep

creat

open

recvfrom

system

fcntl2

pause

recvmsg

tcdrain

fsync

poll

select

usleep

getmsg

pread

sem_timedwait

wait

getpmsg

pthread_cond_timedwait

sem_wait

waitid

lockf

pthread_cond_wait

send

waitpid

mq_receive

pthread_join

sendmsg

write

mq_send

pthread_testcancel

sendto

writev

mq_timedreceive

putmsg

sigpause

cancelability state 
PTHREAD_CANCEL_ENABLE.
PTHREAD_CANCEL_DISABLE, pthread_cancel
. 
.
,
.

492

12.

, . 12.7, POSIX.1
(. 12.8),
.
: , . 12.8, 
. C Single UNIX Specification
.
12.8. ,
POSIX.1
catclose

ftell

getwc

printf

catgets

ftello

getwchar

putc

catopen

ftw

getwd

putc_unlocked

closedir

fwprintf

glob

putchar

closelog

fwrite

iconv_close

putchar_unlocked

ctermid

fwscanf

iconv_open

puts

dbm_close

getc

ioctl

pututxline

dbm_delete

getc_unlocked

lseek

putwc

dbm_fetch

getchar

mkstemp

putwchar

dbm_nextkey

getchar_unlocked nftw

readdir

dbm_open

getcwd

opendir

readdir_r

dbm_store

getdate

openlog

remove

dlclose

getgrent

pclose

rename

dlopen

getgrgid

perror

rewind

endgrent

getgrgid_r

popen

rewinddir

endhostent

getgrnam

posix_fadvise

scanf

endnetent

getgrnam_r

posix_fallocate

seekdir

endprotoent

gethostbyaddr

posix_madvise

semop

endpwent

gethostbyname

posix_spawn

setgrent

endservent

gethostent

posix_spawnp

sethostent

endutxent

gethostname

posix_trace_clear

setnetent

fclose

getlogin

posix_trace_close

setprotoent

fcntl

getlogin_r

posix_trace_create

setpwent

fflush

getnetbyaddr

posix_trace_create_withlog

setservent

fgetc

getnetbyname

posix_trace_eventtypelist_getnext_id setutxent

fgetpos

getnetent

posix_trace_eventtypelist_rewind

strerror

fgets

getprotobyname

posix_trace_flush

syslog

fgetwc

getprotobynumber posix_trace_get_attr

tmpfile

493

12.7.

fgetws

getprotoent

posix_trace_get_filter

tmpnam

fopen

getpwent

posix_trace_get_status

ttyname

fprintf

getpwnam

posix_trace_getnext_event

ttyname_r

fputc

getpwnam_r

posix_trace_open

ungetc

fputs

getpwuid

posix_trace_rewind

ungetwc

fputwc

getpwuid_r

posix_trace_set_filter

unlink

fputws

gets

posix_trace_shutdown

vfprintf

fread

getservbyname

posix_trace_timedgetnext_event

vfwprintf

freopen

getservbyport

posix_typed_mem_open

vprintf

fscanf

getservent

pthread_rwlock_rdlock

vwprintf

fseek

getutxent

pthread_rwlock_timedrdlock

wprintf

fseeko

getutxid

pthread_rwlock_timedwrlock

wscanf

fsetpos

getutxline

pthread_rwlock_wrlock

, . 12.7 12.8,
(,
), 
pthread_testcancel.
#include <pthread.h>
void pthread_testcancel(void);

pthread_testcancel 
, cancela;
bility state ,
. 
, pthread_testcancel .

, . pthread_can
cel , ,
. 
pthread_setcanceltype.
#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
0 ,

type PTHREAD_CANCEL_DEFERRED,
PTHREAD_CANCEL_ASYNCHRONOUS. pthread_setcanceltype 
type
, oldtype.

494

12.

,
. 
,
.

12.8.

. .
, 
. ,
, 
, 
. , ,
, , 

.
. 
, 
, . 
.
10.12 , sig
procmask . sigprocmask 
.
pthread_sigmask.
#include <signal.h>
int pthread_sigmask(int how, const sigset_t *restrict set,
sigset_t *restrict oset);
0 ,

pthread_sigmask sigprocmask,
,
1 errno,
.
, 
sigwait.
#include <signal.h>
int sigwait(const sigset_t *restrict set, int *restrict signop);
0 ,

12.8.

495

set , .
signop 
.
 , set, sig
wait , .
sigwait , 
.
sigwait. sigwait
, 
. sigwait 
. 
, , 
, sigwait.
sigwait ,

. 
, 
. 
, . 
,
,
, 
, .
sig
wait ,
sigwait , . 
(, 
sigaction), ,
sigwait, , 
.

, sigwait 
, .
kill ( 10.9).
pthread_kill.
#include <signal.h>
int pthread_kill(pthread_t thread, int signo);
0 ,

, signo 
0.
,
.

496

12.

: , 
. ,

, ( 12.6).

, 10.16, 
, ,
, . 

, , 
, 
.
, 12.6.
12.6.
#include "apue.h"
#include <pthread.h>
int quitflag;
sigset_t mask;

/* */

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;


pthread_cond_t wait = PTHREAD_COND_INITIALIZER;
void *
thr_fn(void *arg)
{
int err, signo;
for (;;) {
err = sigwait(&mask, &signo);
if (err != 0)
err_exit(err, " sigwait");
switch (signo) {
case SIGINT:
printf("\n\n");
break;
case SIGQUIT:
pthread_mutex_lock(&lock);
quitflag = 1;
pthread_mutex_unlock(&lock);
pthread_cond_signal(&wait);
return(0);
default:
printf(" %d\n", signo);
exit(1);
}
}
}

12.8.

497

int
main(void)
{
int err;
sigset_t oldmask;
pthread_t tid;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
if ((err = pthread_sigmask(SIG_BLOCK, &mask, &oldmask)) != 0)
err_exit(err, " SIG_BLOCK");
err = pthread_create(&tid, NULL, thr_fn, 0);
if (err != 0)
err_exit(err, " ");
pthread_mutex_lock(&lock);
while (quitflag == 0)
pthread_cond_wait(&wait, &lock);
pthread_mutex_unlock(&lock);
/*
* SIGQUIT
* .
*/
quitflag = 0;
/* , SIGQUIT . */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys(" SIG_SETMASK");
exit(0);
}

, 
, .
quitflag , 
, 
pthread_cond_signal. 
,
.
: SIGINT SIGQUIT
. , 
, . 
sigwait , 
. ,
.
, , ,
10.16:
$ ./a.out
?

498

12.

\ $

Linux , 
, clone(2). Linux
,
. POSIX.1
,
, , ,
. Linux 
, , 
, 
. . , 
12.6 , ,
. 
kill, Linux
, .

12.9. fork
fork, 
. 8.3
. ,
, ,
. 
, 
,  . 
, 
, 
exec.
.
, fork.
 ,
. 
, , 
, 
, 
.
, 
fork exec.
,
. : , 
, 
.

499

12.9. fork

, 
, 
pthread_atfork.
#include <pthread.h>
int pthread_atfork(void (*prepare)(void), void (*parent)(void),
void (*child)(void));
0 ,

pthread_atfork , 
. prepare
fork.
, 
. parent 
, , fork . 
,
prepare. child 
, fork . parent, 
child , 
prepare.
: , 
, . 
,
, .
prepare , 
.
,
, 
( ).
, , 
, . ,
, 
, 
:
1. .
2. .
3. .
4. .
pthread_atfork , 
. 
 ,
. 
, . parent child 
, , 

500

12.

prepare . 

.
, , A B
. 
A
B, B
. , fork,
, 
, :
1. prepare A, 
A.
2. prepare B, 
B.
3. .
4. child B B
.
5. child A A
.
6. fork .
7. parent B B 
.
8. parent A A 
.
9. fork .

, ? 
. ,

, . , 
, . 
, 
fork, 
.
,
,
fork.
.

, 12.7,
pthread_atfork .

12.9. fork

12.7. pthread_atfork
#include "apue.h"
#include <pthread.h>
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
void
prepare(void)
{
printf(" ...\n");
pthread_mutex_lock(&lock1);
pthread_mutex_lock(&lock2);
}
void
parent(void)
{
printf(" ...\n");
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2);
}
void
child(void)
{
printf(" ...\n");
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2);
}
void *
thr_fn(void *arg)
{
printf(" ...\n");
pause();
return(0);
}
int
main(void)
{
int err;
pid_t pid;
pthread_t tid;
#if defined(BSD) || defined(MACOS)
printf(" pthread_atfork \n");
#else
if ((err = pthread_atfork(prepare, parent, child)) != 0)
err_exit(err, " ");
err = pthread_create(&tid, NULL, thr_fn, 0);
if (err != 0)

501

502

12.

err_exit(err, " ");


sleep(2);
printf(" fork...\n");
if ((pid = fork()) < 0)
err_quit(" fork");
else if (pid == 0)
/* */
printf(" fork \n");
else
/* */
printf(" fork \n");
#endif
exit(0);
}

, lock1 lock2. prepare 


, child ,
parent .
:
$ ./a.out
...
fork...
...
...
fork
...
fork

, prepare fork, 
child fork ,
parent fork .

12.10. 
3.11 pread pwrite.
, 
.
,
.
A
lseek(fd, 300, SEEK_SET);
read(fd, buf1, 100);

B
lseek(fd, 700, SEEK_SET);
read(fd, buf2, 100);

A lseek, B
lseek , A read, 
. , ,
.
, pread,

.

503

12.11.
A
pread(fd, buf1, 100, 300);

B
pread(fd, buf2, 100, 700);

pread, , A
, 300, B 700. 
, , 
pwrite.

12.11.
UNIX
. 
,
. ,
, . 
. , ,
.

12.1. 12.7 Linux, 


. .
12.2. putenv_r
putenv. ,
, .
12.3. 12.5 
,

? .
12.4. getenv 
12.5. FreeBSD. 
, .
12.5.
, ,
fork.
12.6. 10.21 ,
, nano
sleep.
12.7. fork

pthread_cond_destroy 
pthread_cond_init?

13

13.1.
.
.
, , .
UNIX .
 ,
. , 
, ,
 , .

[Raymond 1996].

13.2.

,
. ps(1) .
,
.
ps axj

BSD 
. a
, , x
, , j
, : 
, ,
.

505

13.2.

, System V, ps
efjc. ( UNIX 
, , 
ps.) ps :
PPID
0
1
1
0
0
0
1
1
1
1
1
1405
1
1

PID
1
2
3
5
6
7
1009
1048
1335
1403
1405
1406
1853
2182

PGID
0
1
1
1
1
1
1009
1048
1335
1
1
1
1853
2182

SID
0
1
1
1
1
1
1009
1048
1335
1
1
1
1853
2182

TTY TPGID UID


?
1 0
?
1 0
?
1 0
?
1 0
?
1 0
?
1 0
?
1 32
?
1 0
?
1 0
?
1 0
?
1 0
?
1 0
?
1 0
?
1 0

COMMAND
init
[keventd]
[kapmd]
[kswapd]
[bdflush]
[kupdated]
portmap
syslogd m 0
xinetd pidfile /var/run/xinetd.pid
[nfsd]
[lockd]
[rpciod]
crond
/usr/sbin/cupsd

, 
. , 
: , ,
, , ,
(
, ), 
.
, (Linux), 
, setsid 
9.5. .
, BSD, session, 
, ( 9.11).

, ,
. 
0,
. ( init,
, .) 
, , .

, .
1 init, 
8.2. , , , 

. , .
Linux keventd 
. kapmd 

506

13.

, 
. kswapd .
, 
,
(dirty pages), .
Linux 
bdflush kupdated. bdflush 
, 
. kupdated 

, .
portmap RPC (Remote
Procedure Call ) . 
syslogd 
.
, . ( syslogd 
13.4.)
9.3 inetd (xinetd).
. nfsd,
lockd rpciod (NFS
Network File System).
cron (crond) . 

cron. cupsd , 
.
: 
( 0).

, 1. 
. 
,
setsid.
, 
. , , ,
init.

13.3.

. 
, daemonize,
.
1. umask, 
0. , 

13.3.

507

,
. , 
, 
. ,
, ,
, .
2. fork .
? , 
, , 
, . , 
, 
; , 
,
setsid, .
3. , setsid. (
9.5) () , ()
() .
, System V, 
fork ,
. ,
, 
System V ( 9.6). ,
,
O_NOCTTY.

4. . 
, , 
. , 
, , , 
, 
, .
, 
, 
. ,
, .
5. . 
,
( ). 
open_max ( 2.4)
getrlimit ( 7.11)
.
6. 0, 1 2
/dev/null , ,

, 

508

13.

. 
,
.
, ,
.
, 
 , 
, .

13.1 , 
, .
13.1. ;
#include
#include
#include
#include

"apue.h"
<syslog.h>
<fcntl.h>
<sys/resource.h>

void
daemonize(const char *cmd)
{
int i, fd0, fd1, fd2;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
/*
* .
*/
umask(0);
/*
* .
*/
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
err_quit("%s: ",
cmd);
/*
* , .
*/
if ((pid = fork()) < 0)
err_quit("%s: fork", cmd);
else if (pid != 0) /* */
exit(0);
setsid();
/*
* .
*/

509

13.3.
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0)
err_quit("%s: SIGHUP");
if ((pid = fork()) < 0)
err_quit("%s: fork", cmd);
else if (pid != 0) /* */
exit(0);
/*
* ,
* .
*/
if (chdir("/") < 0)
err_quit("%s: /");
/*
* .
*/
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
for (i = 0; i < rl.rlim_max; i++)
close(i);
/*
* 0, 1 2 /dev/null.
*/
fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
/*
* .
*/
openlog(cmd, LOG_CONS, LOG_DAEMON);
if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
syslog(LOG_ERR, " %d %d %d",
fd0, fd1, fd2);
exit(1);
}
}

daemonize , 
, 
ps:
$ ./a.out
$ ps axj
PPID
PID PGID SID TTY TPGID UID
1 3346 3345 3345 ?
1 501
$ ps axj | grep 3345
1 3346 3345 3345 ?
1 501

COMMAND
./a.out
./a.out

510

13.

ps ,
3345. ,
( 9.10) ,
. 
fork daemonize. ,
.

13.4.
, ,
. 
,
. ,
, 
. , 
.
, 
, . 
.
syslog BSD 
, 4.2BSD. , BSD, 
syslog.
SVR4 System V
.
syslog Single UNIX Specification XSI.

syslog BSD , 4.2BSD.


. . 13.1 
.
:
1. log.
, 
/dev/klog.
,
.
2. () 
syslog(3). 
.
UNIX /dev/log.
3. , 
,
TCP/IP, UDP 514. 
, syslog 
UDP , 
.

511

13.4.

syslogd

syslog

/dev/log

UDP 514

UNIX

Internet

/dev/klog
log

TCP/IP

. 13.1. syslog BSD;

UNIX [Ste
vens, Fenner, and Rudoff 2004].
syslogd .
( ,
/etc/syslog.conf), , 
. , 
( ), 
.

syslog.
#include <syslog.h>
void openlog(const char *ident, int option, int facility);
void syslog(int priority, const char *format, ...);
void closelog(void);
int setlogmask(int maskpri);

openlog.
syslog openlog , 
. closelog 
, 
syslogd.

512

13.

openlog ident 
, (, cron in
etd). option , 
. . 13.1 ,
. XSI ,
Single UNIX Specification 
openlog.
13.1. ,
option openlog
option

XSI

LOG_CONS

UNIX,
.

LOG_NDELAY

UNIX
syslogd, , .
, ,
.

LOG_NOWAIT

, 
. 
, 
SIGCHLD,
, syslog
wait.

LOG_ODELAY

syslogd
.

syslogd (
Solaris).

LOG_PERROR

LOG_PID

.
, 
( 
, syslogd,
fork).

facility . 13.2.
, Single UNIX Specification
, . facility 
, 
. openlog
facility 0, 
syslog, priority.
syslog . priority
facility (. 13.2)
(. 13.3).
. 13.3 , .

13.4.

513

13.2. facility openlog


facility

XSI

LOG_AUTH

: login, su, getty, ...

LOG_AUTHPRIV

, LOG_AUTH, 

LOG_CRON

cron at

LOG_DAEMON

: inetd, routed, ...

LOG_FTP

FTP (ftpd)

LOG_KERN

LOG_LOCAL0

LOG_LOCAL1

LOG_LOCAL2

LOG_LOCAL3

LOG_LOCAL4

LOG_LOCAL5

LOG_LOCAL6

LOG_LOCAL7

LOG_LPR

: lpd, lpc, ...

LOG_MAIL

LOG_NEWS

Usenet
syslogd

LOG_SYSLOG
LOG_USER
LOG_UUCP

( )
UUCP

13.3. ( )

LOG_EMERG

( ) ( )

LOG_ALERT

LOG_CRIT

(, )

LOG_ERR

LOG_WARNING

LOG_NOTICE

, , , ,

LOG_INFO

LOG_DEBUG

( )

514

13.

format vsprintf
. %m
(strerror), 
errno.
setlogmask 
.
. , , 
, .
: , 0,
.
logger(1),
syslog.
, 
(facility), (ident),
System UNIX Specification 
. logger
, 
.

() :
openlog("lpd", LOG_PID, LOG_LPR);
syslog(LOG_ERR, "open error for %s: %m", filename);

openlog , 
, ,
, , 
. syslog 
.
openlog, syslog :
syslog(LOG_ERR | LOG_LPR, "open error for %s: %m", filename);

priority 
.
syslog, 
, 
.
#include <syslog.h>
#include <stdarg.h>
void vsyslog(int priority, const char *format, va_list arg);

, , vsys
log, Single UNIX Specification.

13.5.

515

syslogd 
.
, 
.
: last message repeated N times (
N ).

13.5.
, 
.
, ,  
. , cron
, 
,
.
,

. 
. ,
, 
.
, 
, 
. ( 14.3.)

,
.
, 
, .

.
, . 
, 
, .

, 13.2, 
,
.
13.2. ,

#include <unistd.h>
#include <stdlib.h>

516

13.

#include
#include
#include
#include
#include
#include

<fcntl.h>
<syslog.h>
<string.h>
<errno.h>
<stdio.h>
<sys/stat.h>

#define LOCKFILE "/var/run/daemon.pid"


#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
extern int lockfile(int);
int
already_running(void)
{
int fd;
char buf[16];
fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE);
if (fd < 0) {
syslog(LOG_ERR, " %s: %s",
LOCKFILE, strerror(errno));
exit(1);
}
if (lockfile(fd) < 0) {
if (errno == EACCES || errno == EAGAIN) {
close(fd);
return(1);
}
syslog(LOG_ERR, " %s: %s",
LOCKFILE, strerror(errno));
exit(1);
}
ftruncate(fd, 0);
sprintf(buf, "%ld", (long)getpid());
write(fd, buf, strlen(buf)+1);
return(0);
}


. 
. , lockfile 
EACCESS EAGAIN errno,
1, ,
.
, 0.
,
, ,
. , ,
12345,
9999. ,

13.6.

517

, 99995.
, 
.

13.6.
UNIX .

, 
/var/run. , , 
. 
name.pid, name . , cron
/var/run/crond.pid.

,
/etc. ,
, name.conf, name . 
, syslogd /etc/syslog.conf.

,  
(/etc/rc*
/etc/init.d/*).
, init,
respawn /etc/inittab.

, 
, 
. ,
,
. 
SIGHUP, 
. 

, 
, SIGHUP. ,
.

, 13.3, 
.
sigwait ,
12.8.
13.3. ,

#include "apue.h"
#include <pthread.h>
#include <syslog.h>

518

13.

sigset_t mask;
extern int already_running(void);
void
reread(void)
{
/* ... */
}
void *
thr_fn(void *arg)
{
int err, signo;
for (;;) {
err = sigwait(&mask, &signo);
if (err != 0) {
syslog(LOG_ERR, " sigwait");
exit(1);
}
switch (signo) {
case SIGHUP:
syslog(LOG_INFO, " ");
reread();
break;
case SIGTERM:
syslog(LOG_INFO, " SIGTERM; ");
exit(0);
default:
syslog(LOG_INFO, " %d\n", signo);
}
}
return(0);
}
int
main(int argc, char *argv[])
{
int err;
pthread_t tid;
char *cmd;
struct sigaction sa;
if ((cmd = strrchr(argv[0], /)) == NULL)
cmd = argv[0];
else
cmd++;
/*
* .
*/
daemonize(cmd);

13.6.

519

/*
* , .
*/
if (already_running()) {
syslog(LOG_ERR, " ");
exit(1);
}
/*
* SIGHUP
* .
*/
sa.sa_handler = SIG_DFL;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0)
err_quit("%s: SIG_DFL SIGHUP");
sigfillset(&mask);
if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0)
err_exit(err, " SIG_BLOCK");
/*
* , SIGHUP SIGTERM.
*/
err = pthread_create(&tid, NULL, thr_fn, 0);
if (err != 0)
err_exit(err, " ");
/*
* .
*/
/* ... */
exit(0);
}

daemonize
13.1. already_running
13.2, 
. SIGHUP ,
, 
sigwait .
,
, ,
. SIGHUP SIGTERM.
SIGHUP reread 
, SIGTERM 
.
. 10.1 , SIGHUP SIG
TERM . 
, , . 

520

13.


sigwait.

12.8, Linux 
. ,
. , ,
, ,  
.
, 13.4, ,
SIGHUP 
, .
13.4. ,

#include "apue.h"
#include <syslog.h>
#include <errno.h>
extern int lockfile(int);
extern int already_running(void);
void
reread(void)
{
/* ... */
}
void
sigterm(int signo)
{
syslog(LOG_INFO, " SIGTERM; ");
exit(0);
}
void
sighup(int signo)
{
syslog(LOG_INFO, " ");
reread();
}
int
main(int argc, char *argv[])
{
char *cmd;
struct sigaction sa;
if ((cmd = strrchr(argv[0], /)) == NULL)
cmd = argv[0];
else

13.6.

521

cmd++;
/*
* .
*/
daemonize(cmd);
/*
* , .
*/
if (already_running()) {
syslog(LOG_ERR, " ");
exit(1);
}
/*
* .
*/
sa.sa_handler = sigterm;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGHUP);
sa.sa_flags = 0;
if (sigaction(SIGTERM, &sa, NULL) < 0) {
syslog(LOG_ERR, " SIGTERM: %s",
strerror(errno));
exit(1);
}
sa.sa_handler = sighup;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGTERM);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0) {
syslog(LOG_ERR, " SIGHUP: %s",
strerror(errno));
exit(1);
}
/*
* .
*/
/* ... */
exit(0);
}

SIG
HUP SIGTERM. SIGHUP:
,
,
.

522

13.

13.7. 
 
. . 13.1 syslogd, 
()
UNIX.
, , 
. , . 13.1
syslogd .
. 13.1
. ,
.
,
, .

13.8.
 
. , 
, 
, 9. 
, 
.

, , , .
, 
UNIX, .

13.1. . 13.1, ,
syslog ( openlog,
syslog)
/dev/log. , 
() chroot
openlog?
13.2. 
.
13.3. , daemonize 
13.1.
getlogin ( 8.15), , 
. 
.

14

14.1.
, 
;: 
, , STREAMS, 
 ( select poll), readv
writev  , (mmap). 
, 
15 17 
.

14.2. 
10.5 ,
: . 
, . 
:

,
, (, 
, ) , .

,
( , . .).

, 
(,
, 
, FIFO 
, , 
).

524

14.

, 
.

ioctl.

, 
( 15).

, , 
, ,

.
 ,
open, read write, , . 
, 

, , .
, 
.
1. open, 
O_NONBLOCK ( 3.3).
2. O_NONBLOCK ,
fcntl ( 3.14). 3.5
,
.
System V 
O_NDELAY.
read 0.
UNIX , read 0 , 
POSIX.1 
. System V, read 0,
, ,
, .
POSIX.1 ,
read 1 EAGAIN 
errno. UNIX, System V, 
O_NDELAY, POSIX.1 O_NONBLOCK, 
,
POSIX.1. O_NDELAY
.
4.3BSD fcntl FNDELAY . 

, 
, ,
( 4.3BSD 
). , 4.3BSD
EWOULDBLOCK,
. BSD

525

14.2. -

O_NONBLOCK EWOULDBLOCK
, EAGAIN.
, POSIX.1: 
,
,
(. 3.1 3.3).

 . ,
14.1, 500 000 
. 
. 

. clr_fl set_fl
3.5. .
14.1.
#include "apue.h"
#include <errno.h>
#include <fcntl.h>
char buf[500000];
int
main(void)
{
int ntowrite, nwrite;
char *ptr;
ntowrite = read(STDIN_FILENO, buf, sizeof(buf));
fprintf(stderr, " %d \n", ntowrite);
set_fl(STDOUT_FILENO, O_NONBLOCK);

/* */

ptr = buf;
while (ntowrite > 0) {
errno = 0;
nwrite = write(STDOUT_FILENO, ptr, ntowrite);
fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno);
if (nwrite > 0) {
ptr += nwrite;
ntowrite = nwrite;
}
}
clr_fl(STDOUT_FILENO, O_NONBLOCK);

/* */

exit(0);
}

, write , 
:

526
$ ls l /etc/termcap
rwrr 1 root
702559 Feb 23
$ ./a.out < /etc/termcap > temp.file
500000
nwrite = 500000, errno = 0
$ ls l temp.file
rwrwr 1 sar
500000 Jul 8

14.

2002 /etc/termcap

write

04:19 temp.file

,
, write , 
500 000, . :
$ ./a.out < /etc/termcap 2>stderr.out
...
$ cat stderr.out
500000
nwrite = 216041, errno = 0
nwrite = 1, errno = 11
1497
. . .
nwrite = 16015, errno = 0
nwrite = 1, errno = 11
1856
. . .
nwrite = 32081, errno = 0
nwrite = 1, errno = 11
1654
. . .
nwrite = 48002, errno = 0
nwrite = 1, errno = 11
1460
. . .
...
nwrite = 7949, errno = 0

11 EAGAIN. ,
, 
. ,
, , 
.
, , .

write, 1020 . 
. ;
(polling),
. 14.5 
.

( 11). 
,
. ,
21; , 
,
.

14.3.

527

14.3.
,
? UNIX 
.
, ,
, . 
UNIX
. ( 20
, .)

,
,
. 
UNIX , UNIX 
, .
,
(, ), 
.

UNIX , 
 
,
. UNIX 
( , ).
flock,
, .
fcntl System V
Release 3. lockf fcntl 
. 
, 
.
POSIX.1 fcntl.
. 14.1 , 
. : Single UNIX Spe
cification lockf XSI.

.
fcntl.
Version 7
(John Bass) 1980 . locking. 
,
System III. Xenix , 

528

14.

System V Intel, OpenServer 5,


Xenix.
14.1. ,
UNIX

fcntl

lockf

flock

SUS

XSI

FreeBSD 5.2.1

Linux 2.4.22

Mac OS X 10.3

Solaris 9

fcntl
fcntl 3.14.
#include <fcntl.h>
int fcntl(int filedes, int cmd, ... /* struct flock *flockptr */ );
cmd (. )
, 1

cmd
F_GETLK, F_SETLK F_SETLKW. (
flockptr) flock.
struct flock {
short l_type;
off_t l_start;
short l_whence;
off_t l_len;
pid_t l_pid;
};

/*
/*
/*
/*
/*

F_RDLCK, F_WRLCK F_UNLCK */


l_whence */
SEEK_SET, SEEK_CUR SEEK_END */
; 0 */
F_GETLK */


: F_RDLCK ( ), F_WRLCK (
) F_UNLCK ( )
(l_start l_whence)
(l_len)
, ,
(
F_GETLK)
, 
, .

529

14.3.

, ,
lseek ( 3.6). l_whence 
SEEK_SET, SEEK_CUR SEEK_END.


,
.

l_len 0, , 
. 
,
, , 
. ( ,
.)

, l_start l_when
ce , , l_len 0.
( ,
l_start 0,
l_whence SEEK_SET.)

( l_type F_RDLCK) 
(F_WRLCK).
, 
,

. , 
, 
, ,
, 
.
. 14.2.
14.2.

OK

OK

OK

,
, ,
.
,

530

14.

.
, 16
32
, ( ,
),
.
,
. ,
.
fcntl,
.
F_GETLK

, 
.
, 
, flockptr 
.
, flockptr ,
l_type, F_UNLCK.

F_SETLK

,
flockptr. ,
( ,
. 14.2), fcntl
EAGAIN EACCES errno.
POSIX.1 ,
, ,
EAGAIN, .

.
l_type F_UNLCK.
F_SETLKW
F_SETLK. ( W wait .) 

 , 
, 
,
. ,

.
,
(F_GETLK) (F_SETLK F_SETLKW)
. ,
fcntl
, .

531

14.3.


, F_SETLK 
.
: POSIX.1 , ,
, 
,

.
, ,
, . 
, 
.

, , , 
.



. , , 100199, 
150, 
: 100149 151199. . 14.1.

100
199
100 199

100

149 151
199
150

. 14.1.

150 , 
100 199 . 
, . 14.1,
. . , .



flock, lock_reg, 
( 14.2).

532

14.

14.2.
#include "apue.h"
#include <fcntl.h>
int
lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
struct flock lock;
lock.l_type = type;
lock.l_start = offset;
lock.l_whence = whence;
lock.l_len = len;

/*
/*
/*
/*

F_RDLCK, F_WRLCK, F_UNLCK */


l_whence */
SEEK_SET, SEEK_CUR, SEEK_END */
(0 ) */

return(fcntl(fd, cmd, &lock));


}


( F_GETLK 
), , 
apue.h ( B).
#define read_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))

,
lseek.



14.3 lock_test,
.
14.3.
#include "apue.h"
#include <fcntl.h>
pid_t
lock_test(int fd, int type, off_t offset, int whence, off_t len)
{
struct flock lock;
lock.l_type = type;
/* F_RDLCK F_WRLCK */
lock.l_start = offset; /* l_whence */

14.3.

533

lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */


lock.l_len = len;
/* (0 ) */
if (fcntl(fd, F_GETLK, &lock) < 0)
err_sys("fcntl error");
if (lock.l_type == F_UNLCK)
return(0);
/* , */
/* */
return(lock.l_pid);
/* , pid */
}

, 
, 
, .
0 (). 
( apue.h).
#define is_read_lockable(fd, offset, whence, len) \
(lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)
#define is_write_lockable(fd, offset, whence, len) \
(lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)

: lock_test
, 
. F_GETLK ,
,
. F_SETLK
F_SETLKW ,
,
. , F_GETLK
, 
.


( ) , 
,
. , 
, 
, 
, .
14.4 .
0, 1. 
, 
.
8.9 (TELL_xxx WAIT_xxx),
,
. 14.4,
:

534

14.

$ ./a.out
: 1
: 0
: writew_lock: Resource deadlock avoided
: 0

14.4.
#include "apue.h"
#include <fcntl.h>
static void
lockabyte(const char *name, int fd, off_t offset)
{
if (writew_lock(fd, offset, SEEK_SET, 1) < 0)
err_sys("%s: writew_lock", name);
printf("%s: %ld\n", name, offset);
}
int
main(void)
{
int fd;
pid_t pid;
/*
* .
*/
if ((fd = creat("templock", FILE_MODE)) < 0)
err_sys(" creat");
if (write(fd, "ab", 2) != 2)
err_sys(" write");
TELL_WAIT();
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) {
/* */
lockabyte ("", fd, 0);
TELL_PARENT(getppid());
WAIT_PARENT();
lockabyte("", fd, 1);
} else {
/* */
lockabyte("", fd, 1);
TELL_CHILD(pid);
WAIT_CHILD();
lockabyte("", fd, 0);
}
exit(0);
}

, 
.
.
, ,
.

14.3.

535



.
1. . 
. , 
. , ,
, , 
. ,
fd1 = open(pathname, ...);
read_lock(fd1, ...);
fd2 = dup(fd1);
close(fd2);

fd2 , 
fd1, . ,
dup open, :
fd1 = open(pathname, ...);
read_lock(fd1, ...);
fd2 = open(pathname, ...)
close(fd2);

, .
2. ,
fork. , ,
fork, , 
,
. 
fcntl, 
, .
,
. 
,
.
3.
exec. closeonexec (
exec), , , 
exec.

FreeBSD
, 
FreeBSD. 1, 
, .
(
, ):

536

14.

fd1 = open(pathname, ...);


write_lock(fd1, 0, SEEK_SET, 1);

/* */
/* 0 */
/* */

if ((pid = fork()) > 0) {


fd2 = dup(fd1);
fd3 = open(pathname, ...);
} else if (pid == 0) {
read_lock(fd1, 1, SEEK_SET, 1); /* */
/* 1 */
}
pause();

. 14.2 , 
pause.

open, fork dup (. 3.3 8.1). ,
, lockf, 
. : lockf 
( ), 
. :


fd1:
fd2:
fd3:
...

fd1:
fd2:
fd3:
...

struct lockf

. .

struct lockf

. .

. 14.2. , ,
FreeBSD

14.3.

537

write_lock ,
read_lock . 
.
fd1,
fd2 fd3 . 
,
, 
. ,

.

13.2 ,
, 
. 14.5 lockfile,
, .
14.5.
#include <unistd.h>
#include <fcntl.h>
int
lockfile(int fd)
{
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.l_len = 0;
return(fcntl(fd, F_SETLK, &fl));
}

, lockfile 
write_lock:
#define lockfile(fd) write_lock((fd), 0, SEEK_SET, 0)


,
. 
l_whence (SEEK_CUR SEEK_END)
l_start
. 

, lseek 
, . (

538

14.

lseek , ,
.)
:
writew_lock(fd, 0, SEEK_END, 0);
write(fd, buf, 1);
un_lock(fd, 0, SEEK_END);
write(fd, buf, 1);

, . 
, 
, , .
, , 
write , 
.
, , 
.
, ,
.
. 14.3.
, 
.
(SEEK_SET), fcntl
(SEEK_CUR) 
(SEEK_END).
,
, ,
.
, ,
1 . 
, 
.

. 14.3.

539

14.3.


, .

, ,
, 
, ( ) 
. 
, , 
. 
,
. 
( ), 
( ) .

open, read write , ,
. ;
.
. 14.1 , Linux 2.4.22 Solaris 9
, FreeBSD 5.2.1 Mac OS X 10.3 . 
Single UNIX Specification.
Linux
, o mand mount.


setgroupID groupexecute (
4.4). setgroupID 
groupexecute, SVR3 
, , 
.
,
, 

, ? 
( ), , 
( ) ,
. . 14.3 
.
14.3. ;

, 



read
write
read
write
OK

OK
EAGAIN

EAGAIN

EAGAIN

540

14.

read write, . 14.3, 



. open , 
.

. 14.3. 
(,
) open O_TRUNC O_CREAT,

EAGAIN open 
O_NONBLOCK.
Solaris O_CREAT 
. Linux , 
. , open
O_TRUNC, ,
, , 
. O_CREAT 
, , , 
. ,
.

open 
. 
, ( 
), 
.
( . 14.3 ,
.) 
, UNIX.
ed,
! , 
. 
trace,
UNIX, , ed 
, 
, .
unlink,
.
Solaris trace truss(1). FreeBSD Mac
OS X ktrace(1) kdump(1). Linux
strace(1) , .

vi . 
,
EAGAIN. write 
. , vi.

14.3.

541

> >> 
Korn shell
cannot create ( ).

Bourne
shell >,
>> . (
>> Korn shell Bourne
shell , Korn shell
open O_CREAT O_APPEND, ,
O_CREAT . 
Bourne shell open O_CREAT,
, open
, write 
.)


. ,
. , 
ed ,
.

,
,
. .
(, 
, 
.) ,

. 
,
.

, 14.6, ,
.
14.6. ,

#include
#include
#include
#include

"apue.h"
<errno.h>
<fcntl.h>
<sys/wait.h>

int
main(int argc, char *argv[])
{
int fd;

542

14.
pid_t pid;
char buf[5];
struct stat statbuf;
if (argc != 2) {
fprintf(stderr, ": %s filename\n", argv[0]);
exit(1);
}
if ((fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, FILE_MODE)) < 0)
err_sys(" open");
if (write(fd, "abcdef", 6) != 6)
err_sys(" write");
/* setgroupID groupexecute */
if (fstat(fd, &statbuf) < 0)
err_sys(" fstat");
if (fchmod(fd, (statbuf.st_mode & S_IXGRP) | S_ISGID) < 0)
err_sys(" fchmod");
TELL_WAIT();
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid > 0) {
/* */
/* */
if (write_lock(fd, 0, SEEK_SET, 0) < 0)
err_sys(" write_lock");
TELL_CHILD(pid);
if (waitpid(pid, NULL, 0) < 0)
err_sys(" waitpid");
} else {
/* */
WAIT_PARENT();
/* , */
set_fl(fd, O_NONBLOCK);
/*
* , ,
* .
*/
if (read_lock(fd, 0, SEEK_SET, 0) != 1) /* */
err_sys(": read_lock ");
printf(" read_lock %d\n",
errno);
/* */
if (lseek(fd, 0, SEEK_SET) == 1)
err_sys(" lseek");
if (read(fd, buf, 2) < 0)
err_ret(" (. )");
else
printf(" (. ),
buf = %2.2s\n", buf);
}

14.3.

543

exit(0);
}


. .
. 

, .
, EACCES
EAGAIN. 
. 
, read
EACCES EAGAIN ( 
). read , 
. Solaris 9 ( 
) :
$ ./a.out temp.lock
read_lock 11
(. ): Resource temporarily unavailable


intro(2), , 11 EAGAIN.
FreeBSD 5.2.1 :
$ ./a.out temp.lock
read_lock 35
(. ), buf = ab

35 EAGAIN. 
.

: ,

? UNIX 
, : 
, .
vi
.
vi, 
, .
, 
,
( ). 
, ,
vi. , 
fork,
. 

544

14.

, 
,
vi. , 
,
. 
wait .
,
. , 
. 
, , , .
, 
, . 
.
20 
,
. 
, , 
.

14.4. STREAMS
STREAMS System V 
. 
STREAMS, System V,
poll  (
14.5.2) , 
STREAMS ( 17.2 17.2.1).
STREAMS stream (), 
 ( 5.2). streams
[Ritchie 1984]
 . ,
, streams SVR3 ,
. STREAMS (
 STREAMS) SVR4.
SVR4 [AT&T 1990d]. [Rago 1993] 
STREAMS , .
STREAMS Single UNIX Specification 
( XSI
STREAMS Option Group). , , 
Solaris STREAMS. Linux
STREAMS, ,
.

(stream) STREAMS
. 
STREAMS

545

14.4. STREAMS


(
)


( )

. 14.4.

STREAMS 
. . 14.4 , 
.

. . 14.5 
.
, 
, ,
, , 
.
.

, . (

. 14.5.

546

14.

, 
.) . 14.5
. , , 
. , , 
.
STREAMS ,
.
(, 
, Linux Solaris), STREAMS 
, , 

.
STREAMS , 
3: open, close, read, write ioctl. ,
STREAMS SVR3 (getmsg,
putmsg poll), SVR4 (getpmsg putpmsg), 
. 
.
, open pathname,
STREAMS /dev.
ls l, ,
STREAMS. STREAMS 
.
STREAMS , 
,
,
. , STREAMS
.
STREAMS 
 (clist ). ( SVR2 BSD4.4
[Bach 1986], 10.3.1, [McKusuck et al. 1996], 10.6, .)

, . 
, 
, read write
. STREAMS ,
STREAMS
.

STREAMS
STREAMS .

read, write, ioctl, getmsg, getpmsg, putmsg
putpmsg. 
, .

14.4. STREAMS

547

,
, , 
. . 14.4 ,
write, put
msg putpmsg. 
strbuf:
struct strbuf
int maxlen; /* */
int len;
/* */
char *buf; /* */
};

putmsg putpmsg len


. 
getmsg getpmsg maxlen ( 
), len
. , 
1 len
.

?
. 5 [Olander, McGrath,
and Israel 1986] 
System V. 5 [AT&T 1990d]
. ,
System V 4 [Rago 1993]
(TLI Transport Layer Interface),
.
, , 
().
,
() ( ).
,
. ,
, , ioctl
write . ,
N , write.

(putmsg getmsg) .
25 ,

.
. ( ,
STREAMS,
.) read, write, getmsg,
getpmsg, putmsg putpmsg :

548

14.

M_DATA ( )
M_PROTO ( )
M_PCPROTO ( )


:
( )

( )
,
0. 1
255, . 

, 
.
,
.
STREAMS . 
( 
), (
). 
. . 14.4 
, write, putmsg putpmsg
.
,
. ,
M_SIG, .
, 
, ,
.

putmsg putpmsg
STREAMS ( , 
) putmsg putpmsg.
, 
.
#include <stropts.h>
int putmsg(int filedes, const struct strbuf *ctlptr,
const struct strbuf *dataptr, int flag);
int putpmsg(int filedes, const struct strbuf *ctlptr,
const struct strbuf *dataptr, int band, int flag);
0 , 1

549

14.4. STREAMS

write,
putmsg, 
0 flag.

: , 
. . 14.4
.
14.4. STREAMS, write,
putmsg putpmsg
?
?

band

flag

write

M_DATA ()

putmsg

C 
, 0

putmsg

M_DATA ()

putmsg

M_PROTO ()

putmsg

RS_HIPRI

M_PCPROTO (
)

putmsg

RS_HIPRI

O EINVAL

putpmsg

0255

O EINVAL

putpmsg

0255

MSG_BAND

C 
, 0

putpmsg

MSG_BAND

M_DATA ()

1255

putpmsg

MSG_BAND

M_DATA ()

putpmsg

MSG_BAND

M_DATA ()

putpmsg

1255

MSG_BAND

M_PROTO ()

putpmsg

MSG_HIPRI M_PCPROTO (
)

putpmsg

MSG_HIPRI O EINVAL

putpmsg

MSG_HIPRI O EINVAL

,
. ? 
ctlptr,
1 ctlptr>len. 
? , ctlptr
ctlptr>len , .
? ( ctlptr 
dataptr).

550

14.

ioctl STREAMS
3.15 , ioctl ,
. STRE
AMS .
Linux Solaris 40 ,
ioctl.
streamio(7).
,
<stropts.h>. ioctl, request 
. 
I_. 
, .

isastream
, STREAMS
. Linux Solaris isas
tream. isatty, ,
( 18.9).
#include <stropts.h>
int isastream(int filedes);
1 (), STREAMS,
0 ()

isatty, 
ioctl, STREAMS.
14.7 .
I_CANPUT, , 
( 0).
.
14.7. , STREAMS
#include <stropts.h>
#include <unistd.h>
int
isastream(int fd)
{
return(ioctl(fd, I_CANPUT, 0) != 1);
}


14.8.
14.8. isastream
#include "apue.h"
#include <fcntl.h>

14.4. STREAMS

551

int
main(int argc, char *argv[])
{
int i, fd;
for (i = 1; i < argc; i++) {
if ((fd = open(argv[i], O_RDONLY)) < 0) {
err_ret(" %s", argv[i]);
continue;
}
if (isastream(fd) == 0)
err_ret("%s: STREAMS", argv[i]);
else
err_msg("%s: STREAMS", argv[i]);
}
exit(0);
}

Solaris 9,
, ioctl:
$ ./a.out /dev/tty /dev/fb /dev/null /etc/motd
/dev/tty: STREAMS
/dev/fb: STREAMS: Invalid argument
/dev/null: STREAMS: No such device or address
/etc/motd: STREAMS: Inappropriate ioctl for device

, /dev/tty Solaris
STREAMS. /dev/fb
STREAMS,
ioctl. EINVAL,
.
/dev/null ioctl,
ENODEV. , ,
/etc/motd ,
ENOTTY. , 
: ENOSTR (Device is not a stream 
).
ENOTTY Not a typewriter ( 
); , ,
UNIX ENOTTY ioctl 
, ,
. Solaris Inappropriate ioctl
for device ( ioctl).

request ioctl I_LIST, 


, ,
. ( , 

552

14.

. 
12 [Rago 1993].)
str_list:
struct str_list {
int sl_nmods;
/* */
struct str_mlist *sl_modlist; /* */
};

sl_modlist
str_mlist, sl_nmods 
:
struct str_mlist {
char l_name[FMNAMESZ+1]; /* , */
};

FMNAMESZ <sys/conf.h>
8. l_name 
.
ioctl 0, 
. 
,
str_mlist.
14.9 I_LIST. 
, ,
, 
.
14.9.
#include
#include
#include
#include

"apue.h"
<fcntl.h>
<stropts.h>
<sys/conf.h>

int
main(int argc, char *argv[])
{
int fd,i, nmods;
struct str_list list;
if (argc != 2)
err_quit(": %s <___>", argv[0]);
if ((fd = open(argv[1], O_RDONLY)) < 0)
err_sys(" %s", argv[1]);
if (isastream(fd) == 0)
err_quit("%s STREAMS", argv[1]);
/*
* .
*/
if ((nmods = ioctl(fd, I_LIST, (void *) 0)) < 0)

14.4. STREAMS

553

err_sys(" I_LIST ");


printf(" = %d\n", nmods);
/*
* .
*/
list.sl_modlist = calloc(nmods, sizeof(struct str_mlist));
if (list.sl_modlist == NULL)
err_sys(" calloc");
list.sl_nmods = nmods;
/*
* .
*/
if (ioctl(fd, I_LIST, &list) < 0)
err_sys(" I_LIST ");
/*
* .
*/
for (i = 1; i <= nmods; i++)
printf(" %s: %s\n", (i == nmods) ? "" : "",
list.sl_modlist++>l_name);
exit(0);
}


STREAMS, , 
. :
$ who
sar console May 1 18:27
sar pts/7 Jul 12 06:53
$ ./a.out /dev/console
= 5
: redirmod
: ttcompat
: ldterm
: ptem
: pts
$ ./a.out /dev/pts/7
= 4
: ttcompat
: ldterm
: ptem
: pts

,
, ,
. 
, 
/dev/console .
19.

554

14.

write STREAMS
. 14.4 , write STREAMS
M_DATA. ,
, .
, 
, . ( 
.)
, , 
(
).
, , write 
, . 
,
. 
.

ioctl, .


ioctl , 
. I_GWROPT
request , 
,
. request I_SWROPT,
,
. 
( 3.14),
,
ioctl.
, .
:
SNDZERO


. write
.

SNDPIPE

write
putmsg, SIGPIPE.

, ,
, getmsg getpmsg.

getmsg getpmsg
STREAMS
read, getmsg getpmsg.

555

14.4. STREAMS

#include <stropts.h>
int getmsg(int filedes, struct strbuf *restrict ctlptr,
struct strbuf *restrict dataptr, int *restrict flagptr);
int getpmsg(int filedes, struct strbuf *restrict ctlptr,
struct strbuf *restrict dataptr, int *restrict bandptr,
int *restrict flagptr);

, 1

: , flagptr
bandptr, ; 
.
.
flagptr 0, getmsg
. 
,
RS_HIPRI. 
, getmsg 
flagptr RS_HIPRI.
getpmsg . getpmsg
, 
flagptr MSG_HIPRI.
( 
), flagptr MSG_BAND,
bandptr () . 
, 
flagptr MSG_ANY;
, MSG_HIPRI MSG_BAND
.
, bandptr
.
ctlptr ctlptr>max
len 1, 
. , 
dataptr dataptr>maxlen 
1, 
.
,
, 
.
getmsg getpmsg
, 0.
, 
, MORECTL. , 

556

14.

, ,
MOREDATA.
, , 
, MORECTL|MOREDATA.


STREAMS 
read. 
.
1. , 
?
2. , read , 
?
1
. read ,

. 
. , , 
, read 
. read, 
.
request ioctl I_GRDOPT, 
, 
. 
request I_SRDOPT,
, 
.
:
RNORM

( ),
, .

RMSGN

.
read ,

. 
, 
read.

RMSGD

.
, , 
.

,
, 
:

557

14.4. STREAMS

RPROTNORM : read
EBADMSG. .
RPROTDAT

: read
, .

RPROTDIS

: 
read ,
.


, , ,
.
RNORM|RPROTNORM.

, 14.10, 
, 3.3, read 
getmsg.
14.10.
getmsg
#include "apue.h"
#include <stropts.h>
#define BUFFSIZE 4096
int
main(void)
{
int n, flag;
char ctlbuf[BUFFSIZE], datbuf[BUFFSIZE];
struct strbuf ctl, dat;
ctl.buf = ctlbuf;
ctl.maxlen = BUFFSIZE;
dat.buf = datbuf;
dat.maxlen = BUFFSIZE;
for ( ; ; ) {
flag = 0;
/*
if ((n = getmsg(STDIN_FILENO, &ctl, &dat, &flag))
err_sys(" getmsg");
fprintf(stderr, "flag = %d, ctl.len = %d, dat.len
flag, ctl.len, dat.len);
if (dat.len == 0)
exit(0);
else if (dat.len > 0)
if (write(STDOUT_FILENO, dat.buf, dat.len) !=
err_sys(" write");
}
}

*/
< 0)
= %d\n",

dat.len)

558

14.

Solaris, , 
STREAMS, :
$ echo , | ./a.out
flag = 0, ctl.len = 1, dat.len = 11
,
flag = 0, ctl.len = 0, dat.len = 0
$ ./a.out

flag = 0, ctl.len = 1, dat.len = 17


flag = 0, ctl.len = 1, dat.len = 15

D
flag = 0, ctl.len = 1, dat.len = 0


STREAMS

STREAMS

STREAMS

EOF

$ ./a.out < /etc/motd


getmsg: Not a stream device

( echo )
14.10 STREAMS: 
, . ( 
15.2.) 
.
STREAMS. ,
,
STREAMS, getmsg.

14.5. 

 , :
while ((n = read(STDIN_FILENO, buf, BUFSIZ)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys(" write");

.
, ? 
,
, 
.
.
telnet(1).
( ) 
,
( ). 

559

14.5. -

telnet

telnetd

. 14.6. telnet

telnetd , , 
. , , 
telnet .
. 14.6.
telnet . 

, ,
.

( fork), 
. . 14.7.
( cu(1) uucp System V
.)
,
.
, . 
( 
telnetd), ,
SIGCHLD. 
( ),
, 
SIGUSR1, .

. , , 
,
, .
, 
, 
read. 
, . , read
. 
telnet
( )

telnetd
telnet
( )

. 14.7. telnet

560

14.

. (,
) .
.
.
, read
. , ,
. , 
, , 
.
.
,
, . 
. ,
( Single UNIX Specification
). System V
SIGPOLL, , 
STREAMS. BSD SIGIO,
,

. , 
(SIGPOLL SIGIO) . 
(
), , , ,
. 
, 
. 
 14.6.
;.
,
( 
), , ,
.
, 
.

poll, pselect select. . 14.5 , 
. : select 
POSIX.1, poll XSI 
.
POSIX , ,
select,
<sys/select.h>. ,
,
. ,
, select.

561

14.5. -

<sys/types.h>,
<sys/time.h> <unistd.h>.
 select 
4.2BSD. , 

. SVR3, STREAMS, poll.
poll STREAMS.
SVR4 .
14.5. ;

poll

pselect

select

<sys/select.h>

SUS

XSI

FreeBSD 5.2.1

Linux 2.4.22

Mac OS X 10.3

Solaris 9

14.5.1. select pselect


select 
POSIX . ,
select, :

(
, , )

(
,
)

, , 

, 
 ( ), , 
.
#include <sys/select.h>
int select(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds,
fd_set *restrict exceptfds, struct timeval *restrict tvptr);
,
, 0 , 1

562

14.

. 
:
struct timeval {
long tv_sec; /* */
long tv_usec; /* */
};

.
tvptr == NULL
.
.
, 
.
select 1 EINTR errno.
tvptr?>tv_sec == 0 && tvptr?>tv_usec == 0
. 
,
.
, 
select.
tvptr?>tv_sec != 0 || tvptr?>tv_usec != 0
.
, 
.
,
, 0. (
, tvptr>
tv_usec .)
, .
POSIX.1 timeval
, select , 
, select.
FreeBSD 5.2.1, Mac OS X 10.3 Solaris 9 ,
Linux 2.4.22 
.

, readfds, writefds exceptfds 


. 
, (
, ).
fd_set. 
,
.
, . 14.8.

14.5. -

readfds

fd 0

fd 1

fd 2

563

...


writefds

...

fd_set
exceptfds

...

. 14.8. select

, fd_set,

.
#include <sys/select.h>
int FD_ISSET(int fd, fd_set *fdset);
, fd
, 0
void FD_CLR(int fd, fd_set *fdset);
void FD_SET(int fd, fd_set *fdset);
void FD_ZERO(fd_set *fdset);

.
FD_ZERO fdset . FD_SET
. FD_CLR . , 
FD_ISSET .

FD_ZERO. 
, :
fd_set rset;
int fd;
FD_ZERO(&rset);
FD_SET(fd, &rset);
FD_SET(STDIN_FILENO, &rset);

select FD_ISSET
, :
if (FD_ISSET(fd, &rset)) {
...
}

564

14.

( ) (
) .
NULL,
,
sleep. ( 10.19 , sleep
. select

.) 
14.6 .
select, maxfdp1,
maximum file descriptor plus 1 ( 1).

, , .
FD_SETSIZE, 
<sys/select.h>. 
( 1024),
. 
3 10 . ( 
, UNIX.)
, 

.
. 14.9 ,
:
fd_set readset, writeset;
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_SET(0, &readset);
FD_SET(3, &readset);
FD_SET(1, &writeset);
FD_SET(2, &writeset);
select(4, &readset, &writeset, NULL, NULL);


, 0, 

readset:

fd 0

fd 1

fd 2

fd 3

writeset:

maxfdp1 = 4

. 14.9. select

14.5. -

565


, ( 0).
select :
1. 1 . 
, , , 
.
.
2. 0 , 
. , 
 
. , 
.
3. 
, . 
.
, ,
, . 
, 
, .
.

readfds ,
read .

writefds ,
write .

exceptfds , 
, 
.
(outofband) ,
, 
, . (
[Stevens 1990], 15.10.)

,
.

, ( 
) ,
select. , 
, ,
select  5 , select 5 
. , ,
select , 
 .
, select
.

566

14.

read 0, UNIX
. ( , select 
.)
POSIX.1 select
pselect.
#include <sys/select.h>
int pselect(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds,
fd_set *restrict exceptfds, const struct timespec *restrict tsptr,
const sigset_t *restrict sigmask);
,
0 , 1

pselect select, :
 select timeval,
pselect timespec. (
timespec 11.6.) 
timespec .

,
.
, , 
const. ,
pselect.
pselect . 
sigmask , pselect 
, select. 
sigmask , 
pselect.
.

14.5.2. poll
poll select,
. poll
System V, STREAMS, 
.
#include <poll.h>
int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);
,
0 , 1

, 
( , , 

14.5. -

567

), select, 
poll pollfd, 

:
struct pollfd {
int fd;
short events;
short revents;

/*
/*
/*
/*

<0, */
*/
*/
*/

};

fdarray nfds.
, nfds. SVR3 
unsigned long, .
SVR4 [AT&T 1990d]
poll size_t. (
. 2.16.) <poll.h> 
unsigned long. Single UNIX Specifica
tion nfds_t, 
.
: , ,
,
.
SVID ( System V), SVR4 [AT&T 1989],
poll, struct pollfd fdarray[],
SVR4 [AT&T 1990d] , 
struct pollfd *fdarray. C .
, , fdar
ray , .

,
events , 
. 14.6. poll 
, . (
: poll events. 
select, 
, .)
, 

. . 14.6
.
revents, , ,
events.
(POLLHUP),
.
, .

568

14.

14.6. events reevents poll

events revents

POLLIN

, , 
,
( POLLRDNORM|POLLRDBAND).

POLLRDNORM

( 0) 
, .

POLLRDBAND


, .

POLLPRI

,
.

POLLOUT

, 
.

POLLWRNORM

, POLLOUT.

POLLWRBAND

,
.

POLLERR

POLLHUP

POLLNVAL

poll , 
. select,
.
timeout == 1
. (
<stropts.h>, INFTIM 
1.) ,

 . 
1 EINTR errno.
timeout == 0
. 
, 
.
, poll.
timeout > 0
timeout . 
,
.  ,
0. ( ,

14.6. -

569

, 
timeout .)

. 
, POLLIN, 
( read 0). POLLHUP
revents.
, POLLHUP.
select,
, poll.

poll select
4.2BSD 
( 10.5), select 
. 
, SA_RESTART. SVR4,
SA_RESTART , select poll 
. ,

, SVR4, 
signal_intr ( 10.13), 
select poll.
, , 
select poll , 
SA_RESTART.

14.6. 
select poll, , 
. 
, (
select poll). 10 ,
. ,
BSD System V,
, (SIGPOLL System V SIGIO
BSD) , 
.
, select poll .
, ,
. , System V,
 STREAMS. , 
BSD, 
.

570

14.

 ,
 
. , 
,
, .
Single UNIX Specification 
, 
. , .
, 
, .

14.6.1.  System V
System V  
STREAMS
STREAMS.  System V
SIGPOLL.
 STRE
AMS, ioctl 
(request) I_SETSIG.
, . 14.7.
<stropts.h>.
14.7. , SIGPOLL

S_INPUT

, 
.

S_RDNORM

S_RDBAND

S_BANDURG

S_RDBAND,
SIGPOLL 
SIGURG.

S_HIPRI

S_OUTPUT

S_WRNORM

, S_OUTPUT.

S_WRBAND

S_MSG

, SIGPOLL.

S_ERROR

M_ERROR.

S_HANGUP

M_HANGUP.

, . 14.7 , 
.

571

14.7. readv writev

ioctl , 
SIGPOLL, 
. . 10.1 , 
SIGPOLL ,
ioctl.

14.6.2.  BSD
 , BSD, 
SIGIO SIGURG.
,
.
SIGIO, 
.
1. SIGIO signal sig
action.
2. F_SETOWN fcntl
,
( 3.14).
3. , 
fcntl F_SETFL,
O_ASYNC (. 3.3).
3 ,
,

 BSD.
SIGURG 1 2.
, 
, .

14.7. readv writev


readv writev 
. 
.
#include <sys/uio.h>
ssize_t readv(int filedes, const struct iovec *iov, int iovcnt);
ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);

, 1

iovec:

572

14.

struct iovec {
void *iov_base; /* */
size_t iov_len; /* */
};

iov iovcnt 
IOV_MAX (. 2.9). . 14.10 
iovec.
writev
iov[0], iov[1] ... iov[iovcnt1]
,
.
readv ,
, 
. .
, readv 0.
4.2BSD SVR4.
Single UNIX Specification XSI.
, Single UNIX Specification
void *, , ,
char *.

20.8, _db_writeidx, 
. 
, 
, 
. .
1. write .
2. ,
write 
.
3. writev.
buffer0

iov[0].iov_base
iov[0].iov_len

len0

iov[1].iov_base
iov[1].iov_len

len0
buffer1

len1

len1

...
bufferI

iov[iovcnt1].iov_base
iov[iovcnt1].iov_len

lenI

. 14.10. iovec readv writev

lenI

573

14.7. readv writev

20.8 writev, 
.
. 14.8 .
14.8. writev

Linux (Intel x86)


Mac OS X (Power PC)
 
 


1,29

3,15

7,39

1,60

17,40

19,84





write

1,03

1,98

6,47

1,10

11,09

12,54


writev

0,70

2,72

6,41

0,86

13,58

14,72

, ,
100 200 . 1 048 576
, 300 .
,
. 14.8. times
( 8.16), .
(, ) 
.
, write 
, write
writev. , . 3.2.
, , ( 
) 
write , writev.
write
, ,
write, . 
writev , 

.
writev.
, ,
writev .
Linux Mac OS X.
, : 

574

14.

, 
. 
,
.

: 
. , ,
write
writev. , , 
, 
.

14.8. readn writen


,
, STREAMS, 
.
1. read , 
, . ,
.
2. write , .
, ,  , 
.
, 
write. ( 

.)
, 

, 
.
, ,
. 
,
. ,
: 
read write ,
.
#include "apue.h"
ssize_t readn(int filedes, void *buf, size_t nbytes);
ssize_t writen(int filedes, void *buf, size_t nbytes);

, 1

14.8. readn writen

575

, , , 
, .
readn writen  .

writen ,
, readn 
, , 
. 14.11
readn writen, .
,

. ,
, , ,
,
, .
14.11. readn writen
#include "apue.h"
ssize_t
/* n */
readn(int fd, void *ptr, size_t n)
{
size_t nleft;
ssize_t nread;
nleft = n;
while (nleft > 0) {
if ((nread = read(fd, ptr, nleft)) < 0) {
if (nleft == n)
return(1); /* , 1 */
else
break;
/* , */
} else if (nread == 0) {
break;
/* */
}
nleft = nread;
ptr += nread;
}
return(n  nleft);
/* >= 0 */
}
ssize_t
/* n */
writen(int fd, const void *ptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
nleft = n;
while (nleft > 0) {
if ((nwritten = write(fd, ptr, nleft)) < 0) {
if (nleft == n)

576

14.
return(1); /* , 1 */
else
break;
/* , */
} else if (nwritten == 0) {
break;
}
nleft = nwritten;
ptr += nwritten;
}
return(n  nleft);

/* >= 0 */

14.9. 

 (memorymapped) 
,

. , 
. 
 read write.
 
. 1981 4.1BSD 
 , vread vwrite.
, 4.2BSD, ,
mmap. mmap 4.2BSD ( ,
2.5 [McKusick et al. 1996]). mmap
[Gingell, Moran, and Shannon 1987]. mmap Single
UNIX Specification, XSI
UNIX.

, 
.
mmap.
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off);

, MAP_FAILED

addr 
. 0,
.
.
filedes .
, . 

577

14.9. -

len , ,
off . (
, off.)
prot .
14.9.
prot

PROT_READ

PROT_WRITE

PROT_EXEC

PROT_NONE

PROT_NONE,
(OR) PROT_READ, PROT_WRITE PROT_
EXEC. ,
, , 
. , PROT_WRITE,
.
flag, . 14.11,
, . ( 
. 7.3). 
, mmap. 
C
C

len

(bss)

off
len

. 14.11.

578

14.


, .
flag 
.
MAP_FIXED


addr. , 
. 
addr ,
addr ,
,
. 
0 addr.
MAP_FIXED POSIX
, XSI .

MAP_SHARED


. 

, . .
write .
, .

MAP_PRIVATE , 

.
. ( 
,
.

.)
,
MAP_xxx.
mmap(2).
off addr ( MAP_FIXED)
.
sysconf ( 2.5.4) _SC_PAGESI
ZE _SC_PAGE_SIZE. off addr 
0, .

, , 
? , 
12 , 512 .

512 , 500 .

14.9. -

579

500 , 
. ,
mmap . 
, 14.12.

. SIGSEGV, ,
.
, 
. SIGBUS 
, 
. , ,
, 
, . ,
, ,
SIGBUS.

fork (
), 
exec.

mprotect.
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
0 , 1

prot , 
prot mmap (. 14.9). addr ,
.
mprotect Single UNIX Specification 
, XSI
.


, msync. msync 
fsync ( 3.13), 
.
#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
0 , 1

580

14.

MAP_PRIVATE, 
.
, addr 
, .
flags 
. , 
MS_ASYNC. 
, ,
MS_SYNC. MS_ASYNC,
MS_SYNC.
MS_INVALIDATE 
, , 
(). 
,
.

munmap. 
.
#include <sys/mman.h>
int munmap(caddr_t addr, size_t len);
0 , 1

munmap , 
munmap
. 
, MAP_SHARED, 
. , ,
MAP_PRIVATE, munmap .

, 14.12, ( 
cp(1)),  
.
14.12. ;

#include "apue.h"
#include <fcntl.h>
#include <sys/mman.h>
int
main(int argc, char *argv[])
{
int fdin, fdout;

14.9. -

581

void *src, *dst;


struct stat statbuf;
if (argc != 3)
err_quit(": %s <fromfile> <tofile>", argv[0]);
if ((fdin = open(argv[1], O_RDONLY)) < 0)
err_sys(" %s ", argv[1]);
if ((fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC,
FILE_MODE)) < 0)
err_sys(" %s ", argv[2]);
if (fstat(fdin, &statbuf) < 0)
err_sys("fstat error");

/* */

/* */
if (lseek(fdout, statbuf.st_size  1, SEEK_SET) == 1)
err_sys(" lseek");
if (write(fdout, "", 1) != 1)
err_sys(" write");
if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED,
fdin, 0)) == MAP_FAILED)
err_sys(" mmap ");
if ((dst = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fdout, 0)) == MAP_FAILED)
err_sys(" mmap ");
memcpy(dst, src, statbuf.st_size); /* */
exit(0);
}

fstat 
.
mmap, , . 
lseek , 
.
, mmap 
, 
SIGBUS.
ftruncate, 
( 4.13).
ftruncate
.

mmap 
, ,
memcpy.
(src) 
. (dst) 
.

582

14.

, , 
.

. , , 
msync MS_SYNC.


read write ( 
8192 ). . 14.10 . 
300 , .
14.10.

Linux (Intel x86)


Solaris 9 (SPARC)
 

read/write

0,04

1,02

39,76

0,18

9,70

41,66

mmap/memcpy

0,64

1,31

24,26

1,68

7,94

28,53

Solaris 9 ( 
) : 9,88 9,62 
. Linux 2.4.22
mmap/memcpy (1,06 1,95 ). ,
,
.
,
mmap/memcpy ,
read/write. , 
mmap/memcpy .
read/write 
(read) (write). 
mmap/memcpy
, , ,
.

.
( 
) , , , 
.

, 
, read write 
. ,
 , , 
.

14.10.

583

[Kreiger, Stumm, and Unrau 1992]


 ( 5), 
.
 15.9
, , 
.

14.10.

,
:

 ,
.

( 
20).

System V STREAMS ( 
17, STREAMS, 

System V).

 select poll (
).

readv writev ( 
).

 (mmap).

14.1. , 
, 
,
,
. , 
, , 
?
14.2. 
select FD_.
14.3.
, fd_set.
, 2048 
. ?

584

14.

14.4. , 
( 10.11),
fd_set. .
14.5. getmsg?
14.6. sleep_us, sleep,

. select
poll. usleep BSD.
14.7. TELL_WAIT, TELL_PARENT, TELL_CHILD,
WAIT_PARENT WAIT_CHILD 10.17, 
? , 
.
14.8. , 
. 
PIPE_BUF 2.
14.9. . 14.8. ,
writev , write.
14.10. 14.12, 
, .
14.11. 14.12 
mmap, ,

.

15

15.1.
8 ,
. 

fork exec .

IPC (Interprocess Communication), 
.
IPC UNIX
, 
. ,
POSIX The Open Group ( X/Open), 
, . . 15.1
IPC,
, .
: Single UNIX Specification ( SUS) 
,

. , , 
, ,
. . 15.1 
, , 
.
. 15.1
(). , 
UNIX ( 17.3), 
UDS (UNIX domain
socket). 

586

15.

, UNIX, ,
UDS .
14.4, STREAMS 
Single UNIX Specification . 
,
STREAMS, Single UNIX Specifica
tion . Linux STREAMS
LiS ( Linux STREAMS), 
. 
, 
, ..
15.1. IPC, UNIX
IPC

SUS

FreeBSD 5.2.1 Linux 2.4.22 Mac OS X 10.3 Solaris 9

, UDS

., UDS

UDS

, UDS

UDS

, UDS

 

XSI,
.

UDS

., UDS

XSI

XSI

XSI

STREAMS

XSI,
.

IPC . 15.1 
,
. STREAMS IPC,

, , .

. IPC:
, , 
.
. 17 
IPC.

587

15.2.

15.2.
(pipes, ) 
, 
UNIX. :
1. ( 
).
, 
.
2.
, . 
, fork,

.
( 15.5) ,
, UNIX (unix domain sockets, 17.3) 
STREAMS ( 17.2.2) .
, 
IPC.
, , 
, 

.
pipe.
#include <unistd.h>
int pipe(int filedes[2]);
0 , 1

filedes : filedes[0]
, filedes[1] . , file
des[1], filedes[0].
4.3BSD, 4.4BSD Mac OS X 10.3
UNIX. , 
, ,
, , 
.
POSIX.1 .
filedes[0] filedes[1] ,
.

. 15.1 
. ,

588

15.

fd[0]

fd[1]

fd[0]

fd[1]

. 15.1.

. 
.
fstat ( 4.2) 
FIFO. , ,
S_ISFIFO.

POSIX.1 , st_size stat 


. fstat , 
, st_size ,
. 
.

, , 
. , pipe, 
fork, , , 

589

15.2.

fd[1]

fd[0]

. 15.3.

. 
. 15.2.
, fork, ,
.
, 
, (fd[0]), 
, (fd[1]). . 15.3 
.
, 
fd[1], fd[0].
,
.
1. , 
, , read 0,
,


fork

fd[0]

fd[1]

fd[0]

fd[1]

. 15.2. fork

590

15.

. (,
, ,
. , 
.
, ,
, .
, ,
.)
2. , 
, , SIGPIPE.

,
write 1 EPIPE errno.

PIPE_BUF. , 
PIPE_BUF, , 
( FIFO) . 
write , PIPE_BUF,
, , 
. PIPE_BUF
pathconf fpathconf ( 2.11).

15.1 , 
.
15.1.

#include "apue.h"
int
main(void)
{
int n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if (pipe(fd) < 0)
err_sys(" pipe");
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid > 0) {
/* */
close(fd[0]);
write(fd[1], ", \n", 12);
} else {
/* */

15.2.

591

close(fd[1]);
n = read(fd[0], line, MAXLINE);
write(STDOUT_FILENO, line, n);
}
exit(0);
}

,
write read.
.
, 
( ) 
( ).

, .
, ,
UNIX, 
,
. 
system
, , 
. 
, fork , 
, ,
exec
. 15.2 , . ( 
,
, . ,
, , .)
15.2.
#include "apue.h"
#include <sys/wait.h>
#define DEF_PAGER "/bin/more" /* */
int
main(int argc, char *argv[])
{
int n;
int fd[2];
pid_t pid;
char *pager, *argv0;
char line[MAXLINE];
FILE *fp;
if (argc != 2)
err_quit(": a.out <pathname>");
if ((fp = fopen(argv[1], "r")) == NULL)

592

15.
err_sys(" %s", argv[1]);
if (pipe(fd) < 0)
err_sys(" pipe");
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid > 0) {
/* */
close(fd[0]);
/* */
/* argv[1] */
while (fgets(line, MAXLINE, fp) != NULL) {
n = strlen(line);
if (write(fd[1], line, n) != n)
err_sys(" ");
}
if (ferror(fp))
err_sys(" fgets");
close(fd[1]);
/* */
if (waitpid(pid, NULL, 0) < 0)
err_sys(" waitpid");
exit(0);
} else {
/* */
close(fd[1]);
/* */
if (fd[0] != STDIN_FILENO) {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
err_sys(" stdin");
close(fd[0]);
/* dup2 */
}
/* execl() */
if ((pager = getenv("PAGER")) == NULL)
pager = DEF_PAGER;
if ((argv0 = strrchr(pager, /)) != NULL)
argv0++;
/* */
else
argv0 = pager;
/* */
if (execl(pager, argv0, (char *)0) < 0)
err_sys(" %s", pager);
}
exit(0);

fork . fork
, ,
, . 
dup2, 
, , .
(fd[0]
), ,
, . 
, dup2 close

15.2.

593

. ( dup2,
, 3.12). ,
, fopen,
,
0, ,
, fd[0] 
. , dup2
close, , 
.
, PAGER, 
, 
. , 
. 
.

TELL_WAIT, TELL_PARENT, TELL_CHILD, WAIT_PARENT


WAIT_CHILD 8.9. 10.17
. 15.3
, .
15.3.
#include "apue.h"
static int pfd1[2], pfd2[2];
void
TELL_WAIT(void)
{
if (pipe(pfd1) < 0 || pipe(pfd2) < 0)
err_sys(" pipe");
}
void
TELL_PARENT(pid_t pid)
{
if (write(pfd2[1], "c", 1) != 1)
err_sys(" write");
}
void
WAIT_PARENT(void)
{
char c;
if (read(pfd1[0], &c, 1) != 1)
err_sys(" read");
if (c != p)
err_quit("WAIT_PARENT: ");
}

594

15.


pfd1[1]
pfd2[0]


"p"
"c"

pfd1[0]
pfd2[1]

. 15.4.

void
TELL_CHILD(pid_t pid)
{
if (write(pfd1[1], "p", 1) != 1)
err_sys(" write");
}
void
WAIT_CHILD(void)
{
char c;
if (read(pfd2[0], &c, 1) != 1)
err_sys(" read");
if (c != c)
err_quit("WAIT_CHILD: ");
}

fork , . 15.4. 
TELL_CHILD
p, TELL_PARENT
c. WAIT_xxx read
.
, 
. ,
pfd1[0], 
, . 
, .

15.3. popen pclose



, , 
 pclose popen.
,
: , ,

595

15.3. popen pclose

, 
.
#include <stdio.h>
FILE *popen(const char *cmdstring, const char *type);
FILE
, NULL
int pclose(FILE *fp);
cmdstring, 1

popen fork exec 


cmdstring FILE.
type r, 
cmdstring (. 15.5).

fp

cmdstring ( )
stdout

. 15.5. fp = popen(cmdstring, r)

type w, 
cmdstring (. 15.6).
popen,
fopen, FILE,
, type r, ,
type w.
pclose , 
,
cmdstring. ( 
8.6. system, 8.13,
.) ,
pclose , 
exit(127).
cmdstring Bourne shell
sh c cmdstring

fp

cmdstring ( )
stdin

. 15.6. fp = popen(cmdstring, w)

596

15.

, 
, cmdstring. ,
,
fp = popen("ls *.c", "r");

fp = popen("cmd 2>&1", "r");

15.2 ,
popen.
15.4.
15.4.
popen
#include "apue.h"
#include <sys/wait.h>
#define PAGER "${PAGER:more}" /* , */
/* */
int
main(int argc, char *argv[])
{
char line[MAXLINE];
FILE *fpin, *fpout;
if (argc != 2)
err_quit(": a.out <__>");
if ((fpin = fopen(argv[1], "r")) == NULL)
err_sys(" %s", argv[1]);
if ((fpout = popen(PAGER, "w")) == NULL)
err_sys(" popen");
/* argv[1] */
while (fgets(line, MAXLINE, fpin) != NULL) {
if (fputs(line, fpout) == EOF)
err_sys(" ");
}
if (ferror(fpin))
err_sys(" fgets");
if (pclose(fpout) == 1)
err_sys(" pclose");
exit(0);
}

popen
.

15.3. popen pclose

597

${PAGER:more} , 
PAGER, 
, more.

popen pclose
15.5 popen pclose.
15.5. popen pclose
#include
#include
#include
#include

"apue.h"
<errno.h>
<fcntl.h>
<sys/wait.h>

/*
* , .
*/
static pid_t *childpid = NULL;
/*
* open_max(), 2.4.
*/
static int maxfd;
FILE *
popen(const char *cmdstring, const char *type)
{
int i;
int pfd[2];
pid_t pid;
FILE *fp;
/* "r" "w" */
if ((type[0] != r && type[0] != w) || type[1] != 0) {
errno = EINVAL;
/* POSIX */
return(NULL);
}
if (childpid == NULL) {
/* */
/* , */
maxfd = open_max();
if ((childpid = calloc(maxfd, sizeof(pid_t))) == NULL)
return(NULL);
}
if (pipe(pfd) < 0)
return(NULL); /* errno pipe() */
if ((pid = fork()) < 0) {
return(NULL); /* errno fork() */
} else if (pid == 0) { /* */
if (*type == r) {
close(pfd[0]);
if (pfd[1] != STDOUT_FILENO) {

598

15.
dup2(pfd[1], STDOUT_FILENO);
close(pfd[1]);
}
} else {
close(pfd[1]);
if (pfd[0] != STDIN_FILENO) {
dup2(pfd[0], STDIN_FILENO);
close(pfd[0]);
}
}
/* childpid[] */
for (i = 0; i < maxfd; i++)
if (childpid[i] > 0)
close(i);
execl("/bin/sh", "sh", "c", cmdstring, (char *)0);
_exit(127);
}
/* ... */
if (*type == r) {
close(pfd[1]);
if ((fp = fdopen(pfd[0], type)) == NULL)
return(NULL);
} else {
close(pfd[0]);
if ((fp = fdopen(pfd[1], type)) == NULL)
return(NULL);
}
childpid[fileno(fp)] = pid; /* pid fd */
return(fp);

}
int
pclose(FILE *fp)
{
int fd, stat;
pid_t pid;
if (childpid == NULL) {
errno = EINVAL;
return(1);

/* popen() */

}
fd = fileno(fp);
if ((pid = childpid[fd]) == 0) {
errno = EINVAL;
return(1);
/* fp popen() */
}
childpid[fd] = 0;
if (fclose(fp) == EOF)

15.3. popen pclose

599

return(1);
while (waitpid(pid, &stat, 0) < 0)
if (errno != EINTR)
return(1); /* waitpid , EINTR */
return(stat);
/* */
}

popen , 
, , 
. , ,
popen,
FILE.
,
. pclose, 
FILE,
fileno 
, waitpid. 
popen ,
popen childpid
.
pipe fork 
, .
POSIX.1 , popen 
, .
childpid 
.
, , pclose, 
SIGCHLD? waitpid
EINTR. , 
SIGCHLD ( ,
waitpid),
waitpid ,
.
:
waitpid , 
popen. waitpid, pclose,
1 ECHILD
errno. POSIX.1.
pclose EINTR,
wait . , 
pclose SIGINT, SIGQUIT
SIGHUP. POSIX.1 .

, popen
, setuserID setgroupID. 
popen

600

15.

execl("/bin/sh", "sh", "c", command, NULL);

command 
, . 
, , 
.
popen 
, 
. , 
.

,
.
popen
, 
. . 15.7 , 
.
, , 
(
).
15.6 .
,
. ,
, , 
fflush .
15.6.

#include "apue.h"
#include <ctype.h>
int
main(void)
{

$
popen

stdout

stdout
stdin

. 15.7. popen

15.4.

601

int c;
while ((c = getchar()) != EOF) {
if (isupper(c))
c = tolower(c);
if (putchar(c) == EOF)
err_sys(" ");
if (c == \n)
fflush(stdout);
}
exit(0);
}

myuclc,
popen , 15.7.
15.7.

#include "apue.h"
#include <sys/wait.h>
int
main(void)
{
char line[MAXLINE];
FILE *fpin;
if ((fpin = popen("myuclc", "r")) == NULL)
err_sys(" popen");
for ( ; ; ) {
fputs("prompt> ", stdout);
fflush(stdout);
if (fgets(line, MAXLINE, fpin) == NULL) /* */
break;
if (fputs(line, stdout) == EOF)
err_sys(" fputs");
}
if (pclose(fpin) == 1)
err_sys(" pclose");
putchar(\n);
exit(0);
}

fflush
, ,
.

15.4.
UNIX , 


602

15.

. , 
. , 
.
Korn shell 
(. [Bolsky and Korn 1995]). Bourne shell, Bour
neagain shell C shell . 
,
.
, ,
, 
( [Bolsky and Korn 1995], . 6263), 
, C.
, 

.
, 
.

. 
: , 
. . 15.8.
15.8 , 
, 
. (
. ,
.)
15.8. ,
#include "apue.h"
int
main(void)
{
int n, int1, int2;
char line[MAXLINE];
while ((n = read(STDIN_FILENO, line, MAXLINE)) > 0) {
line[n] = 0;
/* */

fd1[1]
fd2[0]

()
1

stdin
stdout

. 15.8.

603

15.4.
if (sscanf(line, "%d%d", &int1, &int2) == 2) {
sprintf(line, "%d\n", int1 + int2);
n = strlen(line);
if (write(STDOUT_FILENO, line, n) != n)
err_sys(" write");
} else {
if (write(STDOUT_FILENO, " \n", 19) != 19)
err_sys(" write");
}
}
exit(0);
}

add2.
, 15.9, 
add2. , ,
.
15.9. , add2
#include "apue.h"
static void sig_pipe(int);

/* */

int
main(void)
{
int n, fd1[2], fd2[2];
pid_t pid;
char line[MAXLINE];
if (signal(SIGPIPE, sig_pipe) == SIG_ERR)
err_sys(" signal");
if (pipe(fd1) < 0 || pipe(fd2) < 0)
err_sys(" pipe");
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid > 0) {
/* */
close(fd1[0]);
close(fd2[1]);
while (fgets(line, MAXLINE, stdin) != NULL) {
n = strlen(line);
if (write(fd1[1], line, n) != n)
err_sys(" ");
if ((n = read(fd2[0], line, MAXLINE)) < 0)
err_sys(" ");
if (n == 0) {
err_msg(" ");
break;
}
line[n] = 0; /* */
if (fputs(line, stdout) == EOF)

604

15.
err_sys(" fputs");
}
if (ferror(stdin))
err_sys(" ");
exit(0);
} else {
/* */
close(fd1[1]);
close(fd2[0]);
if (fd1[0] != STDIN_FILENO) {
if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO)
err_sys(" dup2 stdin");
close(fd1[0]);
}
if (fd2[1] != STDOUT_FILENO) {
if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO)
err_sys(" dup2 stdout");
close(fd2[1]);
}
if (execl("./add2", "add2", (char *)0) < 0)
err_sys(" execl");
}
exit(0);

}
static void
sig_pipe(int signo)
{
printf(" SIGPIPE\n");
exit(1);
}

, 
. 
: ,
. , execl, 
dup2, 
.
15.9, 
, . ,
, add2 kill,
,
, SIGPIPE ( 15.4).
. 15.1 , pipe 
. 17.1 .

, .

15.4.

605

add2 ( 15.8)
 ( UNIX): read
write. 
? 15.10.
15.10. ,
;
#include "apue.h"
int
main(void)
{
int int1, int2;
char line[MAXLINE];
while (fgets(line, MAXLINE, stdin) != NULL) {
if (sscanf(line, "%d%d", &int1, &int2) == 2) {
if (printf("%d\n", int1 + int2) == EOF)
err_sys(" printf");
} else {
if (printf(" \n") == EOF)
err_sys(" printf");
}
}
exit(0);
}

, 
15.9, . ,
.
15.10,
fgets 
. 
, .
. add2
,
( 15.9) .
.
15.10, while
:
if (setvbuf(stdin, NULL, _IOLBF, 0) != 0)
err_sys(" setvbuf");
if (setvbuf(stdout, NULL, _IOLBF, 0) != 0)
err_sys(" setvbuf");

fgets , 
, printf fflush 
(

606

15.

 5.4).
setvbuf, 
15.10.
, ,
. , 
awk(1)
( add2), :
#! /bin/awk f
{ print $1 + $2 }

.
awk (, , 
).
, .
, ( 
awk) , 
. 

, setvbuf 
. 19 .

15.5. FIFO
FIFO (First In First Out , )
. 
, 
, . ( 
STREAMS,
17.2.2.) FIFO 
, 
.
4 , FIFO .
st_mode stat ( 4.2) ,
FIFO. FIFO 
S_ISFIFO.
FIFO . 
pathname .
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
0 , 1

15.5. FIFO

607

mode mkfifo ,
open ( 3.3). 
FIFO 4.6.
FIFO mkfifo
open.  (close, read, write,
unlink .) FIFO.
FIFO mknod. 
POSIX.1 mknod,
mkfifo. mknod 
XSI. mkfifo
FIFO mknod.
POSIX.1 mkfifo(1). , 
, .
FIFO , 
.

FIFO O_NONBLOCK .
( O_NONBLOCK ) FIFO
,
. ,
,
.
O_NONBLOCK , 
open .
open 1
ENXIO errno,
.
, 
FIFO, ,
SIGPIPE. FIFO ,
.
FIFO .
, 
, ,
. ( 17.2.2.) 
,
FIFO, , , PIPE_BUF.
FIFO :
1. FIFO 

.
2. FIFO 
.
.

608

15.

FIFO
FIFO , 
. 
( 
). 
, FIFO, 
, .
, 
. . 15.9.
prog3

prog1
prog2

. 15.9. ,

FIFO tee(1) 
. ( tee 
, , , 
.)
mkfifo fifo1
prog3 < fifo1 &
prog1 < infile | tee fifo1 | prog2

FIFO,
prog3, .
prog1, tee 
prog2. . 15.10 
.


FIFO 
. , 
, 
FIFO , .
( , FIFO 
, .) . 15.11
. FIFO 
, , 

609

15.5. FIFO

FIFO

prog1

prog3

tee

prog2

. 15.10. FIFO tee


PIPE_BUF. , 
.
FIFO
.
FIFO,

. ,
.
FIFO , 
. ,
FIFO /tmp/serv1.XXXXX, XXXXX 
. . 15.12 .
, 
. , FIFO,
, 
. ,
SIGPIPE, , 


FIFO

...

. 15.11. FIFO

610

15.

FIFO

FIFO

...

FIFO

. 15.12. ;
FIFO

FIFO 
(), .
17.2.2,
STREAMS.
, . 15.12, FIFO 
, ,
0,
. , 
FIFO , ( 15.10).

15.6. XSI IPC


IPC, XSI IPC, , 
. 
, 
, .
XSI IPC System V IPC. 
70 UNIX AT&T, 
Columbus UNIX. IPC System V.
, ,
.
. 15.1 , ,
Single UNIX Specification XSI.

15.6.1.
IPC ( , 
) ;
. , ,

15.6. XSI IPC

611

. ,
IPC .
,  IPC, , 
, , 
, .
IPC.
, 
IPC. IPC
, .
, IPC (msgget, semget shmget), 
. 
key_t, 
<sys/types.h> . 
.

IPC.
1. IPC IPC_PRIVATE 
 (, ) ,
. IPC_PRIVATE ,
IPC.
, 
,
.
IPC_PRIVATE 
.
IPC IPC_PRIVATE, 

fork. 
exec.
2.
, , , . 
IPC .
, 
IPC .
(msgget, semget shmget)
. 
, IPC .
3. 
(
0 255), ftok

612

15.

.
, .
#include <sys/ipc.h>
key_t ftok(const char *path, int id);
, (key_t) 1

path .
8 id.
st_dev st_ino
stat ( 4.2), ,
. 
, ftok . ,
,
, 
. , , 

, 
.
get (msgget, semget shmget) :
key flag. IPC ( ) , 
key IPC_PRIVATE
 IPC , 
flag IPC_CREAT. 
( ), key 
, ,
, IPC_CREAT .
: IPC_PRIVATE, 
, 
.
,
IPC_PRIVATE, 
IPC (
msgsnd msgrcv) get.
IPC, 
, flag IPC_CREAT
IPC_EXCL. , IPC ,
EEXIST. (
O_CREAT O_EXCL open.)

15.6.2.
IPC XSI IPC ipc_perm.
. 
:

613

15.6. XSI IPC


struct ipc_perm {
uid_t uid;
gid_t gid;
uid_t cuid;
gid_t cgid;
mode_t mode;
.
.
.
};

/*
/*
/*
/*
/*





*/

*/
*/
*/
*/

. 

<sys/ipc.h>.
IPC. 
uid, gid mode
msgctl, semctl shmctl. ,

.
chown chmod .
mode , . 4.5,
. , 

, 
. . 15.2
IPC.
15.2. XSI IPC

userread

0400

userwrite ()

0200

groupread

0040

groupwrite ()

0020

otherread

0004

otherwrite ()

0002


, Sing
le UNIX Specification.

15.6.3.
XSI
IPC.
.
IPC.

614

15.


. FreeBSD 5.2.1, Linux 2.4.22 Mac OS X 10.3 
sysctl, 
. Solaris 9
/etc/system .
Linux , IPC, ipcs l.
FreeBSD ipcs T. Solaris
, sysdef i.

15.6.4.
XSI IPC ,
IPC , ,
. , 
, ,
. , 
msgrcv, 
msgctl ipcrm(1), 
. ,
, ,
. FIFO , 
, FIFO 
, , .
, XSI IPC, ,
.
, 3 4.
IPC
(msgget, semop, shmat ). 
IPC ls, 
rm chmod.
ipcs(1) ipcrm(1).
IPC , 

(select poll). 
IPC  
. , 
,
, 
.
, 
System V IPC, [Andrade, Carges, and Kovach 1989].
, , System V
IPC (), , ,
, 
, 
(msgsnd), IPC :

615

15.6. XSI IPC

open, write close. , 


, ,

. 
. 15.6.1, 
, 
.
, 
, , 
, 
.
14.4, STRE
AMS, open
close . 15.3 
IPC.
15.3. IPC
IPC


 




STREAMS

UNIX,

UNIX,

FIFO ( STREAMS)

(, ,
16. UNIX 17.3.)


IPC. , , 
, 
.
IPC 
, .
, . 
,
, 
. 
, 
.

616

15.

, . 15.3, 

. 17 , STREAMS 
, , .
XSI IPC.

15.7.
, 
. 
, 
.
Single UNIX Specification
.
.


msgget. 
msgsnd. ( 
), (
).
msgsnd .
, 
.
msqid_ds:
struct msqid_ds {
struct ipc_perm msg_perm; /* 15.6.2 */
msgqnum_t msg_qnum;
/* */
msglen_t msg_qbytes;
/* */
pid_t msg_lspid; /* , msgsnd() */
pid_t msg_lrpid; /* , msgrcv() */
time_t msg_stime;
/* msgsnd()*/
time_t msg_rtime;
/* msgrcv()*/
time_t msg_ctime;
/* */
.
.
.
};

. , 
, Single UNIX Specification. 
, , , 
.
. 15.4 , 
. ,
. 
, 

617

15.7.

. , Linux
, 
. , 
1 ,
: _;
_ ___. 
, . 15.4, Linux
262 144. (
, Linux , 
1 , 
, .)
15.4. ,


FreeBSD 5.2.1 Linux 2.4.22 Mac OS X 10.3 Solaris 9
16 384

8 192

 2 048

 2 048
(. .
)

16 384

 4 096


40

16

 50

 40

40

. 15.1 , Mac OS X 10.3 XSI.


Mac OS X FreeBSD, FreeBSD
, Mac OS X .

XSI Mac OS X .

msgget,
.
#include <sys/msg.h>
int msgget(key_t key, int flag);
, 1

15.6.1 
, , 
. 
msqid_ds:

msqid_ds , 15.6.2. 
mode

618

15.

flag. 
. 15.2.

msg_qnum, msg_lspid, msg_lrpid, msg_stime msg_rtime


0.

msg_ctime .

msg_qbytes
.

msgget 
. ,
.
msgctl . 
(semctl shmctl)
ioctl XSI IPC.
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf );
0 , 1

cmd , 
, msqid.
IPC_STAT msqid_ds 
buf.
IPC_SET buf msqid_ds, 
, : msg_perm.uid, msg_perm.gid,
msg_perm.mode msg_qbytes. 
,
msg_perm.cuid msg_perm.uid
. 
msg_qbytes .
IPC_RMID , .
. ,
, EIDRM
. 
,
msg_perm.cuid
msg_perm.uid 
.
, (IPC_STAT, IPC_SET IPC_RMID) 
.

msgsnd.

619

15.7.

#include <sys/msg.h>
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
0 , 1

, , 
, (nbytes) 
( ).
ptr ,
, , 
. (,
, nbytes 0.) 
512 ,
:
struct mymesg {
long mtype;
/* */
char mtext[512]; /* , nbytes */
};

ptr
mymesg.
, 
.
32, 64 . 
. , 64 
Solaris 32, 64 
. 32
64 , 
, 32 
4 , 64 8 . , 32
, mtext 4 , 
64 8 .
mtype 64 32 
mtext, 4 mtext 32 
64 mtype.
XSI. Solaris 
32 64 IPC
.
32 64 
. , 
, , 64 
32 , 8
4 , 32 .
32 .

flag IPC_NOWAIT.
O_NONBLOCK, 

620

15.

 ( 14.2).
(
), IPC_NOWAIT
msgsnd
EAGAIN. IPC_NOWAIT ,
, ,
 
. EIDRM (identi
fier removed ), EINTR.
,
. 
( ), 

. .
, , 
, .
msgsnd msqid_ds,
: msg_lspid 
, msg_stime ,
msg_qnum ( ) .
msgrcv.
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);
, 1

msgsnd, ptr , 
,
. 
nbytes flag
MSG_NOERROR, nbytes. (
, .)
nbytes flag 
MSG_NOERROR,
E2BIG ( ).
type .
type == 0 .
type > 0

, .

type < 0

,
type.

621

15.7.

type , 
.
, type .
type 
,
(, 
).
flag IPC_NOWAIT, 
. ,
msgrcv
1 ENOMSG errno. IPC_NOWAIT
, , 
, (msgrcv
1 EIDRM errno) 
(msgrcv 1
EINTR errno).
msgrcv
msqid_ds, : msg_lrpid
, msg_rtime 
, msg_qnum .




, . ( . 15.1
, 
UNIX ( 17.3), 
pipe.)
. 15.5 So
laris : , STREAMS 
UNIX. IPC,
fork,
200 . 100 000 
2 000 . .
15.5.
IPC Solaris
IPC

0,57

3,63

STREAMS

0,50

3,21

3,71

UNIX

0,43

4,45

5,59

4,22

622

15.

, ,
,
(, STREAMS 
, ). ( 
, IPC 
.) ,
( 15.6.4), , 
.

15.8.
, 
( 
). , 
, .
Single UNIX Specification
.
.

, 
, :
1. , 
.
2. ,
. 1, 
, .
3. , 0, 
, 0.
1.
, 
, 1. 
, 
.
, 
.
.
, 
. 
1. 
, 
, , 
.
, XSI 
. .

623

15.8.

1. . 
, 
. .
2. (semget) 
(semctl). , 

.
3. , XSI IPC, 
, ,

. undo,
.
semid_ds:
struct semid_ds {
struct ipc_perm sem_perm;
unsigned short sem_nsems;
time_t sem_otime;
time_t sem_ctime;
.
.
.
};

/*
/*
/*
/*

15.6.2 */
*/
semop() */
*/

Single UNIX Specificati


on, semid_ds .
,
:
struct {
unsigned short semval; /*
pid_t sempid;
/*
/*
unsigned short semncnt; /*
/*
unsigned short semzcnt; /*
/*
.
.
.
};

, >= 0 */
, */
*/
, */
semval>curval */
, */
semval==0 */

. 15.6 ,
.
semget,
.

624

15.

#include <sys/sem.h>
int semget(key_t key, int nsems, int flag);

, 1

15.6. ,


FreeBSD 5.2.1 Linux 2.4.22 Mac OS X 10.3 Solaris 9
32 767

32 767

32 767

32 767

 16 384
(adjustonexit)
( 

)

32 767

16 384

16 384

10

128

87 381

10

60

32 000

87 381

60

60

250

87 381

25


undo

30

32 000

87 381

30


undo

10

32

10

10


,
semop

100

32

100

10

15.6.1 
, ,
. 
semid_ds:

ipc_perm , 15.6.2. 
mode
flag. 
. 15.2.

sem_otime 0.

sem_ctime .

sem_nsems nsems.

625

15.8.

nsems. 
( ), 
nsems. , 
nsems 0.
semctl.
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd,
... /* union semun arg */);


; , 
semun :
union semun {
int val;
/* SETVAL */
struct semid_ds *buf; /* IPC_STAT IPC_SET */
unsigned short *array; /* GETALL SETALL */
};

, ,
.
cmd , 
,
semid. , 
, semnum. semnum
0 nsems1 .
IPC_STAT semid_ds, 
, arg.buf.
IPC_SET sem_perm.uid, sem_perm.gid
sem_perm.mode 
, arg.buf. 
,
sem_perm.cuid
sem_perm.uid 
.
IPC_RMID . .
, , 
EIDRM .
,

sem_perm.cuid sem_perm.uid
.

626

15.

GETVAL

semval semnum.

SETVAL

semval semnum.
arg.val.

GETPID

sempid semnum.

GETNCNT semncnt semnum.


GETZNCNT semzcnt semnum.
GETALL

.
, arg.array.

SETALL

.
, arg.array.

GET, GETALL, 
. 
0.
semop .
#include <sys/sem.h>
int semop(int semid, struct sembuf semoparray[], size_t nops);
0 , 1

semoparray 
, sembuf:
struct sembuf {
unsigned short sem_num; /*
/*
short sem_op;
/*
short sem_flg;
/*
};

*/
(0, 1, ..., nsems1) */
(<0, 0 >0) */
IPC_NOWAIT, SEM_UNDO */

nops () .
, ,
sem_op. , 
. ( undo.
SEM_UNDO sem_flg.)
1. sem_op. 
, .
sem_op . SEM_UNDO,
(adjustonexit)
.
2. sem_op , , 
, .

15.8.

627

sem_op
( ), sem_op
. , 
. SEM_UNDO,
sem_op
.
, sem_op (
), :
a) IPC_NOWAIT, semop
EAGAIN.
) IPC_NOWAIT ,
semncnt, 
, :


sem_op ( ). 
semncnt (
), 
sem_op .
SEM_UNDO, sem_op 
.

. semop 
EIDRM.

,
. semncnt (
),
semop EINTR.

3. sem_op , , 
, .
, 
.
,
:
a) IPC_NOWAIT, semop
EAGAIN.
) IPC_NOWAIT ,
semzcnt 
, :

.
semzcnt (
).

. semop 
EIDRM.

628

15.

,
. semzcnt (
), semop
EINTR.

semop
, .


, , 
 ,
. ,
SEM_UNDO ( sem_op ), 
,
( sem_op). , 
, , 
, , 
.
semctl 
SETVAL SETALL, 
0.





. 
.
,
. 1.
, semop sem_op, 1.
, semop sem_op, 
+1. , SEM_UNDO
, .

( ) 
. ,
, . 
, ,
, .
. 15.7
Linux. 
100 000 . , . 15.7,
.

629

15.9.

15.7.
Linux
IPC

C SEM_UNDO

0,38

0,48

0,86

0,41

0,95

1,36

Linux
60 .
, 
, , (
) 
XSI,  . 
,
, .

15.9.

. IPC,

.
. 
,
, .
. (, 
,
.)
Single UNIX Specification

. .


, :
struct shmid_ds {
struct ipc_perm shm_perm; /* 15.6.2 */
size_t shm_segsz; /* */
pid_t shm_lpid;
/* , shmop() */
pid_t shm_cpid;
/*  */
shmatt_t shm_nattch; /* */
time_t shm_atime;
/* */
time_t shm_dtime;
/* */
time_t shm_ctime;
/* */
.
.

630

15.
.

};

(
.)
shmatt_t , unsigned
short. . 15.8 ( 15.6.3),
.
15.8. ,


FreeBSD 5.2.1 Linux 2.4.22 Mac OS X 10.3 Solaris 9

33 554 432

33 554 432

4 194 304

8 388 608

192

4 096

32

100

128

4 096


shmget, .
#include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);

, 1

15.6.1 
, , 
.
shmid_ds.
ipc_perm , 15.6.2. 
mode
flag. 
. 15.2.
shm_lpid, shm_nattach, shm_atime shm_dtime 0.
shm_ctime .
shm_segsz size.

631

15.9.

size .
,
, size
, ,
.
( ),
size. 
( ), size
0. , .
shmctl
.
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf );
0 , 1

cmd , 
, shmid.
IPC_STAT shmid_ds 
buf.
IPC_SET

shm_perm.uid, shm_perm.gid shm_perm.mode


buf shmid_ds, 
.
, 
shm_ perm.cuid shm_perm.uid
.

IPC_RMID .
( shm_nat
tach shmod_ds), ,

. ,
, 
,
shmat. 
,
shm_perm.cuid shm_perm.uid
.
Linux Solaris ,
Single UNIX Specification.
SHM_LOCK

.
, 
.

632

15.

SHM_UNLOCK . 
, 
.

shmat.
#include <sys/shm.h>
void *shmat(int shmid, const void *addr, int flag);

, 1

, ,
addr SHM_RND flag.
addr 0,
, .
.
addr SHM_RND 
, , addr.
addr SHM_RND,
, :
(addr (addr mod SHMLBA)). SHM_RND
round (), SHMLBA,
2, low boundary address multiple
( ).
SHMLBA.
, 
( ),
.
addr 0, 
.
flag SHM_RDONLY, 
. 
.
, shmat, ,
.
1. shmat , 
shm_nattch shmid_ds, .

shmdt . :
,
. ,
 ( ) 
shmctl IPC_RMID.

633

15.9.

#include <sys/shm.h>
int shmdt(void *addr);
0 , 1

addr , shmat.
shmdt shm_nattch shmid_ds.

, , 
addr 0, 
. 15.11 , 
, 
.
15.11.
#include "apue.h"
#include <sys/shm.h>
#define
#define
#define
#define

ARRAY_SIZE 40000
MALLOC_SIZE 100000
SHM_SIZE 100000
SHM_MODE 0600

char array[ARRAY_SIZE];

/* */
/* = bss */

int
main(void)
{
int shmid;
char *ptr, *shmptr;
printf("array[] %lx %lx\n", (unsigned long)&array[0],
(unsigned long)&array[ARRAY_SIZE]);
printf(" %lx\n", (unsigned long)&shmid);
if ((ptr = malloc(MALLOC_SIZE)) == NULL)
err_sys(" malloc");
printf(" %lx %lx\n",
(unsigned long)ptr, (unsigned long)ptr+MALLOC_SIZE);
if ((shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE)) < 0)
err_sys(" shmget");
if ((shmptr = shmat(shmid, 0, 0)) == (void *)1)
err_sys(" shmat");
printf(" %lx %lx\n",
(unsigned long)shmptr, (unsigned long)shmptr+SHM_SIZE);
if (shmctl(shmid, IPC_RMID, 0) < 0)
err_sys(" shmctl");
exit(0);
}

634

15.

Linux Intel 
:
$ ./a.out
array[] 804a080 8053cc0
bffff9e4
8053cc8 806c368
40162000 4017a6a0

. 15.13 ,
. :
, .

0xbffff9e4

0x4017a6a0

0x0806c368

(bss)

0x40162000

100 000

malloc
0x08053cc8
0x08053cc0

100 000

array[] 40 000

0x0804a080

. 15.13. Linux Intel

14.9 , mmap 
. 

shmat XSI IPC. , 
, mmap, , 
XSI .

/dev/zero

, .
,
.
FreeBSD 5.2.1, Linux 2.4.22 Solaris 9. Mac OS X 10.3

.

635

15.9.

/dev/zero
. , 
.  
, .
,
mmap . 
, .
.
,
mmap MAP_SHARED.
15.12.
15.12.
;
/dev/zero,
#include "apue.h"
#include <fcntl.h>
#include <sys/mman.h>
#define NLOOPS 1000
#define SIZE sizeof(long) /* */
static int
update(long *ptr)
{
return((*ptr)++);
}

/* */

int
main(void)
{
int fd, i, counter;
pid_t pid;
void *area;
if ((fd = open("/dev/zero", O_RDWR)) < 0)
err_sys(" open");
if ((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0)) == MAP_FAILED)
err_sys(" mmap");
close(fd); /* , , /dev/zero */
TELL_WAIT();
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid > 0) { /* */
for (i = 0; i < NLOOPS; i += 2) {
if ((counter = update((long *)area)) != i)
err_quit(": %d, %d", i, counter);
TELL_CHILD(pid);

636

15.
WAIT_CHILD();
}
} else { /* */
for (i = 1; i < NLOOPS + 1; i += 2) {
WAIT_PARENT();
if ((counter = update((long *)area)) != i)
err_quit(": %d, %d", i, counter);
TELL_PARENT(getppid());
}
}
exit(0);

/dev/zero mmap,
. : 
, .
.
MAP_SHARED, , , 
. (
MAP_PRIVATE, .)

, , 
8.9. ,
, 0. 
1,
2, 3 . . 
, update ,
, .
, 

mmap. /dev/zero 
. ,
, 
. , , 
( 11
12). : , 
.



, 
/dev/zero. ,
mmap MAP_ANON 1
. (

15.10. -

637

 ) , 
.

, . ,
Linux , , MAP_ANONYMOUS,
MAP_ANON 
.

15.12 ,
: ()
/dev/zero, () () 
mmap :
if ((area = mmap(0, SIZE, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, 1, 0)) == MAP_FAILED)

MAP_ANON 1 
. 15.12
.

.
,
,
. XSI, 
, mmap
MAP_SHARED
.

15.10.

, 
IPC,
.
fork exec .
fork
, . . 15.8 
. 
setuserID, 
. , ,
. ( 
8.10 ,
exec.)
.
( 17.5.)
. , 

638

15.

, UNIX /
/. , 
setuserID, 
(, ). 
,
. 
,
, .
, 
, 
. ,
, , .
, 
. 
, , 
, ( 
, 17).
. 15.12. 
, 
IPC. 
.
IPC ,
(FIFO) . ,
, 
, 
. , 
. (
System V. 
lp(1),
lpsched. , 
.)

.
1. 
. type 
. , ,
type 1. 
. 
, type 1 (
msgrcv), ,
type .
2.
. 
IPC_PRIVATE. 
, 

15.10. -

639

. 
, , 

, .
.
, 

, .  
, 
.
,
, select, poll .
, ,

( ).
(
) , 
.
, , .
, , , 
setuserID. IPC ,
.
,
, 
, msg_lspid
. , ,

. ,
.
(, , ,
, .)
17.3
.
, ,
. , 
, . 15.12,
. FIFO
,
. ,
( 
), ,
. 
FIFO
( ), 
stat fstat . , 

640

15.


FIFO ( st_uid stat). ,
. 
, , FIFO (
st_atime, st_mtime st_ctime stat), (
, 15 30 ).
FIFO
, , 
.
XSI IPC, , 
, 
ipc_perm, IPC (
cuid cgid). FIFO, ,
IPC 
. , ,
( IPC
, ).
17.2.2 , 
, 
.
STREAMS, .

15.11.
:
IPC,
XSI IPC ( , ).

, , 
, .

popen, , 
.


. 
,  

.
. 
, .
,
mmap ( 14.9).
, 
.

15.11.

641

15.1. 15.2 close 


waitpid . , .
15.2. 15.2 waitpid
. , .
15.3. , popen
? , 
.
15.4. 15.9 ,
.
, 
SIGPIPE ?
15.5. 15.9
read write
.
15.6. POSIX.1 
waitpid ,
:
if ((fp = popen("/bin/true", "r")) == NULL)
...
if ((rc = system("sleep 100")) == 1)
...
if (pclose(fp) == 1)
...

,
waitpid wait?
15.7. , select poll 
.
, : 
select, poll.
15.8. , cmdstring, popen
"r" type, 
?
15.9. cmdstring popen 
.
cmdstring? (: .)
15.10. POSIX.1 ,
FIFO open
, UNIX . 
FIFO
.

642

15.

15.11. ,
. (
.) 
, 
,
? 
, ?
15.12. , :
,
, ;
IPC_PRIVATE 
. 
ipcs(1). , 
.
15.13. ,
. 
?
15.14.
15.12, i 
, 
update. ,
fork
.
15.15. 15.12 ,

XSI 15.9.
15.16. 15.12 ,

.
15.17. 15.12 ,

.
 
Books.Ru 
ISBN 5932860898,
UNIX. , 2 
 Books.Ru  . 
 , 

. ,
 (piracy@symbol.ru),
.

16
:

16.1.

, ,
, 
UNIX. 
, .
IPC, , 
( ), 
.
, 

, . 
: 
,
. , 
,
TCP/IP,
 .
POSIX.1, 
4.4BSD. 
,
, 80 4.2BSD.

. ,
UNIX [Stevens, Fenner, and Ru
doff 2004].

643

16.2.

16.2.
.
,
. UNIX 
, . 
, ,
read write, .
socket.
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
() , 1

domain ,
( ). . 16.1 
, POSIX.1. 
AF_ ( address family ), 

.
16.1.

AF_INET

IPv4

AF_UNIX

UNIX

AF_INET6

IPv6

AF_UNSPEC

UNIX 17.3. 
AF_LOCAL, 
AF_UNIX. AF_UNSPEC ,
. 
,
AF_IPX NetWare, POSIX.1
.
type , 
. , 
POSIX.1, . 16.2, 
.
protocol 0, 
. 
,
.
SOCK_STREAM AF_INET TCP (Trans
mission Control Protocol ). 

644

16.

SOCK_DGRAM AF_INET UDP (User


Datagram Protocol ).
16.2.

SOCK_DGRAM

,
,

SOCK_RAW

IP ( POSIX.1)

SOCK_SEQPACKET , 
, , 

SOCK_STREAM

, 
, , 

(SOCK_DGRAM) 
, 
. , 
, .
, , 
. (SOCK_STREAM),
, , 
, , 
, .
. 
. 
, , 
. 
, 
. .
, , 
, .
, , , 
, . 
, , 
. ,


.
SOCK_STREAM 
,
. , 
, 
. , ,
.

16.2.

645

SOCK_SEQPACKET SOCK_STREAM, 
, /
. ,
, SOCK_SEQPACKET,
. 

STP (Stream Control Transmission Protocol 
).
SOCK_RAW
( IP ). 

,
( TCP UDP). 
SOCK_RAW ,
.
socket open.
, 
. close, 

.
,
,
. . 16.3
, ,
. 
,
, , , 
. , lseek , 
.
16.3.

close ( 3.3)

dup, dup2 ( 3.12)


fchdir ( 4.22)

ENOTDIR errno

fchmod ( 4.9)

fchown ( 4.11)

fcntl ( 3.14)

, F_DUPFD, F_GETFD,
F_GETFL, F_GETOWN, F_SETFD, F_SETFL F_SETOWN

fdatasync, fsync
( 3.13)

fstat ( 4.2)

stat,

646

16.

16.3 ()

ftruncate
( 4.13)

getmsg, getpmsg
( 14.4)

, STREAMS (. .
Solaris)

ioctl ( 3.15)

lseek ( 3.6)

(
ESPIPE)

mmap ( 14.9)

poll ( 14.5.2)

putmsg, putpmsg
( 14.4)

, STREAMS (. .
Solaris)

read ( 3.7)
readv ( 14.7)

recv ( 16.5) 

select ( 14.5.1) ,
write ( 3.8)
writev ( 14.7)

send ( 16.5) 

. 
shut
down.
#include <sys/socket.h>
int shutdown(int sockfd, int how);
0 , 1

how SHUT_RD, 
. how SHUT_WR,
. how 
SHUT_RDWR,
.
shutdown, close 
? . , close
, 
. , 
(, dup),
close ,
, . shutdown

. ,

647

16.3.

. ,
, , 
, ,
,
.

16.3.

. , , 
, 
. . 
,
, 
.

16.3.1.
,
, .
, 
, ,
. . 16.1 32 .
(big;endian) ,
(). 
(little;endian) 
. :
() , 
. , 32 
0x04030201, 4,
1, .
char * (cp), 
.
(big$endian)

n +1

n +2

n +3

(little$endian)

n +3

n +2

n +1

. 16.1. 32;

648

16.

(little;endian) , cp[0]
, 1,
cp[3] , 4.
(big;endian) , cp[0]
4, cp[3]
1. . 16.4 , 
.
16.4.

FreeBSD 5.2.1

Intel Pentium

(little;endian)

Linux 2.4.22

Intel Pentium

Mac OS X 10.3

PowerPC

(big;endian)

Solaris 9

Sun SPARC


, .


,
. TCP/IP (
, big;endian) . ,
.
TCP/IP 
,
, , 
. , ,
.

.
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostint32);
32
uint16_t htons(uint16_t hostint16);
16
uint32_t ntohl(uint32_t netint32);
32
uint16_t ntohs(uint16_t netint16);
16

649

16.3.

n network ( ), h
host (). l long (, 4,
), s short (, 2, ). 
<arpa/inet.h>, 
<neti
net/in.h>.

16.3.2.
.
.
,
, 
sockaddr:
struct sockaddr {
sa_family_t sa_family; /* c */
char
sa_data[]; /* */
.
.
.
};


sa_data. , Linux
struct sockaddr {
sa_family_t sa_family; /* c */
char
sa_data[14]; /* */
};

FreeBSD
struct sockaddr {
unsigned char sa_len;
/* */
sa_family_t sa_family; /* */
char
sa_data[14]; /* */
};


<netinet/in.h>. IPv4 (AF_INET) 
sockaddr_in:
struct in_addr {
in_addr_t s_addr; /* IPv4 */
};
struct sockaddr_in
sa_family_t
in_port_t
struct in_addr
};

{
sin_family; /* */
sin_port;
/* */
sin_addr;
/* IPv4 */

650

16.

in_port_t uint16_t, in_addr_t uint32_t.



<stdint.h>.
AF_INET, IPv6 (AF_INET6)
sockaddr_ip6:
struct in6_addr {
uint8_t s6_addr[16]; /* IPv6 */
};
struct sockaddr_in6
sa_family_t
in_port_t
uint32_t sin6_
struct in6_addr
uint32_t sin6_
};

{
sin6_family;
sin6_port;
flowinfo;
sin6_addr;
scope_id;

/*
/*
/*
/*
/*

*/
*/
*/
IPv6 */
*/

, Single UNIX Specification. 


. ,
Linux sockaddr_in
struct sockaddr_in
sa_family_t
in_port_t
struct in_addr
unsigned char
};

{
sin_family;
sin_port;
sin_addr;
sin_zero[8];

/*
/*
/*
/*

*/
*/
IPv4 */
*/

sin_zero 
.
, sockaddr_in sockaddr_in6 
, sockaddr
, . 17.3 , 
UNIX 
.
, 
. BSD inet_ntoa
inet_addr,
 
(a.b.c.d). IPv4.
inet_ntop inet_pton,
, IPv6.
inet_ntop
. inet_pton 
. 
domain: AF_INET AF_INET6.

651

16.3.

#include <arpa/inet.h>
const char *inet_ntop(int domain, const void *restrict addr,
char *restrict str, socklen_t size);

, NULL
int inet_pton(int domain, const char *restrict str, void *restrict addr);
1 ,
0 , 1

size inet_ntop (str),


. : INET_ADDRSTRLEN,
, 
IPv4, INET6_ADDRSTRLEN, , 
IPv6. addr inet_pton
32
, domain AF_INET, 128
, domain AF_INET6.

16.3.3.

. sockaddr
 ,
, 
.
BSD 
. 6.7

. 
, .

(/etc/hosts, /etc/services ) 
, DNS (Domain Name System
) NIS (Network Information Service ).
, , 
.
, , 
gethostent.
gethostent 
. , gethostent .
sethostent , .
endhostent .

652

16.

#include <netdb.h>
struct hostent *gethostent(void);
, NULL
void sethostent(int stayopen);
void endhostent(void);

gethostent ,
hostent, 
, .
hostent :
struct hostent {
char *h_name;
char **h_aliases;
int
h_addrtype;
int
h_length;
char **h_addr_list;
.
.
.
};

/*
/*
/*
/*
/*

*/
*/
*/
*/
*/

.
, gethostbyname gethostbyaddr,
hostent, 
. , .

.
#include <netdb.h>
struct netent *getnetbyaddr(uint32_t net, int type);
struct netent *getnetbyname(const char *name);
struct netent *getnetent(void);
, NULL
void setnetent(int stayopen);
void endnetent(void);

netent :
struct netent {
char
*n_name;
char **n_aliases;
int
n_addrtype;
uint32_t n_net;

/*
/*
/*
/*

*/
*/
*/
*/

653

16.3.
.
.
.
};

. ,
(, AF_INET).

.
#include <netdb.h>
struct protoent *getprotobyname(const char *name);
struct protoent *getprotobynumber(int proto);
struct protoent *getprotoent(void);
, NULL
void setprotoent(int stayopen);
void endprotoent(void);

protoent POSIX.1
:
struct protoent {
char *p_name;
/* */
char **p_aliases; /* */
int
p_proto; /* */
.
.
.
};

, . 
. 
getservbyname,
getservbyport.
getservent
.
#include <netdb.h>
struct servent *getservbyname(const char *name, const char *proto);
struct servent *getservbyport(int port, const char *proto);
struct servent *getservent(void);
, NULL
void setservent(int stayopen);
void endservent(void);

654

16.

servent :
struct servent {
char *s_name;
char **s_aliases;
int
s_port;
char *s_proto;
.
.
.
};

/*
/*
/*
/*

*/
*/
*/
*/

POSIX.1 , 
, . 
gethostbyname gethostbyaddr.
getaddrinfo
.
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *restrict host, const char *restrict service,
const struct addrinfo *restrict hint,
struct addrinfo **restrict res);
0 ,

void freeaddrinfo (struct addrinfo *ai);

, . 
, .
, 
.
getaddrinfo addrinfo.
freeaddrinfo ,
.
addrinfo :
struct addrinfo {
int
int
int
int
socklen_t
struct sockaddr
char
struct addrinfo
.
.
.
};

ai_flags;
ai_family;
ai_socktype;
ai_protocol;
ai_addrlen;
*ai_addr;
*ai_canonname;
*ai_next;

/*
/*
/*
/*
/*
/*
/*
/*

*/
*/
*/
*/
*/
*/
*/
*/

655

16.3.

hint
. ,
, ai_family, ai_flags,
ai_protocol ai_socktype. 
0, NULL. . 16.5 ,
ai_flags, .
16.5. addrinfo

AI_ADDRCONFIG

(IPv4 IPv6).

AI_ALL

IPv4 IPv6 ( 
AI_V4MAPPED).

AI_CANONNAME

( ).

AI_NUMERICHOST .
AI_NUMERICSERV .
AI_PASSIVE

AI_V4MAPPED

IPv6 , IPv4
IPv6.

getaddrinfo ,
perror strerror .

gai_strerror.
#include <netdb.h>
const char *gai_strerror(int error);

getnameinfo .
#include <sys/socket.h>
#include <netdb.h>
int getnameinfo(const struct sockaddr *restrict addr,
socklen_t alen, char *restrict host,
socklen_t hostlen, char *restrict service,
socklen_t servlen, unsigned int flags);
0 ,

(addr) .
host , 
, hostlen. 
. , service 

656

16.

, servlen , 
.
flags .
. 16.6 .
16.6. getnameinfo

NI_DGRAM

, .

NI_NAMEREQD

, .

NI_NOFQDN

NI_NUMERICHOST .
NI_NUMERICSERV (
).

16.1 getaddrinfo.
16.1.
#include "apue.h"
#include <netdb.h>
#include <arpa/inet.h>
#if defined(BSD) || defined(MACOS)
#include <sys/socket.h>
#include <netinet/in.h>
#endif
void
print_family(struct addrinfo *aip)
{
printf(" ");
switch (aip>ai_family) {
case AF_INET:
printf("inet");
break;
case AF_INET6:
printf("inet6");
break;
case AF_UNIX:
printf("unix");
break;
case AF_UNSPEC:
printf(" ");
break;
default:
printf("");
}
}

16.3.
void
print_type(struct addrinfo *aip)
{
printf(" ");
switch (aip>ai_socktype) {
case SOCK_STREAM:
printf("stream");
break;
case SOCK_DGRAM:
printf("datagram");
break;
case SOCK_SEQPACKET:
printf("seqpacket");
break;
case SOCK_RAW:
printf("raw");
break;
default:
printf(" (%d)", aip>ai_socktype);
}
}
void
print_protocol(struct addrinfo *aip)
{
printf(" ");
switch (aip>ai_protocol) {
case 0:
printf(" ");
break;
case IPPROTO_TCP:
printf("TCP");
break;
case IPPROTO_UDP:
printf("UDP");
break;
case IPPROTO_RAW:
printf("raw");
break;
default:
printf(" (%d)", aip>ai_protocol);
}
}
void
print_flags(struct addrinfo *aip)
{
printf("");
if (aip>ai_flags == 0) {
printf(" 0");
} else {
if (aip>ai_flags & AI_PASSIVE)
printf(" passive");

657

658

16.

if (aip>ai_flags & AI_CANONNAME)


printf(" canon");
if (aip>ai_flags & AI_NUMERICHOST)
printf(" numhost");
#if defined(AI_NUMERICSERV)
if (aip>ai_flags & AI_NUMERICSERV)
printf(" numserv");
#endif
#if defined(AI_V4MAPPED)
if (aip>ai_flags & AI_V4MAPPED)
printf(" v4mapped");
#endif
#if defined(AI_ALL)
if (aip>ai_flags & AI_ALL)
printf(" all");
#endif
}
}
int
main(int argc, char *argv[])
{
struct addrinfo *ailist, *aip;
struct addrinfo hint;
struct sockaddr_in *sinp;
const char *addr;
int err;
char abuf[INET_ADDRSTRLEN];
if (argc != 3)
err_quit(": %s _ ", argv[0]);
hint.ai_flags = AI_CANONNAME;
hint.ai_family = 0;
hint.ai_socktype = 0;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
if ((err = getaddrinfo(argv[1], argv[2], &hint, &ailist)) != 0)
err_quit(" getaddrinfo: %s", gai_strerror(err));
for (aip = ailist; aip != NULL; aip = aip>ai_next) {
print_flags(aip);
print_family(aip);
print_type(aip);
print_protocol(aip);
printf("\n\t %s", aip>ai_canonname?aip>ai_canonname:"");
if (aip>ai_family == AF_INET) {
sinp = (struct sockaddr_in *)aip>ai_addr;
addr = inet_ntop(AF_INET, &sinp>sin_addr, abuf,
INET_ADDRSTRLEN);
printf(" %s", addr?addr:" ");
printf(" %d", ntohs(sinp>sin_port));

659

16.3.
}
printf("\n");
}
exit(0);
}

getaddrinfo.
, 
. 
IPv4 (ai_family AF_INET).
AF_INET, 
ai_family hint.
:
$ ./a.out harry nfs
canon
harry
canon
harry

inet stream TCP


192.168.1.105 2049
inet datagram UDP
192.168.1.105 2049

16.3.4.
, ,
, 
.
, .
, ,
,
/etc/services .
, bind.
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
0 , 1

, :
,
,
.
,
, .
1024, 
(, ).

,
.

660

16.

IP INADDR_ANY, 
. , 
, 
. ,
connect listen.
, ,
getsockname.
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *restrict addr,
socklen_t *restrict alenp);
0 , 1

getsockname alenp 
, addr.

. , .
, .
, 
, getpeername.
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *restrict addr,
socklen_t *restrict alenp);
0 , 1

, , 
getsockname.

16.4.
, 
(SOCK_STREAM SOCK_SEQPACKET),
,
, (), , 
().
connect.
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
0 , 1

16.4.

661

, connect, ,
. sockfd 
, .

. , ,
. , 
, 
,
( ). , 
.

16.2 , 
. 
,
.
16.2.
#include "apue.h"
#include <sys/socket.h>
#define MAXSLEEP 128
int
connect_retry(int sockfd, const struct sockaddr *addr, socklen_t alen)
{
int nsec;
/*
* .
*/
for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) {
if (connect(sockfd, addr, alen) == 0) {
/*
* .
*/
return(0);
}
/*
* .
*/
if (nsec <= MAXSLEEP/2)
sleep(nsec);
}
return(1);
}

;
. connect ,
,
, 2 .

662

16.

, 
16.8, ,
connect 1 EINPROGRESS errno.
, 
, poll select. 
.
connect , 
(SOCK_DGRAM). ,
 , , 
. connect SOCK_DGRAM,
,
connect,
. , 
.
listen 
.
#include <sys/socket.h>
int listen(int sockfd, int backlog);
0 , 1

backlog
, .
, 
SOMAXCONN <sys/socket.h>.
Solaris <sys/socket.h> . 
. , TCP 
128.


, backlog 
,
.
listen
. accept 
.
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *restrict addr,
socklen_t *restrict len);
() , 1

accept , ,
connect.
, sockfd. ,

16.4.

663

accept, , 
.
, 
addr len NULL.
addr
, len , 
. accept
, len .
, , , accept
, . sockfd
, accept 1
EAGAIN EWOULDBLOCK errno.
, , EAGAIN
, EWOULDBLOCK.

accept 
, , .
, poll select 
. , 
, .

16.3 ,
.
16.3.
#include "apue.h"
#include <errno.h>
#include <sys/socket.h>
int
initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)
{
int fd;
int err = 0;
if ((fd = socket(addr>sa_family, type, 0)) < 0)
return(1);
if (bind(fd, addr, alen) < 0) {
err = errno;
goto errout;
}
if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
if (listen(fd, qlen) < 0) {
err = errno;
goto errout;
}
}
return(fd);

664

16.

errout:
close(fd);
errno = err;
return(1);
}

, TCP, 
, 
. 16.9 ,
.

16.5.
, 
read write, .
, SOCK_DGRAM 
, connect 
. 
read write 
, ,
,
. , 
, , .
read write
, , .
 
,
, , 
.
,
. , 
.
send. write, 
, 
.
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);

, 1

write, send
. buf nbytes
, write.

665

16.5.

, write, send 
flags. Single UNIX Specification ,
.
. 16.7.
16.7. , send

POSIX.1 FreeBSD Linux Mac OS X Sola


5.2.1
2.4.22 10.3
ris 9

MSG_DONTROUTE

MSG_DONTWAIT 

(
O_NONBLOCK)

MSG_EOR


, 

MSG_OOB


, 

( 16.7)

send ,
. ,
send ,
.
, 
, 
, send EMSGSIZE
errno. , 
, send , 
.
sendto send. , sendto
SOCK_DGRAM.
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flags,
const struct sockaddr *destaddr, socklen_t destlen);

, 1

, ,
, .
, , 

666

16.

send, connect,
sendto .
,
. sendmsg msghdr,
,
writev ( 14.7).
#include <sys/socket.h>
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

, 1

POSIX.1, msghdr 
:
struct msghdr {
void
socklen_t
struct iovec
int
void
socklen_t
int
.
.
.
};

*msg_name;
msg_namelen;
*msg_iov;
msg_iovlen;
*msg_control;
msg_controllen;
msg_flags;

/*
/*
/*
/*
/*
/*
/*

*/
*/
 */
*/
*/
*/
*/

iovec 14.7. 
17.4.2.
recv read, 
, .
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
, 0

, 1

, recv,
. 16.8. Single UNIX Specifi
cation.
MSG_PEEK,
, .
read 
recv.

667

16.5.

16.8. , recv

POSIX.1 FreeBSD Linux Mac OS X Sola


5.2.1
2.4.22 10.3
ris 9

MSG_OOB


,
( 16.7)

MSG_PEEK


, 

MSG_TRUNC

, 

,

MSG_WAITALL , 
(
SOCK_STREAM)

SOCK_STREAM
, . MSG_WAITALL 
recv, ,
. SOCK_DGRAM SOCK_SEQ
PACKET MSG_WAITALL recv,

.
shutdown ( 16.2),
,
, recv 
0 .
, 
recvfrom, , 
.
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags,
struct sockaddr *restrict addr, socklen_t *restrict addrlen);
, 0

, 1

addr ,
, . 
recvfrom addrelen 
, addr.
.

668

16.

, 
SOCK_DGRAM.
recvfrom recv.
,
readv ( 14.7), ( 17.4.2),
recvmsg.
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
, 0

, 1

msghdr (
sendmsg). recvmsg
flags.
msg_flags msghdr 
. ( recvmsg 
msg_flags .) , 
recvmsg, . 16.9. 
17.
16.9. , recvmsg msg_flags

MSG_CTRUNC

POSIX.1 FreeBSD Linux Mac OS X Sola


5.2.1
2.4.22 10.3
ris 9

MSG_DONTWAIT 
recvmsg

MSG_EOR

MSG_OOB

MSG_TRUNC

,

16.4 ,
uptime.
remote uptime ( uptime) , , rup
time.

16.5.

669

16.4. , uptime

#include
#include
#include
#include

"apue.h"
<netdb.h>
<errno.h>
<sys/socket.h>

#define MAXADDRLEN 256


#define BUFLEN 128
extern int connect_retry(int, const struct sockaddr *, socklen_t);
void
print_uptime(int sockfd)
{
int n;
char buf[BUFLEN];
while ((n = recv(sockfd, buf, BUFLEN, 0)) > 0)
write(STDOUT_FILENO, buf, n);
if (n < 0)
err_sys(" recv");
}
int
main(int argc, char *argv[])
{
struct addrinfo *ailist, *aip;
struct addrinfo hint;
int sockfd, err;
if (argc != 2)
err_quit(": ruptime hostname");
hint.ai_flags = 0;
hint.ai_family = 0;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
if ((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)
err_quit(" getaddrinfo: %s", gai_strerror(err));
for (aip = ailist; aip != NULL; aip = aip>ai_next) {
if ((sockfd = socket(aip>ai_family, SOCK_STREAM, 0)) < 0)
err = errno;
if (connect_retry(sockfd, aip>ai_addr, aip>ai_addrlen) < 0) {
err = errno;
} else {
print_uptime(sockfd);
exit(0);
}

670

16.
}
fprintf(stderr, " %s: %s\n", argv[1],
strerror(err));
exit(1);

,
. 
SOCK_STREAM, , 
recv , 
,
0.
getaddrinfo , 
.
,
. 
connect_retry 16.2.

,

16.5 , 
uptime 16.4.
16.5. ,
uptime
#include
#include
#include
#include
#include
#define
#define
#ifndef
#define
#endif

"apue.h"
<netdb.h>
<errno.h>
<syslog.h>
<sys/socket.h>

BUFLEN 128
QLEN 10
HOST_NAME_MAX
HOST_NAME_MAX 256

extern int initserver(int, struct sockaddr *, socklen_t, int);


void
serve(int sockfd)
{
int clfd;
FILE *fp;
char buf[BUFLEN];
for (;;) {
clfd = accept(sockfd, NULL, NULL);
if (clfd < 0) {
syslog(LOG_ERR, "ruptimed: accept: %s",

16.5.
strerror(errno));
exit(1);
}
if ((fp = popen("/usr/bin/uptime", "r")) == NULL) {
sprintf(buf, ": %s\n", strerror(errno));
send(clfd, buf, strlen(buf), 0);
} else {
while (fgets(buf, BUFLEN, fp) != NULL)
send(clfd, buf, strlen(buf), 0);
pclose(fp);
}
close(clfd);
}
}
int
main(int argc, char *argv[])
{
struct addrinfo *ailist, *aip;
struct addrinfo hint;
int sockfd, err, n;
char *host;
if (argc != 1)
err_quit(": ruptimed");
#ifdef _SC_HOST_NAME_MAX
n = sysconf(_SC_HOST_NAME_MAX);
if (n < 0)
/* , */
#endif
n = HOST_NAME_MAX;
host = malloc(n);
if (host == NULL)
err_sys(" malloc");
if (gethostname(host, n) < 0)
err_sys(" gethostname");
daemonize("ruptimed");
hint.ai_flags = AI_CANONNAME;
hint.ai_family = 0;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
if ((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0) {
syslog(LOG_ERR, "ruptimed: getaddrinfo: %s",
gai_strerror(err));
exit(1);
}
for (aip = ailist; aip != NULL; aip = aip>ai_next) {
if ((sockfd = initserver(SOCK_STREAM, aip>ai_addr,

671

672

16.
aip>ai_addrlen, QLEN)) >= 0) {
serve(sockfd);
exit(0);
}
}
exit(1);

,
, .
_SC_HOST_NAME_MAX,
HOST_NAME_MAX. HOST_NAME_MAX,
. POSIX.1 ,
255 
,
HOST_NAME_MAX 256 .
gethostname 
uptime. getaddrinfo 
, ,
.
.
initserver 
16.3. . (
16.9, 
, 16.6.)

,

, 
, 
, 
. 16.6 . ,
uptime
, 
uptime , .
16.6. ,
#include
#include
#include
#include
#include
#include
#include

"apue.h"
<netdb.h>
<errno.h>
<syslog.h>
<fcntl.h>
<sys/socket.h>
<sys/wait.h>

#define QLEN 10
#ifndef HOST_NAME_MAX

16.5.
#define HOST_NAME_MAX 256
#endif
extern int initserver(int, struct sockaddr *, socklen_t, int);
void
serve(int sockfd)
{
int clfd, status;
pid_t pid;
for (;;) {
clfd = accept(sockfd, NULL, NULL);
if (clfd < 0) {
syslog(LOG_ERR, "ruptimed: accept: %s",
strerror(errno));
exit(1);
}
if ((pid = fork()) < 0) {
syslog(LOG_ERR, "ruptimed: fork: %s",
strerror(errno));
exit(1);
} else if (pid == 0) { /* */
/*
* daemonize ( 13.1),
* STDIN_FILENO, STDOUT_FILENO STDERR_FILENO
* /dev/null.
* close
* clfd .
*/
if (dup2(clfd, STDOUT_FILENO) != STDOUT_FILENO ||
dup2(clfd, STDERR_FILENO) != STDERR_FILENO) {
syslog(LOG_ERR, "ruptimed: ");
exit(1);
}
close(clfd);
execl("/usr/bin/uptime", "uptime", (char *)0);
syslog(LOG_ERR, "ruptimed: exec: %s",
strerror(errno));
} else { /* */
close(clfd);
waitpid(pid, &status, 0);
}
}
}
int
main(int argc, char *argv[])
{
struct addrinfo *ailist, *aip;
struct addrinfo hint;
int sockfd, err, n;
char *host;

673

674

16.

if (argc != 1)
err_quit(": ruptimed");
#ifdef _SC_HOST_NAME_MAX
n = sysconf(_SC_HOST_NAME_MAX);
if (n < 0) /* , */
#endif
n = HOST_NAME_MAX;
host = malloc(n);
if (host == NULL)
err_sys(" malloc");
if (gethostname(host, n) < 0)
err_sys(" gethostname");
daemonize("ruptimed");
hint.ai_flags = AI_CANONNAME;
hint.ai_family = 0;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
if ((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0) {
syslog(LOG_ERR, "ruptimed: getaddrinfo: %s",
gai_strerror(err));
exit(1);
}
for (aip = ailist; aip != NULL; aip = aip>ai_next) {
if ((sockfd = initserver(SOCK_STREAM, aip>ai_addr,
aip>ai_addrlen, QLEN)) >= 0) {
serve(sockfd);
exit(0);
}
}
exit(1);
}

popen uptime 
fork, 
, STDOUT_FILENO STDERR_FILENO
. uptime, 
, , .
, 
, . 
,
. uptime , 
,
.
, 
.

16.5.

675

,
. ? 
, 
? , 
.
, ,
,
, , 
. 
. , 
, , 
, .
, , 
.
.
,

. , 
, 
, , ,
, .

.
, 
, .
, 
, , 
, , 
.

,

16.7 16.4, 
.
16.7. ,
#include
#include
#include
#include

"apue.h"
<netdb.h>
<errno.h>
<sys/socket.h>

#define BUFLEN 128


#define TIMEOUT 20
void
sigalrm(int signo)

676

16.

{
}
void
print_uptime(int sockfd, struct addrinfo *aip)
{
int n;
char buf[BUFLEN];
buf[0] = 0;
if (sendto(sockfd, buf, 1, 0, aip>ai_addr, aip>ai_addrlen) < 0)
err_sys(" sendto");
alarm(TIMEOUT);
if ((n = recvfrom(sockfd, buf, BUFLEN, 0, NULL, NULL)) < 0) {
if (errno != EINTR)
alarm(0);
err_sys(" recv");
}
alarm(0);
write(STDOUT_FILENO, buf, n);
}
int
main(int argc, char *argv[])
{
struct addrinfo *ailist, *aip;
struct addrinfo hint;
int sockfd, err;
struct sigaction sa;
if (argc != 2)
err_quit(": ruptime hostname");
sa.sa_handler = sigalrm;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGALRM, &sa, NULL) < 0)
err_sys(" sigaction");
hint.ai_flags = 0;
hint.ai_family = 0;
hint.ai_socktype = SOCK_DGRAM;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
if ((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)
err_quit(" getaddrinfo: %s", gai_strerror(err));
for (aip = ailist; aip != NULL; aip = aip>ai_next) {
if ((sockfd = socket(aip>ai_family, SOCK_DGRAM, 0)) < 0) {
err = errno;
} else {
print_uptime(sockfd, aip);
exit(0);

16.5.

677

}
}
fprintf(stderr, " %s: %s\n", argv[1],
strerror(err));
exit(1);
}

main , 
SIGALRM. alarm 
, recvfrom
.
, ,
.
, ,
.
, 
. 1 .
, 
. ,
,
, 1
.
, 
recvfrom. , 
, connect 
, . 
recvfrom.

,

16.8 uptime,
.
16.8. , uptime

#include
#include
#include
#include
#include
#define
#define
#ifndef
#define
#endif

"apue.h"
<netdb.h>
<errno.h>
<syslog.h>
<sys/socket.h>

BUFLEN 128
MAXADDRLEN 256
HOST_NAME_MAX
HOST_NAME_MAX 256

extern int initserver(int, struct sockaddr *, socklen_t, int);

678

16.

void
serve(int sockfd)
{
int n;
socklen_t alen;
FILE *fp;
char buf[BUFLEN];
char abuf[MAXADDRLEN];
for (;;) {
alen = MAXADDRLEN;
if ((n = recvfrom(sockfd, buf, BUFLEN, 0,
(struct sockaddr *)abuf, &alen)) < 0) {
syslog(LOG_ERR, "ruptimed: recvfrom: %s",
strerror(errno));
exit(1);
}
if ((fp = popen("/usr/bin/uptime", "r")) == NULL) {
sprintf(buf, ": %s\n", strerror(errno));
sendto(sockfd, buf, strlen(buf), 0,
(struct sockaddr *)abuf, alen);
} else {
if (fgets(buf, BUFLEN, fp) != NULL)
sendto(sockfd, buf, strlen(buf), 0,
(struct sockaddr *)abuf, alen);
pclose(fp);
}
}
}
int
main(int argc, char *argv[])
{
struct addrinfo *ailist, *aip;
struct addrinfo hint;
int sockfd, err, n;
char *host;
if (argc != 1)
err_quit(": ruptimed");
#ifdef _SC_HOST_NAME_MAX
n = sysconf(_SC_HOST_NAME_MAX);
if (n < 0)
/* , */
#endif
n = HOST_NAME_MAX;
host = malloc(n);
if (host == NULL)
err_sys(" malloc");
if (gethostname(host, n) < 0)
err_sys(" gethostname");
daemonize("ruptimed");
hint.ai_flags = AI_CANONNAME;
hint.ai_family = 0;

679

16.6.
hint.ai_socktype = SOCK_DGRAM;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
if ((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0) {
syslog(LOG_ERR, "ruptimed: getaddrinfo: %s",
gai_strerror(err));
exit(1);
}
for (aip = ailist; aip != NULL; aip = aip>ai_next) {
if ((sockfd = initserver(SOCK_DGRAM, aip>ai_addr,
aip>ai_addrlen, 0)) >= 0) {
serve(sockfd);
exit(0);
}
}
exit(1);
}

recvfrom . 
, 
popen uptime.
sendto , .

16.6.

, . 
, .
:
1. , .
2. , , 
.
3. , .
Single UNIX Specification , 
( 
).
setsockopt.
#include <sys/socket.h>
int setsockopt(int sockfd, int level, int option, const void *val,
socklen_t len);
0 , 1

680

16.

level , 
. , level
SOL_SOCKET. level
, IPPROTO_TCP TCP
IPPROTO_IP IP. . 16.10 
, Single UNIX Specification.
16.10.

val

SO_ACCEPTCONN int

,
( getsockopt).

SO_BROADCAST int


, *val .

SO_DEBUG

int


, *val .

SO_DONTROUTE int


, *val .

SO_ERROR

int

, 
( getsockopt).

SO_KEEPALIVE int



, *val .

SO_LINGER

, 
.

struct linger

SO_OOBINLINE int


, *val .

SO_RCVBUF

int

SO_RCVLOWAT

int

,
.

SO_RCVTIMEO

struct timeval


.

SO_REUSEADDR int


bind, *val 
.

SO_SNDBUF

int

SO_SNDTIMEO

struct timeval


.

SO_TYPE

int

( getsockopt).

val ,
. , 
.

681

16.6.

, . ,
. len , 
val.
getsoc
kopt.
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int option, void *restrict val,
socklen_t *restrict lenp);
0 , 1

: lenp . 
getsockopt 
, . 
, . 
, lenp
.

, 16.3,
,
. , TCP 
, 
, 
. , SO_REUSE
ADDR, 16.9.
16.9.

#include "apue.h"
#include <errno.h>
#include <sys/socket.h>
int
initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)
{
int fd, err;
int reuse = 1;
if ((fd = socket(addr>sa_family, type, 0)) < 0)
return(1);
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(int)) < 0) {
err = errno;
goto errout;
}
if (bind(fd, addr, alen) < 0) {

682

16.
err = errno;
goto errout;
}
if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
if (listen(fd, qlen) < 0) {
err = errno;
goto errout;
}
}
return(fd);
errout:
close(fd);
errno = err;
return(1);

, 
SO_REUSEADDR, 
setsockopt 
val. len ,
, val.

16.7.

, ,
. 
. TCP 
, UDP .
TCP.
TCP urgent (). 
,
. ,
MSG_OOB send. MSG_OOB
,
.
SIGURG 
. 3.14 14.6.2 , 
F_SETOWN fcntl, 
. fcntl ,
, ,
, 1. , 
, ,
fcntl(sockfd, F_SETOWN, pid);

, ,
F_GETOWN. F_SETOWN, 

16.8. -

683

,
. ,
owner = fcntl(sockfd, F_GETOWN, 0);

owner , 
, ,
, owner 
,
.
TCP :
, .
,
, SO_OOBINLINE.
sockatmark.
#include <sys/socket.h>
int sockatmark(int sockfd);
1, , 0 , 1


, sockatmark 1.
select ( 14.5.1) 
, 
. : 
recv, 
MSG_OOB . 
TCP .
, ,
.

16.8. 
, , recv
. send, 

. ,
. ,
EWOULDBLOCK EAGAIN
errno. , 
, poll select.
Single UNIX Specification 
. 
 ,
Single UNIX Specification.

684

16.


, ,
 .

SIGIO, 
.
 :
1. , 
.
2. , ,
 .
:
1. F_SETOWN fcntl.
2. FIOSETOWN ioctl.
3. SIOCSPGRP ioctl.
, :
1. C F_SETFL fcntl O_ASYNC.
2. FIOASYNC ioctl.
, . . 16.11 
, .
, + , 
. , Linux 
FIOSETOWN SIOCSPGRP UNIX.
16.11. ;

POSIX.1 FreeBSD Linux


5.2.1
2.4.22

Solaris 9

ioctl(fd, FIOSETOWN, pid)

ioctl(fd, SIOCSPGRP, pid)

fcntl(fd, F_SETFL, flags|O_ASYNC)

ioctl(fd, FIOASYNC, &n)

fcntl(fd, F_SETOWN, pid)

Mac OS X
10.3

16.9.
IPC,
, 
, . , 
, .

16.9.

685

, ,
( ) 
. 
 , 
.
, IPC,
, 
.

16.1. , .
16.2. stat, 
.
, .
16.3. 16.5
. , 
(
) .
16.4. ,
, 
.
16.5. 16.6 ,
, , 
uptime . ,
.
16.6. ,
 ,
. . 16.11, 

.

17
IPC
17.1.
IPC, 
.
IPC STREAMS UNIX. 
IPC 
, 
, 
. , , 
. ,
,
[Presotto and Ritchie 1990].

17.2. STREAMS
STREAMS (
STREAMS) () .

, STREAMS.
15.1 , STREAMS Solaris
, , Linux.

. 17.1 STREAMS. 
. 15.1 ,
, STREAMS , 
.
STREAMS (. 17.2), ,
, (WQ, write queue)
(RQ, read queue) 
. , , 
.

687

17.2. STREAMS

fd[0]

fd[0]

fd[1]

fd[1]

. 17.1. STREAMS

WQ

WQ

fd[0]

fd[1]
RQ

RQ

. 17.2. STREAMS

STREAMS STREAMS,
STREAMS 
, (. 17.3). ,
, . 
, 
.
STREAMS,
, 
, STREAMS , 
ioctl, streamio(7).
17.2.2 STREAMS 
, , 
.

WQ

WQ

WQ

fd[0]

fd[1]
RQ

RQ

RQ

. 17.3. STREAMS

688

17.

15.9
, STREAMS. 17.1
main. add2 
( 15.8). STREAMS s_pipe.
(
STREAMS UNIX.)
17.1. , add2
STREAMS
#include "apue.h"
static void sig_pipe(int);

/* */

int
main(void)
{
int n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if (signal(SIGPIPE, sig_pipe) == SIG_ERR)
err_sys(" signal");
if (s_pipe(fd) < 0)
/* */
err_sys(" pipe");
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid > 0) {
/* */
close(fd[1]);
while (fgets(line, MAXLINE, stdin) != NULL) {
n = strlen(line);
if (write(fd[0], line, n) != n)
err_sys(" ");
if ((n = read(fd[0], line, MAXLINE)) < 0)
err_sys(" ");
if (n == 0) {
err_msg(" ");
break;
}
line[n] = 0;
/* */
if (fputs(line, stdout) == EOF)
err_sys(" fputs");
}
if (ferror(stdin))
err_sys(" ");
exit(0);
} else {
/* */
close(fd[0]);
if (fd[1] != STDIN_FILENO &&

689

17.2. STREAMS
dup2(fd[1], STDIN_FILENO) != STDIN_FILENO)
err_sys(" dup2 stdin");
if (fd[1] != STDOUT_FILENO &&
dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
err_sys(" dup2 stdout");
if (execl("./add2", "add2", (char *)0) < 0)
err_sys(" execl");
}
exit(0);
}
static void
sig_pipe(int signo)
{
printf(" SIGPIPE\n");
exit(1);
}

fd[0],
fd[1]. STREAMS 
, fd[0], 
fd[1] ,
. . 17.4 
. , 
,
STREAMS, ,
STREAMS, .
STREAMS [Rago 1993]. . 15.1 
, FreeBSD ,
STREAMS.

s_pipe ,
pipe. , 
, s_pipe, ,
.

()
stdin

fd[0]

fd[1]
stdout

. 17.4.

s_pipe STREAMS
17.2 s_pipe, 
STREAMS. pipe, 
.

690

17.

17.2. s_pipe STREAMS


#include "apue.h"
/*
* STREAMS fd[0] fd[1].
*/
int
s_pipe(int fd[2])
{
return(pipe(fd));
}

17.2.1. STREAMS
, 
:
. 15.5 ,

(FIFO),
. STREAMS 
. 
FIFO.
STREAMS, fattach.
#include <stropts.h>
int fattach(int filedes, const char *path);
0 , 1

path , 

, .
STREAMS
, . , 
, ,
. , fattach
, . 
, 
.
. 17.5 , /tmp/pipe. 
. 
.

STREAMS,
STREAMS.
STREAMS,
fdetach.

691

17.2. STREAMS

#include <stropts.h>
int fdetach(const char *path);
0 , 1

fdetach , 
STREAMS ,
, , 
path
.

/tmp/pipe

. 17.5. ,

17.2.2.
STREAMS 
,  

STREAMS. 
.
PIPE_BUF , , ,
, 
, 
, . 
,
.
STREAMS connld.
, 
connld , .
, . 17.6.
. 17.6 , 
/tmp/pipe. 
STREAMS . ,
, . 17.7.

, .
/tmp/pipe 

692

17.

/tmp/pipe

CONNLD

. 17.6. connld

. 
(
). 
.
STREAMS
17.4.1.
fattach mount. 
STREAMS . 
connld (Presotto)
(Ritchie) 1990 Research UNIX. 
SVR4.

,
.
16.4 
, .
STREAMS, ( 17.3)
C

/tmp/pipe

CONNLD

. 17.7. connld

17.2. STREAMS

693

, 
UNIX.
#include "apue.h"
int serv_listen(const char *name);
,
,
int serv_accept(int listenfd, uid_t *uidptr);
,

int cli_conn(const char *name);
,

serv_listen ( 17.3), 

( ).
.
STREAMS .
17.3. serv_listen, STREAMS
#include "apue.h"
#include <fcntl.h>
#include <stropts.h>
/* : rw, rw, rw */
#define FIFO_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
/*
* .
* fd , <0 .
*/
int
serv_listen(const char *name)
{
int tempfd;
int fd[2];
/*
* fattach().
*/
unlink(name);
if ((tempfd = creat(name, FIFO_MODE)) < 0)
return(1);
if (close(tempfd) < 0)
return(2);
if (pipe(fd) < 0)
return(3);
/*

694

17.
* connld fattach() fd[1].
*/
if (ioctl(fd[1], I_PUSH, "connld") < 0) {
close(fd[0]);
close(fd[1]);
return(4);
}
if (fattach(fd[1], name) < 0) {
close(fd[0]);
close(fd[1]);
return(5);
}
close(fd[1]); /* fattach */
return(fd[0]); /* fd[0] */
/* */

serv_accept ( 17.4) 
. 
STREAMS, 
. , 
uidptr.
17.4. serv_accept, STREAMS
#include "apue.h"
#include <stropts.h>
/*
* .
* , .
* fd , <0 .
*/
int
serv_accept(int listenfd, uid_t *uidptr)
{
struct strrecvfd recvfd;
if (ioctl(listenfd, I_RECVFD,
return(1);
/*
if (uidptr != NULL)
*uidptr = recvfd.uid; /*
return(recvfd.fd);
/*

&recvfd) < 0)
EINTR */
uid */
*/

, cli_conn (
17.5). name , 
serv_listen. 

STREAMS, .
17.5. cli_conn, STREAMS
#include "apue.h"
#include <fcntl.h>

695

17.3. UNIX
#include <stropts.h>
/*
* .
* fd , <0 .
*/
int
cli_conn(const char *name)
{
int fd;
/* */
if ((fd = open(name, O_RDWR)) < 0)
return(1);
if (isastream(fd) == 0) {
close(fd);
return(2);
}
return(fd);
}


STREAMS , ,
.
17.6.

17.3. UNIX
UNIX 
, .
, UNIX
. UNIX
,
, , 
.
UNIX , 
. UNIX 
. 
. UNIX 
.
UNIX 
, UNIX
socketpair.
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sockfd[2]);
0 , 1

696

17.

, , 
socketpair , 

UNIX.

s_pipe
UNIX
17.6 s_pipe ( 17.2), 
.
UNIX.
17.6. s_pipe,
#include "apue.h"
#include <sys/socket.h>
/*
* ( UNIX)
* fd[0] fd[1].
*/
int
s_pipe(int fd[2])
{
return(socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
}

, BSD, UNIX 
. pipe 

. ,
socketpair.

17.3.1. UNIX
socketpair ,
. , 
.
16.3.4 , 
. UNIX 
.
UNIX .
16.3 , 
. UNIX
sockaddr_un. Linux 2.4.22 Solaris 9 sockaddr_un
<sys/un.h> :
struct sockaddr_un {
sa_family_t sun_family;
/* AF_UNIX */
char
sun_path[108]; /* */
};

17.3. UNIX

697

FreeBSD 5.2.1 Mac OS X 10.3 sockaddr_un 


:
struct sockaddr_un {
unsigned char sun_len;
/* , */
sa_family_t sun_family; /* AF_UNIX */
char
sun_path[104]; /* */
};

sun_path .
UNIX, S_IFSOCK .
, 
. 
.
,
bind .
, 
.

, 17.7, 
UNIX.
17.7. UNIX
#include "apue.h"
#include <sys/socket.h>
#include <sys/un.h>
int
main(void)
{
int fd, size;
struct sockaddr_un un;
un.sun_family = AF_UNIX;
strcpy(un.sun_path, "foo.socket");
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
err_sys(" socket");
size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
if (bind(fd, (struct sockaddr *)&un, size) < 0)
err_sys(" bind");
printf(" UNIX \n");
exit(0);
}

, bind 
, , 
, .
, .

698

17.

$ ./a.out

UNIX
$ ls l foo.socket

srwxrwxrx 1 sar 0 Aug 22 12:43 foo.socket
$ ./a.out

bind: Address already in use
$ rm foo.socket

$ ./a.out

UNIX

sun_path
sockaddr_un 
. sun_path
sockaddr_un ,

offsetoff, <stddef.h>
( apue.h). <stddef.h>
:
#define offsetof(TYPE, MEMBER) ((int)&((TYPE *)0)>MEMBER)

, 
0.

17.3.2.
UNIX
, bind, listen accept.
connect; 
, 
.
, 16.4 16.5.
17.8 serv_listen, 
UNIX.
17.8. serv_listen,
UNIX
#include "apue.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#define QLEN 10
/*
* .
* fd , <0 .
*/
int
serv_listen(const char *name)
{
int fd, len, err, rval;

17.3. UNIX

699

struct sockaddr_un un;


/* UNIX SOCK_STREAM */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return(1);
unlink(name); /* name */
/* */
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, name);
len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
/* */
if (bind(fd, (struct sockaddr *)&un, len) < 0) {
rval = 2;
goto errout;
}
if (listen(fd, QLEN) < 0) { /* , */
rval = 3;
goto errout;
}
return(fd);
errout:
err = errno;
close(fd);
errno = err;
return(rval);
}

socket UNIX.
sockaddr_un , 
. bind. 
: sun_len, 
,
, , bind.
listen ( 16.4),
, , 
. , 
serv_accept ( 17.9).
17.9. serv_accept,
UNIX
#include
#include
#include
#include
#include

"apue.h"
<sys/socket.h>
<sys/un.h>
<time.h>
<errno.h>

#define STALE 30

/* , , */
/* () */

700

17.

/*
* .
* ,
* .
* fd , <0 .
*/
int
serv_accept(int listenfd, uid_t *uidptr)
{
int clifd, len, err, rval;
time_t staletime;
struct sockaddr_un un;
struct stat statbuf;
len = sizeof(un);
if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0)
return(1); /* errno=EINTR, */
/* */
len = offsetof(struct sockaddr_un, sun_path); /* */
un.sun_path[len] = 0; /* */
if (stat(un.sun_path, &statbuf) < 0) {
rval = 2;
goto errout;
}
#ifdef S_ISSOCK /* SVR4 */
if (S_ISSOCK(statbuf.st_mode) == 0) {
rval = 3;
/* */
goto errout;
}
#endif
if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) ||
(statbuf.st_mode & S_IRWXU) != S_IRWXU) {
rval = 4;
/* rwx */
goto errout;
}
staletime = time(NULL)  STALE;
if (statbuf.st_atime < staletime ||
statbuf.st_ctime < staletime ||
statbuf.st_mtime < staletime) {
rval = 5;
/* */
goto errout;
}
if (uidptr != NULL)
*uidptr = statbuf.st_uid; /* */
unlink(un.sun_path);
/* */
return(clifd);
errout:
err = errno;
close(clifd);
errno = err;

17.3. UNIX

701

return(rval);
}

accept, ,
cli_conn. accept , 
, . (
connld STREAMS.) , , 
( 
), accept (
sockaddr_un).
stat. 
, , 
, 
. , ,
30 . ( 6.10
, time 
, .)
, , 
. 
, , . (
,
accept, I_RECVFD ioctl.)
, cli_conn (
17.10).
17.10. cli_conn,
UNIX
#include
#include
#include
#include

"apue.h"
<sys/socket.h>
<sys/un.h>
<errno.h>

#define CLI_PATH "/var/tmp/" /* +5 = 14 */


#define CLI_PERM S_IRWXU
/* rwx */
/*
* .
* fd , <0 .
*/
int
cli_conn(const char *name)
{
int fd, len, err, rval;
struct sockaddr_un un;
/* UNIX SOCK_STREAM */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return(1);
/* */
memset(&un, 0, sizeof(un));

702

17.
un.sun_family = AF_UNIX;
sprintf(un.sun_path, "%s%05d", CLI_PATH, getpid());
len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
unlink(un.sun_path);
/* */
if (bind(fd, (struct sockaddr *)&un, len) < 0) {
rval = 2;
goto errout;
}
if (chmod(un.sun_path, CLI_PERM) < 0) {
rval = 3;
goto errout;
}
/* */
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, name);
len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
if (connect(fd, (struct sockaddr *)&un, len) < 0) {
rval = 4;
goto errout;
}
return(fd);

errout:
err = errno;
close(fd);
errno = err;
return(rval);
}

socket.
sockaddr_un , .
,
.
,
.

. unlink, 
.
bind, .
. chmod 
, , 
. serv_accept, 
, 
.
sockaddr_un, 
. connect,
.

703

17.4.

17.4.

 
. ( )
, ( 
, ,
), ,
.
, 
.

. . 3.2 ,
.
(vnode),
.
,
, 
. . 17.8 ,
.

.


$

fd 0:
fd 1:
fd 2:
fd 3:
...

fd 0:
fd 1:
fd 2:
fd 3:
fd 4:
...

. 17.8.

704

17.

. (
,

,
.) , 
, , 
fork (. 8.1).
, 
.
, ,
( 
).
,
.
, 
STREAMS, .
#include "apue.h"
int send_fd(int fd, int fd_to_send);
int send_err(int fd, int status, const char *errmsg);
0 , 1
int recv_fd(int fd, ssize_t (*userfunc)(int, const void *, size_t));
,

( ), 
, send_fd send_err. , 
( ), recv_fd.
send_fd fd_to_send
STREAMS UNIX, fd.
, 
STREAMS, UNIX, 
spipe.

send_err errmsg, 
status. status 
1 255.
recv_fd. 
( send_fd), 
. 
status,
send_err ( 1 255). ,
, 

17.4.

705

userfunc. 
STDERR_FILENO, ,
. userfunc 
.
write userfunc.
,
. , send_fd
0, . 
, send_err errmsg,
0
(1255). recv_fd , spipe,
, . ,
, userfunc. ,
recv_fd, . 0, 
, ,
.
spipe send_err 
send_fd. send_err 17.11.
17.11 send_err
#include "apue.h"
/*
*
* send_fd()/recv_fd(), .
*/
int
send_err(int fd, int errcode, const char *msg)
{
int n;
if ((n = strlen(msg)) > 0)
if (writen(fd, msg, n) != n) /* */
return(1);
if (errcode >= 0)
errcode = 1;

/* */

if (send_fd(fd, errcode) < 0)


return(1);
return(0);
}

send_fd recv_fd.

17.4.1.
STREAMS
STREAMS 
ioctl: I_SENDFD I_RECVFD. ,

706

17.

ioctl . 
17.12.
17.12 send_fd, STREAMS
#include "apue.h"
#include <stropts.h>
/*
* .
* fd<0, , fd.
*/
int
send_fd(int fd, int fd_to_send)
{
char buf[2]; /* 2 send_fd()/recv_fd() */
buf[0] = 0; /* recv_fd() */
if (fd_to_send < 0) {
buf[1] = fd_to_send; /* */
if (buf[1] == 0)
buf[1] = 1; /* 256 */
} else {
buf[1] = 0;
/* */
}
if (write(fd, buf, 2) != 2)
return(1);
if (fd_to_send >= 0)
if (ioctl(fd, I_SENDFD, fd_to_send) < 0)
return(1);
return(0);
}

ioctl 
strrecvfd:
struct strrecvfd {
int fd;
/* */
uid_t uid; /* */
gid_t gid; /* */
char fill[8];
};

recv_fd STREAMS ,
2 ( ).
ioctl I_RECVFD
,
I_SENDFD, .
17.13.
17.13. recv_fd, STREAMS
#include "apue.h"
#include <stropts.h>

17.4.

707

/*
* ().
* , , ,
* (*userfunc)(STDERR_FILENO, buf, nbytes). ,
* 2 .
*/
int
recv_fd(int fd, ssize_t (*userfunc)(int, const void *, size_t))
{
int newfd, nread, flag, status;
char *ptr;
char buf[MAXLINE];
struct strbuf dat;
struct strrecvfd recvfd;
status = 1;
for ( ; ; ) {
dat.buf = buf;
dat.maxlen = MAXLINE;
flag = 0;
if (getmsg(fd, NULL, &dat, &flag) < 0)
err_sys(" getmsg");
nread = dat.len;
if (nread == 0) {
err_ret(" ");
return(1);
}
/*
* ,
* . ,
*  .
* , .
*/
for (ptr = buf; ptr < &buf[nread]; ) {
if (*ptr++ == 0) {
if (ptr != &buf[nread1])
err_dump(" ");
status = *ptr & 0xFF; /* */
if (status == 0) {
if (ioctl(fd, I_RECVFD, &recvfd) < 0)
return(1);
newfd = recvfd.fd; /* */
} else {
newfd = status;
}
nread = 2;
}
}
if (nread > 0)
if ((*userfunc)(STDERR_FILENO, buf, nread) != nread)
return(1);

708

17.

if (status >= 0) /* */
return(newfd); /* */
}
}

17.4.2.
UNIX

UNIX recvmsg(2) sendmsg(2) (
16.5). msghdr, 
, 
. :
struct msghdr {
void
socklen_t
struct iovec
int
void
socklen_t
int
};

*msg_name;
msg_namelen;
*msg_iov;
msg_iovlen;
*msg_control;
msg_controllen;
msg_flags;

/*
/*
/*
/*
/*
/*
/*

*/
*/
 */
*/
*/
*/
*/


, 
. 
, readv writev ( 
, 14.7). msg_flags , 
( . 16.9).
.
msg_control cmsghdr (
), msg_controllen 
.
struct cmsghdr {
socklen_t cmsg_len; /* , */
int
cmsg_level; /* */
int
cmsg_type; /* */
/* */
};

, cmsg_len
cmsghdr (). cmsg_level
SOL_SOCKET, cmsg_type SCM_RIGHTS,
, . ( SCM
socket;level control message 
.) UNIX.
cmsg_type,
, CMSG_DATA.

17.4.

709


, cmsg_len.
#include <sys/socket.h>
unsigned char *CMSG_DATA(struct cmsghdr *cp);
, cmsghdr
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *mp);
cmsghdr,
msghdr, NULL,
struct cmsghdr *CMSG_NXTHDR(struct msghdr *mp,
struct cmsghdr *cp);
cmsghdr,
msghdr,
cmsghdr NULL,
unsigned int CMSG_LEN(unsigned int nbytes);
,
nbytes

Single UNIX Specification , CMSG_LEN.

CMSG_LEN ,
nbytes cmsghdr 
,
.
17.14 send_fd,
UNIX.
17.14. send_fd, UNIX
#include "apue.h"
#include <sys/socket.h>
/* / */
#define CONTROLLEN CMSG_LEN(sizeof(int))
static struct cmsghdr *cmptr = NULL; /* */
/*
* .
* fd<0, , fd.
*/
int
send_fd(int fd, int fd_to_send)
{
struct iovec iov[1];
struct msghdr msg;
char buf[2]; /* 2 send_fd()/recv_fd() */

710

17.
iov[0].iov_base = buf;
iov[0].iov_len = 2;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
if (fd_to_send < 0) {
msg.msg_control = NULL;
msg.msg_controllen = 0;
buf[1] = fd_to_send; /* */
if (buf[1] == 0)
buf[1] = 1;
/* 256 */
} else {
if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL)
return(1);
cmptr>cmsg_level = SOL_SOCKET;
cmptr>cmsg_type = SCM_RIGHTS;
cmptr>cmsg_len = CONTROLLEN;
msg.msg_control = cmptr;
msg.msg_controllen = CONTROLLEN;
*(int *)CMSG_DATA(cmptr) = fd_to_send; /* */
buf[1] = 0;
/* */
}
buf[0] = 0;
/* recv_fd() */
if (sendmsg(fd, &msg, 0) != 2)
return(1);
return(0);

sendmsg (
), .
( 17.15), 
cmsghdr , 
msg_control
recvmsg.
CMSG_LEN.
, 
, . ,
, 
. 17.15.
17.15. recv_fd, UNIX
#include "apue.h"
#include <sys/socket.h> /* struct msghdr */
/* / */
#define CONTROLLEN CMSG_LEN(sizeof(int))
static struct cmsghdr *cmptr = NULL; /* */

17.4.

711

/*
* . ,
* (*userfunc)(STDERR_FILENO, buf, nbytes).
* , 2 .
*/
int
recv_fd(int fd, ssize_t (*userfunc)(int, const void *, size_t))
{
int newfd, nr, status;
char *ptr;
char buf[MAXLINE];
struct iovec iov[1];
struct msghdr msg;
status = 1;
for ( ; ; ) {
iov[0].iov_base = buf;
iov[0].iov_len = sizeof(buf);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL)
return(1);
msg.msg_control = cmptr;
msg.msg_controllen = CONTROLLEN;
if ((nr = recvmsg(fd, &msg, 0)) < 0) {
err_sys(" recvmsg");
} else if (nr == 0) {
err_ret(" ");
return(1);
}
/*
* ,
* . ,
*  .
* , .
*/
for (ptr = buf; ptr < &buf[nr]; ) {
if (*ptr++ == 0) {
if (ptr != &buf[nr1])
err_dump(" ");
status = *ptr & 0xFF; /* */
if (status == 0) {
if (msg.msg_controllen != CONTROLLEN)
err_dump(" 0, fd");
newfd = *(int *)CMSG_DATA(cmptr);
} else {
newfd = status;
}
nr = 2;
}

712

17.
}
if (nr > 0 && (*userfunc)(STDERR_FILENO, buf, nr) != nr)
return(1);
if (status >= 0)
/* */
return(newfd); /* */
}

: recvmsg
( msg_control msg_controllen), 
, msg_contollen
, .

STREAMS UNIX , 
STREAMS , 
. UNIX
,
.
Linux 2.4.22 FreeBSD 5.2.1 
UNIX, 
. Mac OS X 10.3 FreeBSD, 
. Solaris 9 
UNIX.

FreeBSD
cmsgcred:
#define CMGROUP_MAX 16
struct cmsgcred {
pid_t cmcred_pid;
uid_t cmcred_uid;
uid_t
gid_t
short
gid_t

/*
/*
/*
/*
/*
/*
/*

*/
*/
*/
cmcred_euid;
*/
*/
cmcred_gid;
*/
*/
cmcred_ngroups;
/* */
cmcred_groups[CMGROUP_MAX]; /* */

};


cmsgcred. ,
.
Linux ucred:
struct ucred
uint32_t
uint32_t
uint32_t
};

{
pid; /* */
uid; /* */
gid; /* */

17.4.

713

FreeBSD, Linux , 
. , 

, 
.
17.16 send_fd,

.
17.16.
UNIX
#include "apue.h"
#include <sys/socket.h>
#if defined(SCM_CREDS) /* BSD */
#define CREDSTRUCT cmsgcred
#define SCM_CREDTYPE SCM_CREDS
#elif defined(SCM_CREDENTIALS) /* Linux */
#define CREDSTRUCT ucred
#define SCM_CREDTYPE SCM_CREDENTIALS
#else
#error !
#endif
/* / */
#define RIGHTSLEN CMSG_LEN(sizeof(int))
#define CREDSLEN CMSG_LEN(sizeof(struct CREDSTRUCT))
#define CONTROLLEN (RIGHTSLEN + CREDSLEN)
static struct cmsghdr *cmptr = NULL; /* */
/*
* .
* fd<0, fd.
*/
int
send_fd(int fd, int fd_to_send)
{
struct CREDSTRUCT *credp;
struct cmsghdr *cmp;
struct iovec iov[1];
struct msghdr msg;
char buf[2]; /* 2 send_fd()/recv_fd() */
iov[0].iov_base = buf;
iov[0].iov_len = 2;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_flags = 0;
if (fd_to_send < 0) {

714

17.
msg.msg_control = NULL;
msg.msg_controllen = 0;
buf[1] = fd_to_send; /* */
if (buf[1] == 0)
buf[1] = 1;
/* 256 */
} else {
if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL)
return(1);
msg.msg_control = cmptr;
msg.msg_controllen = CONTROLLEN;
cmp = cmptr;
cmp>cmsg_level = SOL_SOCKET;
cmp>cmsg_type = SCM_RIGHTS;
cmp>cmsg_len = RIGHTSLEN;
*(int *)CMSG_DATA(cmp) = fd_to_send; /* */

cmp = CMSG_NXTHDR(&msg, cmp);


cmp>cmsg_level = SOL_SOCKET;
cmp>cmsg_type = SCM_CREDTYPE;
cmp>cmsg_len = CREDSLEN;
credp = (struct CREDSTRUCT *)CMSG_DATA(cmp);
#if defined(SCM_CREDENTIALS)
credp>uid = geteuid();
credp>gid = getegid();
credp>pid = getpid();
#endif
buf[1] = 0; /* */
}
buf[0] = 0;
/* recv_ufd() */
if (sendmsg(fd, &msg, 0) != 2)
return(1);
return(0);
}

: 
Linux.
17.17 recv_fd,
recv_ufd.
, .
17.17.
UNIX
#include "apue.h"
#include <sys/socket.h>
#include <sys/un.h>

/* struct msghdr */

#if defined(SCM_CREDS)
/* BSD */
#define CREDSTRUCT cmsgcred
#define CR_UID cmcred_uid
#define CREDOPT LOCAL_PEERCRED
#define SCM_CREDTYPE SCM_CREDS

715

17.4.
#elif defined(SCM_CREDENTIALS) /* Linux */
#define CREDSTRUCT ucred
#define CR_UID uid
#define CREDOPT SO_PASSCRED
#define SCM_CREDTYPE SCM_CREDENTIALS
#else
#error !
#endif

/* / */
#define RIGHTSLEN CMSG_LEN(sizeof(int))
#define CREDSLEN CMSG_LEN(sizeof(struct CREDSTRUCT))
#define CONTROLLEN (RIGHTSLEN + CREDSLEN)
static struct cmsghdr *cmptr = NULL;

/* */

/*
* . ,
* (*userfunc)(STDERR_FILENO, buf, nbytes).
* , 2 .
*/
int
recv_ufd(int fd, uid_t *uidptr,
ssize_t (*userfunc)(int, const void *, size_t))
{
struct cmsghdr *cmp;
struct CREDSTRUCT *credp;
int newfd,nr, status;
char *ptr;
char buf[MAXLINE];
struct iovec iov[1];
struct msghdr msg;
const int on = 1;
status = 1;
newfd = 1;
if (setsockopt(fd, SOL_SOCKET, CREDOPT, &on, sizeof(int)) < 0) {
err_ret(" setsockopt");
return(1);
}
for ( ; ; ) {
iov[0].iov_base = buf;
iov[0].iov_len = sizeof(buf);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL)
return(1);
msg.msg_control = cmptr;
msg.msg_controllen = CONTROLLEN;
if ((nr = recvmsg(fd, &msg, 0)) < 0) {

716

17.
err_sys(" recvmsg");
} else if (nr == 0) {
err_ret(" ");
return(1);
}
/*
* ,
* . ,
*  .
* , .
*/
for (ptr = buf; ptr < &buf[nr]; ) {
if (*ptr++ == 0) {
if (ptr != &buf[nr1])
err_dump(" ");
status = *ptr & 0xFF; /* */
if (status == 0) {
if (msg.msg_controllen != CONTROLLEN)
err_dump(" 0, fd");
/* */
for (cmp = CMSG_FIRSTHDR(&msg);
cmp != NULL; cmp = CMSG_NXTHDR(&msg, cmp)) {
if (cmp>cmsg_level != SOL_SOCKET)
continue;
switch (cmp>cmsg_type) {
case SCM_RIGHTS:
newfd = *(int *)CMSG_DATA(cmp);
break;
case SCM_CREDTYPE:
credp = (struct CREDSTRUCT *)CMSG_DATA(cmp);
*uidptr = credp>CR_UID;
}
}
} else {
newfd = status;
}
nr = 2;
}
}
if (nr > 0 && (*userfunc)(STDERR_FILENO, buf, nr) != nr)
return(1);
if (status >= 0) /* */
return(newfd); /* */
}

FreeBSD 
SCM_CREDS, Linux SCM_CREDENTIALS.

17.5. , 1

717

17.5. , 1
, 
, , 
. ,
, 
. 
( ), 
. , IPC 
(
) ( ).
.
, (
, ,
), :
,
.
, 
, 
.
, 
,
, 
(, 
).
( 7.7).
setuserID,
, .
, ( 
) .
spipe (
STREAMS, UNIX) fork exec
.
spipe .

.
1. spipe open <pathname>
<openmode>\0, <openmode> ASCII,
open. 
.
2.
, send_fd
send_err .

718

17.


. 17.6 ,
, 
.
open.h ( 17.18),

.
17.18. open.h
#include "apue.h"
#include <errno.h>
#define CL_OPEN "open" /* , */
int csopen(char *, int);

main ( 17.19) ,

. csopen,
.
17.19. main , 1
#include "open.h"
#include <fcntl.h>
#define BUFFSIZE 8192
int
main(int argc, char *argv[])
{
int n, fd;
char buf[BUFFSIZE], line[MAXLINE];
/* */
while (fgets(line, MAXLINE, stdin) != NULL) {
if (line[strlen(line)  1] == \n)
line[strlen(line)  1] = 0; /* */
/* */
/* */
if ((fd = csopen(line, O_RDONLY)) < 0)
continue; /* csopen() , */
/* */
while ((n = read(fd, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys(" write");
if (n < 0)
err_sys(" read");
close(fd);
}
exit(0);
}

17.5. , 1

719

csopen fork exec ,


spipe.
17.20. csopen, 1
#include "open.h"
#include <sys/uio.h> /* struct iovec */
/*
* name oflag
* .
*/
int
csopen(char *name, int oflag)
{
pid_t pid;
int len;
char buf[10];
struct iovec iov[3];
static int fd[2] = { 1, 1 };
if (fd[0] < 0) { /* */
if (s_pipe(fd) < 0)
err_sys(" s_pipe");
if ((pid = fork()) < 0) {
err_sys(" fork");
} else if (pid == 0) { /* */
close(fd[0]);
if (fd[1] != STDIN_FILENO &&
dup2(fd[1], STDIN_FILENO) != STDIN_FILENO)
err_sys(" stdin dup2");
if (fd[1] != STDOUT_FILENO &&
dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
err_sys(" stdout dup2");
if (execl("./opend", "opend", (char *)0) < 0)
err_sys(" execl");
}
close(fd[1]); /* */
}
sprintf(buf, " %d", oflag); /* oflag */
iov[0].iov_base = CL_OPEN " ";
/* */
iov[0].iov_len = strlen(CL_OPEN) + 1;
iov[1].iov_base = name;
iov[1].iov_len = strlen(name);
iov[2].iov_base = buf;
iov[2].iov_len = strlen(buf) + 1; /* +1 */
len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
if (writev(fd[0], &iov[0], 3) != len)
err_sys(" writev");
/* , write() */
return(recv_fd(fd[0], write));
}

720

17.

,
. ,
. (
.)
,
. recv_fd 
.
write.
. ,
opend, 17.20.
opend.h ( 17.21), 

.
17.21. opend.h, 1
#include "apue.h"
#include <errno.h>
#define CL_OPEN "open" /* , */
extern char errmsg[]; /* , */
extern int oflag;
/* open(): O_xxx ... */
extern char *pathname; /* , */
int
cli_args(int, char **);
void
request(char *, int, int);

main ( 17.22) spipe (


) request.
17.22. main , 1
#include "opend.h"
char errmsg[MAXLINE];
int oflag;
char *pathname;
int
main(void)
{
int nread;
char buf[MAXLINE];
for ( ; ; ) {
/* */
if ((nread = read(STDIN_FILENO, buf, MAXLINE)) < 0)
err_sys(" ");
else if (nread == 0)
break; /* */
request(buf, nread, STDOUT_FILENO);
}
exit(0);
}

17.5. , 1

721

request ( 17.23).
buf_args 
argv cli_args.
, open, 
, send_fd
spipe ( ). , 
send_err, ,
.
17.23. request, 1
#include "opend.h"
#include <fcntl.h>
void
request(char *buf, int nread, int fd)
{
int newfd;
if (buf[nread1] != 0) {
sprintf(errmsg,
" : %*.*s\n",
nread, nread, buf);
send_err(fd, 1, errmsg);
return;
}
if (buf_args(buf, cli_args) < 0) { /* */
send_err(fd, 1, errmsg);
return;
}
if ((newfd = open(pathname, oflag)) < 0) {
sprintf(errmsg, " %s: %s\n", pathname,
strerror(errno));
send_err(fd, 1, errmsg);
return;
}
if (send_fd(fd, newfd) < 0)
/* */
err_sys(" send_fd");
close(newfd); /* */
}


, . 
buf_args 17.24 
argv .
buf_args. 
strtok, 
ISO C.
17.24. buf_args
#include "apue.h"
#define MAXARGC 50

/* */

722

17.

#define WHITE " \t\n" /* , */


/*
* buf[] , .
* argv
* (optfunc) .
*
* 1, optfunc().
* : buf[]
* ( ).
*/
int
buf_args(char *buf, int (*optfunc)(int, char **))
{
char *ptr, *argv[MAXARGC];
int argc;
if (strtok(buf, WHITE) == NULL) /* argv[0] */
return(1);
argv[argc = 0] = buf;
while ((ptr = strtok(NULL, WHITE)) != NULL) {
if (++argc >= MAXARGC1) /* 1 */
/* */
return(1);
argv[argc] = ptr;
}
argv[++argc] = NULL;
/*
* argv[] ,
* buf[],
* , , argv[]
* .
*/
return((*optfunc)(argc, argv));
}

, buf_args, cli_args
( 17.25). 
.
17.25. cli_args
#include "opend.h"
/*
* buf_args(),
* request(). buf_args()
* argv[] , .
*/
int
cli_args(int argc, char **argv)

723

17.6. , 2
{
if (argc != 3 || strcmp(argv[0], CL_OPEN) != 0) {
strcpy(errmsg, ": <pathname> <oflag>\n");
return(1);
}
pathname = argv[1]; /* */
oflag = atoi(argv[2]);
return(0);
}

,
, . fork
spipe, 
.
.

17.6. , 2
,
fork exec.

. ,
. .
, , 
fork exec.
 spipe

.
serv_listen, serv_accept cli_conn, 17.2.2.
, 
select poll (
14.5).
, 
17.5. main ( 17.19).
open.h ( 17.18) :
#define CS_OPEN "/home/sar/opend"

/* */

open.c ( 17.20) ,
fork exec cli_conn.
17.26.
17.26. csopen, 2
#include "open.h"
#include <sys/uio.h> /* struct iovec */
/*
* name oflag
* .

724

17.

*/
int
csopen(char *name, int oflag)
{
int len;
char buf[10];
struct iovec iov[3];
static int csfd = 1;
if (csfd < 0) { /* */
if ((csfd = cli_conn(CS_OPEN)) < 0)
err_sys(" cli_conn");
}
sprintf(buf, " %d", oflag);
/* oflag ascii */
iov[0].iov_base = CL_OPEN " ";
/* */
iov[0].iov_len = strlen(CL_OPEN) + 1;
iov[1].iov_base = name;
iov[1].iov_len = strlen(name);
iov[2].iov_base = buf;
iov[2].iov_len = strlen(buf) + 1; /* */
len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
if (writev(csfd, &iov[0], 3) != len)
err_sys(" writev");
/* , write() */
return(recv_fd(csfd, write));
}

.
. opend.h (
17.27) 
.
17.27. opend.h, 2
#include "apue.h"
#include <errno.h>
#define CS_OPEN "/home/sar/opend" /* */
#define CL_OPEN "open" /* , */
extern int debug; /*
/* ( ) */
extern char errmsg[]; /* , */
extern int oflag;
/* open: O_xxx ... */
extern char *pathname; /* , */
typedef struct {
int fd;
uid_t uid;
} Client;

/* Client */
/* fd 1, */

extern Client *client; /* */

17.6. , 2
extern int client_size;

725

/* client[] */

int cli_args(int, char **);


int client_add(int, uid_t);
void client_del(int);
void loop(void);
void request(char *, int, int, uid_t);

,
. 
client,
opend.h. 17.28 , 
.
17.28. client
#include "opend.h"
#define NALLOC 10 /* client alloc/realloc */
static void
client_alloc(void) /* client[] */
{
int i;
if (client == NULL)
client = malloc(NALLOC * sizeof(Client));
else
client = realloc(client, (client_size+NALLOC)*sizeof(Client));
if (client == NULL)
err_sys(" ");
/* */
for (i = client_size; i < client_size + NALLOC; i++)
client[i].fd = 1;
/* fd = 1 , */
client_size += NALLOC;
}
/*
* loop() .
*/
int
client_add(int fd, uid_t uid)
{
int i;
if (client == NULL) /* */
client_alloc();
again:
for (i = 0; i < client_size; i++) {
if (client[i].fd == 1) { /* */
client[i].fd = fd;
client[i].uid = uid;
return(i); /* client[] */
}

726

17.
}
/* , */
client_alloc();
goto again; /* ( ) */

}
/*
* loop() .
*/
void
client_del(int fd)
{
int i;
for (i = 0; i < client_size; i++) {
if (client[i].fd == fd) {
client[i].fd = 1;
return;
}
}
log_quit(" %d", fd);
}

client_add client_alloc,

malloc. ,
client_add
realloc.
,

.
log_ ( B), ,
.
main ( 17.29) , 
loop.
d, .
.
17.29. main , 2
#include "opend.h"
#include <syslog.h>
int
char
char
Client

debug, oflag, client_size, log_to_stderr;


errmsg[MAXLINE];
*pathname;
*client = NULL;

int
main(int argc, char *argv[])
{
int c;

17.6. , 2

727

log_open("open.serv", LOG_PID, LOG_USER);


opterr = 0; /* getopt() stderr */
while ((c = getopt(argc, argv, "d")) != EOF) {
switch (c) {
case d:
/* */
debug = log_to_stderr = 1;
break;
case ?:
err_quit(" : %c", optopt);
}
}
if (debug == 0)
daemonize("opend");
loop();

/* */

loop .
. 17.30 ,
select, 17.31 poll.
17.30. loop select
#include "opend.h"
#include <sys/time.h>
#include <sys/select.h>
void
loop(void)
{
int i, n, maxfd, maxi, listenfd, clifd, nread;
char buf[MAXLINE];
uid_t uid;
fd_set rset, allset;
FD_ZERO(&allset);
/* fd, */
if ((listenfd = serv_listen(CS_OPEN)) < 0)
log_sys(" serv_listen");
FD_SET(listenfd, &allset);
maxfd = listenfd;
maxi = 1;
for ( ; ; ) {
rset = allset; /* rset */
if ((n = select(maxfd + 1, &rset, NULL, NULL, NULL)) < 0)
log_sys(" select");
if (FD_ISSET(listenfd, &rset)) {
/* */
if ((clifd = serv_accept(listenfd, &uid)) < 0)
log_sys(" serv_accept: %d", clifd);
i = client_add(clifd, uid);

728

17.
FD_SET(clifd, &allset);
if (clifd > maxfd)
maxfd = clifd; /* fd select() */
if (i > maxi)
maxi = i;
/* client[] */
log_msg(" : uid %d, fd %d", uid, clifd);
continue;
}
for (i = 0; i <= maxi; i++) {
/* client[] */
if ((clifd = client[i].fd) < 0)
continue;
if (FD_ISSET(clifd, &rset)) {
/* */
if ((nread = read(clifd, buf, MAXLINE)) < 0) {
log_sys(" read fd %d", clifd);
} else if (nread == 0) {
log_msg(": uid %d, fd %d",
client[i].uid, clifd);
client_del(clifd);
/* */
FD_CLR(clifd, &allset);
close(clifd);
} else {
/* */
request(buf, nread, clifd, client[i].uid);
}
}
}
}


serv_listen. , 
select,
.
1. listenfd . ,
cli_conn. 
serv_accept, client
. ( 

select.
.)
2. .
, ,
. read 0 ( ),
, . read 
0, , , 
request.
allset. 
, 

17.6. , 2

729

. , , 
.
, (, 
),
( , )
.
XSI IPC.
loop, poll,
17.31.
17.31. loop poll
#include "opend.h"
#include <poll.h>
#if !defined(BSD) && !defined(MACOS)
#include <stropts.h>
#endif
void
loop(void)
{
int i, maxi, listenfd, clifd, nread;
char buf[MAXLINE];
uid_t uid;
struct pollfd *pollfd;
if ((pollfd = malloc(open_max() * sizeof(struct pollfd))) == NULL)
err_sys("malloc error");
/* fd, */
if ((listenfd = serv_listen(CS_OPEN)) < 0)
log_sys(" serv_listen");
client_add(listenfd, 0); /* listenfd */
pollfd[0].fd = listenfd;
pollfd[0].events = POLLIN;
maxi = 0;
for ( ; ; ) {
if (poll(pollfd, maxi + 1, 1) < 0)
log_sys(" poll");
if (pollfd[0].revents & POLLIN) {
/* */
if ((clifd = serv_accept(listenfd, &uid)) < 0)
log_sys(" serv_accept: %d", clifd);
i = client_add(clifd, uid);
pollfd[i].fd = clifd;
pollfd[i].events = POLLIN;
if (i > maxi)
maxi = i;
log_msg(" : uid %d, fd %d", uid, clifd);
}

730

17.
for (i = 1; i <= maxi; i++) {
if ((clifd = client[i].fd) < 0)
continue;
if (pollfd[i].revents & POLLHUP) {
goto hungup;
} else if (pollfd[i].revents & POLLIN) {
/* */
if ((nread = read(clifd, buf, MAXLINE)) < 0) {
log_sys(" fd %d", clifd);
} else if (nread == 0) {

hungup:
log_msg(": uid %d, fd %d",
client[i].uid, clifd);
client_del(clifd); /* */
pollfd[i].fd = 1;
close(clifd);
} else {
/* */
request(buf, nread, clifd, client[i].uid);
}
}
}
}
}

,
,
pollfd. ( open_max 2.4.)
client ( 0) 
listenfd. , client 
pollfd.
POLLIN
listenfd. , 
serv_accept.

poll: ( POLLHUP) 
( POLLIN). 15.7 
, 
, . 

. 
, 
. , .
select,
request ( 17.32). 
( 17.23). buf_args (
17.24), cli_args ( 17.24),
, 
.

17.7.

731

17.32. request, 2
#include "opend.h"
#include <fcntl.h>
void
request(char *buf, int nread, int clifd, uid_t uid)
{
int newfd;
if (buf[nread1] != 0) {
sprintf(errmsg,
" uid %d : %*.*s\n",
uid, nread, nread, buf);
send_err(clifd, 1, errmsg);
return;
}
log_msg(": %s, uid %d", buf, uid);
/* */
if (buf_args(buf, cli_args) < 0) {
send_err(clifd, 1, errmsg);
log_msg(errmsg);
return;
}
if ((newfd = open(pathname, oflag)) < 0) {
sprintf(errmsg, " %s: %s\n",
pathname, strerror(errno));
send_err(clifd, 1, errmsg);
log_msg(errmsg);
return;
}
/* */
if (send_fd(clifd, newfd) < 0)
log_sys(" send_fd");
log_msg(" fd %d fd %d %s", newfd, clifd, pathname);
close(newfd);
/* */
}

,

.

17.7.


. , STREAMS
UNIX. ,
UNIX (. 15.1), 
, 
.

732

17.

. 
fork exec.
,
.
. ,
,
17.2.2, 
, 14.5.

17.1. 17.1 , 
STREAMS read write
.
17.2. /

8.9, .
fork, 
.
lseek
.
, , .
,

. ,
. 

.
17.3. 17.22 17.23  
. ?
17.4. buf_args ( 17.24) , 
argv.
.
17.5. , loop
17.30 17.31. .

18

18.1.
, ,
. UNIX
.
.
70 ,
System III 
, , Version 7. 
System III System V, Version 7
BSD. , 

POSIX.1. ,
, , 
.
 ,
:
, , 
, , . .

18.2.
 :
1. . 
.
.
2. . 
.
, 
. ,

734

18.

,
read write, 
read 
. , , 
vi, ,

. , 
, 
. , ControlD,

, vi  .
Version 7 BSD
: () (cooked mode 
), () 
(raw mode 
) () (cbreak mode 
, ).
18.10 POSIX.1, 
.

POSIX.1 11 , 9
. ,
( ControlD)
( ControlZ). 18.3 .
,
, . 
, . 18.1.
:
 
.
MAX_INPUT (. 2.8).


MAX_INPUT

. 18.1.

735

18.2.

. UNIX, ,
.

, ,
, MAX_CANON. 

.

, 
, , ,
, , 
, , ,
.

, tcflush 
. 
tcsetattr ,
, 
. ( , ,
.)
. ( 

,
.)

UNIX
, terminal line discipline ( 
). 
, 
/ (. 18.2).
, . 18.2 STREAMS
. 14.5.
19, .
, , 
termios. 
<termios.h>, 
:
struct termios {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t
c_cc[NCCS];
};

/*
/*
/*
/*
/*

*/
*/
*/
*/
*/

, , 
(
, . .),
( , 

736

18.

. 18.2. ,

CR/LF ), 
RS232 (
, . .). ,

(/ ,
, / . .).
tcflag_t ,
. unsigned int un
signed long. c_cc ,
. NCCS ,
15 20 ( 
UNIX 11 POSIX.1
). cc_t , 
, 
unsigned char.
System V, POSIX.1, 
<termio.h> termio. POSIX.1 s,
.

. 18.118.4 , 
.
, Single UNIX Specification
,
. 

737

18.2.

. 
18.5.
18.1.

CBAUDEXT

POSIX.1 FreeBSD Linux MacOS X Sola


5.2.1
2.4.22 10.3
ris 9

CCAR_OFLOW DCD

CCTS_OFLOW CTS

CDSR_OFLOW DSR

CDTR_IFLOW DTR

CIBAUDEXT

CIGNORE

CLOCAL

CREAD

CRTSCTS

CRTS_IFLOW RTS

CRTSXOFF

CSIZE

CSTOPB

HUPCL

MDMBUF

, CCAR_OFLOW

738

18.

18.1 ()

PARENB

PAREXT


mark space

PARODD


odd even

POSIX.1 FreeBSD Linux MacOS X Sola


5.2.1
2.4.22 10.3
ris 9

18.2.

POSIX.1 FreeBSD Linux MacOS X Sola


5.2.1
2.4.22 10.3
ris 9

BRKINT

SIGINT
BREAK

ICRNL

CR
( ) NL
( )

IGNBRK

BREAK

IGNCR

CR

IGNPAR

IMAXBEL

INLCR

NL
CR

INPCK

ISRIP

IUCLC

IXANY

IXOFF

XSI



START/STOP

IXON



START/STOP

PARMRK

739

18.2.

18.3.

POSIX.1 FreeBSD Linux MacOS Sola


5.2.1
2.4.22 X 10.3 ris 9

ALTWERASE 

WERASE

ECHO

ECHOCTL


^ ()

ECHOE

ECHOK

ECHOKE

ECHONL

ECHOPRT

EXTPROC

FLUSHO

ICANON

IEXTEN

ISIG

NOFLSH



SIGINT SIGQUIT

NOKERNINFO
STATUS
PENDIN

TOSTOP

SIGTTOU 

XCASE

, , 
? . 18.5 
, Single UNIX Specification 
. (
POSIX.1, 

740

18.

tcgetsid, XSI. 
tcgetpgrp, tcgetsid tcsetpgrp 9.7.)
18.4.

BSDLY

POSIX.1 FreeBSD Linux MacOS X Sola


5.2.1
2.4.22 10.3
ris 9
XSI

CMSPAR
mark space

CRDLY

CR
( )

XSI

FFDLY

FF
( )

XSI

NLDLY

NL
( )

XSI

OCRNL

CR NL

XSI

OFDEL

DEL
,
NUL

XSI

OFILL

XSI

OLCUC

ONLCR

NL

CRNL

XSI

ONLRET NL
CR

XSI

XSI

ONOCR

CR

ONOEOT EOT (^D)

OPOST

OXTABS

TABDLY

VTDLY

XSI

XSI

741

18.2.

: Single UNIX Specification


ioctl
. 13 , 
. 18.5. ,
ioctl ,
.
13 
, . 18.5
70 (. 18.118.4). 

, 
(, , ).
18.5. ,

tcgetattr

( termios)

tcsetattr

( termios)

cfgetispeed

cfgetospeed

csetispeed

csetospeed

tcdrain

tcflow

tcflush

tcsendbreak

BREAK

tcgetpgrp

tcsetpgrp

tcgetsid

. 18.5 . 18.3.
POSIX.1 , termios 
. 
, Linux Solaris, c_cflag. ,
BSD, FreeBSD Mac OS X,
: , .

742

cfgetospeed

cfsetospeed

tcsetpgrp

tcgetpgrp

tcgetsid

tcflow

tcflush

tcdrain

tcsendbreak

tcgetattr



tcsetattr

struct
termios

cfgetispeed

cfsetispeed

18.

. 18.3. ,

18.3.
POSIX.1 11 ( )
. .
. 18.6 .

CR




c_cc

( c_lflag
)

ICANON \r

VDISCARD

c_lflag

VDSUSP

DISCARD

POSIX.1
FreeBSD
5.2.1
Linux
2.4.22
MacOS
X 10.3
Solaris 9

18.6.

IEXTEN ^O

c_lflag

ISIG

DSUSP


(SIGTSTP)

EOF

VEOF

c_lflag

ICANON ^D

EOL

VEOL

c_lflag

ICANON

EOL2


VEOL2

c_lflag

ICANON

ERASE

c_lflag

ICANON ^H,^?

VERASE

^Y

743

c_cc




POSIX.1
FreeBSD
5.2.1
Linux
2.4.22
MacOS
X 10.3
Solaris 9

18.3.

ERASE2


VERASE2

c_lflag

ICANON ^H,^?

INTR

(SIGINT)

VINTR

c_lflag

ISIG

^?,^C

KILL

VKILL

c_lflag

ISIG

^U

LNEXT

VLNEXT

c_lflag

ICANON ^V

NL

( c_lflag
)

ICANON \n

QUIT

(SIGQUIT)

VQUIT

c_lflag

ISIG

VREPRINT

c_lflag

ICANON ^R

REPRINT 


^\

START

VSTART

c_lflag

IXON/
IXOFF

STATUS

VSTATUS

c_lflag

ICANON ^T

STOP

VSTOP

c_lflag

IXON/
IXOFF

^S

SUSP

(SIGTSTP)

VSUSP

c_lflag

ISIG

^Z

WERASE

VWERASE

c_lflag

ICANON ^W

^Q

POSIX.1 11 , 9
. 
(\r \n 
) , , STOP START ( ).
, 
c_cc termios. 
, V ( . 18.6).
POSIX.1 .
_POSIX_VDISABLE.

744

18.

Single UNIX Specification _PO


SIX_VDISABLE . ,
.
, , .
Linux 2.4.22 Solaris 9 _POSIX_VDISABLE 0,
FreeBSD 5.2.1 Mac OS X 10.3 0xff.
UNIX
, 0.

, 
, . 
18.1 ControlB
.
18.1.
#include "apue.h"
#include <termios.h>
int
main(void)
{
struct termios term;
long vdisable;
if (isatty(STDIN_FILENO) == 0)
err_quit(" ");
if ((vdisable = fpathconf(STDIN_FILENO, _PC_VDISABLE)) < 0)
err_quit(" fpathconf _POSIX_VDISABLE ");
if (tcgetattr(STDIN_FILENO, &term) < 0) /* */
err_sys(" tcgetattr");
term.c_cc[VINTR] = vdisable; /* INTR */
term.c_cc[VEOF] = 2;
/* ControlB */
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) < 0)
err_sys(" tcsetattr");
exit(0);
}

:
,
.
isatty ( 18.9).
_POSIX_VDISABLE
fpathconf.
tcgetattr ( 18.4) ter
mios. tcsetattr,

18.3.

745

. ,
.

, 
SIGINT. 18.1 
, 
SIGINT. 
, kill .

.
, START STOP
(ControlQ ControlS) 
. , 
, 
. 
(NL, EOL,
EOL2) (CR).
CR

. .
. 
ICANON ( ) ICRNL (
CR NL) IGNCR ( CR), CR 
NL NL. 
(, NL).

DISCARD (IEXTEN) 

,
DISCARD
( FLUSHO). (. . 
).
DSUSP

. 
(IEXTEN),
ISIG.
SUSP,
SIGTSTP, 
(. 9.7).
, ,
. 
(. . ).

EOF

. 
(ICANON). 
.
, , 
. ,
, EOF .
,
(. . ).

EOL

, NL.
(ICANON) 
. .

746
EOL2

18.

, NL. 
, EOL.

ERASE .
(ICANON). , 
. 
, (. . ).
ERASE2 . ,
ERASE.
INTR

. , 
ISIG, SIGINT, 
(. 9.7).
(. . ).

KILL

. ( kill ,
kill,
.
lineerase ( ), . .
.)
(ICANON). (. .
).

LNEXT . 
(IEXTEN); 
.
, . 
. LNEXT
, .
NL

, .
(ICANON). 
, .

QUIT

. , 
ISIG. QUIT SIGQUIT,

(. 9.7). (. .
).
. 10.1 , INTR QUIT 
, QUIT
, (core).

REPRINT . 
( , IEXTEN ICANON) 
( ).
(. . ).
START

. ,
IXON, ,
IXOFF. START IXON 
,
STOP. START
(. . ).

18.3.

747

IXOFF 
START, ,
 .
STATUS BSD. 
(
, IEXTEN ICANON) SIGINFO,
(. 9.7). 
, NOKERNINFO,
. 
(. . ).
STOP

. ,
IXON, ,
IXOFF. STOP IXON 
. STOP
(. . ).
START.
IXOFF, 
STOP, .

SUSP

. ,
ISIG.
SUSP SIGTSTP, 
(. 9.7). 
(. . ).

WERASE . 
( , IEXTEN ICANON)
.
( 
), . 
. 
. 
, ALTWERASE.

. (. .
).

, , BREAK
( ). BREAK 
, , 
.
BREAK ,
.
BREAK, 
BREAK. ,
BREAK . 
. BREAK
. , ControlBREAK
Windows .

748

18.


BREAK , 
,
. 
BREAK. 18.8 ,
BREAK tcsendbreak.

18.4.

termios, 
: tcgetattr tcsetattr. 
, 
, .
#include <termios.h>
int tcgetattr(int filedes, struct termios *termptr);
int tcsetattr(int filedes, int opt, const struct termios *termptr);
0 , 1

termios
, .
, 
, filedes , 
ENOTTY errno.
opt tcsetattr , 
. 
.
TCSANOW

TCSADRAIN ,
, . 
, .
TCSAFLUSH ,
, . , 
,
().
tcsetattr . 
, ,
,
. , tcsetattr 
, , 
. , tcsetattr

18.5.

749

tcgetattr 
.

18.5.
, 
. 18.118.4.
, . 
, . (
, .) , 
, Single UNIX Specification,
, .
,
.  
, . 
. ,
, ,
CSIZE, CS5, CS6, CS7 CS8.
, Linux Solaris,
: BSDLY, CRDLY, FFDLY, NLDLY, TABDLY VTDLY.
termio(7I)
Solaris. , 
. , OFILL OFDEL , 

.

18.2
.
18.2. tcgetattr tcsetattr
#include "apue.h"
#include <termios.h>
int
main(void)
{
struct termios term;
if (tcgetattr(STDIN_FILENO, &term) < 0)
err_sys(" tcgetattr");
switch (term.c_cflag & CSIZE) {
case CS5:
printf("5 \n");
break;
case CS6:
printf("6 \n");

750

18.
break;
case CS7:
printf("7 \n");
break;
case CS8:
printf("8 \n");
break;
default:
printf(" \n");
}
term.c_cflag &= CSIZE; /* */
term.c_cflag |= CS8;
/* 8 */
if (tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0)
err_sys(" tcsetattr");
exit(0);

.
ALTWERASE (c_lflag, FreeBSD, Mac OS X) , 
WERASE.
,
, .
BRKINT

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, IGNBRK , BREAK 
SIGINT.
, 
.
, BRKINT IGNBRK, , BREAK
\0, PARMRK, 
\377, \0, \0, PARMRK .

BSDLY

(c_oflag, Solaris) .
: BS0 BS1.

CBAUDEXT

(c_cflag, Solaris) . 
, , B38400.
( 18.7.)

CCAR_OFLOW (c_cflag, FreeBSD, Mac OS X) 


RS232
DCD (DataCarrierDetect ).
, MDMBUF.
CCTS_OFLOW (c_cflag, FreeBSD, Mac OS X, Solaris) 
RS232
CTS (ClearToSend ).
CDSR_OFLOW (c_cflag, FreeBSD, Mac OS X) 
RS232 DSR (Da
taSendReady ).

18.5.

751

CDTR_IFLOW (c_cflag, FreeBSD, MacOS X) 


RS232 DTR (Da
taTerminalReady ).
CIBAUDEXT (c_cflag, Solaris) . 
, ,
B38400. ( 18.7.)
CIGNORE

(c_cflag, FreeBSD, Mac OS X) .

CLOCAL

(c_cflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, . 
,
. , 
, , , 
.

CMSPAR

(c_oflag, Linux) MARK


SPACE. PARODD, 
1 ( MARK).
0 ( SPACE).

CRDLY

(c_oflag, XSI, Linux, Solaris) CR. 


: CR0, CR1, CR2 CR3.

CREAD

(c_cflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


.

CRTSCTS

(c_cflag, FreeBSD, Linux, Mac OS X, Solaris) 


. Solaris 
.
, ,
( CCTS_OFLOW|CRTS_OFLOW).

CRTS_IFLOW (c_cflag, FreeBSD, Mac OS X, Solaris) 


RS232
RTS (RequestToSend ).
CRTSXOFF

(c_cflag, Solaris)
. RS232 RTS.

CSIZE

(c_cflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, 
/. . 
: CS5, CS6, CS7 CS8, 5, 6, 7
8 .

CSTOPB

(c_cflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, , .

ECHO

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


,  .  
, .

752

18.

ECHOCTL

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


ECHO, ASCII
( 0 37 ), 
ASCII TAB, ASCII NL, START STOP, 
^X, X , 
100.
, , ControlA (
1) ^A. , ASCII DE
LETE ( 177) ^?.
, ASCII .
ECHO, 
, .
, EOF
, . . ControlD. (ControlD
ASCII EOT,
.) . .

ECHOE

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


ICANON, ERASE

. 
: (backspace),
(space), (backspace).
WERASE,
ECHOE ,

.
ECHOPRT, ECHOE 
, ECHOPRT .

ECHOK

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


ICANON, KILL 
NL ( ,
).
ECHOKE, ECHOK 
, ECHOKE .

ECHOKE

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


ICANON, KILL 
. , 
, ECHOE ECHOPRT.

ECHONL

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


ICANON,  NL
, ECHO .

ECHOPRT

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


ICANON ECHO,
ERASE ( WERASE, )
, .
, 
, .

18.5.

753

EXTPROC (c_oflag, XSI, Linux, Solaris) , 


. , 
, 
. 
( 19).
FFDLY

(c_oflag, XSI, Linux, Solaris) FF (


). : FF0 FF1.

FLUSHO

(c_lflag, FreeBSD, Linux, Mac OS X, Solaris)


.
DISCARD
. , .

HUPCL

(c_cflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


,
, .

ICANON

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, ( 18.10),
EOF, EOL, EOL2, ERASE, KILL, RE
PRINT, STATUS WERASE. .

, MIN
 TIME .
. 18.11.

ICRNL

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


IGNCR, CR 
NL.

IEXTEN

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, 
, .

IGNBRK

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, BREAK .
BRKINT , BREAK 
SIGINT, .

IGNCR

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, CR . ,
CR
NL ICRNL.

IGNPAR

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, ,
( BREAK) 
, .

IMAXBEL (c_iflag, FreeBSD, Linux, Mac OS X, Solaris) , 


.
INLCR

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, NL CR.

754

18.

INPCK

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, . ,
.

. PARENB.
,

. PARODD ODD ()
EVEN (). 
, INPCK. 
, IGNPAR ( , 
, 
). ,
PARMRK, , ,
.

ISIG

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, 
( INTR, QUIT, SUSP DSUSP).
, 
.

ISTRIP

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, 8 . ,
8 .

IUCLC

(c_iflag, Linux, Solaris) , 


.

IXANY

(c_iflag, XSI, FreeBSD, Linux, Mac OS X, Solaris) 


, .

IXOFF

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


,
START/STOP. ,
STOP. 
, , 
. , ,
START,
.

IXON

(c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


,
START/STOP. STOP, 
.
START, . ,
START STOP .

MDMBUF

(c_cflag, FreeBSD, Mac OS X) 


DCD .
CCAR_OFLOW.

NLDLY

(c_oflag, XSI, Linux, Solaris) NL.


: NL0 NL1.

18.5.

NOFLSH

755

(c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) ,


SIGINT SIGQUIT,
( ) . , 
SIGSUSP, .
NOFLSH, 
.

NOKERNINFO (c_oflag, XSI, FreeBSD, Mac OS X)



STATUS. STATUS
SIGINFO,
.
OCRNL

(c_oflag, XSI, FreeBSD, Linux, Solaris) , 


CR NL.

OFDEL

(c_oflag, XSI, Linux, Solaris) , 


 ASCII DEL,
ASCII NUL. . OFILL.

OFILL

(c_oflag, XSI, Linux, Solaris) ,


 (ASCII DEL
ASCII NUL). : BSDLY, CRDLY, FFDLY,
NLDLY, TABDLY VTDLY.

OLCUC

(c_oflag, Linux, Solaris) , 


.

ONLCR

(c_oflag, XSI, FreeBSD, Linux, Mac OS X, Solaris) 


, NL
CRNL.

ONLRET

(c_oflag, XSI, FreeBSD, Linux, Solaris) , 


, NL 
.

ONOCR

(c_oflag, XSI, FreeBSD, Linux, Solaris) ,


CR, , .

ONOEOT

(c_oflag, FreeBSD, Mac OS X) , EOT (^D)


. 
, ControlD
.

OPOST

(c_oflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, ,
. . 18.4
, .

OXTABS

(c_cflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 


, .
, 
(TABDLY)
XTABS TAB3.

756

18.

PARENB (c_cflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 



. PARODD,
, . 
. INPCK, IGNPAR PARMRK.
PAREXT (c_cflag, Solaris) MARK/SPACE.
PARODD, 1 (MARK).
0 (SPACE).
PARMRK (c_iflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 
IGNPAR, , 
(
BREAK) ,
: \377, \0, X, X , 
. ISTRIP , \377 
: \377, \377. IGNPAR
PARMRK , ,
( BREAK) 
, \0.
PARODD (c_cflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 
, 
. 
. :
PARENB.
, PARODD 
MARK SPACE, CMSPAR PAREXT.
PENDIN (c_lflag, FreeBSD, Linux, Mac OS X, Solaris) ,
,
.
, REPRINT.
TABDLY (c_oflag, XSI, Linux, Solaris)
. : TAB0, TAB1, TAB2 TAB3.
XTABS TAB3. 
. 
,
, .
TOSTOP (c_lflag, POSIX.1, FreeBSD, Linux, Mac OS X, Solaris) 
,

SIGTTOU. 
. 
, , 
, , .
VTDLY

(c_oflag, XSI, Linux, Solaris)


. : VT0 VT1.

18.6. stty

XCASE

757

(c_lflag, Linux, Solaris) 


ICANON,
, .
. 

. ( , 
,
, .)

18.6. stty
, , 
tcgetattr tcsetattr
( 18.4) ( )
stty(1).
. 18.5. 
a, :
$ stty a
speed 9600 baud; 25 rows; 80 columns;
lflags: icanon isig iexten echo echoe echok echoke echonl echoctl
echoprt altwerase noflsh tostop flusho pendin nokerninfo
extproc
iflags: istrip icrnl inlcr igncr ixon ixoff ixany imaxbel ignbrk
brkint inpck ignpar parmrk
oflags: opost onlcr ocrnl oxtabs onocr onlret
cflags: cread cs8 parenb parodd hupcl clocal cstopb crtscts
dsrflow dtrflow mdmbuf
cchars: discard = O; dsusp = Y; eof = D; eol = <undef>;
eol2 = <undef>; erase = H; erase2 = ?; intr = C; kill = U;
lnext = V; min = 1; quit = ; reprint = R; start = Q;
status = T; stop = S; susp = Z; time = 0; werase = W;

, , , . 

( 18.3).

18.12.
stty 
.
, POSIX.1 ,
. ,
, stty, 
. , tty1a,
:
stty a </dev/tty1a

758

18.

18.7.
,
. 
, ,
, 

#include <termios.h>
speed_t cfgetispeed(const struct termios *termptr);
speed_t cfgetospeed(const struct termios *termptr);

int cfsetispeed(struct termios *termptr, speed_t speed);
int cfsetospeed(struct termios *termptr, speed_t speed);
0 , 1

, cfget
cfset, 
: B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800, B9600,
B19200 B38400. B0 . 
tcsetattr B0,
.
: B57600 B115200.

,
termios, . 18.3. 
 cfget, 
termios tcgetattr.
, termios 
cfset tc
setattr. , 
, tcsetattr.
, ,

. , , , BSD,
( 9600 
9600), Linux System V 
. cfget ,
cfset ,
termios.

18.8.

759

18.8.

. ,
filedes , 

ENOTTY errno.
#include <termios.h>
int tcdrain(int filedes);
int tcflow(int filedes, int action);
int tcflush(int filedes, int queue);
int tcsendbreak(int filedes, int duration);
0 , 1

tcdrain , .
tcflow 
. action
:
TCOOFF .
TCOON

TCIOFF STOP, 
.
TCION

START, 
.

tcflush ()
( ,
), (
, ). queue 
:
TCIFLUSH

TCOFLUSH

TCIOFLUSH

tcsendbreak 
. duration 0,
0,25 0,5 
. POSIX.1 ,
duration .

760

18.

18.9.
UNIX 
/dev/tty. POSIX.1 ,

.
#include <stdio.h>
char *ctermid(char *ptr);

,

ptr , ,
L_ctermid .
. 
L_ctermid <stdio.h>. ptr
, ( 
)
.

. UNIX 
/dev/tty,

.
, , ctermid 
/dev/tty.

ctermid
18.3 ctermid POSIX.1.
18.3. ctermid POSIX.1
#include <stdio.h>
#include <string.h>
static char ctermid_name[L_ctermid];
char *
ctermid(char *str)
{
if (str == NULL)
str = ctermid_name;
return(strcpy(str, "/dev/tty")); /* strcpy() str */
}

: , 
,
.

18.9.

761

UNIX 
. isatty, , 
, ttyname, 
.
#include <unistd.h>
int isatty(int filedes);
1 (), filedes
, 0 ()
char *ttyname(int filedes);

, , NULL

isatty
isatty , 18.4.
( 
) .
18.4. isatty POSIX.1
#include <termios.h>
int
isatty(int fd)
{
struct termios ts;
return(tcgetattr(fd, &ts) != 1); /* , ( ) */
}

isatty 
18.5.
18.5. isatty
#include "apue.h"
int
main(void)
{
printf("fd 0: %s\n", isatty(0) ? "tty" : " tty");
printf("fd 1: %s\n", isatty(1) ? "tty" : " tty");
printf("fd 2: %s\n", isatty(2) ? "tty" : " tty");
exit(0);
}

:
$ ./a.out
fd 0: tty

762

18.

fd 1: tty
fd 2: tty
$ ./a.out </etc/passwd 2>/dev/null
fd 0: tty
fd 1: tty
fd 2: tty

ttyname
ttyname ( 18.6) , 
.
18.6. ttyname POSIX.1
#include
#include
#include
#include
#include
#include
#include

<sys/stat.h>
<dirent.h>
<limits.h>
<string.h>
<termios.h>
<unistd.h>
<stdlib.h>

struct devdir {
struct devdir *d_next;
char
*d_name;
};
static struct devdir *head;
static struct devdir *tail;
static char
pathname[_POSIX_PATH_MAX + 1];
static void
add(char *dirname)
{
struct devdir *ddp;
int len;
len = strlen(dirname);
/*
* ., .. /dev/fd.
*/
if ((dirname[len1] == .) && (dirname[len2] == / ||
(dirname[len2] == . && dirname[len3] == /)))
return;
if (strcmp(dirname, "/dev/fd") == 0)
return;
ddp = malloc(sizeof(struct devdir));
if (ddp == NULL)
return;
ddp>d_name = strdup(dirname);
if (ddp>d_name == NULL) {
free(ddp);
return;
}

18.9.
ddp>d_next = NULL;
if (tail == NULL) {
head = ddp;
tail = ddp;
} else {
tail>d_next = ddp;
tail = ddp;
}
}
static void
cleanup(void)
{
struct devdir *ddp, *nddp;
ddp = head;
while (ddp != NULL) {
nddp = ddp>d_next;
free(ddp>d_name);
free(ddp);
ddp = nddp;
}
head = NULL;
tail = NULL;
}
static char *
searchdir(char *dirname, struct stat *fdstatp)
{
struct stat devstat;
DIR *dp;
int devlen;
struct dirent *dirp;
strcpy(pathname, dirname);
if ((dp = opendir(dirname)) == NULL)
return(NULL);
strcat(pathname, "/");
devlen = strlen(pathname);
while ((dirp = readdir(dp)) != NULL) {
strncpy(pathname + devlen, dirp>d_name,
_POSIX_PATH_MAX  devlen);
/*
* .
*/
if (strcmp(pathname, "/dev/stdin") == 0 ||
strcmp(pathname, "/dev/stdout") == 0 ||
strcmp(pathname, "/dev/stderr") == 0)
continue;
if (stat(pathname, &devstat) < 0)
continue;
if (S_ISDIR(devstat.st_mode)) {

763

764

18.
add(pathname);
continue;
}
if (devstat.st_ino == fdstatp>st_ino &&
devstat.st_dev == fdstatp>st_dev) {
/* */
closedir(dp);
return(pathname);
}
}
closedir(dp);
return(NULL);

}
char *
ttyname(int fd)
{
struct stat fdstat;
struct devdir *ddp;
char *rval;
if (isatty(fd) == 0)
return(NULL);
if (fstat(fd, &fdstat) < 0)
return(NULL);
if (S_ISCHR(fdstat.st_mode) == 0)
return(NULL);
rval = searchdir("/dev", &fdstat);
if (rval == NULL) {
for (ddp = head; ddp != NULL; ddp = ddp>d_next)
if ((rval = searchdir(ddp>d_name, &fdstat)) != NULL)
break;
}
cleanup();
return(rval);
}

/dev 
. 4.23, 
(
st_dev stat, 4.2),
( st_ino stat). ,

, , 
. , 
st_rdev 
.
,

( 
), .

18.9.

765


/dev. 
/dev. /dev/., /dev/..
/dev/fd. /dev/stdin, /dev/stdout
/dev/stderr, , 
/dev/fd.
ttyname
, 18.7.
18.7. ttyname
#include "apue.h"
int
main(void)
{
char *name;
if (isatty(0)) {
name = ttyname(0);
if (name == NULL)
name = " ";
} else {
name = " tty";
}
printf("fd 0: %s\n", name);
if (isatty(1)) {
name = ttyname(1);
if (name == NULL)
name = " ";
} else {
name = " tty";
}
printf("fd 1: %s\n", name);
if (isatty(2)) {
name = ttyname(2);
if (name == NULL)
name = " ";
} else {
name = " tty";
}
printf("fd 2: %s\n", name);
exit(0);
}

18.7 
:
$ ./a.out < /dev/console 2> /dev/null
fd 0: /dev/console
fd 1: /dev/ttyp3
fd 2: tty

766

18.

18.10.
: , 
, .
:
.
. , 
; 
.
. 18.3 ,
NL, EOL,
EOL2 EOF. , 18.5 , CR
, ICRNL,
IGNCR .
, (EOF)
. 
.
,
( 10.5).

getpass
getpass,
, .
login(1) crypt(1). ,
, , 
. 18.8
UNIX.
:

(/dev/tty), ctermid.
/
, ,
. 
getpass BSD 
,
. System V

, .
18.8. getpass
#include <signal.h>
#include <stdio.h>
#include <termios.h>
#define MAX_PASS_LEN 8 /* */

18.10.

767

char *
getpass(const char *prompt)
{
static char buf[MAX_PASS_LEN + 1]; /* */
char *ptr;
sigset_t sig, osig;
struct termios ts, ots;
FILE *fp;
int c;
if ((fp = fopen(ctermid(NULL), "r+")) == NULL)
return(NULL);
setbuf(fp, NULL);
sigemptyset(&sig);
sigaddset(&sig, SIGINT);
/* SIGINT */
sigaddset(&sig, SIGTSTP);
/* SIGTSTP */
sigprocmask(SIG_BLOCK, &sig, &osig); /* */
tcgetattr(fileno(fp), &ts);
/* */
ots = ts;
/* */
ts.c_lflag &= (ECHO | ECHOE | ECHOK | ECHONL);
tcsetattr(fileno(fp), TCSAFLUSH, &ts);
fputs(prompt, fp);
ptr = buf;
while ((c = getc(fp)) != EOF && c != \n)
if (ptr < &buf[MAX_PASS_LEN])
*ptr++ = c;
*ptr = 0;
/* */
putc(\n, fp);
/* */
tcsetattr(fileno(fp), TCSAFLUSH, &ots); /* */
sigprocmask(SIG_SETMASK, &osig, NULL); /* */
fclose(fp);
/* /dev/tty */
return(buf);
}

SIGINT SIGTSTP. ,
INTR
. , SUSP

. 
, 
.
, ,
. 
. SIGINT (
) getpass, 

. SIGINT ( 
) 

768

18.

kill.
getpass ,
SIGQUIT , QUIT 
, , 
.
, ( Korn
shell) , 
. 

, .
, 
QUIT,
 . ,
Bourne shell,
.
 stty.
getpass
. 


, ( 
fflush).
 ( 3), 
getc read.
. 
.
, 18.9, getpass 
, , , ERASE KILL
( 
).
18.9. getpass
#include "apue.h"
char *getpass(const char *);
int
main(void)
{
char *ptr;
if ((ptr = getpass(" :")) == NULL)
err_sys(" getpass");
printf(": %s\n", ptr);
/* (, ) ... */
while (*ptr != 0)
*ptr++ = 0;

/* , */

18.11.

769

exit(0);
}

,
, 
.
core, ,
,
. ( 
, getpass. 
, , UNIX .
, , pw_passwd 
, .)

18.11.
ICANON 
c_lflag termios. 
, ERASE, KILL,
EOF, NL, EOL, EOL2, CR, REPRINT, STATUS WERASE .
, :
. , 

? , 
. ( . 3.2,
, ,

.) , 
.
, , 

. c_cc termi
os MIN TIME, VMIN VTIME.
MIN , 
read . TIME 
, 
. , .
: MIN > 0, TIME > 0
TIME ,
. MIN ,
, read MIN . 
, MIN , read
, . (
,
.) ,

770

18.

. read 
, ,
read.
: MIN > 0, TIME == 0
read ,
MIN . , 
.
: MIN == 0, TIME > 0
TIME , 
read. ( , 
, .) read

. ,
, read 0.
: MIN == 0, TIME == 0
 , read 
, , .
, read 0.
, MIN
. ,
.
, MIN .
18.7 .
nbytes read (
, ).
18.7.
MIN > 0

MIN == 0

: read [MIN, nbytes] , : read


;
[1, nbytes] ,
read [1, MIN]
;
TIME > 0
.
read 0 

( 
.
.)
: read [MIN, nbytes],
.
TIME == 0
( 
.)

: read
[0, nbytes] .

, POSIX.1 , VMIN VTIME


VEOF VEOL . , Solaris
System V.
. 

18.11.

771

VEOF
VEOL. , VMIN VEOF
, VMIN 
1, ControlA.
termios
.

18.10 tty_cbreak tty_raw, 


(cbreak)
(raw) . ( cbreak raw 
Version 7.) (
) 
tty_reset.
tty_cbreak tty_reset,
tty_raw.
tty_cbreak tty_raw. ,
, , 
.
: tty_atexit, 
,
exit, tty_ter
mios, termios, 
.
18.10.
#include "apue.h"
#include <termios.h>
#include <errno.h>
static struct termios save_termios;
static int ttysavefd = 1;
static enum { RESET, RAW, CBREAK } ttystate = RESET;
int
tty_cbreak(int fd) /* */
{
int err;
struct termios buf;
if (ttystate != RESET) {
errno = EINVAL;
return(1);
}
if (tcgetattr(fd, &buf) < 0)
return(1);
save_termios = buf; /* */
/*
*  .
*/

772

18.
buf.c_lflag &= (ECHO | ICANON);
/*
* : 1 , .
*/
buf.c_cc[VMIN] = 1;
buf.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
return(1);
/*
* , . tcsetattr
* 0, .
*/
if (tcgetattr(fd, &buf) < 0) {
err = errno;
tcsetattr(fd, TCSAFLUSH, &save_termios);
errno = err;
return(1);
}
if ((buf.c_lflag & (ECHO | ICANON)) || buf.c_cc[VMIN] != 1 ||
buf.c_cc[VTIME] != 0) {
/*
* .
* .
*/
tcsetattr(fd, TCSAFLUSH, &save_termios);
errno = EINVAL;
return(1);
}
ttystate = CBREAK;
ttysavefd = fd;
return(0);

}
int
tty_raw(int fd) /* (raw) */
{
int err;
struct termios buf;
if (ttystate != RESET) {
errno = EINVAL;
return(1);
}
if (tcgetattr(fd, &buf) < 0)
return(1);
save_termios = buf; /* */
/*
* , ,
* , ,
* .
*/

18.11.
buf.c_lflag &= (ECHO | ICANON | IEXTEN | ISIG);
/*
* SIGINT BREAK,
* CR>NL, ,
* 8 , .
*/
buf.c_iflag &= (BRKINT | ICRNL | INPCK | ISTRIP | IXON);
/*
* , .
*/
buf.c_cflag &= (CSIZE | PARENB);
/*
* 8 /.
*/
buf.c_cflag |= CS8;
/*
* .
*/
buf.c_oflag &= (OPOST);
/*
* : 1 , .
*/
buf.c_cc[VMIN] = 1;
buf.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
return(1);
/*
* , . tcsetattr
* 0, .
*/
if (tcgetattr(fd, &buf) < 0) {
err = errno;
tcsetattr(fd, TCSAFLUSH, &save_termios);
errno = err;
return(1);
}
if ((buf.c_lflag & (ECHO | ICANON | IEXTEN | ISIG)) ||
(buf.c_iflag & (BRKINT | ICRNL | INPCK | ISTRIP | IXON)) ||
(buf.c_cflag & (CSIZE | PARENB | CS8)) != CS8 ||
(buf.c_oflag & OPOST) || buf.c_cc[VMIN] != 1 ||
buf.c_cc[VTIME] != 0) {
/*
* .
* .
*/
tcsetattr(fd, TCSAFLUSH, &save_termios);
errno = EINVAL;

773

774

18.
return(1);
}
ttystate = RAW;
ttysavefd = fd;
return(0);

}
int
tty_reset(int fd) /* */
{
if (ttystate == RESET)
return(0);
if (tcsetattr(fd, TCSAFLUSH, &save_termios) < 0)
return(1);
ttystate = RESET;
return(0);
}
void
tty_atexit(void) /* atexit(tty_atexit) */
{
if (ttysavefd >= 0)
tty_reset(ttysavefd);
}
struct termios *
tty_termios(void) /* */
{
/* */
return(&save_termios);
}

(cbreak) :
. , 
.
,
. 
, 
, , 
.
, , 
, . 
.
 .
.
MIN 1, TIME 0.
. 18.7. read , 
1 .

18.11.

775

(raw) :
. , 
(ISIG),
(IEXTEN). SIGINT
BREAK, BRKINT.
 .
CR>NL (ICRNL),
(INPCK), (ISTRIP) 
(IXON).
8 (CS8), (PARENB).
(OPOST).
(MIN = 1, TIME = 0).
18.11 
.
18.11. raw cbreak
#include "apue.h"
static void
sig_catch(int signo)
{
printf(" \n");
tty_reset(STDIN_FILENO);
exit(0);
}
int
main(void)
{
int i;
char c;
if (signal(SIGINT, sig_catch) == SIG_ERR) /* */
err_sys(" signal(SIGINT)");
if (signal(SIGQUIT, sig_catch) == SIG_ERR)
err_sys(" signal(SIGQUIT)");
if (signal(SIGTERM, sig_catch) == SIG_ERR)
err_sys(" signal(SIGTERM)");
if (tty_raw(STDIN_FILENO) < 0)
err_sys(" tty_raw");
printf(" raw, DELETE\n");
while ((i = read(STDIN_FILENO, &c, 1)) == 1) {
if ((c &= 255) == 0177) /* 0177 = ASCII DELETE */
break;
printf("%o\n", c);
}
if (tty_reset(STDIN_FILENO) < 0)
err_sys(" tty_reset");

776

18.
if (i <= 0)
err_sys(" ");
if (tty_cbreak(STDIN_FILENO) < 0)
err_sys(" tty_cbreak");
printf("\n cbreak, SIGINT\n");
while ((i = read(STDIN_FILENO, &c, 1)) == 1) {
c &= 255;
printf("%o\n", c);
}
if (tty_reset(STDIN_FILENO) < 0)
err_sys(" tty_reset");
if (i <= 0)
err_sys(" ");
exit(0);

18.11, 
:
$ ./a.out
raw, DELETE
4
33
133
61
70
176
DELETE
cbreak, SIGINT
1
Control;A
10
backspace

(raw) ControlD (04)


F7.
: ESC (033), [ (0133), 1 (061), 8 (070)
~ (0176). : (~OPOST),
.
, (cbreak) 
( 
(ControlD) (backspace)), , 
,  .

18.12.
UNIX

.
winsize:

18.12.

777

struct winsize {
unsigned short ws_row;
/* */
unsigned short ws_col;
/* */
unsigned short ws_xpixel; /* */
/* ( ) */
unsigned short ws_ypixel; /* ( ) */
};

:
TI
OCGWINSZ ioctl ( 3.15).
,
TIOCSWINSZ ioctl. 
, SIGWINCH.
( , . 10.1
.)

, .
.

( vi) .
, 
.

18.12 ,
. , 
, SIGWINCH
. , 
.
18.12.
#include "apue.h"
#include <termios.h>
#ifndef TIOCGWINSZ
#include <sys/ioctl.h>
#endif
static void
pr_winsize(int fd)
{
struct winsize size;
if (ioctl(fd, TIOCGWINSZ, (char *) &size) < 0)
err_sys(" TIOCGWINSZ");
printf("%d , %d \n", size.ws_row, size.ws_col);
}

778

18.

static void
sig_winch(int signo)
{
printf(" SIGWINCH\n");
pr_winsize(STDIN_FILENO);
}
int
main(void)
{
if (isatty(STDIN_FILENO) == 0)
exit(1);
if (signal(SIGWINCH, sig_winch) == SIG_ERR)
err_sys(" signal");
pr_winsize(STDIN_FILENO); /* */
for ( ; ; )
/* */
pause();
}

, 
:
$ ./a.out
35 ,

40 ,

42 ,
? $

80
SIGWINCH
123
SIGWINCH
33


:

,

18.13. termcap, terminfo curses


termcap ( ter
minal capability )
vi. /etc/ter
mcap . termcap 
: 
( , . .)
( 
, ). 
, 
, 
vi .
termcap vi 
curses. 
,
, 
.

18.14.

779

termcap . 
termcap,
, 
. , 
. 
terminfo curses. 
terminfo ,

. terminfo SVR2
System V.
, System V, terminfo, BSD
termcap, . 
Mac OS X terminfo.

terminfo curses [Goodheart 1991],


. [Strang 1986]
curses . [Strang, Mui, and OReilly 1988]
termcap terminfo.
ncurses, 
, curses SVR4, : http://invisible
island.net/ncurses/ncurses.html.

termcap, terminfo ,
( ,
, 
).
( , ) 
. , curses 
, .

,  . .
curses  , 
.

18.14.
,
. 
, 
.
,
.
(
) . 


780

18.

(raw) (cbreak) . 
, .

18.1. , tty_raw 
( ).
reset(1) (
, ), 
.
18.2. ODD EVEN
PARODD c_cflag. tip BSD, , 
0 1. ?
18.3. stty(1) MIN
TIME, .
vi . 
stty , MIN
TIME vi (
). (
, , 
.)

19

19.1.
9 ,
, . 

(. 18.2), 
( , 
, .) . 


. . 9.5 , 
.

, . 
,
.
, 
, , 
pty.
:  ( script(1))
, , 
15.10.

19.2.
,
, . . 19.1
. ,
:
(master) , 
fork. ,

782

19.

fork
exec

stdin, stdout, stderr

read
write

read
write

. 19.1. ,

(slave) ,
, 
exec. 
.
, 
, , ,
.
18, 
.
, ,
( , 
BREAK, ), .
, ,
, . , 
, , 
. 
, , 
, 
.

. 19.1 , FreeBSD,
Mac OS X Linux. 19.3.2 19.3.3 ,
.
Solaris STREAMS (
14.4). . 19.2 

783

19.2.

fork
exec

stdin, stdout,
stderr

STREAMS
ttcompat

STREAMS
ldterm

STREAMS
pckt

STREAMS
ptem

. 19.2. Solaris

STREAMS Solaris. , 
, . pckt ptem 
. (ldterm ttcompat)
.
,
,
14.9, 
. 19.3.1 ,
STREAMS.
,
read write (. 19.1) (. 19.2). ,
PTY, , 
PTY . 19.2,
, . 19.1.
.

784

19.


, 
. telnetd rlogind.
rlogin 15 [Stevens 1990]. 
, 
. 19.3.
telnetd.
rlogind
exec, 
login.
, , 
, 
. 
TCP/IP. ,
 ( 14.5),
select poll, .

script
UNIX script(1),
. ,

. . 19.4
script. , 
, script , 
.

rlogind

fork
exec, exec

stdout
stderr

stdin

TCP/IP

PTY

PTY

. 19.3.
rlogind

785

19.2.

fork
exec

script

()

fork
exec

stdout
stderr

stdin

PTY

PTY

. 19.4. script

script ,
, 
PTY, (
typescript).
, , 
. , ,
,  .

script , ,
. 
script ,
.

19.5 pty ,
script 
.

expect

.
. passwd(1),
.

786

19.


, . 
expect (. [Libes 1990, 1991, 1994]).
, pty 19.5,
. , expect 

, 
, . 
, 
.
, 
, .


15.10 
,


, . 
, 
,
fflush, . 15.8
. , , 
, . 19.5,
, ,
.

, , 

.

. (
15.9,
, 17.1,
STREAMS.)
, pty_fork ( 19.4). 
exec pty ( 19.5)
C
1

stdin

stdout

. 19.5.

787

19.2.

. 
, pty.

,

,

. ,
, 
, 
 
, 8192 .
, 
fflush. 
pty, 
 , .
. 19.6 ,
. slowout ,
. ,

fork
exec

pty

fork
exec

slowout
stdout
stderr

stdin

PTY

PTY

. 19.6. ,

788

19.

pty, , , 
.

19.3.

. , Single UNIX
Specification XSI. 
,
STREAMS System V Release 4.
posix_openpt 
.
#include <stdlib.h>
#include <fcntl.h>
int posix_openpt(int oflag);

PTY , 1

oflag open(2) 
, .
. 
posix_openpt O_RDWR, 
, O_NOCTTY,
. 
.
, 
, 
. grantpt.

,
; 
, 
. ,
(0620).
#include <stdlib.h>
int grantpt(int filedes);
int unlockpt(int filedes);
0 , 1

, grantpt
setuser
ID (, /usr/lib/pt_chmod Solaris). , 

789

19.3.

grantpt , 
SIGCHLD.
unlockpt , 
,
. ,  

, .
, 
, .
ptsname 
. 

, . , 
,
ptsname.
#include <stdlib.h>
char *ptsname(int filedes);

PTY , NULL

. 19.1 , Single UNIX


Specification , , 
, .
FreeBSD unlockpt , O_NOCTTY
,
posix_openpt.
, O_NOCTTY .
19.1. XSI

grantpt


PTY

posix_openpt
PTY

XSI

FreeBSD Linux
5.2.1
2.4.22

Mac OS X Sola
10.3
ris 9

ptsname


PTY

unlockpt


PTY

, Single UNIX Specification 


,

790

19.

, . 19.1. 
,
: ptym_open 
PTY, ptys_open .
#include "apue.h"
int ptym_open(char *pts_name, int pts_namesz);

PTY , 1
int ptys_open(char *pts_name);

PTY , 1

; 
pty_fork ( 19.4), 
.
ptym_open PTY 
. , 
;
( pts_name)
PTY. ptys_open, 
.
pts_namesz, ptym_open ,
.
,
, , 
pty_fork. ptym_open ,
.
fork ptys_open
,
setsid. 
.

19.3.1. STREAMS

STREAMS Solaris C [Sun Microsystems
2002]. PTY
STREAMS. 
, 
. ( 
STREAMS, [Rago 1993].)
, PTY, /dev/ptmx.
,

19.3.

791

PTY . ( 
, BSD 
PTY.)
19.1. ,
STREAMS
#include
#include
#include
#include

"apue.h"
<errno.h>
<fcntl.h>
<stropts.h>

int
ptym_open(char *pts_name, int pts_namesz)
{
char *ptr;
int fdm;
/*
* ,
* .
* , ,
* strlen("/dev/ptmx") > pts_namesz.
*/
strncpy(pts_name, "/dev/ptmx", pts_namesz);
pts_name[pts_namesz  1] = \0;
if ((fdm = open(pts_name, O_RDWR)) < 0)
return(1);
if (grantpt(fdm) < 0) { /* */
close(fdm);
return(2);
}
if (unlockpt(fdm) < 0) { /* */
close(fdm);
return(3);
}
if ((ptr = ptsname(fdm)) == NULL) { /* */
close(fdm);
return(4);
}
/*
* .
* , ,
* strlen(ptr) > pts_namesz.
*/
strncpy(pts_name, ptr, pts_namesz);
pts_name[pts_namesz  1] = \0;
return(fdm);
/* */
}
int
ptys_open(char *pts_name)

792

19.

{
int fds, setup;
/*
* .
*/
if ((fds = open(pts_name, O_RDWR)) < 0)
return(5);
/*
* ,
* .
*/
if ((setup = ioctl(fds, I_FIND, "ldterm")) < 0) {
close(fds);
return(6);
}
if (setup == 0) {
if (ioctl(fds, I_PUSH, "ptem") < 0) {
close(fds);
return(7);
}
if (ioctl(fds, I_PUSH, "ldterm") < 0) {
close(fds);
return(8);
}
if (ioctl(fds, I_PUSH, "ttcompat") < 0) {
close(fds);
return(9);
}
}
return(fds);
}

/dev/ptmx, 
PTY. 
.
grantpt, 
. Solaris 
,
tty,
,
. tty, 
wall(1) write(1) setgroupID,
tty. grantpt /usr/lib/pt_chmod, 
setuserID,
root, 
.
, 
unlockpt.

19.3.

793

. ,
ptsname. /dev/
pts/NNN.
ptys_open, 
. Solaris System V :
,
, open
PTY . 
, open O_NOCTTY.
STREAMS 
. 
(ptem)
(ldterm) . ttcompat 
ioctl
V7, 4BSD Xenix. ,

( 14.9),
.
. STRE
AMS , autopush
( ).
,
(
[Rago 1993]). I_FIND ioctl 
ldterm . , ,

.
ptym_open ptys_open
: ,
.

19.3.2. BSD
BSD Linux
XSI, , 
.
posix_openpt
PTY. ,
/dev/ptyp0, 
, . open 
: EIO , , ENOENT
, . 
, .
PTY /dev/ptyMN
/dev/ttyMN. Linux, 

794

19.

/dev/pty/mXX,
/dev/pty/sXX.
19.2. BSD Linux
#include
#include
#include
#include

"apue.h"
<errno.h>
<fcntl.h>
<grp.h>

#ifndef _HAS_OPENPT
int
posix_openpt(int oflag)
{
int fdm;
char *ptr1, *ptr2;
char ptm_name[16];
strcpy(ptm_name, "/dev/ptyXY");
/* : 0123456789 ( ) */
for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
ptm_name[8] = *ptr1;
for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
ptm_name[9] = *ptr2;
/*
* PTY.
*/
if ((fdm = open(ptm_name, oflag)) < 0) {
if (errno == ENOENT) /* EIO */
return(1);
/* pty */
else
continue;
/* pty */
}
return(fdm);
/* , fd pty */
}
}
errno = EAGAIN;
return(1);

/* pty */

}
#endif
#ifndef _HAS_PTSNAME
char *
ptsname(int fdm)
{
static char pts_name[16];
char *ptm_name;
ptm_name = ttyname(fdm);
if (ptm_name == NULL)
return(NULL);
strncpy(pts_name, ptm_name, sizeof(pts_name));
pts_name[sizeof(pts_name)  1] = \0;

19.3.
if (strncmp(pts_name, "/dev/pty/", 9) == 0)
pts_name[9] = s; /* /dev/pty/mXX /dev/pty/sXX */
else
pts_name[5] = t; /* "pty" "tty" */
return(pts_name);
}
#endif
#ifndef _HAS_GRANTPT
int
grantpt(int fdm)
{
struct group *grptr;
int gid;
char *pts_name;
pts_name = ptsname(fdm);
if ((grptr = getgrnam("tty")) != NULL)
gid = grptr>gr_gid;
else
gid = 1;
/* tty groups */
/*
* .
*/
if (chown(pts_name, getuid(), gid) < 0)
return(1);
return(chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP));
}
#endif
#ifndef _HAS_UNLOCKPT
int
unlockpt(int fdm)
{
return(0); /* */
}
#endif
int
ptym_open(char *pts_name, int pts_namesz)
{
char *ptr;
int fdm;
/*
* ,
* .
* , ,
* , pts_namesz.
*/
strncpy(pts_name, "/dev/ptyXX", pts_namesz);
pts_name[pts_namesz  1] = \0;
if ((fdm = posix_openpt(O_RDWR)) < 0)

795

796

19.
return(1);
if (grantpt(fdm) < 0) { /* */
close(fdm);
return(2);
}
if (unlockpt(fdm) < 0) { /* */
close(fdm);
return(3);
}
if ((ptr = ptsname(fdm)) == NULL) { /* */
close(fdm);
return(4);
}
/*
* .
* , ,
* strlen(ptr) > pts_namesz.
*/
strncpy(pts_name, ptr, pts_namesz);
pts_name[pts_namesz  1] = \0;
return(fdm);
/* */

}
int
ptys_open(char *pts_name)
{
int fds;
if ((fds = open(pts_name, O_RDWR)) < 0)
return(5);
return(fds);
}

grantpt chown chmod, ,


, 
. 
,
setuserID, 
root, Solaris.
ptys_open 19.2 
. . 
open PTY BSD 
. 19.4 
, BSD.
posix_openpt , 
16 16 , /dev/ptyp0 /dev/ptyTf.
: () 
, , () ,
/dev. , ,
() ().

19.3.

797

19.3.3. Linux
Linux ,
BSD, 19.2 Linux.
Linux, , 
/dev/ptmx (
STREAMS).

. ,
Linux, 19.3.
19.3. Linux
#include "apue.h"
#include <fcntl.h>
#ifndef _HAS_OPENPT
int
posix_openpt(int oflag)
{
int fdm;
fdm = open("/dev/ptmx", oflag);
return(fdm);
}
#endif
#ifndef _HAS_PTSNAME
char *
ptsname(int fdm)
{
int sminor;
static char pts_name[16];
if (ioctl(fdm, TIOCGPTN, &sminor) < 0)
return(NULL);
snprintf(pts_name, sizeof(pts_name), "/dev/pts/%d", sminor);
return(pts_name);
}
#endif
#ifndef _HAS_GRANTPT
int
grantpt(int fdm)
{
char *pts_name;
pts_name = ptsname(fdm);
return(chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP));
}
#endif
#ifndef _HAS_UNLOCKPT
int
unlockpt(int fdm)

798

19.

{
int lock = 0;
return(ioctl(fdm, TIOCSPTLCK, &lock));
}
#endif
int
ptym_open(char *pts_name, int pts_namesz)
{
char *ptr;
int fdm;
/*
* ,
* .
* , ,
* , pts_namesz.
*/
strncpy(pts_name, "/dev/ptmx", pts_namesz);
pts_name[pts_namesz  1] = \0;
fdm = posix_openpt(O_RDWR);
if (fdm < 0)
return(1);
if (grantpt(fdm) < 0) { /* */
close(fdm);
return(2);
}
if (unlockpt(fdm) < 0) { /* PTY */
close(fdm);
return(3);
}
if ((ptr = ptsname(fdm)) == NULL) { /* PTY */
close(fdm);
return(4);
}
/*
* .
* , ,
* strlen(ptr) > pts_namesz.
*/
strncpy(pts_name, ptr, pts_namesz);
pts_name[pts_namesz  1] = \0;
return(fdm); /* PTY */
}
int
ptys_open(char *pts_name)
{
int fds;
if ((fds = open(pts_name, O_RDWR)) < 0)
return(5);

19.4. pty_fork

799

return(fds);
}

Linux tty, ,
grantpt, 
.

19.4. pty_fork
,
, ptym_open ptys_open, pty_fork.
, 

.
#include "apue.h"
#include <termios.h>
#include <sys/ioctl.h> /* find struct winsize on BSD systems */
pid_t pty_fork(int *ptrfdm, char *slave_name, int slave_namesz,
const struct termios *slave_termios,
const struct winsize *slave_winsize);
0 ,
, 1

PTY ptrfdm.
slave_name ,
. , 
,
.
slave_termios ,
, , 
.
NULL, termios 
, .

, slave_winsize .
NULL, , , win
size .
19.4 . 
, , 
ptym_open ptys_open.
PTY fork. 
, ptys_open , 
setsid.
setsid , 

800

19.

, 9.5: () 
, , () 
() 
.
Linux Solaris ptys_open
. FreeBSD Mac OS X
TIOCSCTTY
ioctl. (Linux TIOCSCTTY io
ctl.) termios
winsize. 
PTY , 
. , ,
exec,
PTY ( ).
fork 
PTY . 
pty_fork pty.
19.4. pty_fork
#include "apue.h"
#include <termios.h>
#ifndef TIOCGWINSZ
#include <sys/ioctl.h>
#endif
pid_t
pty_fork(int *ptrfdm, char *slave_name, int slave_namesz,
const struct termios *slave_termios,
const struct winsize *slave_winsize)
{
int fdm, fds;
pid_t pid;
char pts_name[20];
if ((fdm = ptym_open(pts_name, sizeof(pts_name))) < 0)
err_sys(" pty: %s, %d",
pts_name, fdm);
if (slave_name != NULL) {
/*
* .
* , ,
* strlen(ptr) > pts_namesz.
*/
strncpy(slave_name, pts_name, slave_namesz);
slave_name[slave_namesz  1] = \0;
}
if ((pid = fork()) < 0) {
return(1);
} else if (pid == 0) { /* */
if (setsid() < 0)

19.5. pty

801

err_sys(" setsid");
/*
* System V .
*/
if ((fds = ptys_open(pts_name)) < 0)
err_sys(" pty");
close(fdm); /* pty */
#if defined(TIOCSCTTY)
/*
* TIOCSCTTY BSD.
*/
if (ioctl(fds, TIOCSCTTY, (char *)0) < 0)
err_sys(" TIOCSCTTY");
#endif
/*
* termios winsize pty.
*/
if (slave_termios != NULL) {
if (tcsetattr(fds, TCSANOW, slave_termios) < 0)
err_sys(" tcsetattr pty");
}
if (slave_winsize != NULL) {
if (ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
err_sys(" TIOCSWINSZ pty");
}
/*
* stdin/stdout/stderr .
*/
if (dup2(fds, STDIN_FILENO) != STDIN_FILENO)
err_sys(" dup2 stdin");
if (dup2(fds, STDOUT_FILENO) != STDOUT_FILENO)
err_sys(" dup2 stdout");
if (dup2(fds, STDERR_FILENO) != STDERR_FILENO)
err_sys(" dup2 stderr");
if (fds != STDIN_FILENO && fds != STDOUT_FILENO &&
fds != STDERR_FILENO)
close(fds);
return(0); /* 0 , fork() */
} else {
/* */
*ptrfdm = fdm; /* fd pty */
return(pid); /* pid */
}
}

19.5. pty
pty , 

pty prog arg1 arg2

802

19.

prog arg1 arg2

pty, 
, .
pty.
main ( 19.5). pty_fork, 
.
19.5. main pty
#include "apue.h"
#include <termios.h>
#ifndef TIOCGWINSZ
#include <sys/ioctl.h>
#endif

/* struct winsize */

#ifdef LINUX
#define OPTSTR "+d:einv"
#else
#define OPTSTR "d:einv"
#endif
static void set_noecho(int); /* */
void do_driver(char *);
/* driver.c */
void loop(int, int);
/* loop.c */
int
main(int argc, char *argv[])
{
int fdm, c, ignoreeof, interactive, noecho, verbose;
pid_t pid;
char *driver;
char slave_name[20];
struct termios orig_termios;
struct winsize size;
interactive = isatty(STDIN_FILENO);
ignoreeof = 0;
noecho = 0;
verbose = 0;
driver = NULL;
opterr = 0; /* , getopt() stderr */
while ((c = getopt(argc, argv, OPTSTR)) != EOF) {
switch (c) {
case d: /* stdin/stdout */
driver = optarg;
break;
case e: /*  pty */
noecho = 1;
break;
case i: /* EOF */

19.5. pty

803

ignoreeof = 1;
break;
case n: /* */
interactive = 0;
break;
case v: /* */
verbose = 1;
break;
case ?:
err_quit(" : %c", optopt);
}
}
if (optind >= argc)
err_quit(": "
"pty [ d driver einv ] program [ arg ... ]");
if (interactive) { /* termios winsize */
if (tcgetattr(STDIN_FILENO, &orig_termios) < 0)
err_sys(" tcgetattr stdin");
if (ioctl(STDIN_FILENO, TIOCGWINSZ, (char *) &size) < 0)
err_sys(" TIOCGWINSZ");
pid = pty_fork(&fdm, slave_name, sizeof(slave_name),
&orig_termios, &size);
} else {
pid = pty_fork(&fdm, slave_name, sizeof(slave_name),
NULL, NULL);
}
if (pid < 0) {
err_sys(" fork");
} else if (pid == 0) { /* */
if (noecho)
set_noecho(STDIN_FILENO); /* stdin pty */
if (execvp(argv[optind], &argv[optind]) < 0)
err_sys(" : %s", argv[optind]);
}
if (verbose) {
fprintf(stderr, " = %s\n", slave_name);
if (driver != NULL)
fprintf(stderr, " = %s\n", driver);
}
if (interactive && driver == NULL) {
if (tty_raw(STDIN_FILENO) < 0) /* tty */
err_sys(" tty_raw");
if (atexit(tty_atexit) < 0) /* tty */
err_sys(" atexit");
}
if (driver)
do_driver(driver);
/* stdin/stdout */
loop(fdm, ignoreeof); /* stdin > ptym, ptym > stdout */
exit(0);
}

804

19.

static void
set_noecho(int fd) /*  ( pty) */
{
struct termios stermios;
if (tcgetattr(fd, &stermios) < 0)
err_sys(" tcgetattr");
stermios.c_lflag &= (ECHO | ECHOE | ECHOK | ECHONL);
/*
* , NL CR/NL .
*/
stermios.c_oflag &= (ONLCR);
if (tcsetattr(fd, TCSANOW, &stermios) < 0)
err_sys(" tcsetattr");
}

,
pty. getopt 
. 
21.
pty_fork
termios winsize pty_fork 
. , PTY 
, .
pty_fork  
PTY ( ) ex
ecvp , .
.

(raw) ( )
, 
, exit. do_driver
.
loop ( 19.6),
, 
PTY. 
,

 select poll .
19.6. loop
#include "apue.h"
#define BUFFSIZE 512
static void sig_term(int);
static volatile sig_atomic_t sigcaught; /* */
void

19.5. pty
loop(int ptym, int ignoreeof)
{
pid_t child;
int nread;
char buf[BUFFSIZE];
if ((child = fork()) < 0) {
err_sys(" fork");
} else if (child == 0) { /* stdin ptym */
for ( ; ; ) {
if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) < 0)
err_sys(" stdin");
else if (nread == 0)
break; /* EOF stdin */
if (writen(ptym, buf, nread) != nread)
err_sys(" pty");
}
/*
* , EOF stdin,
* , ignoreeof == 0.
*/
if (ignoreeof == 0)
kill(getppid(), SIGTERM); /* */
exit(0);
/* ; */
/* */
}
/*
* ptym stdout.
*/
if (signal_intr(SIGTERM, sig_term) == SIG_ERR)
err_sys(" signal_intr SIGTERM");
for ( ; ; ) {
if ((nread = read(ptym, buf, BUFFSIZE)) <= 0)
break; /* , EOF */
if (writen(STDOUT_FILENO, buf, nread) != nread)
err_sys(" stdout");
}
/*
* : sig_term()
* () SIGTERM ,
* EOF pty ( ,
* ) .
*/
if (sigcaught == 0)
/* , */
kill(child, SIGTERM); /* */
/*
* .
*/
}

805

806

19.

/*
* SIGTERM, EOF pty
* read() . , ptym.
*/
static void
sig_term(int signo)
{
sigcaught = 1; /* */
}

: , 
, SIGTERM.

19.6. pty
pty
.
Korn shell, 

pty ksh

,
.
, 18.7 ttyname,
:
$ who
sar :0 Oct 5 18:07
sar pts/0 Oct 5 18:07
sar pts/1 Oct 5 18:07
sar pts/2 Oct 5 18:07
sar pts/3 Oct 5 18:07
sar pts/4 Oct 5 18:07 pts/4
$ pty
fd 0:
fd 1:
fd 2:

ttyname
/dev/pts/5
/dev/pts/5
/dev/pts/5

PTY,

18.7 PTY
pts/5 PTY

utmp
6.8 utmp,
. 
.
telnetd rlogin utmp 
. 

, script, .
utmp, 

19.6. pty

807

. utmp,
who(1), , ,
.
utmp (,
, ),
, , 
.


pty , 
, . 
,
pty ksh

Korn shell pty.



, . 
pty , 
, 
,
pty cat

, 
. ^Z 
. BSD cat pty
.
, 
, . . 19.7
, pty cat.
(ControlZ),
( . 19.7
cat), pty (
pty) . 
cat, 
( 9.10). cat pty, 
.
 .
POSIX.1 , SIGTSTP 
. , 4.3BSD, 
SIGKILL, . 4.4BSD
POSIX.1.
SIGKILL 4.4BSD
SIGTSTP, 
. 
.

808

19.
C

pty

pty

cat

PTY

PTY

. 19.7. , pty cat

pty , 
, , 
, , 
.
ControlZ , ,
.
,
pty,
pty , 
( 
pty),
.

,


. 19.6. , 
,
pty slowout > file.out &

pty , 
( 
). , 
, 

809

19.6. pty

. ,
pty , :
pty slowout < /dev/null > file.out &

pty , 
, .
i, ,
, 
:
pty i slowout < /dev/null > file.out &

, pty 
19.6 ,
.
PTY
( file.out).

script
pty script(1)
:
#!/bin/sh
pty "${SHELL:/bin/sh}" | tee typescript


ps. ,
, . 19.8.

typescript

sh

pty

tee

pty

ksh

ps

TTY

PTY

. 19.8. , script

PTY

810

19.

, SHELL 
Korn shell ( , /bin/ksh). 
, script , 
( , ).
, ,
PTY, ,
typescript.


15.9
, 
, , .
pty,
if (execl("./add2", "add2", (char *)0) < 0)

if (execl("./pty", "pty", "e", "add2", (char *)0) < 0)

,
.
. 19.9
 . 
. 19.5 
. 
15.9, execl.
fork, exec

fork
exec

pty fork

pty

add2
()

2
1

PTY

PTY

. 19.9. ;

19.6. pty

811

, pty e
( ). pty 
, . 19.5
interactive , isatty
. , 
, ,
. e 
 , 
PTY. , 
.
, e ONLCR termios, 
, 
, CRNL.

, 14.8,
readn writen. , read 
, , 
, . 15.9
pty 
read , read 
. ,
15.9 15.5,
 
, 
. fgets read 
, . while 
15.9 , , 
, , .

,
pty , pty
. 
, pty , 
, PTY ,
PTY, , .
, telnet pty, 
:
pty telnet 192.168.1.3


telnet 192.168.1.3, 
telnet , 

812

19.

. , telnet.cmd, 
:
sar
passwd
uptime
exit

, , 
, ,
.
pty i < telnet.cmd telnet 192.168.1.3

. , 
telnet.cmd , 
. 
login tcsetattr, 
, . , 
.
telnet , 
, ,
pty . 

, pty, expect.
pty , 15.9, 
, ,
, , , 
. 
,
. , 15.9 
, . ,
 ,
.

. pty 
,
pty. 
, 
, pty_fork.
expect.

pty d. 
() 
pty . 
. . 19.9, 
pty. , 

19.6. pty

813

pty 
.
19.7 do_driver, 
main ( 19.5), d.
19.7. do_driver pty
#include "apue.h"
void
do_driver(char *driver)
{
pid_t child;
int pipe[2];
/*
* .
*/
if (s_pipe(pipe) < 0)
err_sys(" ");
if ((child = fork()) < 0) {
err_sys(" fork");
} else if (child == 0) { /* */
close(pipe[1]);
/* stdin */
if (dup2(pipe[0], STDIN_FILENO) != STDIN_FILENO)
err_sys(" dup2 stdin");
/* stdout */
if (dup2(pipe[0], STDOUT_FILENO) != STDOUT_FILENO)
err_sys(" dup2 stdout");
if (pipe[0] != STDIN_FILENO && pipe[0] != STDOUT_FILENO)
close(pipe[0]);
/* stderr */
execlp(driver, driver, (char *)0);
err_sys(" execlp : %s", driver);
}
close(pipe[0]); /* */
if (dup2(pipe[1], STDIN_FILENO) != STDIN_FILENO)
err_sys(" dup2 stdin");
if (dup2(pipe[1], STDOUT_FILENO) != STDOUT_FILENO)
err_sys(" dup2 stdout");
if (pipe[1] != STDIN_FILENO && pipe[1] != STDOUT_FILENO)
close(pipe[1]);
/*
* , stdin stdout
* .
*/
}

814

19.

, pty, 
.
, 
pty,  
, /dev/tty. 
, expect, pty 
, 50 .

19.7.
, 
.
[Sun Microsystems 2002] BSD 
pty(4).


PTY 
PTY. Solaris
pckt STREAMS PTY.
. 19.2. FreeBSD, Linux Mac OS X 
TIOCPKT ioctl.
Solaris 
. Solaris, ,
PTY, getmsg, 
, pckt
STREAMS, . 
PTY ,
.
,
, , 
PTY, , 
, 
PTY: , , 
(, ControlS), , 
XON/XOFF ,
, XON/XOFF 
, . , , 
rlogin rlogind.


PTY PTY ,
ioctl TIOCREMOTE. FreeBSD 5.2.1, Mac OS X
10.3 Solaris 9
, Solaris ioctl 

19.8.

815

, FreeBSD Mac OS X . ( Li


nux 2.4.22 .)
PTY 
PTY , 
, PTY,
termios
PTY. ,
, .


, PTY, TI
OCWINSZ ioctl PTY.
,
PTY SIGWINCH.


, PTY, 
PTY. Solaris 9
TIOCSIGNAL ioctl,
. FreeBSD 5.2.1 Mac OS X 10.3
TIOCSIG ioctl, 
, . ( Li
nux 2.4.22 .)

19.8.

. 

, .
pty_fork,
. 
pty,
.

UNIX .
script

.

19.1. BSD
telnet rlogin 

816

19.

PTY , 
19.3.2. ?
19.2. grantpt 19.2 ,
PTY BSD
setuserID
( Solaris).
19.3. pty , 
termios winsize PTY
.
19.4. loop ( 19.6)
, select poll.
19.5. pty_fork
, 
. ,
, 
?
19.6. . 19.7 , 
, . 
.
19.7. . 19.7, 
? , 
, .
19.8. script(1)
, ,
. 
, .
19.9. , data 
, ttyname
?
$ cat data
hello,
world
$ pty i < data ttyname
hello,
world
fd 0: /dev/ttyp5

;i , EOF

?

ttyname

fd 1: /dev/ttyp5
fd 2: /dev/ttyp5

19.10. , pty_fork, 
,
. , 
, SIGTERM SIGWINCH. 

19.8.

817


, SIGWINCH 
.

PTY ioctl, 
19.7, PTY 
, .
PTY 
PTY.
, .
, .

20

20.1.
80 UNIX 
. (. [Stonebraker
1981] [Weinberger 1982].) UNIX, Version 7,
, 
 
( ) , 
. 
. 80
UNIX , 

. 
.
C,

. 
.
, , 
.
UNIX,
, 
( , 14.3).

20.2.
, 
UNIX, dbm(3). , 
(Ken Thompson),
. Version 7,

819

20.2.

BSD, SVR4
BSD [AT&T 1990c]. BSD 
dbm ndbm. ndbm
BSD, SVR4. ndbm
XSI Single UNIX Specification.
, 
dbm ,
gdbm (GNU dbm), [Seltzer and Yigit
1991]. , 
, 
. 
(,
).
4.4BSD db(3),
: () , () ()
(Btree). 
( BUGS
db(3)).
Sleepycat Software (http://www.sleepycat.com)
db, ,
.


.
, 
14.3, ,
, , 
.

(B+ tree) [Comer 1979] 
, [Litwin1980]
[Faginet al. 1979].
. 20.1 ,
, . 
, Linux dbm ndbm 
gdbm.
20.1. ,

POSIX.1

FreeBSD 5.2.1

dbm
ndbm
db

Linux 2.4.22

Mac OS X 10.3

XSI

Solaris 9

gdbm

gdbm

820

20.

20.3.
, , 
ndbm,
. 
C, .
(
), . 
, .
#include "apue_db.h"
DBHANDLE db_open(const char *pathname, int oflag, ... /* int mode */);

, NULL
void db_close(DBHANDLE db);

db_open , : 
pathname.idx pathname.dat. oflag
, open ( 3.3)
( ,
, , , . .). mode 

open ( ).

db_close. 
, .

, . , 
, 
, , , 
, . . ,
. ( ,
, , .)
#include "apue_db.h"
int db_store(DBHANDLE db, const char *key, const char *data, int flag);
0 ,
(. )

key data , .
, , ,
, 
, , .

821

20.3.

flag DB_INSERT (
), DB_REPLACE ( ) DB_STORE (
,
). 
apue_db.h. DB_INSERT DB_STORE
, . DB_REPLACE
DB_STORE , 
. DB_REPLACE,
, 1 ENOENT 
errno, .
DB_INSERT , 
. 1, 
(1).
, .
#include "apue_db.h"
char *db_fetch(DBHANDLE db, const char *key);
,
NULL,

, , 
key. 
, .
#include "apue_db.h"
int db_delete(DBHANDLE db, const char *key);
0 , 1,

, 
, .
db_rewind, ,
db_nextrec, .
#include "apue_db.h"
void db_rewind(DBHANDLE db);
char *db_nextrec(DBHANDLE db, char *key);
,
NULL

key , db_nextrec
.
, db_nextrec, 
. , , ,

822

20.

. ,
A, B C, , 
db_nextrec. B, A,
C  ( ) . 
.
.
, .

20.4.
, , 
: .
() 
. 
, 
;
.  
, 
. db_open ,
: .idx, .dat.
,
;
.
(, 1, 2 4
), . 

. ,
,
, ,
. ( 
,
.) , ,
. 
, .
db_store 
. 

, . 
, 
,
( ).
, 
, 
. 
. (,

823

20.4.


: , 
. 
, ,
.)
. 20.1 .
: 
, . . 20.1 ,
, 
ASCII.
, db_fetch
,
. ( 0;
, .) 


$

\n

$
$

\n

\n

. 20.1.

824

20.

, 
, . 
0, ,
.
. 
20.1
. ASCII,
,
UNIX:
$ ls l db4.*
rwrr 1 sar
rwrr 1 sar
$ cat db4.idx
0 53 35
0
0 10Alpha:0:6
0 10beta:6:14
17 11gamma:20:8
$ cat db4.dat
data1
Data for beta
record3

28 Oct 19 21:33 db4.dat


72 Oct 19 21:33 db4.idx

, ;
ASCII,
. ,
, ,
9999 . 20.9,
,
(
1 ),
100.

0

53

35

(0 
) : 53, 35 0. 

0

10Alpha:0:6

. (0) 
.
. (10)
4 .
:
( ), 
( ).
, ;
 ( 

20.4.

825

).  ,
. 
.
. , ,
.
,

, cat more. ,
.
(0) (6) .
, 
6 . ( , 
,

.
db_fetch .)
20.1.
#include "apue.h"
#include "apue_db.h"
#include <fcntl.h>
int
main(void)
{
DBHANDLE db;
if ((db = db_open("db4", O_RDWR | O_CREAT | O_TRUNC,
FILE_MODE)) == NULL)
err_sys(" db_open");
if (db_store(db, "Alpha", "data1", DB_INSERT) != 0)
err_quit(" db_store ");
if (db_store(db, "beta", "Data for beta", DB_INSERT) != 0)
err_quit(" db_store ");
if (db_store(db, "gamma", "record3", DB_INSERT) != 0)
err_quit(" db_store ");
db_close(db);
exit(0);
}

, ,
53 (gamma). 
17 (Alpha)
.
35 (beta) . .
, 
, 
db_store 20.3. db_open
O_TRUNC,

826

20.

, .
db_store 
. , db_store
, .

.
, .
, ,

. 
( [Lit
win 1980] [Fagin et al. 1979]). 
()
( db_nextrec, ).

20.5. ?
, 
, :
1. .
,
.
IPC.
2. .

( ) .

.
, , 
, IPC. . 20.2 
.
,
, ,
UNIX . ( 
, 15.9, 
.) ,

IPC. 
. : 
.

. 
,
.
 . 

827

20.5. ?

IPC

. 20.2.

.
, 
, , ,
?
, 
, ,
.
,
,
, ,
.
. 20.3 
. .
,
, 
, 
.

828

20.

. 20.3.

20.6.

( ), 
. . 
.



, 
.
(coarse;grained locking). , 
, ,
, . , 
, 
.
UNIX, 
, 
(. 14.2). db_fetch db_nextrec

20.7.

829

, db_delete, db_store
db_open . (
db_open ,
.)
,
. 
 , 
.


,
, (fine;;grained
locking). ,
, 
.
,
. , , 
( db_delete db_store), 
. , ,

, db_store
.
, 
. 20.9
. 20.8

.
( .)

 read, write, readv writev.

,
. , fgets
, 5
.

. 
. 
[Date 2004].

20.7.
: 
C.
:

830

20.

gcc I../include Wall c db.c


ar rsv libapue_db.a db.o

, libapue_db.a, 
libapue.a, 
.
,
, :
gcc I../include Wall fPIC c db.c
gcc shared Wl,soname,libapue_db.so.1 o libapue_db.so.1 \
L../lib lapue lc db.o

libapue_db.so.1 
, / .
, 
LD_LIBRARY_PATH ,
.

. Linux, GNU C
compiler.

20.8.

apue_db.h. , 
.
, 
. ,
, , .
. ,
, 
, .
(John Lions) , 
UNIX Version 6 [Lions 1977, 1996].
.

: .
, pr(1),
.
1
2

#ifndef _APUE_DB_H
#define _APUE_DB_H

typedef void * DBHANDLE;

4
5
6

DBHANDLE db_open(const char *, int, ...);


void db_close(DBHANDLE);
char *db_fetch(DBHANDLE, const char *);

831

20.8.
7
8
9
10

int db_store(DBHANDLE, const char *, const char *, int);


int db_delete(DBHANDLE, const char *);
void db_rewind(DBHANDLE);
char *db_nextrec(DBHANDLE, char *);

11
12
13
14
15
16

/*
* db_store().
*/
#define DB_INSERT 1
/* */
#define DB_REPLACE 2
/* */
#define DB_STORE 3
/* */

17
18
19
20
21
22
23

/*
* .
*/
#define IDXLEN_MIN
6 /*
/*
#define IDXLEN_MAX 1024 /*
#define DATLEN_MIN
2 /*
#define DATLEN_MAX 1024 /*

24

#endif

, , , */
, , \n */
*/
, */
*/

/* _APUE_DB_H */

[13]

_APUE_DB_H , 
. DBHANDLE 

.
FILE 
.

[410]

. 
, 
, .

[1124] , db_store.

. ,
.
IDX
LEN_MIN. 1 , 1
, 1 , 1 ,
1 . ( 
. 20.1.) 
IDXLEN_MIN ,
.

db.c, C. 
.
, ,
static.
1
2
3

#include "apue.h"
#include "apue_db.h"
#include <fcntl.h> /* open db_open */

832

20.
4
5
6

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

#include <stdarg.h>
#include <errno.h>
#include <sys/uio.h> /* struct iovec */
/*
* , .
*
* .
*/
#define IDXLEN_SZ 4 /* */
/* ( ASCII) */
#define SEP
: /*  */
#define SPACE
/* */
#define NEWLINE \n /* */

24

/*
*
*  .
*/
#define PTR_SZ
6 /*  */
#define PTR_MAX 999999 /* */
/* = 10**PTR_SZ  1 */
#define NHASH_DEF 137 /*  */
#define FREE_OFF
0 /* */
/* */
#define HASH_OFF PTR_SZ /*  */

25
26

typedef unsigned long DBHASH; /* */


typedef unsigned long COUNT; /* */

22
23

[16]

apue.h, 
. , apue.h
,
<stdio.h> <unistd.h>. <stdarg.h> ,

, db_open.

[726]

, ,
IDXLEN_SZ. , 
, 
. 
.
, ,
. ,
 137 . ,

db_open, .
.

27
28
29
30
31

/*
* .
*/
typedef struct {
int idxfd;
/* */

20.8.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

833

int datfd;
/* */
char *idxbuf; /* */
char *datbuf; /* */
char *name; /* , */
off_t idxoff; /* */
/* (idxoff + PTR_SZ + IDXLEN_SZ) */
size_t idxlen; /* */
/* IDXLEN_SZ , */
/* */
off_t datoff; /* */
size_t datlen; /* */
/* */
off_t ptrval; /* */
off_t ptroff; /* , */
off_t chainoff; /* */
off_t hashoff; /*  */
DBHASH nhash; /*  */
COUNT cnt_delok;
/* */
COUNT cnt_delerr; /* */
COUNT cnt_fetchok; /* */
COUNT cnt_fetcherr; /* */
COUNT cnt_nextrec; /* nextrec */
COUNT cnt_stor1; /* store: DB_INSERT, , */
COUNT cnt_stor2; /* store: DB_INSERT, , */
/* */
COUNT cnt_stor3; /* store: DB_REPLACE, , */
COUNT cnt_stor4; /* store: DB_REPLACE, , */
COUNT cnt_storerr; /* */
} DB;

[2748] DB
. DBHANDLE, db_open
, 
,
.

ASCII, 
. ,
, , .
,

( 20.7).
[4959] DB ,
. 
, , 
,
.
60
61
62

/*
* .
*/

834

20.

63
64
65
66
67
68
69
70
71
72
73
74

static
static
static
static
static
static
static
static
static
static
static
static

75
76
77
78
79
80
81
82
83
84
85
86
87

/*
* . open(2).
*/
DBHANDLE
db_open(const char *pathname, int oflag, ...)
{
DB
*db;
int
len, mode;
size_t i;
char asciiptr[PTR_SZ + 1],
hash[(NHASH_DEF + 1) * PTR_SZ + 2];
/* +2 */
struct stat statbuff;

88
89
90
91
92
93

DB
void
int
int
void
DBHASH
char
off_t
off_t
void
void
void

*_db_alloc (int);
_db_dodelete(DB *);
_db_find_and_lock(DB *, const char *, int);
_db_findfree(DB *, int, int);
_db_free(DB *);
_db_hash(DB *, const char *);
*_db_readdat(DB *);
_db_readidx(DB *, off_t);
_db_readptr(DB *, off_t);
_db_writedat(DB *, const char *, off_t, int);
_db_writeidx(DB *, const char *, off_t, int, off_t);
_db_writeptr(DB *, off_t, off_t);

/*
* DB .
*/
len = strlen(pathname);
if ((db = _db_alloc(len)) == NULL)
err_dump("db_open: _ DB");

[6074] : 
db_, 
_db_.
apue_db.h. 
static,
, (
).
[7593] db_open , open(2).
,

. db_open
.
_db_alloc,
DB.
94
95
96

db>nhash = NHASH_DEF; /* */
db>hashoff = HASH_OFF; /*  */
strcpy(db>name, pathname);

20.8.
97

strcat(db>name, ".idx");

98
99

if (oflag & O_CREAT) {


va_list ap;

100
101
102

835

va_start(ap, oflag);
mode = va_arg(ap, int);
va_end(ap);

103
104
105
106
107
108
109
110
111
112
113
114
115
116

/*
* .
*/
db>idxfd = open(db>name, oflag, mode);
strcpy(db>name + len, ".dat");
db>datfd = open(db>name, oflag, mode);
} else {
/*
* .
*/
db>idxfd = open(db>name, oflag);
strcpy(db>name + len, ".dat");
db>datfd = open(db>name, oflag);
}

117
118
119
120

if (db>idxfd < 0 || db>datfd < 0) {


_db_free(db);
return(NULL);
}

[9497]

DB. ,
, 
. ,
.idx.

[98108]

,
, ,

<stdarg.h>.
open. :
,
, .dat.

[109116] O_CREAT, 
. open
.
[117120] , 
_db_free, , DB, 
NULL . ,
, , _db_free
,
.
121
122

if ((oflag & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) {


/*

836

20.

123
124
125
126
127
128

* ,
* .
* .
*/
if (writew_lock(db>idxfd, 0, SEEK_SET, 0) < 0)
err_dump("db_open: writew_lock");

129
130

if (fstat(db>idxfd, &statbuff) < 0)


err_sys("db_open: fstat");

131
132
133
134
135

if (statbuff.st_size == 0) {
/*
* (NHASH_DEF + 1)
* . +1 
*
* .
*/
sprintf(asciiptr, "%*d", PTR_SZ, 0);

136
137

[121130] 
. ,
.
fstat
, fstat .
db_open, , , 
.
.
, 
db_open fstat.
, 
( fstat ,
), 
, , 
. ,
. 
readw_lock, writew_lock un_lock 14.3.
[131137] , , 

. , ,
, ASCII
%*d. (
_db_writeidx _db_writeptr.)
sprintf, PTR_SZ 
, 
0 (
, ).
, , PTR_SZ 
( ). _db_writeidx _db_write
ptr
PTR_MAX,
, , ,
PTR_SZ (6) .

837

20.8.
138
139
140
141
142
143
144
145
146
147
148
149
150
151

hash[0] = 0;
for (i = 0; i < NHASH_DEF + 1; i++)
strcat(hash, asciiptr);
strcat(hash, "\n");
i = strlen(hash);
if (write(db>idxfd, hash, i) != i)
err_dump("db_open: ");

152
153
154
155
156
157
158

/*
* DB .
*/
static DB *
_db_alloc(int namelen)
{
DB *db;

}
if (un_lock(db>idxfd, 0, SEEK_SET, 0) < 0)
err_dump("db_open: un_lock");
}
db_rewind(db);
return(db);

159
160
161
162
163
164

/*
* calloc .
*/
if ((db = calloc(1, sizeof(DB))) == NULL)
err_dump("_db_alloc: DB");
db>idxfd = db>datfd = 1; /* */

165
166
167
168
169
170

/*
* .
* +5 ".idx" ".dat" .
*/
if ((db>name = malloc(namelen + 5)) == NULL)
err_dump("_db_alloc: ");

[138151] . 
. 
, 

DB , 
.
[152164] DB,
db_open _db_alloc.
DB calloc, 
, . 
0,
1, , 
.
[165170] .

, db_open.

838

20.

171
172
173
174
175
176
177
178
179
180

/*
* .
* +2 .
*/
if ((db>idxbuf = malloc(IDXLEN_MAX + 2)) == NULL)
err_dump("_db_alloc: ");
if ((db>datbuf = malloc(DATLEN_MAX + 2)) == NULL)
err_dump("_db_alloc: ");
return(db);
}

181
182
183
184
185
186
187
188

/*
* .
*/
void
db_close(DBHANDLE h)
{
_db_free((DB *)h); /* , */
}

189
190
191
192
193
194
195
196
197
198
199

/*
* , DB .
* , .
*/
static void
_db_free(DB *db)
{
if (db>idxfd >= 0)
close(db>idxfd);
if (db>datfd >= 0)
close(db>datfd);

[171180] , 
. 
apue_db.h. 

.
realloc, 
.
DB, .
[181188] db_close , 
DB* _db_free,
.
[189199] _db_free db_open,
, db_close, 
. 
, . 
. ( , _db_alloc 
1.
 ,
1 .)

20.8.
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
215

/*
* . .
*/
char *
db_fetch(DBHANDLE h, const char *key)
{
DB *db = h;
char *ptr;

839

if (db>idxbuf != NULL)
free(db>idxbuf);
if (db>datbuf != NULL)
free(db>datbuf);
if (db>name != NULL)
free(db>name);
free(db);

216
217
218
219
220
221
222

if (_db_find_and_lock(db, key, 0) < 0) {


ptr = NULL;
/* , */
db>cnt_fetcherr++;
} else {
ptr = _db_readdat(db); /* */
db>cnt_fetchok++;
}

223
224
225
226
227
228
229

/*
* , _db_find_and_lock.
*/
if (un_lock(db>idxfd, db>chainoff, SEEK_SET, 1) < 0)
err_dump("db_fetch: un_lock");
return(ptr);
}

[200207] , , 
.
free,
, 
, , , 
( 
, free).
, DB.
[208218] db_fetch
. _db_find_and_lock
. , NULL
.
_db_find_and_lock
, , .
[219229] , _db_readdat, 
. 

un_lock. 
( NULL, ).

840
230
231
232
233
234
235
236
237

20.
/*
* . db_delete, db_fetch
* db_store. .
*/
static int
_db_find_and_lock(DB *db, const char *key, int writelock)
{
off_t offset, nextoffset;

238
239
240
241
242
243
244
245

/*
*
* .
* .
*  .
*/
db>chainoff = (_db_hash(db, key) * PTR_SZ) + db>hashoff;
db>ptroff = db>chainoff;

246
247
248
249
250
251
252
253
254
255
256

/*
* .
* . : .
*/
if (writelock) {
if (writew_lock(db>idxfd, db>chainoff, SEEK_SET, 1) < 0)
err_dump("_db_find_and_lock: writew_lock");
} else {
if (readw_lock(db>idxfd, db>chainoff, SEEK_SET, 1) < 0)
err_dump("_db_find_and_lock: readw_lock");
}

257
258
259
260
261

/*
*
* ( 0).
*/
offset = _db_readptr(db, db>ptroff);

[230237]

_db_find_and_lock 
. writelock
,
. ,
writelock 0.

[238256]

_db_find_and_lock 
. , 
(chainoff).
, , 
. : 
. 
.

[257261]

,
_db_readptr. 0, , .

262
263

while (offset != 0) {
nextoffset = _db_readidx(db, offset);

20.8.
264
265
266
267
268

if (strcmp(db>idxbuf, key) == 0)
break;
/* */
db>ptroff = offset; /* */
offset = nextoffset; /* */
}

269
270
271
272
273

274
275
276
277
278
279
280
281
282

/*
* .
*/
static DBHASH
_db_hash(DB *db, const char *key)
{
DBHASH hval = 0;
char c;
int i;

283
284
285
286 }

841

/*
* offset == 0 ( ).
*/
return(offset == 0 ? 1 : 0);

for (i = 1; (c = *key++) != 0; i++)


hval += c * i; /* ASCII */
return(hval % db>nhash);

[262268] while 
.
_db_readidx. idxbuf .
_db_readidx 0, .
[269273] offset 0,
, ,
, 1. 
( while
break), 0.
ptroff , dataoff
, datalen .
,
, 
,
, .
[274286] _db_hash .
ASCII (
1) . 
[Knuth 1998], 
.
287
288
289

/*
* :
* , 

842
290
291
292
293
294
295

20.
* .
*/
static off_t
_db_readptr(DB *db, off_t offset)
{
char asciiptr[PTR_SZ + 1];

296
297
298
299
300
301
302

if (lseek(db>idxfd, offset, SEEK_SET) == 1)


err_dump("_db_readptr: ");
if (read(db>idxfd, asciiptr, PTR_SZ) != PTR_SZ)
err_dump("_db_readptr: ");
asciiptr[PTR_SZ] = 0; /* */
return(atol(asciiptr));
}

303
304
305
306
307
308
309
310
311
312
313
314
315
316

/*
* ,
* . db>idxbuf,
*  . ,
* db>datoff db>datlen
* .
*/
static off_t
_db_readidx(DB *db, off_t offset)
{
ssize_t i;
char *ptr1, *ptr2;
char asciiptr[PTR_SZ + 1], asciilen[IDXLEN_SZ + 1];
struct iovec iov[2];

[287302] _db_readptr : ()
, ()
,
() ,
(, 
).
ASCII . _db_readptr 

.
[303316] _db_readidx 
. 

DB: idxoff , ptr
val , idxlen 
, idxbuf , dataoff 
datalen .
317
318
319
320
321

/*
* . db_nextrec
* offset==0, .
* lseek, .
*/

20.8.
322
323
324

if ((db>idxoff = lseek(db>idxfd, offset,


offset == 0 ? SEEK_CUR : SEEK_SET)) == 1)
err_dump("_db_readidx: lseek");

325
326
327
328
329
330
331
332
333
334
335
336
337
338

/*
*
* .
* .
*/
iov[0].iov_base = asciiptr;
iov[0].iov_len = PTR_SZ;
iov[1].iov_base = asciilen;
iov[1].iov_len = IDXLEN_SZ;
if ((i = readv(db>idxfd, &iov[0], 2)) != PTR_SZ + IDXLEN_SZ) {
if (i == 0 && offset == 0)
return(1); /* db_nextrec */
err_dump("_db_readidx: readv ");
}

339
340
341
342
343

/*
* , >= 0.
*/
asciiptr[PTR_SZ] = 0;
/* */
db>ptrval = atol(asciiptr); /* */

344
345
346
347

asciilen[IDXLEN_SZ] = 0;
/* */
if ((db>idxlen = atoi(asciilen)) < IDXLEN_MIN ||
db>idxlen > IDXLEN_MAX)
err_dump("_db_readidx: ");

843

[317324] ,
. DB, 
,
( offset 0),
lseek, . 
0,

.
[325338] readv 
:
.
[339347] 
ptrval (
). 
,
idxlen.
348
349
350
351

/*
* .
* , .
*/

844

20.

352
353
354
355
356

if ((i = read(db>idxfd, db>idxbuf, db>idxlen)) != db>idxlen)


err_dump("_db_readidx: ");
if (db>idxbuf[db>idxlen1] != NEWLINE) /* */
err_dump("_db_readidx: ");
db>idxbuf[db>idxlen1] = 0; /* NL */

357
358
359
360
361
362

/*
*  .
*/
if ((ptr1 = strchr(db>idxbuf, SEP)) == NULL)
err_dump("_db_readidx: ");
*ptr1++ = 0; /* SEP */

363
364
365

if ((ptr2 = strchr(ptr1, SEP)) == NULL)


err_dump("_db_readidx: ");
*ptr2++ = 0; /* SEP */

366
367

if (strchr(ptr2, SEP) != NULL)


err_dump("_db_readidx: ");

368
369
370
371
372
373
374
375
376 }

/*
* .
*/
if ((db>datoff = atol(ptr1)) < 0)
err_dump("_db_readidx: < 0");
if ((db>datlen = atol(ptr2)) <= 0 || db>datlen > DATLEN_MAX)
err_dump("_db_readidx: ");
return(db>ptrval); /* */

[348356]

idxbuf DB.
, 
. ,
core, err_dump.

[357367]

: , 
. strchr 
. 
 ( SEP, 
).

[368376]


DB.
. : 
.
, db_fetch. ,
_db_find_and_lock , 
.

377
378
379
380
381

/*
* .
* , .
*/
static char *

20.8.
382
383
384
385
386
387
388
389
390
391
392

_db_readdat(DB *db)
{
if (lseek(db>datfd, db>datoff, SEEK_SET) == 1)
err_dump("_db_readdat: lseek");
if (read(db>datfd, db>datbuf, db>datlen) != db>datlen)
err_dump("_db_readdat: read");
if (db>datbuf[db>datlen1] != NEWLINE) /* */
err_dump("_db_readdat: ");
db>datbuf[db>datlen1] = 0; /* NL */
return(db>datbuf); /* */
}

393
394
395
396
397
398
399
400

/*
* .
*/
int
db_delete(DBHANDLE h, const char *key)
{
DB *db = h;
int rc = 0; /* , */

401
402 _
403
404
405
406
407
408
409
410
411 }

845

if (_db_find_and_lock(db, key, 1) == 0) {
db_dodelete(db);
db>cnt_delok++;
} else {
rc = 1; /* */
db>cnt_delerr++;
}
if (un_lock(db>idxfd, db>chainoff, SEEK_SET, 1) < 0)
err_dump("db_delete: un_lock");
return(rc);

[377392] _db_readdat databuf DB


, , dataoff datalen 
.
[393411] db_delete 
. _db_find_and_lock 
, , 
_db_dodelete, .
_db_find_and_lock
. 
, 
. _db_find_and_lock 
, ,
.
412
413
414
415
416

/*
* , DB.
* db_delete db_store ,
* _db_find_and_lock.
*/

846
417
418
419
420
421
422

20.
static void
_db_dodelete(DB *db)
{
int i;
char *ptr;
off_t freeptr, saveptr;

423
424
425
426
427
428
429
430
431

/*
* , .
*/
for (ptr = db>datbuf, i = 0; i < db>datlen  1; i++)
*ptr++ = SPACE;
*ptr = 0; /* _db_writedat */
ptr = db>idxbuf;
while (*ptr)
*ptr++ = SPACE;

432
433
434
435
436

/*
* .
*/
if (writew_lock(db>idxfd, FREE_OFF, SEEK_SET, 1) < 0)
err_dump("_db_dodelete: writew_lock");

437
438
439
440

/*
* .
*/
_db_writedat(db, db>datbuf, db>datoff, SEEK_SET);

[412431] _db_dodelete
. ( db_store.)
, : 
,
. 
. db_nextrec, 
.
[432440] ,
writew_lock. 

. 
,
.
_db_
writedat. :
. db_delete 
, ,
.
441
442
443
444
445

/*
* .
* .
* , .
*/

20.8.
446

freeptr = _db_readptr(db, FREE_OFF);

447
448
449
450
451

/*
* , ,
* _db_writeidx.
*/
saveptr = db>ptrval;

452
453
454
455
456
457

/*
* .
* , ,
* , .
*/
_db_writeidx(db, db>idxbuf, db>idxoff, SEEK_SET, freeptr);

458
459
460
461

/*
* .
*/
_db_writeptr(db, FREE_OFF, db>idxoff);

462
463
464
465
466
467
468
469
470
471

/*
* , .
* , _db_find_and_lock db>ptroff
* . ,
* , saveptr.
*/
_db_writeptr(db, db>ptroff, saveptr);
if (un_lock(db>idxfd, FREE_OFF, SEEK_SET, 1) < 0)
err_dump("_db_dodelete: un_lock");

847

[441461] 
,
. (
, 0.)
. 
, 
. , 
, ,
(
).

. 
, 
. 
, .
[462471] ,
, .
.
.
472
473

/*
* . _db_dodelete (

848
474
475
476
477
478
479
480

20.
* , ) db_store.
*/
static void
_db_writedat(DB *db, const char *data, off_t offset, int whence)
{
struct iovec iov[2];
static char newline = NEWLINE;

481
482
483
484
485
486
487
488

/*
* ,
* , lseek write .
* , .
*/
if (whence == SEEK_END) /* , */
if (writew_lock(db>datfd, 0, SEEK_SET, 0) < 0)
err_dump("_db_writedat: writew_lock");

489
490
491

if ((db>datoff = lseek(db>datfd, offset, whence)) == 1)


err_dump("_db_writedat: lseek");
db>datlen = strlen(data) + 1; /* datlen NL */

492
493
494
495
496
497

iov[0].iov_base = (char *) data;


iov[0].iov_len = db>datlen  1;
iov[1].iov_base = &newline;
iov[1].iov_len = 1;
if (writev(db>datfd, &iov[0], 2) != db>datlen)
err_dump("_db_writedat: ");

498
499
500
501

if (whence == SEEK_END)
if (un_lock(db>datfd, 0, SEEK_SET, 0) < 0)
err_dump("_db_writedat: un_lock");
}

[472491] _db_writedat, . 
, _db_writedat 
, . _db_writedat 
, db_delete 
,
. , 
, . 
db_store, ,
_db_writedat 
.
, . 
1 
.
[492501] iovec writev,
. ,
, ,
, ,
. 
, .

20.8.
502
503
504
505
506
507
508
509
510
511
512
513
514

849

/*
* . _db_writedat,
* datoff datlen DB,
* .
*/
static void
_db_writeidx(DB *db, const char *key,
off_t offset, int whence, off_t ptrval)
{
struct iovec iov[2];
char asciiptrlen[PTR_SZ + IDXLEN_SZ +1];
int len;
char *fmt;

515
516
517
518
519
520
521
522
523
524

if ((db>ptrval = ptrval) < 0 || ptrval > PTR_MAX)


err_quit("_db_writeidx: : %d", ptrval);
if (sizeof(off_t) == sizeof(long long))
fmt = "%s%c%lld%c%d\n";
else
fmt = "%s%c%ld%c%d\n";
sprintf(db>idxbuf, fmt, key, SEP, db>datoff, SEP, db>datlen);
if ((len = strlen(db>idxbuf)) < IDXLEN_MIN || len > IDXLEN_MAX)
err_dump("_db_writeidx: ");
sprintf(asciiptrlen, "%*ld%*d", PTR_SZ, ptrval, IDXLEN_SZ, len);

525
526
527
528
529
530
531
532
533

/*
* ,
* , lseek write .
* , .
*/
if (whence == SEEK_END) /* */
if (writew_lock(db>idxfd, ((db>nhash+1)*PTR_SZ)+1,
SEEK_SET, 0) < 0)
err_dump("_db_writeidx: writew_lock");

[502524]

_db_writeidx , 
. 

idxbuf. , 
,
asciiptrlen.
: , sprintf, 
off_t. 32
64 ,
 off_t.

[525533]

_db_writedat,
,
. _db_dodelete, 
.

, .

850

20.

534
535
536
537
538

/*
* .
*/
if ((db>idxoff = lseek(db>idxfd, offset, whence)) == 1)
err_dump("_db_writeidx: lseek");

539
540
541
542
543
544

iov[0].iov_base = asciiptrlen;
iov[0].iov_len = PTR_SZ + IDXLEN_SZ;
iov[1].iov_base = db>idxbuf;
iov[1].iov_len = len;
if (writev(db>idxfd, &iov[0], 2) != PTR_SZ + IDXLEN_SZ + len)
err_dump("_db_writeidx: ");

545
546
547
548
549

if (whence == SEEK_END)
if (un_lock(db>idxfd, ((db>nhash+1)*PTR_SZ)+1,
SEEK_SET, 0) < 0)
err_dump("_db_writeidx: un_lock");
}

550
551
552
553
554
555
556
557

/*
*  :
* ,  .
*/
static void
_db_writeptr(DB *db, off_t offset, off_t ptrval)
{
char asciiptr[PTR_SZ + 1];

558
559
560

if (ptrval < 0 || ptrval > PTR_MAX)


err_quit("_db_writeptr: : %d", ptrval);
sprintf(asciiptr, "%*ld", PTR_SZ, ptrval);

561
562
563
564
565

if (lseek(db>idxfd, offset, SEEK_SET) == 1)


err_dump("_db_writeptr: ");
if (write(db>idxfd, asciiptr, PTR_SZ) != PTR_SZ)
err_dump("_db_writeptr: ");
}

[534549] , 
, idxoff DB.
,
writev.
, , 
. 

, 
.
[550565] _db_writeptr 
. 
ASCII. 
.
566
567

/*
* . 0 ; 1,

20.8.
568
569
570
571
572
573
574
575

851

* DB_INSERT; 1 .
*/
int
db_store(DBHANDLE h, const char *key, const char *data, int flag)
{
DB *db = h;
int rc, keylen, datlen;
off_t ptrval;

576
577
578
579
580
581
582
583
584

if (flag != DB_INSERT && flag != DB_REPLACE &&


flag != DB_STORE) {
errno = EINVAL;
return(1);
}
keylen = strlen(key);
datlen = strlen(data) + 1; /* +1 */
if (datlen < DATLEN_MIN || datlen > DATLEN_MAX)
err_dump("db_store: ");

585
586
587
588
589
590
591
592
593
594
595
596
597
598

/*
* _db_find_and_lock , 
* (db>chainoff), ,
* . _db_writeptr
* , .
* .
*/
if (_db_find_and_lock(db, key, 1) < 0) { /* */
if (flag == DB_REPLACE) {
rc = 1;
db>cnt_storerr++;
errno = ENOENT; /* , */
goto doreturn;
}

[566584]

db_store
. , 
. . 
, core
. ,

,
, .

[585598]

_db_find_and_lock, 
. , DB_INSERT
DB_STORE, DB_REPLACE
DB_STORE, .
, , , 
. ,
_db_find_and_lock , 
, , ,
.

852

20.

599
600
601
602
603

/*
* _db_find_and_lock ;
* .
*/
ptrval = _db_readptr(db, db>chainoff);

604
605
606
607
608
609
610

if (_db_findfree(db, keylen, datlen) < 0) {


/*
* .
* .
*/
_db_writedat(db, data, 0, SEEK_END);
_db_writeidx(db, key, 0, SEEK_END, ptrval);

611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627

/*
* db>idxoff _db_writeidx.
* .
*/
_db_writeptr(db, db>chainoff, db>idxoff);
db>cnt_stor1++;
} else {
/*
* . _db_findfree
*
* db>datoff db>idxoff. .
*/
_db_writedat(db, data, db>datoff, SEEK_SET);
_db_writeidx(db, key, db>idxoff, SEEK_SET, ptrval);
_db_writeptr(db, db>chainoff, db>idxoff);
db>cnt_stor2++;
}

[599603] _db_find_and_lock
. , , 
.
.
[604616] 1: _db_findfree 

. , 
. 
_db_writedat, _db_write
idx, 
_db_writeptr. (cnt_stor1) 
, , 
.
[617627] 2: _db_findfree 
(
_db_findfree).

, . (cnt_stor2)
, .

853

20.8.
628
629
630
631
632
633
634
635
636
637
638
639
640 _

} else { /* */
if (flag == DB_INSERT) {
rc = 1;
/* , */
db>cnt_storerr++;
goto doreturn;
}
/*
* . ,
* ,
* .
*/
if (datlen != db>datlen) {
db_dodelete(db); /* */

641
642
643
644
645

/*
* 
* ( ).
*/
ptrval = _db_readptr(db, db>chainoff);

646
647
648
649
650

/*
* .
*/
_db_writedat(db, data, 0, SEEK_END);
_db_writeidx(db, key, 0, SEEK_END, ptrval);

651
652
653
654
655
656

/*
* .
*/
_db_writeptr(db, db>chainoff, db>idxoff);
db>cnt_stor3++;
} else {

[628633] ,
. 
, , 
, ,
,
, .
[634656] 3: ,
.
_do_delete, .
,
. 
_db_writeidx
_db_writedat. ( .
, ,
.)  
_db_writeptr. cnt_stor3 DB 
, .
657
658

/*
* , .

854

20.

659
660
661
662
663
664

*/
_db_writedat(db, data, db>datoff, SEEK_SET);
db>cnt_stor4++;
}
}
rc = 0; /* OK */

665
666
667
668
669

doreturn:
/* , _db_find_and_lock */
if (un_lock(db>idxfd, db>chainoff, SEEK_SET, 1) < 0)
err_dump("db_store: un_lock");
return(rc);
}

670
671
672
673
674
675
676
677
678

/*
*
* . db_store.
*/
static int
_db_findfree(DB *db, int keylen, int datlen)
{
int rc;
off_t offset, nextoffset, saveoffset;

679
680
681
682
683

/*
* .
*/
if (writew_lock(db>idxfd, FREE_OFF, SEEK_SET, 1) < 0)
err_dump("_db_findfree: writew_lock");

684
685
686
687
688

/*
* .
*/
saveoffset = FREE_OFF;
offset = _db_readptr(db, saveoffset);

[657663]

4: ,

.
(cnt_stor4) .

[664669]

,
.
 ,
_db_find_and_lock,
.

[670688]

_db_findfree
. 
, 
. 
, .

689
690

while (offset != 0) {
nextoffset = _db_readidx(db, offset);

20.8.

855

691
692
693
694
695

if (strlen(db>idxbuf) == keylen && db>datlen == datlen)


break; /* */
saveoffset = offset;
offset = nextoffset;
}

696
697
698
699
700
701
702
703
704
705
706
707
708

if (offset == 0) {
rc = 1; /* */
} else {
/*
* .
* _db_readidx,
* db>ptrval. , saveoffset
* ,
* . db>ptrval,
* .
*/
_db_writeptr(db, saveoffset, db>ptrval);
rc = 0;

709
710
711
712
713
714
715
716
717
718
719
720
721

/*
* : _db_readidx db>idxoff
* db>datoff.
* db_store .
*/
}
/*
* .
*/
if (un_lock(db>idxfd, FREE_OFF, SEEK_SET, 1) < 0)
err_dump("_db_findfree: un_lock");
return(rc);
}

[689695] while
.

, 
. 
, 
.
[696714] ,
,
.
, . 
.
[715721] 
.
722
723

/*
* db_nextrec.

856
724
725
726
727
728
729
730
731

20.
* db_open.
* db_nextrec.
*/
void
db_rewind(DBHANDLE h)
{
DB *db = h;
off_t offset;

732

offset = (db>nhash + 1) * PTR_SZ; /* +1 */

733
734
735
736
737
738
739
740

/*
*
* .
* +1, .
*/
if ((db>idxoff = lseek(db>idxfd, offset+1, SEEK_SET)) == 1)
err_dump("db_rewind: lseek");
}

741
742
743
744
745
746
747
748
749
750
751
752

/*
* .
* , .
*
* db_rewind.
*/
char *
db_nextrec(DBHANDLE h, char *key)
{
DB *db = h;
char c;
char *ptr;

[722740] db_rewind

( ). (
, . 20.1.)
[741752] db_nextrec . 
.
key ,
, . 

. IDXLEN_MAX
.
,
. , . ,
,
,
.
753
754

/*
* ,

20.8.
755
756
757
758

* .
*/
if (readw_lock(db>idxfd, FREE_OFF, SEEK_SET, 1) < 0)
err_dump("db_nextrec: readw_lock");

759
760
761
762
763
764
765
766

do {

767
768
769
770
771
772
773

/*
* , ( ).
*/
ptr = db>idxbuf;
while ((c = *ptr++) != 0 && c == SPACE)
;
/* , */
} while (c == 0); /* , */

774
775
776
777

if (key != NULL)
strcpy(key, db>idxbuf); /* */
ptr = _db_readdat(db);
/* */
db>cnt_nextrec++;

778
779
780
781
782

857

/*
* .
*/
if (_db_readidx(db, 0) < 0) {
ptr = NULL; /* */
goto doreturn;
}

doreturn:
if (un_lock(db>idxfd, FREE_OFF, SEEK_SET, 1) < 0)
err_dump("db_nextrec: un_lock");
return(ptr);
}

[753758]

, 
.

[759773] _db_readidx.
0, , 
. 
,
. ,
,
( _db_dodelete , ).
[774782]

,
, . 

, .
db_nextrec,
.

, db_rewind db_nextrec ,
db_rewind(db);
while ((ptr = db_nextrec(db, key)) != NULL) {

858

20.
/* */

,
.
db_nextrec
, , db_nextrec,

. db_nextrec , 
, 
, . , 
db_nextrec. ,
, db_nextrec
, ,
. 
db_nextrec,
, 
.
, db_nextrec . 
 , 
. , ,
,
db_nextrec . , db_nextrec
, 
_db_dodelete _db_findfree.
db.c, 
,
. 1 3 db_store _db_wri
teidx _db_writedat, 0, 
SEEK_END. ,
. _db_writeidx 
 .

( )

. _db_writedat
. 
(
) 
( 20.3).

20.9.

, 
. : 

20.9.

859

(nrec), 
. 
( db_open),
.
.
1. nrec .
2. nrec .
3. nrec 5 .
a. .
b. 37 .
c. 11 
.
d. 17 .
, 
.
4. . 
.
, , 
cnt_xxx DB. ,
, , 
,
. ,
nrec, 500, . 20.2.
20.2. ,
nrec = 500

db_store, DB_INSERT, ,

678

db_store, DB_INSERT,

164

db_store, DB_REPLACE, ,

97

db_store, DB_REPLACE, ,

109

db_store,
db_fetch,

19
8 114

db_fetch,

732

db_delete,

842

db_delete,

110

860

20.


,
.
(,
) , 
. 
, 
( ). 

. (
nrec , nrec 2 . .)

,
( , 
, ), .
( 20.8)
.
, 20.6.
, 

. ( 
) ,
,
. ( , 
, 
.)


. 20.3
, nrec, 500, 1000 2000.
20.3. , nrec,

nrec

500

0,42

0,89

1,31

0,42

1,17

1,59

0,41

1,04

1,45

0,46

1,49

1,95

1000 1,51

3,89

5,41

1,64

4,13

5,78

1,63

4,12

5,76

1,73

6,34

8,07

2000 3,91

10,06 13,98 4,09

10,30 14,39 4,03

10,63 14,66 4,47

16,21 20,70

20.9.

861

. 20.3 .

. , 
, .
, ,
.
,
.

, 
, ,
2 31 . , 
( 
), fcntl
. : 
. , , 
, ( 
fcntl).
. 20.3: 
4354
, 
. 

, ,
.

, 
. , 
. , ,
, .
. 
:
, .



. ,
, 
,
. . 20.4 nrec = 500
1 12.

. 
.

862

20.

20.4. nrec = 500

1,00

1,42

0,41

1,05

1,47

0,05

0,47

1,40

1,87

33

1,10

2,81

3,92

1,11

2,80

3,92

0,00

1,15

4,06

5,22

45

0,07 2,31

2,17

5,27

7,44

2,19

5,18

7,37

3,36

8,55

11,91 3,26

8,67

11,94 0,03

4,72

6
7

0,41

7,67

9,99

48

3,51

12,69

16,20

46

13,08 17,80 4,99

12,64 17,64 0,16 4,91

19,21

24,14

52

6,45

17,96 24,42 6,83

17,29 24,14 0,28 7,03

26,59

33,66

54

8,46

23,12 31,62 8,67

22,96 31,65 0,03

35,47

44,74

54

9,25

10,83 29,68 40,55 11,00 29,39 40,41 0,14 11,67 45,90

57,63

56

13,35 36,81 50,23 13,43 36,28 49,76 0,47 14,45 58,02

72,49

60

10

16,35 45,28 61,66 16,09 44,10 60,23 1,43 17,43 70,90

88,37

61

11

18,97 54,24 73,24 19,13 51,70 70,87 2,37 20,62 84,98

105,69 64

12

22,92 63,54 86,51 22,94 61,28 84,29 2,22 24,41 101,68 126,20 66

, , ,

. 
,
. , 
, ,
.
, ,
, 
, ( 3%), 
, ,
, .
, 
(
), 

. ,

fcntl, .
. 20.2, , 
21 730 fcntl, 

20.9.

863

25 292 . ( , ,
. 20.2 fcntl
db_store,
( ), 
fcntl .) ,
fcntl
16% .
,
,
, .
, 

, 
.

, .
12 ,
,
,
. , 
.
, %,

.
, . 20.3, 
( 33 66%)
.
, ,
( 
fcntl 
, ),
, 
.
. 20.4 . 20.3
nrec = 500. .
. 20.4. . 20.4
. 
(112),
, 
.
: , 
, , 
. ,
, 

864

90
8
80
70


( )

6
60
50
4
40

,
/

30
2
20

/

10

, / ,
/
( )

20.

0
0

10

11

12

. 20.4. . 20.4

. 
, , 
,
, .


.  ,
_db_find_and_lock
.

20.10.

.
, 
, 
.


, ( )
. , 
10%

20.10.

865

, 
,
3366% , 
.

20.1. _db_dodelete 
. , , 

, 
,
writew_lock 
_db_writedat _db_readptr. , ?
20.2. , db_nextrec
, , 
. ,
db_nextrec , 
(, ). (:
_db_dodelete.)
20.3. 20.8 , 
_db_writeidx _db_writedat. ,

, db_store.

?
20.4. fsync 
?
20.5. db_store , .
, ?
20.6. . 
,
db_nextrec _db_hash, 
. , 
. 
, , 
_db_hash?
20.7. ,
 .
20.8. , 
()
() ,
NFS.
?

21

21.1.
, 
. 
Ethernet ,
, PostScript.

IPP (Internet Printing Protocol ), 
.
: ( ) , 
, , 
. 
( , 
, , ), 
,
. , 
( 11 12),
, ,
( 16).

21.2.

. IPP, 
, 
. , 
, . IPP 
(IP),
TCP/IP
.

867

21.2.

Ethernet

IP

TCP

HTTP

IP

. 21.1. IPP

, IPP HTTP
(Hypertext Transfer Protocol , 21.3).
, HTTP TCP/IP. 
IPP . 21.1.
IPP . 
 , . IPP
, . 
, ,
, ,
, , 
.
. 21.2 IPP. 2
IPP. 1.1 
1. 2 ,
. 2 .
4 .
,
. ,
.

(, bigendian) . .
1 ,
, 2 , , 2
.
,
, .

(2 )

()/ ()

(2 )

(4 )

. 21.2. IPP

( 0 n )
(1 )
( 0 n )

868

21.

= 0 47

(1 )

= 18

(2 )

= attributescharset

(18 )

= 5

(2 )

= utf8

(5 )

. 21.3. IPP

. 21.3 , IPP attri


butescharset utf8.

, . , . 21.1 
, .
21.1.

attributescharset

,
, type name

attributesnatu
rallanguage

, 
, type name

printeruri

requestinguser
name

, 
( ,
)

jobname

, 

ippattributefi
delity

, 
,
, 
,

documentname

( ,
, )

documentformat

( , PostScript
.)

documentnatural
language

869

21.3.

compression

jobkoctets

1024

jobimpressions

( 
, ),

jobmediasheets

IPP , . 
,
. 
,
, .
, ,
. 
, .
IPP (RFC, Requests For
Comments ), http://
www.pwg.org/ipp. . 21.2, 
, ,
.
21.2. RFC, IPP
RFC

2567

Design Goals for an Internet Printing Protocol


2568

Rationale for Structure of the Model and Protocol for the Internet Printing
Protocol IPP

2911

Internet Printing Protocol/1.1:Model and Semantics IPP/1.1:


2910

Internet Printing Protocol/1.1:Encoding and Transport IPP/


1.1:

3196

Internet Printing Protocol/1.1:Implementators Guide IPP/


1.1:

21.3.
1.1 HTTP RFC 2616. HTTP 
.  
, , 
. IPP
.

870

21.

HTTP ASCII, 
(\r) (\n).
, (URL
Uniform Resource Locator), , ,
HTTP. IPP 
HTTP POST.
, 
. ,
, .
. , ,
IPP,
ContentType: application/ipp

 HTTP ,
.
. 
 , : ,
.
HTTP , 
:
POST /phaser860/ipp HTTP/1.1M
ContentLength: 21931M
ContentType: application/ippM
Host: phaser860:ippM
M

^M 
, .
. , 

.

21.4.
, , 
( ) . 
, 
,
.
UNIX .
, FreeBSD LPD (Line Printer Daemon
) (. lpd(8) 13 [Stevens 1990]). Li
nux Mac OS X CUPS (Common UNIX Print
ing System UNIX) (. cupsd(8)). Solaris
System V (. lp(1)
lpsched(1M)). 

871

21.4.

, .
, 
().
,
. 
( ,
PostScript). print.
printd , 
,
.

, print.
, 
.
, 
.
.
. 21.4 , .

print

printd

. 21.4.

/etc/printer.conf.
, , 
. , 
printserver,
. ,
printer, 
.
:
printserver
printer

blade
phaser860

872

21.

blade , 
, phaser860 .

, , 
.
, , 

.
, , 
,
TCP. , :
, 
( 8.11). ,
,
 , root
(, lp). , 
, , 
. 
.
, ,
.

, .
,
.

21.5.
, , ,
, 
:
ipp.h

IPP

print.h

util.c

print.c

print,

printd.c

.
ipp.h.
1
2

#ifndef _IPP_H
#define _IPP_H

873

21.5.
3
4
5
6

/*
* IPP,
* . RFC2911 RFC2910.
*/

7
8
9
10
11
12
13
14

/*
* .
*/
#define STATCLASS_OK(x)
#define STATCLASS_INFO(x)
#define STATCLASS_REDIR(x)
#define STATCLASS_CLIERR(x)
#define STATCLASS_SRVERR(x)

15
16
17
18
19
20

/*
*
*/
#define
#define
#define

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define

[114]

((x)
((x)
((x)
((x)
((x)

>=
>=
>=
>=
>=

0x0000
0x0100
0x0200
0x0400
0x0500

&&
&&
&&
&&
&&

(x)
(x)
(x)
(x)
(x)

<=
<=
<=
<=
<=

0x00ff)
0x01ff)
0x02ff)
0x04ff)
0x05ff)

.
STAT_OK
0x0000 /* */
STAT_OK_ATTRIGN 0x0001 /* OK; */
STAT_OK_ATTRCON 0x0002 /* OK; */
/* */
STAT_CLI_BADREQ
STAT_CLI_FORBID
STAT_CLI_NOAUTH
STAT_CLI_NOPERM
STAT_CLI_NOTPOS
STAT_CLI_TIMOUT
STAT_CLI_NOTFND
STAT_CLI_OBJGONE
STAT_CLI_TOOBIG
STAT_CLI_TOOLNG
STAT_CLI_BADFMT
STAT_CLI_NOTSUP
STAT_CLI_NOSCHM
STAT_CLI_NOCHAR
STAT_CLI_ATTRCON
STAT_CLI_NOCOMP
STAT_CLI_COMPERR
STAT_CLI_FMTERR
STAT_CLI_ACCERR

0x0400
0x0401
0x0402
0x0403
0x0404
0x0405
0x0406
0x0407
0x0408
0x0409
0x040a
0x040b
0x040c
0x040d
0x040e
0x040f
0x0410
0x0411
0x0412

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

*/
*/
*/
*/
*/
*/
URI */
*/
*/
*/
*/
*/
URI */
*/
*/
*/
*/
*/
*/

#ifndef,
, 
.
IPP ( 13 RFC 2911).

[1539] RFC 2911.


, 21.1.
40
41
42

#define STAT_SRV_INTERN 0x0500 /* */


#define STAT_SRV_NOTSUP 0x0501 /* */
#define STAT_SRV_UNAVAIL 0x0502 /* */

874

21.

43
44
45
46
47
48
49

#define
#define
#define
#define
#define
#define
#define

STAT_SRV_BADVER
STAT_SRV_DEVERR
STAT_SRV_TMPERR
STAT_SRV_REJECT
STAT_SRV_TOOBUSY
STAT_SRV_CANCEL
STAT_SRV_NOMULTI

0x0503
0x0504
0x0505
0x0506
0x0507
0x0508
0x0509

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

/*
* .
*/
#define OP_PRINT_JOB
#define OP_PRINT_URI
#define OP_VALIDATE_JOB
#define OP_CREATE_JOB
#define OP_SEND_DOC
#define OP_SEND_URI
#define OP_CANCEL_JOB
#define OP_GET_JOB_ATTR
#define OP_GET_JOBS
#define OP_GET_PRINTER_ATTR
#define OP_HOLD_JOB
#define OP_RELEASE_JOB
#define OP_RESTART_JOB
#define OP_PAUSE_PRINTER
#define OP_RESUME_PRINTER
#define OP_PURGE_JOBS

69
70
71
72
73
74
75
76

/*
* .
*/
#define TAG_OPERATION_ATTR
#define TAG_JOB_ATTR
#define TAG_END_OF_ATTR
#define TAG_PRINTER_ATTR
#define TAG_UNSUPP_ATTR

/*
/*
/*
/*
/*
/*
/*
/*

*/
*/
*/
*/
*/
*/
*/
*/

0x02
0x03
0x04
0x05
0x06
0x07
0x08
0x09
0x0a
0x0b
0x0c
0x0d
0x0e
0x10
0x11
0x12

0x01
0x02
0x03
0x04
0x05

/*
/*
/*
/*
/*

*/
*/
*/
*/
*/

[4049] . 0x500 0x5ff


. 
13.1.113.1.5 RFC 2911.
[5068] . 
, IPP, 
( 4.4.15 RFC 2911). 
OP_PRINT_JOB.
[6976] , 
IPP. 3.5.1 RFC 2910.
77
78
79

/*
* .
*/

875

21.5.
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define

TAG_UNSUPPORTED
TAG_UNKNOWN
TAG_NONE
TAG_INTEGER
TAG_BOOLEAN
TAG_ENUM
TAG_OCTSTR
TAG_DATETIME
TAG_RESOLUTION
TAG_INTRANGE
TAG_TEXTWLANG
TAG_NAMEWLANG
TAG_TEXTWOLANG
TAG_NAMEWOLANG
TAG_KEYWORD
TAG_URI
TAG_URISCHEME
TAG_CHARSET
TAG_NATULANG
TAG_MIMETYPE

0x10
0x12
0x13
0x21
0x22
0x23
0x30
0x31
0x32
0x33
0x35
0x36
0x41
0x42
0x44
0x45
0x46
0x47
0x48
0x49

100
101
102
103
104
105
106
107
108
109
110

struct ipp_hdr {
int8_t major_version; /*
int8_t minor_version; /*
union {
int16_t op;
/*
int16_t st;
/*
} u;
int32_t request_id; /*
char attr_group[1]; /*
/*
};

111
112

#define operation u.op


#define status u.st

113

#endif /* _IPP_H */

[7799]

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
URI */
URI */
*/
*/
MIME */

1 */
1 */
*/
*/
*/
*/
*/


. 3.5.2 RFC 2910.

[100113] IPP.  
 ,
,  
.
#endif,
#ifndef,
.

print.h.
1
2

#ifndef _PRINT_H
#define _PRINT_H

876

21.

3
4
5
6
7
8
9
10
11
12

/*
* .
*/
#include <sys/socket.h>
#include <arpa/inet.h>
#if defined(BSD) || defined(MACOS)
#include <netinet/in.h>
#endif
#include <netdb.h>
#include <errno.h>

13
14
15
16
17

#define
#define
#define
#define
#define

CONFIG_FILE
SPOOLDIR
JOBFILE
DATADIR
REQDIR

18
19
20
21
22

#define
#define
#define
#define
#define

FILENMSZ
FILEPERM
USERNM_MAX
JOBNM_MAX
MSGLEN_MAX

23
24
25

#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 256
#endif

26
27
28
29
30

#define
#define
#define
#define
#define

[112]

"/etc/printer.conf"
"/var/spool/printer"
"jobno"
"data"
"reqs"

64
(S_IRUSR|S_IWUSR)
64
256
512

IPP_PORT 631
QLEN
10
IBUFSZ 512 /* IPP */
HBUFSZ 512 /* HTTP */
IOBUFSZ 8192 /* */

,
, . 
print.h, 
.

[1317] , . 
/var/spool/printer/data,
/var/spool/
printer/reqs. , ,
/var/spool/printer/jobno.
[1830] . 
, , FILEPERM. 
, 
,
. 631 IPP . 
QLEN backlog listen ( 16.4).
31
32
33

#ifndef ETIME
#define ETIME ETIMEDOUT
#endif

21.5.
34
35
36
37
38
39
40
41

extern int getaddrlist(const char *, const char *,


struct addrinfo **);
extern char *get_printserver(void);
extern struct addrinfo *get_printaddr(void);
extern ssize_t tread(int, void *, size_t, unsigned int);
extern ssize_t treadn(int, void *, size_t, unsigned int);
extern int connect_retry(int, const struct sockaddr *, socklen_t);
extern int initserver(int, struct sockaddr *, socklen_t, int);

42
43
44
45
46
47
48
49
50

/*
* , print.
*/
struct printreq {
long size;
/* */
long flags;
/* . */
char usernm[USERNM_MAX]; /* */
char jobnm[JOBNM_MAX]; /* */
};

51
52
53
54

/*
* .
*/
#define PR_TEXT
0x01 /* */

55
56
57
58
59
60
61
62

/*
* print.
*/
struct printresp {
long retcode;
/* 0=, !0= */
long jobid;
/* */
char msg[MSGLEN_MAX]; /* */
};

63

#endif /* _PRINT_H */

877

[3133] ETIME,
.
[3441] ,
util.c ( ). , 
connect_retry 16.2 initserver 16.9 
util.c.
[4263] printreq printresp 
print . print
printreq, ,
. printresp, 
, 
.

util.c, .
1
2
3

#include "apue.h"
#include "print.h"
#include <ctype.h>

878

21.
4

#include <sys/select.h>

5
6
7

#define MAXCFGLINE 512


#define MAXKWLEN 16
#define MAXFMTLEN 16

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[17]

/*
*
* ailistpp. 0
* ( ). :
* errno.
*
* : .
*/
int
getaddrlist(const char *host, const char *service,
struct addrinfo **ailistpp)
{
int
err;
struct addrinfo hint;
hint.ai_flags = AI_CANONNAME;
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
err = getaddrinfo(host, service, &hint, ailistpp);
return(err);
}
, 
. MAXCFGLINE
, MAXKWLEN 
, MAXFMTLEN
, sscanf.

[832] getaddrlist. 
getaddrinfo ( 16.3.3), getad
drinfo hint. 
: .

. , 
( ), ,
, , 
.
33
34
35
36

/*
*
* , .
*

21.5.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

879

* : .
*/
static char *
scan_configfile(char *keyword)
{
int
n, match;
FILE
*fp;
char
keybuf[MAXKWLEN], pattern[MAXFMTLEN];
char
line[MAXCFGLINE];
static char valbuf[MAXCFGLINE];
if ((fp = fopen(CONFIG_FILE, "r")) == NULL)
log_sys(" %s", CONFIG_FILE);
sprintf(pattern, "%%%ds %%%ds", MAXKWLEN1, MAXCFGLINE1);
match = 0;
while (fgets(line, MAXCFGLINE, fp) != NULL) {
n = sscanf(line, pattern, keybuf, valbuf);
if (n == 2 && strcmp(keyword, keybuf) == 0) {
match = 1;
break;
}
}
fclose(fp);
if (match != 0)
return(valbuf);
else
return(NULL);
}

[3346] scan_configfile
.
[4763] 
, . %%%ds 
, ,
, .

, . ,
. 
, .
, 
, , 
, NULL.
(valbuf), 
. 
, scan_configfile 
, , 
.
64 /*
65 * , , NULL
66 *

880

21.

67
68
69
70
71
72
73

* : .
*/
char *
get_printserver(void)
{
return(scan_configfile("printserver"));
}

74
75
76
77
78
79
80
81
82
83
84

/*
* NULL .
*
* : .
*/
struct addrinfo *
get_printaddr(void)
{
int
err;
char
*p;
struct addrinfo *ailist;

85
86
87
88
89
90
91
92
93
94

if ((p = scan_configfile("printer")) != NULL) {


if ((err = getaddrlist(p, "ipp", &ailist)) != 0) {
log_msg(" %s", p);
return(NULL);
}
return(ailist);
}
log_msg(" ");
return(NULL);
}

[6473] get_printserver , 
scan_configfile, , 
.
[7494] get_printaddr,
. ,

.
, get_printserver get_printaddr,
scan_configfile. ,
scan_configfile log_sys, , 
. get_printserver 
print, get_printaddr , log_sys
,

, 
.
95
96
97

/*
* 
* (5 select,

21.5.
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

881

* ). 1 ().
*
* : .
*/
ssize_t
tread(int fd, void *buf, size_t nbytes, unsigned int timout)
{
int
nfds;
fd_set
readfds;
struct timeval tv;
tv.tv_sec = timout;
tv.tv_usec = 0;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
nfds = select(fd+1, &readfds, NULL, NULL, &tv);
if (nfds <= 0) {
if (nfds == 0)
errno = ETIME;
return(1);
}
return(read(fd, buf, nbytes));
}

[95107] tread, 
, timeout .

.  , 
1 ETIME errno. 
,
nbytes , ,
, .
tread
(denialofservice DOS) . 
, 
,
. 
, 
. ,
, ,

, . ,
,
, 
.
[108119] , , 
select.  , 
, select 0,
errno ETIME. 
 select 
1. , .

882

21.

120
121
122
123
124
125
126
127
128
129
130
131

/*
* 
* read, nbytes .
* 1 .
*
* : .
*/
ssize_t
treadn(int fd, void *buf, size_t nbytes, unsigned int timout)
{
size_t nleft;
ssize_t nread;

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

nleft = nbytes;
while (nleft > 0) {
if ((nread = tread(fd, buf, nleft, timout)) < 0) {
if (nleft == nbytes)
return(1); /* , 1 */
else
break;
/* , , */
} else if (nread == 0) {
break;
/* */
}
nleft = nread;
buf += nread;
}
return(nbytes  nleft); /* >= 0 */
}

[120146] tread, treadn.


, 
. readn, 14.8,
,
.
, 
read. 
 read. 
,
. ,
, timeval 
select, , ,
( 14.5.1).

read. 
. 
nbytestimeout
( 1 ).
nleft , 
. tread ,
,
while , , 1.

21.5.

883

print,
. C print.c.
1
2
3
4
5
6
7
8
9

/*
* . .
* :
* print [t] filename
*/
#include "apue.h"
#include "print.h"
#include <fcntl.h>
#include <pwd.h>

10
11
12
13

/*
* .
*/
int log_to_stderr = 1;

14

void submit_file(int, int, const char *, size_t, int);

15
16
17
18
19
20
21

int
main(int argc, char *argv[])
{
int
fd, sockfd, err, text, c;
struct stat
sbuf;
char
*host;
struct addrinfo *ailist, *aip;

22
23
24
25
26
27
28
29
30
31
32
33
[114]

err = 0;
text = 0;
while ((c = getopt(argc, argv, "t")) != 1) {
switch (c) {
case t:
text = 1;
break;
case ?:
err = 1;
break;
}
}
log_to_stderr, 
. 
, 
,
. print.c 
, print print.o
util.o, util.c , .

[1533] t, 
, ( PostScript, 
). 
getopt(3).

884

21.

34
35
36
37
38
39
40
41

if (err || (optind != argc  1))


err_quit(": print [t] filename");
if ((fd = open(argv[optind], O_RDONLY)) < 0)
err_sys("print: %s", argv[1]);
if (fstat(fd, &sbuf) < 0)
err_sys("print: %s", argv[1]);
if (!S_ISREG(sbuf.st_mode))
err_quit("print: %s \n", argv[1]);

42
43
44
45
46
47
48

/*
* , .
*/
if ((host = get_printserver()) == NULL)
err_quit("print: ");
if ((err = getaddrlist(host, "print", &ailist)) != 0)
err_quit("print: getaddrinfo: %s", gai_strerror(err));

49
50
51
52
53
54

for (aip = ailist; aip != NULL; aip = aip>ai_next) {


if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
err = errno;
} else if (connect_retry(sockfd, aip>ai_addr,
aip>ai_addrlen) < 0) {
err = errno;

[3441] getopt , 
optind .
, 
, (
). 
, , 
, (
 ).
[4248] , , 
get_printserver util.c, 
getaddrlist ( util.c).
: print. 
, /etc/services ( 
) , .
,
. 

, ,
, . ,
1024 ( 16.3.4) 
, 
.
[4954] , 
, getaddrinfo.
, .
55
56

} else {
submit_file(fd, sockfd, argv[1], sbuf.st_size, text);

885

21.5.
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
74
75

/*
* .
*/
void
submit_file(int fd, int sockfd, const char *fname, size_t nbytes,
int text)
{
int nr, nw, len;
struct passwd *pwd;
struct printreq req;
struct printresp res;
char buf[IOBUFSZ];

76
77
78
79
80
81
82
83
84
85
86
87

exit(0);
}
}
errno = err;
err_ret("print: %s", host);
exit(1);

/*
* .
*/
if ((pwd = getpwuid(geteuid())) == NULL)
strcpy(req.usernm, "unknown");
else
strcpy(req.usernm, pwd>pw_name);
req.size = htonl(nbytes);
if (text)
req.flags = htonl(PR_TEXT);
else
req.flags = 0;

[5563] ,
submit_file. ,
. 
err_sys err_ret exit, 
, main
return exit.
[6487] submit_file
. printreq.
getuid ,
getpwuid, 
. 
, , 
unknown (). 
,
.
PR_TEXT, .
88

if ((len = strlen(fname)) >= JOBNM_MAX) {

886

21.
89
90
91
92
93
94
95
96
97

/*
* ( 5 ,
* ).
*/
strcpy(req.jobnm, "... ");
strncat(req.jobnm, &fname[lenJOBNM_MAX+5], JOBNM_MAX5);
} else {
strcpy(req.jobnm, fname);
}

98
99
100
101
102
103
104
105
106
107
108

/*
* .
*/
nw = writen(sockfd, &req, sizeof(struct printreq));
if (nw != sizeof(struct printreq)) {
if (nw < 0)
err_sys(" ");
else
err_quit(" (%d/%d)",
nw, sizeof(struct printreq));
}

109
110
111
112
113
114
115
116
117
118
119
120
121

/*
* .
*/
while ((nr = read(fd, buf, IOBUFSZ)) != 0) {
nw = writen(sockfd, buf, nr);
if (nw != nr) {
if (nw < 0)
err_sys(" ");
else
err_quit(" (%d/%d)",
nw, nr);
}
}

[88108]

.
, , , 
, , 
. 
writen.

, .

[109121] ,
. IOBUFSZ
writen. 
, 
, 
.
122
123

/*
* .

21.5.
124
125
126
127
128
129
130
131
132
133
134
135

887

*/
if ((nr = readn(sockfd, &res, sizeof(struct printresp))) !=
sizeof(struct printresp))
err_sys(" ");
if (res.retcode != 0) {
printf(" : %s\n", res.msg);
exit(1);
} else {
printf(" %ld\n", ntohl(res.jobid));
}
exit(0);
}

[122135] , .
, (retcode) , 
, . 
, 
, , 
. ( 
, .
, 
, .)
:
, . 
, .

, print.c, 
. , , getopt,
pty 19.
, 
, . 
,
, .
, 
. ,
,
 . 

,
.
Single UNIX Specification 
, .
, 

.
, getopt, 
.

888

21.

#include <fcntl.h>
int getopt(int argc, const * const argv[], const char *options);
extern int optind, opterr, optopt;
extern char *optarg;

1,

argc argv , main. 


options , 
. , , , 
. 
. , command 
:
command [i] [u username] [z] filename

options "iu:z".
getopt , ,
getopt 1. getopt
.
, getopt
.
getopt ,
. , getopt
, options
, . 
 getopt 
1. 
, , . 
, bar,
rm bar

rm bar . 
, ,
rm  bar

getopt .
optarg , getopt 
optarg .
opterr , getopt
. ,
opterr 0.
optind argv , . 
1 1 , 
getopt.

21.5.

889

optopt , getopt
optopt , .

, ,
C.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

/*
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

15
16
17
18
19

/*
* HTTP.
*/
#define HTTP_INFO(x) ((x) >= 100 && (x) <= 199)
#define HTTP_SUCCESS(x) ((x) >= 200 && (x) <= 299)

20
21
22
23
24
25
26
27
28

/*
* .
*/
struct job {
struct job
*next; /* */
struct job
*prev; /* */
long
jobid; /* */
struct printreq req; /* */
};

29
30
31
32
33
34
35
36
37

/*
* , .
*/
struct worker_thread {
struct worker_thread *next; /* */
struct worker_thread *prev; /* */
pthread_t
tid;
/* */
int
sockfd; /* */
};

[119]

.
"apue.h"
"print.h"
"ipp.h"
<fcntl.h>
<dirent.h>
<ctype.h>
<pwd.h>
<pthread.h>
<strings.h>
<sys/select.h>
<sys/uio.h>


IPP, .
HTTP_INFO HTTP_SUCCESS HTTP ( 
, IPP HTTP).

[2037] job worker_thread 


, , .

890

21.

38
39
40
41

/*
* .
*/
int log_to_stderr = 0;

42
43
44
45
46
47
48

/*
* , .
*/
struct addrinfo
*printer;
char
*printer_name;
pthread_mutex_t
configlock = PTHREAD_MUTEX_INITIALIZER;
int reread;

49
50
51
52
53
54

/*
* , .
*/
struct worker_thread *workers;
pthread_mutex_t
workerlock = PTHREAD_MUTEX_INITIALIZER;
sigset_t
mask;

55
56
57
58
59

/*
* , .
*/
struct job
*jobhead, *jobtail;
int
jobfd;

[3841] 
log_to_stderr. 0, 
, 
. print.c 
log_to_stderr 1, 
print. 
,
.
[4248] printer . 
printer_name. configlock 
reread, , 
,
.
[4954] , . 
workers ,
.
workerlock. mask 
, .
[5559] jobhead , jobtail
, . 
, ,
. 
, 
,
. jobfd .

21.5.
60
61
62

long
nextjob;
pthread_mutex_t joblock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t jobwait = PTHREAD_COND_INITIALIZER;

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

/*
* .
*/
void
init_request(void);
void
init_printer(void);
void
update_jobno(void);
long
get_newjobno(void);
void
add_job(struct printreq *, long);
void
replace_job(struct job *);
void
remove_job(struct job *);
void
build_qonstart(void);
void
*client_thread(void *);
void
*printer_thread(void *);
void
*signal_thread(void *);
ssize_t readmore(int, char **, int, int *);
int
printer_status(int, struct job *);
void
add_worker(pthread_t, int);
void
kill_workers(void);
void
client_cleanup(void *);
/*
* .
* .
*
* : .
*/
int
main(int argc, char *argv[])
{
pthread_t
tid;
struct addrinfo *ailist, *aip;
int
sockfd, err, i, n, maxfd;
char
*host;
fd_set
rendezvous, rset;
struct sigaction sa;
struct passwd
*pwdp;

891

[6062] nextjob ,
. joblock
, jobwait.
[6381] ,
. , 
, .
[8297] main :
.
98
99
100

if (argc != 1)
err_quit(": printd");
daemonize("printd");

892
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
[98100]

21.

sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &sa, NULL) < 0)
log_sys(" sigaction");
sigemptyset(&mask);
sigaddset(&mask, SIGHUP);
sigaddset(&mask, SIGTERM);
if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0)
log_sys(" pthread_sigmask");
init_request();
init_printer();
#ifdef _SC_HOST_NAME_MAX
n = sysconf(_SC_HOST_NAME_MAX);
if (n < 0) /* , */
#endif
n = HOST_NAME_MAX;
if ((host = malloc(n)) == NULL)
log_sys(" malloc");
if (gethostname(host, n) < 0)
log_sys(" gethostname");
, , 
argc 1, err_quit,
. dae
monize 13.1, .


.

[101112] SIGPIPE. 
, , 
SIGPIPE,
. SIGHUP
SIGTERM . ,
, .
SIGHUP, 
, SIGTERM , 
. init_request 
,
, ,
init_printer,
( ).
[113121] _SC_HOST_NAME_MAX,
sysconf, 
. sysconf
, HOST_NAME_MAX
, . 
, ,
, print.h.

21.5.

893


gethostname, .
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

if ((err = getaddrlist(host, "print", &ailist)) != 0) {


log_quit(" getaddrinfo: %s", gai_strerror(err));
exit(1);
}
FD_ZERO(&rendezvous);
maxfd = 1;
for (aip = ailist; aip != NULL; aip = aip>ai_next) {
if ((sockfd = initserver(SOCK_STREAM, aip>ai_addr,
aip>ai_addrlen, QLEN)) >= 0) {
FD_SET(sockfd, &rendezvous);
if (sockfd > maxfd)
maxfd = sockfd;
}
}
if (maxfd == 1)
log_quit(" ");

138
139
140
141
142
143
144

pwdp = getpwnam("lp");
if (pwdp == NULL)
log_sys(" lp");
if (pwdp>pw_uid == 0)
log_quit("lp ");
if (setuid(pwdp>pw_uid) < 0)
log_sys(" lp");

[122135] ,
. 
rendezvous, select 
. 
1,
, ,
, maxfd. 
initserver ( 16.9), 
. initserver
rendevouz , 
, maxfd .
[136137] addrinfo
maxfd 1, , 
.
[138144] ,
. ,
, , 
lp
( 21.4). 
,
. getpwnam,
, lp.

894

21.

, 
, 
. 
setuid, 
lp.
,
, .
145
146
147

pthread_create(&tid, NULL, printer_thread, NULL);


pthread_create(&tid, NULL, signal_thread, NULL);
build_qonstart();

148

log_msg(" ");

149
150
151
152
153
154

for (;;) {
rset = rendezvous;
if (select(maxfd+1, &rset, NULL, NULL, NULL) < 0)
log_sys(" select");
for (i = 0; i <= maxfd; i++) {
if (FD_ISSET(i, &rset)) {

155
156
157
158
159
160
161
162
163
164
}
165
}
166
}
167
exit(1);
168 }

/*
*
* .
*/
sockfd = accept(i, NULL, NULL);
if (sockfd < 0)
log_ret(" accept");
pthread_create(&tid, NULL, client_thread,
(void *)sockfd);

[145148] pthread_create,
. (
,
, .) 
build_qonstart, /var/spool/
printer , , 
. , , ,
,
. 
, ,
.
[149168] rendevouz rset 
select, ,
. rendevouz, select

, .

21.5.

895

, 
, 
. select , 
rset .
, accept, 
. accept , 
,
. ,
. main , 
, 
exit.
169
170
171
172
173
174
175
176
177
178
179

/*
* .
* , .
*
* : , .
*/
void
init_request(void)
{
int n;
char name[FILENMSZ];

180
181
182
183
184
185
186
187
188
189
190
191
192
193

sprintf(name, "%s/%s", SPOOLDIR, JOBFILE);


jobfd = open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
if (write_lock(jobfd, 0, SEEK_SET, 0) < 0)
log_quit(" ");
/*
* .
*/
if ((n = read(jobfd, name, FILENMSZ)) < 0)
log_sys(" ");
if (n == 0)
nextjob = 1;
else
nextjob = atol(name);
}

[169183] init_request : 
/var/spool/printer/jobno ,
, .
,
, . 
, , 
.
( 13.2, write_lock
14.3.)
[184193] ASCII.
, 
nextjob 1.

896

21.

atol , 
. 
jobfd , 
.
, , 
, .
, 64 , 

21 . 
, FILENMSZ 
print.h 64.
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

/*
* .
*
* : .
*/
void
init_printer(void)
{
printer = get_printaddr();
if (printer == NULL) {
log_msg(" ");
exit(1);
}
printer_name = printer>ai_canonname;
if (printer_name == NULL)
printer_name = "printer";
log_msg(" : %s", printer_name);
}

212
213
214
215
216
217
218
219
220

/*
* .
*
* : .
*/
void
update_jobno(void)
{
char buf[32];

221
222
223
224
225

lseek(jobfd, 0, SEEK_SET);
sprintf(buf, "%ld", nextjob);
if (write(jobfd, buf, strlen(buf)) < 0)
log_sys(" ");
}

21.5.

897

[194211]

init_printer ,
.
get_printaddr ( util.c). 
, . 
log_sys, get_printaddr 
, errno. 
, get_printaddr
errno,
. ai_canonname 
addrinfo. ,
printer. :
, 
.

[212225]

update_jobno /var/
spool/printer/jobno.
.
. 
, .

226
227
228
229
230
231
232
233
234

/*
* .
*
* : joblock.
*/
long
get_newjobno(void)
{
long jobid;

235
236
237
238
239
240
241

242
243
244
245
246
247
248
249
250
251

/*
* .
* , .
*
* : joblock.
*/
void
add_job(struct printreq *reqp, long jobid)
{
struct job *jp;

252
253
254

pthread_mutex_lock(&joblock);
jobid = nextjob++;
if (nextjob <= 0)
nextjob = 1;
pthread_mutex_unlock(&joblock);
return(jobid);

if ((jp = malloc(sizeof(struct job))) == NULL)


log_sys(" malloc");
memcpy(&jp>req, reqp, sizeof(struct printreq));

898

21.

[226241] get_newjobno , 
. joblock.
nextjob 1 
. ,
nextjob . get_newjobno
,
, 
, . ( . 11.4
, ,
.)
[242254] add_job
.
job. , 
.
, 
.
printreq, , job.
print.h , job 
, printreq,
print.
255
256
257
258
259
260
261
262
263
264
265
266

jp>jobid = jobid;
jp>next = NULL;
pthread_mutex_lock(&joblock);
jp>prev = jobtail;
if (jobtail == NULL)
jobhead = jp;
else
jobtail>next = jp;
jobtail = jp;
pthread_mutex_unlock(&joblock);
pthread_cond_signal(&jobwait);
}

267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

/*
* .
*
* : joblock.
*/
void
replace_job(struct job *jp)
{
pthread_mutex_lock(&joblock);
jp>prev = NULL;
jp>next = jobhead;
if (jobhead == NULL)
jobtail = jp;
else
jobhead>prev = jp;
jobhead = jp;
pthread_mutex_unlock(&joblock);
}

21.5.

899

[255266] , 
. 
. 

. , 
jobhead. 
.
jobtail.
, 
, .
[267284] replace_job , 
. joblock, NULL
,
.
, jobtail.

. 
jobhead. 
.
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301

/*
* .
*
* : joblock.
*/
void
remove_job(struct job *target)
{
if (target>next != NULL)
target>next>prev = target>prev;
else
jobtail = target>prev;
if (target>prev != NULL)
target>prev>next = target>next;
else
jobhead = target>next;
}

302
303
304
305
306
307
308
309
310
311
312
313
314

/*
* .
*
* : .
*/
void
build_qonstart(void)
{
int
fd, err, nr;
long jobid;
DIR
*dirp;
struct dirent *entp;
struct printreq req;

900

21.

315

char

dname[FILENMSZ], fname[FILENMSZ];

316
317
318

sprintf(dname, "%s/%s", SPOOLDIR, REQDIR);


if ((dirp = opendir(dname)) == NULL)
return;

[285301] remove_job ,
.
joblock remove_job.
, 
, 
.
,
jobtail. 
,
, . 
, 
jobhead.
[302318] build_qonstart,
, /var/spool/
printer/reqs. ,
, .
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346

while ((entp = readdir(dirp)) != NULL) {


/*
* "." ".."
*/
if (strcmp(entp>d_name, ".") == 0 ||
strcmp(entp>d_name, "..") == 0)
continue;
/*
* .
*/
sprintf(fname, "%s/%s/%s", SPOOLDIR, REQDIR, entp>d_name);
if ((fd = open(fname, O_RDONLY)) < 0)
continue;
nr = read(fd, &req, sizeof(struct printreq));
if (nr != sizeof(struct printreq)) {
if (nr < 0)
err = errno;
else
err = EIO;
close(fd);
log_msg("build_qonstart: %s: %s",
fname, strerror(err));
unlink(fname);
sprintf(fname, "%s/%s/%s", SPOOLDIR, DATADIR,
entp>d_name);
unlink(fname);
continue;
}

21.5.
347
348
349
350
351
352

901

jobid = atol(entp>d_name);
log_msg(" %ld", jobid);
add_job(&req, jobid);
}
closedir(dirp);
}

[319325] , .
. ...
[326346] , 
. , 
.
printreq, . 
, ,
. 
.
[347352] printreq, 
( 
),
. readdir 
NULL, .
353 /*
354
* .
355
*
356
* : .
357
*/
358 void *
359 client_thread(void *arg)
360 {
361
int
n, fd, sockfd, nr, nw, first;
362
long
jobid;
363
pthread_t tid;
364
struct
printreq req;
365
struct
printresp res;
366
char
name[FILENMSZ];
367
char
buf[IOBUFSZ];
368
369
370
371

tid = pthread_self();
pthread_cleanup_push(client_cleanup, (void *)tid);
sockfd = (int)arg;
add_worker(tid, sockfd);

372
373
374
375
376
377
378
379

/*
* .
*/
if ((n = treadn(sockfd, &req, sizeof(struct printreq), 10)) !=
sizeof(struct printreq)) {
res.jobid = 0;
if (n < 0)
res.retcode = htonl(errno);

902
380
381
382
383
384
385

21.
else
res.retcode = htonl(EIO);
strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);
writen(sockfd, &res, sizeof(struct printresp));
pthread_exit((void *)1);
}

[353371] client_thread ,
main .
, ,
. ,
, .
(
11.5).
client_cleanup, 
. 
. add_worker, 
worker_thread .
[372385] ,
. 
, ,  
, , 
, pthread_exit .
386
387

req.size = ntohl(req.size);
req.flags = ntohl(req.flags);

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404

/*
* .
*/
jobid = get_newjobno();
sprintf(name, "%s/%s/%ld", SPOOLDIR, DATADIR, jobid);
if ((fd = creat(name, FILEPERM)) < 0) {
res.jobid = 0;
if (n < 0)
res.retcode = htonl(errno);
else
res.retcode = htonl(EIO);
log_msg("client_thread: %s: %s", name,
strerror(res.retcode));
strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);
writen(sockfd, &res, sizeof(struct printresp));
pthread_exit((void *)1);
}

405
406
407
408
409
410

/*
* .
*/
first = 1;
while ((nr = tread(sockfd, buf, IOBUFSZ, 20)) > 0) {
if (first) {

903

21.5.
411
412
413
414

first = 0;
if (strncmp(buf, "%!PS", 4) != 0)
req.flags|= PR_TEXT;
}

[386404]
, , get_new
jobno, 
. var/spool/
printer/data/jobid, jobid 
. ,
( FILEPERM
S_IRUSR|S_IWUSR print.h).
, ,
pthre
ad_exit.
[405414] ,
. , 
,
PostScript. 
%!PS, ,
, PR_TEXT . ( 
, ,
print t.) PostScript 
,
[Adobe Systems 1999]
.
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430

nw = write(fd, buf, nr);


if (nw != nr) {
if (nw < 0)
res.retcode = htonl(errno);
else
res.retcode = htonl(EIO);
log_msg("client_thread: %s: %s", name,
strerror(res.retcode));
close(fd);
strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);
writen(sockfd, &res, sizeof(struct printresp));
unlink(name);
pthread_exit((void *)1);
}
}
close(fd);

431
432
433
434
435
436

/*
* .
*/
sprintf(name, "%s/%s/%ld", SPOOLDIR, REQDIR, jobid);
fd = creat(name, FILEPERM);
if (fd < 0) {

904
437
438
439
440
441
442
443
444
445
446
447
448
449

21.
res.jobid = 0;
if (n < 0)
res.retcode = htonl(errno);
else
res.retcode = htonl(EIO);
log_msg("client_thread: %s: %s", name,
strerror(res.retcode));
strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);
writen(sockfd, &res, sizeof(struct printresp));
sprintf(name, "%s/%s/%ld", SPOOLDIR, DATADIR, jobid);
unlink(name);
pthread_exit((void *)1);
}

[415430] , .
, , 
, , 

pthread_exit.
, ,
.
[431449] /var/spool/printer/reqs/jobid,
. ,
, 
, .
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467

nw = write(fd, &req, sizeof(struct printreq));


if (nw != sizeof(struct printreq)) {
res.jobid = 0;
if (nw < 0)
res.retcode = htonl(errno);
else
res.retcode = htonl(EIO);
log_msg("client_thread: %s: %s", name,
strerror(res.retcode));
close(fd);
strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);
writen(sockfd, &res, sizeof(struct printresp));
unlink(name);
sprintf(name, "%s/%s/%ld", SPOOLDIR, DATADIR, jobid);
unlink(name);
pthread_exit((void *)1);
}
close(fd);

468
469
470
471
472
473

/*
* .
*/
res.retcode = 0;
res.jobid = htonl(jobid);
sprintf(res.msg, "request ID %ld", jobid);

21.5.
474

writen(sockfd, &res, sizeof(struct printresp));

475
476
477
478
479
480
481
482

/*
* .
*/
log_msg(" %ld", jobid);
add_job(&req, jobid);
pthread_cleanup_pop(1);
return((void *)0);

905

[450466] printreq . 
,
, , 
.
[467474]

(retcode = 0).
[475482] add_job, , pth
read_cleanup_pop, . 
return.
:
, . 
,
,
. , ,
.
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504

/*
* .
*
* : workerlock.
*/
void
add_worker(pthread_t tid, int sockfd)
{
struct worker_thread *wtp;
if ((wtp = malloc(sizeof(struct worker_thread))) == NULL) {
log_ret("add_worker: malloc");
pthread_exit((void *)1);
}
wtp>tid = tid;
wtp>sockfd = sockfd;
pthread_mutex_lock(&workerlock);
wtp>prev = NULL;
wtp>next = workers;
if (workers == NULL)
workers = wtp;
else
workers>prev = wtp;

906

21.

505
506

507
508
509
510
511
512
513
514
515

/*
* .
*
* : workerlock.
*/
void
kill_workers(void)
{
struct worker_thread *wtp;

516
517
518
519
520

pthread_mutex_unlock(&workerlock);

pthread_mutex_lock(&workerlock);
for (wtp = workers; wtp != NULL; wtp = wtp>next)
pthread_cancel(wtp>tid);
pthread_mutex_unlock(&workerlock);
}

[483506] add_worker worker_thread


. , 
, workerlock, 
.
[507520] kill_workers 
.
workerlock. , pthread_cancel 
, 
, .
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542

/*
* .
*
* : workerlock.
*/
void
client_cleanup(void *arg)
{
struct worker_thread *wtp;
pthread_t
tid;
tid = (pthread_t)arg;
pthread_mutex_lock(&workerlock);
for (wtp = workers; wtp != NULL; wtp = wtp>next) {
if (wtp>tid == tid) {
if (wtp>next != NULL)
wtp>next>prev = wtp>prev;
if (wtp>prev != NULL)
wtp>prev>next = wtp>next;
else
workers = wtp>next;
break;
}

21.5.
543
544
545
546
547
548
549

907

}
pthread_mutex_unlock(&workerlock);
if (wtp != NULL) {
close(wtp>sockfd);
free(wtp);
}
}

[521543] client_cleanup ,
. ,
pthread_exit pthread_cleanup_pop 

. ,
.
workerlock 
. ,
.
[544549] workerlock, , 
, , 
worker_thread.
workerlock, 
, kill_workers
, , kill_workers ,
.
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574

/*
* .
*
* : configlock.
*/
void *
signal_thread(void *arg)
{
int err, signo;
for (;;) {
err = sigwait(&mask, &signo);
if (err != 0)
log_quit(" sigwait: %s", strerror(err));
switch (signo) {
case SIGHUP:
/*
* .
*/
pthread_mutex_lock(&configlock);
reread = 1;
pthread_mutex_unlock(&configlock);
break;
case SIGTERM:
kill_workers();
log_msg(" %s", strsignal(signo));

908

21.

575
576
577
578
579
580
581

exit(0);
default:
kill_workers();
log_quit(" %d", signo);
}
}
}

[550563] signal_thread ,
. , 
main, SIGHUP SIGTERM.
sigwait, .
,
.
[564571] SIGHUP, configlock, 
1 reread .

.
[572575] SIGTERM, 
kill_workers,
exit, .
[576581] , ,
log_quit,
.
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604

/*
* IPP.
*
* : .
*/
char *
add_option(char *cp, int tag, char *optname, char *optval)
{
int n;
union {
int16_t s;
char c[2];
} u;
*cp++ = tag;
n = strlen(optname);
u.s = htons(n);
*cp++ = u.c[0];
*cp++ = u.c[1];
strcpy(cp, optname);
cp += n;
n = strlen(optval);
u.s = htons(n);
*cp++ = u.c[0];

21.5.
605
606
607
608

909

*cp++ = u.c[1];
strcpy(cp, optval);
return(cp + n);
}

[582594] add_option
IPP, . . 21.3 ,
1 , 
, 2 , 
, ,
, , .
IPP 
, . 
, SPARC, , 
. ,
,
, int16_t.
, .
(union), 16 
2 .
[595608]
.
.

, .
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632

/*
* , .
*
* : joblock configlock.
*/
void *
printer_thread(void *arg)
{
struct job *jp;
int
hlen, ilen, sockfd, fd, nr, nw;
char
*icp, *hcp;
struct
ipp_hdr *hp;
struct
stat sbuf;
struct iovec iov[2];
char
name[FILENMSZ];
char
hbuf[HBUFSZ];
char
ibuf[IBUFSZ];
char
buf[IOBUFSZ];
char
str[64];
for (;;) {
/*
* .
*/
pthread_mutex_lock(&joblock);

910

21.

633
634
635
636
637
638
639

while (jobhead == NULL) {


log_msg("printer_thread: ...");
pthread_cond_wait(&jobwait, &joblock);
}
remove_job(jp = jobhead);
log_msg("printer_thread: %ld", jp>jobid);
pthread_mutex_unlock(&joblock);

640

update_jobno();

[609627] printer_thread , 
. icp ibuf 
IPP, hcp hbuf
HTTP.
. HTTP ASCII,
IPP, . 
writev 
.
[628640] 
, .
joblock. 
, pthread_cond_wait,
. ,
remove_job.
,
update_jobno, /var/spool/
printer/jobno.
641
642
643
644
645
646
647
648
649
650
651
652
653
654

/*
* .
*/
pthread_mutex_lock(&configlock);
if (reread) {
freeaddrinfo(printer);
printer = NULL;
printer_name = NULL;
reread = 0;
pthread_mutex_unlock(&configlock);
init_printer();
} else {
pthread_mutex_unlock(&configlock);
}

655
656
657
658
659
660
661
662

/*
* .
*/
sprintf(name, "%s/%s/%ld", SPOOLDIR, DATADIR, jp>jobid);
if ((fd = open(name, O_RDONLY)) < 0) {
log_msg(" %ld %s: %s",
jp>jobid, name, strerror(errno));
free(jp);

21.5.
663
664
665
666
667
668
669
670
671

911

continue;
}
if (fstat(fd, &sbuf) < 0) {
log_msg(" %ld  fstat %s: %s",
jp>jobid, name, strerror(errno));
free(jp);
close(fd);
continue;
}

[641654] , , 
. confi
glock reread.
, , addrinfo 
, , init_printer, 
.
main 
, ,
 , 
configlock reread.
: 
, 
,
( 11.6).
[655671] , ,
, job, 
.
fstat, . ,
, , job,
.
672
673
674
675
676
677
678
679
680
681
682

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {


log_msg(" %ld : %s",
jp>jobid, strerror(errno));
goto defer;
}
if (connect_retry(sockfd, printer>ai_addr,
printer>ai_addrlen) < 0) {
log_msg(" %ld : %s",
jp>jobid, strerror(errno));
goto defer;
}

683
684
685
686
687
688
689
690

/*
* IPP.
*/
icp = ibuf;
hp = (struct ipp_hdr *)icp;
hp>major_version = 1;
hp>minor_version = 1;
hp>operation = htons(OP_PRINT_JOB);

912
691
692
693
694
695
696
697
698
699

21.
hp>request_id = htonl(jp>jobid);
icp += offsetof(struct ipp_hdr, attr_group);
*icp++ = TAG_OPERATION_ATTR;
icp = add_option(icp, TAG_CHARSET, "attributescharset",
"utf8");
icp = add_option(icp, TAG_NATULANG,
"attributesnaturallanguage", "enus");
sprintf(str, "http://%s:%d", printer_name, IPP_PORT);
icp = add_option(icp, TAG_URI, "printeruri", str);

[672682] . 
socket , defer, 
, .
, connect_retry, 
.
[683699] IPP. 
. htons
htonl 2 4
,
, .

. add_option
. . 21.1 
. 
. UTF8, 
.
enus, . 

(URI Universal Resource Identifier). http://prin
ter_name:631. (
URI ,
, .)
700
701
702
703
704
705
706
707
708
709
710
711
712

icp = add_option(icp, TAG_NAMEWOLANG,


"requestingusername", jp>req.usernm);
icp = add_option(icp, TAG_NAMEWOLANG, "jobname",
jp>req.jobnm);
if (jp>req.flags & PR_TEXT) {
icp = add_option(icp, TAG_MIMETYPE, "documentformat",
"text/plain");
} else {
icp = add_option(icp, TAG_MIMETYPE, "documentformat",
"application/postscript");
}
*icp++ = TAG_END_OF_ATTR;
ilen = icp  ibuf;

713
714
715
716

/*
* HTTP.
*/
hcp = hbuf;

21.5.
717
718
719
720
721
722
723
724
725
726
727
728

913

sprintf(hcp, "POST /%s/ipp HTTP/1.1\r\n", printer_name);


hcp += strlen(hcp);
sprintf(hcp, "ContentLength: %ld\r\n",
(long)sbuf.st_size + ilen);
hcp += strlen(hcp);
strcpy(hcp, "ContentType: application/ipp\r\n");
hcp += strlen(hcp);
sprintf(hcp, "Host: %s:%d\r\n", printer_name, IPP_PORT);
hcp += strlen(hcp);
*hcp++ = \r;
*hcp++ = \n;
hlen = hcp  hbuf;

[700712] requestingusername , 
. jobname . 
, print , 
,
, . 
, , documentformat. ,
,
. PostScript , , 
PostScript,
PostScript 
PostScript PCL (Printer Command Language
HewlettPackard). PR_TEXT, 
text/plain, application/
postscript. 
IPP.
[713728] , IPP ,
HTTP. Context
Length IPP . 
ContentType application/ipp. 
HTTP .
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745

/*
* , .
*/
iov[0].iov_base = hbuf;
iov[0].iov_len = hlen;
iov[1].iov_base = ibuf;
iov[1].iov_len = ilen;
if ((nw = writev(sockfd, iov, 2)) != hlen + ilen) {
log_ret(" ");
goto defer;
}
while ((nr = read(fd, buf, IOBUFSZ)) > 0) {
if ((nw = write(sockfd, buf, nr)) != nr) {
if (nw < 0)
log_ret(" ");
else
log_msg(" (%d/%d)", nw, nr);

914

21.

746
747
748
749
750
751
752

goto defer;
}
if (nr < 0) {
log_ret(" %s", name);
goto defer;
}

753
754
755
756
757
758
759
760
761
762

/*
* .
*/
if (printer_status(sockfd, jp)) {
unlink(name);
sprintf(name, "%s/%s/%ld", SPOOLDIR, REQDIR, jp>jobid);
unlink(name);
free(jp);
jp = NULL;
}

[729739] iovec HTTP, 


IPP. writev 
. , 
defer, 

.
[740752] .
IOBUFSZ ,
.  
, defer.
[753762] printer_status,
.
printer_status , 
, . 
, job,
NULL defer.
763
764
765
766
767
768
769
770
771
772

defer:

773
774
775
776

/*
* , .
* 1 .
*

close(fd);
if (sockfd >= 0)
close(sockfd);
if (jp != NULL) {
replace_job(jp);
sleep(60);
}
}
}

21.5.
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796

915

* : .
*/
ssize_t
readmore(int sockfd, char **bpp, int off, int *bszp)
{
ssize_t nr;
char
*bp = *bpp;
int
bsz = *bszp;
if (off >= bsz) {
bsz += IOBUFSZ;
if ((bp = realloc(*bpp, bsz)) == NULL)
log_sys("readmore: ");
*bszp = bsz;
*bpp = bp;
}
if ((nr = tread(sockfd, &bp[off], bszoff, 1)) > 0)
return(off+nr);
else
return(1);
}

[763772] defer . 
, . 

1 . jp
NULL, ,
.
[773796] readmore , 
, . 
, 
bpp bszp .
, 
, , 
.
.
, 1.
797
798
799
800
801
802
803
804
805
806
807
808
809

/*
* . 1,
* , 0 .
*
* : .
*/
int
printer_status(int sockfd, struct job *jp)
{
int
i, success, code, len, found, bufsz;
long
jobid;
ssize_t nr;
char
*statcode, *reason, *cp, *contentlen;

916

21.

810
811

struct ipp_hdr *hp;


char
*bp;

812
813
814
815
816
817
818
819
820

/*
* HTTP IPP.
*
* ContentLength.
*/
success = 0;
bufsz = IOBUFSZ;
if ((bp = malloc(IOBUFSZ)) == NULL)
log_sys("printer_status: ");

821
822
823
824
825
826
827
828
829
830
831
832
833

while ((nr = tread(sockfd, bp, IOBUFSZ, 5)) > 0) {


/*
* . "HTTP/x.y",
* 8 .
*/
cp = bp + 8;
while (isspace((int)*cp))
cp++;
statcode = cp;
while (isdigit((int)*cp))
cp++;
if (cp == statcode) {/* , */
log_msg(bp);

[797811]

printer_status . 
, 
, 
HTTP 100 Continue. 
.

[812833]


, , 5 .
HTTP/1.1 
. .
, .

834
835
836
837
838
839
840
841
842
843
844
845
846

} else {
*cp++ = \0;
reason = cp;
while (*cp != \r && *cp != \n)
cp++;
*cp = \0;
code = atoi(statcode);
if (HTTP_INFO(code))
continue;
if (!HTTP_SUCCESS(code)) { /* : */
bp[nr] = \0;
log_msg(": %s", reason);
break;

917

21.5.
847

848
849
850
851
852
853
854
855
856
857
858
859
860
861
862

/*
* HTTP ,
* IPP.
* ContentLength.
*/
i = cp  bp;
for (;;) {
while (*cp != C && *cp != c && i < nr) {
cp++;
i++;
}
if (i >= nr && /* */
((nr = readmore(sockfd, &bp, i, &bufsz)) < 0))
goto out;
cp = &bp[i];

[834839] , 
.
reason ( ).

.
[840847] . 
, , 
. ,
. , 
.
[848862] ,
IPP. ContentLength, 
C c. HTTP 
, 
.
, . 
readmore realloc,
,
cp , .
863
864
865
866
867
868
869
870
871
872
873
874

if (strncasecmp(cp, "ContentLength:", 15) == 0) {


cp+= 15;
while (isspace((int)*cp))
cp++;
contentlen = cp;
while (isdigit((int)*cp))
cp++;
*cp++ = \0;
i= cp  bp;
len = atoi(contentlen);
break;
}else {

918

21.

875
876
877
878
879
880
881
882

cp++;
i++;
}
}
if (i >= nr && /* */
((nr = readmore(sockfd, &bp, i, &bufsz)) < 0))
goto out;
cp = &bp[i];

883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900

found = 0;
while (!found) { /* HTTP */
while (i < nr  2) {
if (*cp == \n && *(cp + 1) == \r &&
*(cp + 2) ==\n) {
found = 1;
cp+= 3;
i+= 3;
break;
}
cp++;
i++;
}
if (i >= nr && /* */
((nr = readmore(sockfd, &bp, i, &bufsz)) < 0))
goto out;
cp = &bp[i];
}

[863882] ContentLength, 
. 
, for 
, . ,
ContentLength , 
.
[883900] ContentLength, 
HTTP . ,
found .
901
902
903
904

if (nr  i < len && /* */


((nr = readmore(sockfd, &bp, i, &bufsz)) < 0))
goto out;
cp = &bp[i];

905
906
907
908
909
910
911
912

hp = (struct ipp_hdr *)cp;


i = ntohs(hp>status);
jobid = ntohl(hp>request_id);
if (jobid != jp>jobid) {
/*
* . .
*/
log_msg(" %ld, %d", jobid, i);

21.6.
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927

919

break;
}
if (STATCLASS_OK(i))
success = 1;
break;
}
}
out:
free(bp);
if (nr < 0) {
log_msg(" %ld: : %s",
jobid, strerror(errno));
}
return(success);
}

[901904] HTTP. 
, . 
HTTP , ,
HTTP.
HTTP IPP (
ContentLength), .
[905927] IPP.
,
ntohs ntohl 
, 
. , 

while. IPP ,
. 
, 1, 0.

.
PostScript
Xerox Phaser 860. , 
text/plain,
PostScript. , 
,
PostScript, PostScript
, ,
a2ps(1), PostScript.

21.6.
: 
, ,
, 
. , 

920

21.

, 
: , , 
, .

21.1. IPP, ipp.h, 


. , 
printer_status 
, IPP .
21.2. print printd 
. .
21.3. , 
,
. , 
, .
21.4. , 
, .
21.5. , 
, .
21.6. 
.
.

A

,
ISO C POSIX, UNIX, . 
, (
fgets FILE?)
( sprintf 
?). ,

ISO C,
.

, .
.
,
. , 
, .
, 
. , 
.
void

int

int

abort(void);
<stdlib.h>

accept(int sockfd, struct sockaddr *restrict addr,
socklen_t *restrict len);
<sys/socket.h>
()
, 1
access(const char *pathname, int mode);
<unistd.h>
mode: R_OK, W_OK, X_OK, F_OK
0 , 1

. 414

. 662

. 139

922

unsigned
int
alarm(unsigned int seconds);
<unistd.h>
. 385
0 ,

char
*asctime(const struct tm *tmptr);
<time.h>
. 229
,

int

int

void

atexit(void (*func)(void));
<stdlib.h>
0 ,

bind(int sockfd, const struct sockaddr *addr, socklen_t len);
<sys/socket.h>
0 , 1
*calloc(size_t nobj, size_t size);
<stdlib.h>
,
NULL

. 237

. 659

. 245

speed_t cfgetispeed(const struct termios *termptr);


<termios.h>

. 758

speed_t cfgetospeed(const struct termios *termptr);


<termios.h>

. 758

int

int

int

int

int

void

cfsetispeed(struct termios *termptr, speed_t speed);


<termios.h>
0 , 1

. 758

cfsetospeed(struct termios *termptr, speed_t speed);


<termios.h>
0 , 1

. 758

chdir(const char *pathname);


<unistd.h>
0 , 1

. 172

chmod(const char *pathname, mode_t mode);


<sys/stat.h>
mode: S_IS[UG]ID, S_ISVTX, S_I[RWX](USR|GRP|OTH)
0 , 1
chown(const char *pathname, uid_t owner, gid_t group);
<unistd.h>
0 , 1
clearerr(FILE *fp);
<stdio.h>

. 143

. 147

. 190


int

int

923

close(int filedes);
<unistd.h>
0 , 1

. 101

closedir(DIR *dp);
<dirent.h>
0 , 1

. 167

void

closelog(void);
<syslog.h>
unsigned
char
*CMSG_DATA(struct cmsghdr *cp);
<sys/socket.h>
,
cmsghdr

. 511

. 709

struct
cmsghdr *CMSG_FIRSTHDR(struct msghdr *mp);
<sys/socket.h>
. 709
cmsghdr,
msghdr, NULL,
unsigned
int
CMSG_LEN(unsigned int nbytes);
<sys/socket.h>
,
nbytes

. 709

struct
cmsghdr *CMSG_NXTHDR(struct msghdr *mp, struct cmsghdr *cp);
<sys/socket.h>
. 709
cmsghdr,
msghdr,
cmsghdr, NULL,
int

connect(int sockfd, const struct sockaddr *addr, socklen_t len);


<sys/socket.h>
0 , 1

. 660

int

creat(const char *pathname, mode_t mode);


<fcntl.h>
. 100
mode: S_IS[UG]ID, S_ISVTX, S_I[RWX](USR|GRP|OTH)
, ,
, 1

char

*ctermid(char *ptr);
<stdio.h>
. 760

,

char

*ctime(const time_t *calptr);


<time.h>
,

. 229

924

int

dup(int filedes);
<unistd.h>
. 115
,
1

int

dup2(int filedes, int filedes2);


<unistd.h>
. 115
,
1

void

endgrent(void);
<grp.h>

. 220

endhostent(void);
<netdb.h>

. 651

endnetent(void);
<netdb.h>

. 652

endprotoent(void);
<netdb.h>

. 653

endpwent(void);
<pwd.h>

. 216

endservent(void);
<netdb.h>

. 653

void
void
void
void
void
void

endspent(void);
<shadow.h>
: Linux 2.4.22, Solaris 9

. 219

int

execl(const char *pathname, const char *arg0, ... /* (char *) 0 */);


<unistd.h>
. 292
1 ,

int

execle(const char *pathname, const char *arg0, ... /* (char *) 0,


char *const envp[] */);
<unistd.h>
1 ,

. 292

int

execlp(const char *filename, const char *arg0, ... /* (char *) 0 */);


<unistd.h>
. 292
1 ,

int

execv(const char *pathname, char *const argv[]);


<unistd.h>
1 ,

int

. 292

execve(const char *pathname, char *const argv[], char *const envp[]);


<unistd.h>
. 292
1 ,


int

void

void

void

int

int

int

int

int

int

int

void

execvp(const char *filename, char *const argv[]);


<unistd.h>
1 ,

925

. 292

_Exit(int status);
<stdlib.h>

. 235

_exit(int status);
<unistd.h>

. 235

exit(int status);
<stdlib.h>

. 235

fattach(int filedes, const char *path);


<stropts.h>
0 , 1
: Linux 2.4.22, Solaris 9
fchdir(int filedes);
<unistd.h>
0 , 1
fchmod(int filedes, mode_t mode);
<sys/stat.h>
mode: S_IS[UG]ID, S_ISVTX, S_I[RWX](USR|GRP|OTH)
0 , 1

. 690

. 172

. 143

fchown(int filedes, uid_t owner, gid_t group);


<unistd.h>
0 , 1

. 147

fclose(FILE *fp);
<stdio.h>
0 , EOF

. 189

fcntl(int filedes, int cmd, ... /* int arg */);


<fcntl.h>
cmd: F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL,
F_GETOWN, F_SETOWN, F_GETLK, F_SETLK, F_SETLKW
cmd
, 1
fdatasync(int filedes);
<unistd.h>
0 , 1
: Linux 2.4.22, Solaris 9
FD_CLR(int fd, fd_set *fdset);
<sys/select.h>

. 118

. 117

. 563

926
int

int

FILE

A
fdetach(const char *path);
<stropts.h>
0 , 1 .
: Linux 2.4.22, Solaris 9
FD_ISSET(int fd, fd_set *fdset);
<sys/select.h>
, fd
, 0
*fdopen(int filedes, const char *type);
<stdio.h>
type: "r", "w", "a", "r+", "w+", "a+",
FILE
, NULL

. 691

. 563

. 187

void

FD_SET(int fd, fd_set *fdset);


<sys/select.h>

. 563

void

FD_ZERO(fd_set *fdset);
<sys/select.h>

. 563

int

feof(FILE *fp);
<stdio.h>
. 190
(),
, 0 ()

int

ferror(FILE *fp);
<stdio.h>
. 190
(),
, 0 ()

int

fflush(FILE *fp);
<stdio.h>
0 , EOF

int

int

char

fgetc(FILE *fp);
<stdio.h>
,
EOF
fgetpos(FILE *restrict fp, fpos_t *restrict pos);
<stdio.h>
0 ,

*fgets(char *restrict buf, int n, FILE *restrict fp);
<stdio.h>
buf , NULL

. 186

. 190

. 199

. 192

int

fileno(FILE *fp);
<stdio.h>
. 205
,

void

flockfile(FILE *fp);
<stdio.h>

. 482

927


FILE

*fopen(const char *restrict pathname, const char *restrict type);


<stdio.h>
. 187
type: "r", "w", "a", "r+", "w+", "a+",
FILE ,
NULL

pid_t

fork(void);
<unistd.h>
. 268
0 ,
, 1

long

fpathconf(int filedes, int name);


<unistd.h>
. 76
name: _PC_ASYNC_IO, _PC_CHOWN_RESTRICTED,
_PC_FILESIZEBITS, _PC_LINK_MAX, _PC_MAX_CANON,
_PC_MAX_INPUT, _PC_NAME_MAX, _PC_NO_TRUNC,
_PC_PATH_MAX, _PC_PIPE_BUF, _PC_PRIO_IO,
_PC_SYNC_IO, _PC_SYMLINK_MAX, _PC_VDISABLE
,
1

int

fprintf(FILE *restrict fp, const char *restrict format, ...);


<stdio.h>
. 200

,

int

fputc(int c, FILE *fp);


<stdio.h>
. 192
c , EOF

int