-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcsapp.c
More file actions
1234 lines (1009 loc) · 28.3 KB
/
Copy pathcsapp.c
File metadata and controls
1234 lines (1009 loc) · 28.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
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
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* csapp.c - Functions for the CS:APP3e book
*
* Updated 4/2017 shrikang:
* - Improved comments.
*
* Updated 4/2017 szz:
* - Improved style
* - Fixed several warnings
*
* Updated 10/2016 reb:
* - Fixed bug in sio_ltoa that didn't cover negative numbers
*
* Updated 2/2016 droh:
* - Updated open_clientfd and open_listenfd to fail more gracefully
*
* Updated 8/2014 droh:
* - New versions of open_clientfd and open_listenfd are reentrant and
* protocol independent.
*
* - Added protocol-independent inet_ntop and inet_pton functions. The
* inet_ntoa and inet_aton functions are obsolete.
*
* Updated 7/2014 droh:
* - Aded reentrant sio (signal-safe I/O) routines
*
* Updated 4/2013 droh:
* - rio_readlineb: fixed edge case bug
* - rio_readnb: removed redundant EINTR check
*/
/* $begin csapp.c */
#include "csapp.h"
/**************************
* Error-handling functions
**************************/
/* $begin errorfuns */
/* $begin unixerror */
/* Unix-style error */
void unix_error(char *msg) {
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(0);
}
/* $end unixerror */
/* Posix-style error */
void posix_error(int code, char *msg) {
fprintf(stderr, "%s: %s\n", msg, strerror(code));
exit(0);
}
/* Getaddrinfo-style error */
void gai_error(int code, char *msg) {
fprintf(stderr, "%s: %s\n", msg, gai_strerror(code));
exit(0);
}
/* Application error */
void app_error(char *msg) {
fprintf(stderr, "%s\n", msg);
exit(0);
}
/* $end errorfuns */
/* Obsolete gethostbyname error */
void dns_error(char *msg) {
fprintf(stderr, "%s\n", msg);
exit(0);
}
/*********************************************
* Wrappers for Unix process control functions
********************************************/
/**
* @brief Wrapper for libc fork(). Exits on failure.
* @return PID of child process in parent, 0 in child.
*/
pid_t Fork(void) {
pid_t pid;
if ((pid = fork()) < 0) {
unix_error("Fork error");
}
return pid;
}
/**
* @brief Wrapper for libc execve(). Exits on error.
* @param filename Executable file
* @param argv[] Argument vector
* @param envp[] Environment variables
*/
void Execve(const char *filename, char *const argv[], char *const envp[]) {
if (execve(filename, argv, envp) < 0) {
unix_error("Execve error");
}
}
/**
* @brief Wrapper for libc wait(). Exits on failure.
* @param status Pointer to status code.
*
* @return PID of reaped child.
*/
pid_t Wait(int *status) {
pid_t pid;
if ((pid = wait(status)) < 0) {
unix_error("Wait error");
}
return pid;
}
/**
* @brief Wrapper for libc waitpid(). Exits on error.
* @param pid PID to wait on.
* @param iptr Pointer to status code.
* @param options Modify wait behavior.
*
* @return PID of reaped child (see man waitpid(3)).
*/
pid_t Waitpid(pid_t pid, int *iptr, int options) {
pid_t retpid;
if ((retpid = waitpid(pid, iptr, options)) < 0) {
unix_error("Waitpid error");
}
return retpid;
}
/**
* @brief Wrapper for libc kill(). Exits on failure.
* @param pid PID of the process.
* @param signum Signal to send.
*/
void Kill(pid_t pid, int signum) {
int rc;
if ((rc = kill(pid, signum)) < 0) {
unix_error("Kill error");
}
}
void Pause() {
(void) pause();
return;
}
/**
* @brief Wrapper for libc sleep(). Exits on failure.
* @param secs Count of seconds to wait for.
*
* @return Zero after time elapsed, seconds left if interrupted.
*/
unsigned int Sleep(unsigned int secs) {
int rc;
if ((rc = sleep(secs)) < 0) {
unix_error("Sleep error");
}
return rc;
}
unsigned int Alarm(unsigned int seconds) {
return alarm(seconds);
}
/**
* @brief Wrapper for libc setpgid(). Exits on failure.
* @param pid PID of the process.
* @param pgid New PGID.
*/
void Setpgid(pid_t pid, pid_t pgid) {
int rc;
if ((rc = setpgid(pid, pgid)) < 0) {
unix_error("Setpgid error");
}
return;
}
pid_t Getpgrp(void) {
return getpgrp();
}
/************************************
* Wrappers for Unix signal functions
***********************************/
/**
* @brief Wrapper for the new sigaction interface. Exits on error.
* @param signum Signal to set handler for.
* @param handler Handler function.
*
* @return Previous disposition of the signal.
*/
handler_t *Signal(int signum, handler_t *handler) {
struct sigaction action, old_action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
action.sa_flags = SA_RESTART; /* Restart syscalls if possible */
if (sigaction(signum, &action, &old_action) < 0) {
unix_error("Signal error");
}
return old_action.sa_handler;
}
/**
* @brief Wrapper for libc sigprocmask(). Exits on failure.
* @param how How to modify the current mask.
* @param set Set of signals to modify the mask with.
* @param oldset Signal set to save old signal mask.
*/
void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset) {
if (sigprocmask(how, set, oldset) < 0) {
unix_error("Sigprocmask error");
}
return;
}
/**
* @brief Wrapper for libc sigemptyset(). Exits on failure.
* @param set Set to initialize to empty.
*/
void Sigemptyset(sigset_t *set) {
if (sigemptyset(set) < 0) {
unix_error("Sigemptyset error");
}
return;
}
/**
* @brief Wrapper for libc sigfillset(). Exits on failure.
* @param set Set to initialize to full.
*/
void Sigfillset(sigset_t *set) {
if (sigfillset(set) < 0) {
unix_error("Sigfillset error");
}
return;
}
/**
* @brief Wrapper for libc sigaddset(). Exits on failure.
* @param set Set to add signal to.
* @param signum Signal to add.
*/
void Sigaddset(sigset_t *set, int signum) {
if (sigaddset(set, signum) < 0) {
unix_error("Sigaddset error");
}
return;
}
/**
* @brief Wrapper for libc sigdelset(). Exits on failure.
* @param set Set to delete signal from.
* @param signum Signal to delete.
*/
void Sigdelset(sigset_t *set, int signum) {
if (sigdelset(set, signum) < 0) {
unix_error("Sigdelset error");
}
return;
}
/**
* @brief Wrapper for libc sigismember(). Exits on failure.
* @param set Set to check.
* @param signum Signal to check for.
*
* @return 1 if signal present in set, 0 otherwise.
*/
int Sigismember(const sigset_t *set, int signum) {
int rc;
if ((rc = sigismember(set, signum)) < 0) {
unix_error("Sigismember error");
}
return rc;
}
/**
* @brief Wrapper for libc sigsuspend(). Exits on failure.
* @param set Set to check.
*
* @return -1
*/
int Sigsuspend(const sigset_t *set) {
int rc = sigsuspend(set); /* always returns -1 */
if (errno != EINTR) {
unix_error("Sigsuspend error");
}
return rc;
}
/*************************************************************
* The Sio (Signal-safe I/O) package - simple reentrant output
* functions that are safe for signal handlers.
*************************************************************/
/* Private sio functions */
/* $begin sioprivate */
/* sio_reverse - Reverse a string (from K&R) */
static void sio_reverse(char s[]) {
int c, i, j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
/* sio_ltoa - Convert long to base b string (from K&R) */
static void sio_ltoa(long v, char s[], int b) {
int c, i = 0;
int neg = v < 0;
if (neg)
v = -v;
do {
s[i++] = ((c = (v % b)) < 10) ? c + '0' : c - 10 + 'a';
} while ((v /= b) > 0);
if (neg)
s[i++] = '-';
s[i] = '\0';
sio_reverse(s);
}
/* sio_strlen - Return length of string (from K&R) */
static size_t sio_strlen(char s[]) {
int i = 0;
while (s[i] != '\0')
++i;
return i;
}
/* $end sioprivate */
/* Public Sio functions */
/* $begin siopublic */
/* Put string */
ssize_t sio_puts(char s[]) {
return write(STDOUT_FILENO, s, sio_strlen(s)); //line:csapp:siostrlen
}
/* Put long */
ssize_t sio_putl(long v) {
char s[128];
sio_ltoa(v, s, 10); /* Based on K&R itoa() */ //line:csapp:sioltoa
return sio_puts(s);
}
/* Put error message and exit */
void sio_error(char s[]) {
sio_puts(s);
_exit(1); //line:csapp:sioexit
}
/* $end siopublic */
/*******************************
* Wrappers for the SIO routines
******************************/
ssize_t Sio_putl(long v) {
ssize_t n;
if ((n = sio_putl(v)) < 0) {
sio_error("Sio_putl error");
}
return n;
}
/**
* @brief Wrapper for sio_puts(). Exits on failure.
* @param s[] String to print to stdout.
* @return Number of bytes written.
*/
ssize_t Sio_puts(char s[]) {
ssize_t n;
if ((n = sio_puts(s)) < 0) {
sio_error("Sio_puts error");
}
return n;
}
/**
* @brief Wrapper for sio_error(). Exits on failure.
* @param s[] Error message to print to stdout.
*/
void Sio_error(char s[]) {
sio_error(s);
}
/********************************
* Wrappers for Unix I/O routines
********************************/
/**
* @brief Wrapper for libc open(). Exits on failure.
* @param pathname Path to file.
* @param flags Access mode.
* @param mode File mode bits.
*
* @return New file descriptor if successful.
*/
int Open(const char *pathname, int flags, mode_t mode) {
int rc;
if ((rc = open(pathname, flags, mode)) < 0) {
unix_error("Open error");
}
return rc;
}
/**
* @brief Wrapper for libc read(). Exits on failure.
* @param fd File descriptor.
* @param buf Buffer to read into.
* @param count Number of bytes to read.
*
* @return Number of bytes read.
*/
ssize_t Read(int fd, void *buf, size_t count) {
ssize_t rc;
if ((rc = read(fd, buf, count)) < 0) {
unix_error("Read error");
}
return rc;
}
/**
* @brief Wrapper for libc write(). Exits on failure.
* @param fd File descriptor to write to.
* @param buf Buffer pointing to source data.
* @param count Number of bytes to write.
*
* @return Number of bytes written.
*/
ssize_t Write(int fd, const void *buf, size_t count) {
ssize_t rc;
if ((rc = write(fd, buf, count)) < 0) {
unix_error("Write error");
}
return rc;
}
off_t Lseek(int fildes, off_t offset, int whence) {
off_t rc;
if ((rc = lseek(fildes, offset, whence)) < 0) {
unix_error("Lseek error");
}
return rc;
}
/**
* @brief Close open file descriptor. Exits on failure.
* @param fd File descriptor.
*/
void Close(int fd) {
int rc;
if ((rc = close(fd)) < 0) {
unix_error("Close error");
}
}
int Select(int n, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout) {
int rc;
if ((rc = select(n, readfds, writefds, exceptfds, timeout)) < 0) {
unix_error("Select error");
}
return rc;
}
int Dup2(int fd1, int fd2) {
int rc;
if ((rc = dup2(fd1, fd2)) < 0) {
unix_error("Dup2 error");
}
return rc;
}
void Stat(const char *filename, struct stat *buf) {
if (stat(filename, buf) < 0) {
unix_error("Stat error");
}
}
void Fstat(int fd, struct stat *buf) {
if (fstat(fd, buf) < 0) {
unix_error("Fstat error");
}
}
/*********************************
* Wrappers for directory function
*********************************/
DIR *Opendir(const char *name) {
DIR *dirp = opendir(name);
if (!dirp) {
unix_error("opendir error");
}
return dirp;
}
struct dirent *Readdir(DIR *dirp) {
struct dirent *dep;
errno = 0;
dep = readdir(dirp);
if ((dep == NULL) && (errno != 0)) {
unix_error("readdir error");
}
return dep;
}
int Closedir(DIR *dirp) {
int rc;
if ((rc = closedir(dirp)) < 0) {
unix_error("closedir error");
}
return rc;
}
/***************************************
* Wrappers for memory mapping functions
***************************************/
void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) {
void *ptr;
if ((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *) -1)) {
unix_error("mmap error");
}
return ptr;
}
void Munmap(void *start, size_t length) {
if (munmap(start, length) < 0) {
unix_error("munmap error");
}
}
/***************************************************
* Wrappers for dynamic storage allocation functions
***************************************************/
void *Malloc(size_t size) {
void *p;
if ((p = malloc(size)) == NULL) {
unix_error("Malloc error");
}
return p;
}
void *Realloc(void *ptr, size_t size) {
void *p;
if ((p = realloc(ptr, size)) == NULL) {
unix_error("Realloc error");
}
return p;
}
void *Calloc(size_t nmemb, size_t size) {
void *p;
if ((p = calloc(nmemb, size)) == NULL) {
unix_error("Calloc error");
}
return p;
}
void Free(void *ptr) {
free(ptr);
}
/******************************************
* Wrappers for the Standard I/O functions.
******************************************/
void Fclose(FILE *fp) {
if (fclose(fp) != 0) {
unix_error("Fclose error");
}
}
FILE *Fdopen(int fd, const char *type) {
FILE *fp;
if ((fp = fdopen(fd, type)) == NULL) {
unix_error("Fdopen error");
}
return fp;
}
char *Fgets(char *ptr, int n, FILE *stream) {
char *rptr;
if (((rptr = fgets(ptr, n, stream)) == NULL) && ferror(stream)) {
app_error("Fgets error");
}
return rptr;
}
FILE *Fopen(const char *filename, const char *mode) {
FILE *fp;
if ((fp = fopen(filename, mode)) == NULL) {
unix_error("Fopen error");
}
return fp;
}
void Fputs(const char *ptr, FILE *stream) {
if (fputs(ptr, stream) == EOF) {
unix_error("Fputs error");
}
}
size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t n;
if (((n = fread(ptr, size, nmemb, stream)) < nmemb) && ferror(stream)) {
unix_error("Fread error");
}
return n;
}
void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
if (fwrite(ptr, size, nmemb, stream) < nmemb) {
unix_error("Fwrite error");
}
}
/****************************
* Sockets interface wrappers
****************************/
int Socket(int domain, int type, int protocol) {
int rc;
if ((rc = socket(domain, type, protocol)) < 0) {
unix_error("Socket error");
}
return rc;
}
void Setsockopt(int s, int level, int optname, const void *optval, int optlen) {
int rc;
if ((rc = setsockopt(s, level, optname, optval, optlen)) < 0) {
unix_error("Setsockopt error");
}
}
void Bind(int sockfd, struct sockaddr *my_addr, int addrlen) {
int rc;
if ((rc = bind(sockfd, my_addr, addrlen)) < 0) {
unix_error("Bind error");
}
}
void Listen(int s, int backlog) {
int rc;
if ((rc = listen(s, backlog)) < 0) {
unix_error("Listen error");
}
}
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
int rc;
if ((rc = accept(s, addr, addrlen)) < 0) {
unix_error("Accept error");
}
return rc;
}
void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen) {
int rc;
if ((rc = connect(sockfd, serv_addr, addrlen)) < 0) {
unix_error("Connect error");
}
}
/*******************************
* Protocol-independent wrappers
*******************************/
/* $begin getaddrinfo */
void Getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res) {
int rc;
if ((rc = getaddrinfo(node, service, hints, res)) != 0) {
gai_error(rc, "Getaddrinfo error");
}
}
/* $end getaddrinfo */
void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags) {
int rc;
if ((rc = getnameinfo(sa, salen, host, hostlen, serv,
servlen, flags)) != 0) {
gai_error(rc, "Getnameinfo error");
}
}
void Freeaddrinfo(struct addrinfo *res) {
freeaddrinfo(res);
}
void Inet_ntop(int af, const void *src, char *dst, socklen_t size) {
if (!inet_ntop(af, src, dst, size)) {
unix_error("Inet_ntop error");
}
}
void Inet_pton(int af, const char *src, void *dst) {
int rc;
rc = inet_pton(af, src, dst);
if (rc == 0)
app_error("inet_pton error: invalid dotted-decimal address");
else if (rc < 0)
unix_error("Inet_pton error");
}
/*******************************************
* DNS interface wrappers.
*
* NOTE: These are obsolete because they are not thread safe. Use
* getaddrinfo and getnameinfo instead
***********************************/
/* $begin gethostbyname */
struct hostent *Gethostbyname(const char *name) {
struct hostent *p;
if ((p = gethostbyname(name)) == NULL) {
dns_error("Gethostbyname error");
}
return p;
}
/* $end gethostbyname */
struct hostent *Gethostbyaddr(const char *addr, int len, int type) {
struct hostent *p;
if ((p = gethostbyaddr(addr, len, type)) == NULL) {
dns_error("Gethostbyaddr error");
}
return p;
}
/************************************************
* Wrappers for Pthreads thread control functions
************************************************/
void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
void * (*routine)(void *), void *argp) {
int rc;
if ((rc = pthread_create(tidp, attrp, routine, argp)) != 0) {
posix_error(rc, "Pthread_create error");
}
}
void Pthread_cancel(pthread_t tid) {
int rc;
if ((rc = pthread_cancel(tid)) != 0) {
posix_error(rc, "Pthread_cancel error");
}
}
void Pthread_join(pthread_t tid, void **thread_return) {
int rc;
if ((rc = pthread_join(tid, thread_return)) != 0) {
posix_error(rc, "Pthread_join error");
}
}
/* $begin detach */
void Pthread_detach(pthread_t tid) {
int rc;
if ((rc = pthread_detach(tid)) != 0) {
posix_error(rc, "Pthread_detach error");
}
}
/* $end detach */
void Pthread_exit(void *retval) {
pthread_exit(retval);
}
pthread_t Pthread_self(void) {
return pthread_self();
}
void Pthread_once(pthread_once_t *once_control, void (*init_function)()) {
pthread_once(once_control, init_function);
}
/*******************************
* Wrappers for Posix semaphores
*******************************/
void Sem_init(sem_t *sem, int pshared, unsigned int value) {
if (sem_init(sem, pshared, value) < 0) {
unix_error("Sem_init error");
}
}
void P(sem_t *sem) {
if (sem_wait(sem) < 0) {
unix_error("P error");
}
}
void V(sem_t *sem) {
if (sem_post(sem) < 0) {
unix_error("V error");
}
}
/****************************************
* The Rio package - Robust I/O functions
****************************************/
/*
* rio_readn - Robustly read n bytes (unbuffered)
*/
/* $begin rio_readn */
ssize_t rio_readn(int fd, void *usrbuf, size_t n) {
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nread = read(fd, bufp, nleft)) < 0) {
if (errno != EINTR) {
return -1; /* errno set by read() */
}
/* Interrupted by sig handler return, call read() again */
nread = 0;
} else if (nread == 0) {
break; /* EOF */
}
nleft -= nread;
bufp += nread;
}
return n - nleft; /* Return >= 0 */
}
/* $end rio_readn */
/*
* rio_writen - Robustly write n bytes (unbuffered)
*/
/* $begin rio_writen */
ssize_t rio_writen(int fd, void *usrbuf, size_t n) {
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nwritten = write(fd, bufp, nleft)) <= 0) {
if (errno != EINTR) {
return -1; /* errno set by write() */
}
/* Interrupted by sig handler return, call write() again */
nwritten = 0;
}
nleft -= nwritten;
bufp += nwritten;
}
return n;
}
/* $end rio_writen */
/*
* rio_read - This is a wrapper for the Unix read() function that
* transfers min(n, rio_cnt) bytes from an internal buffer to a user
* buffer, where n is the number of bytes requested by the user and
* rio_cnt is the number of unread bytes in the internal buffer. On
* entry, rio_read() refills the internal buffer via a call to
* read() if the internal buffer is empty.
*/
/* $begin rio_read */
static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n) {
int cnt;
while (rp->rio_cnt <= 0) { /* Refill if buf is empty */
rp->rio_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));
if (rp->rio_cnt < 0) {
if (errno != EINTR) {
return -1; /* errno set by read() */
}
/* Interrupted by sig handler return, nothing to do */
} else if (rp->rio_cnt == 0) {
return 0; /* EOF */
} else {
rp->rio_bufptr = rp->rio_buf; /* Reset buffer ptr */
}
}
/* Copy min(n, rp->rio_cnt) bytes from internal buf to user buf */
cnt = n;
if ((size_t) rp->rio_cnt < n) {
cnt = rp->rio_cnt;
}
memcpy(usrbuf, rp->rio_bufptr, cnt);
rp->rio_bufptr += cnt;
rp->rio_cnt -= cnt;
return cnt;
}
/* $end rio_read */
/*
* rio_readinitb - Associate a descriptor with a read buffer and reset buffer
*/
/* $begin rio_readinitb */
void rio_readinitb(rio_t *rp, int fd) {
rp->rio_fd = fd;
rp->rio_cnt = 0;
rp->rio_bufptr = rp->rio_buf;
}
/* $end rio_readinitb */
/*
* rio_readnb - Robustly read n bytes (buffered)
*/
/* $begin rio_readnb */