forked from brandongooch/apue.3e
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprint.c
146 lines (132 loc) · 3.2 KB
/
print.c
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
/*
* The client command for printing documents. Opens the file
* and sends it to the printer spooling daemon. Usage:
* print [-t] filename
*/
#include "apue.h"
#include "print.h"
#include <fcntl.h>
#include <pwd.h>
/*
* Needed for logging funtions.
*/
int log_to_stderr = 1;
void submit_file(int, int, const char *, size_t, int);
int
main(int argc, char *argv[])
{
int fd, sfd, err, text, c;
struct stat sbuf;
char *host;
struct addrinfo *ailist, *aip;
err = 0;
text = 0;
while ((c = getopt(argc, argv, "t")) != -1) {
switch (c) {
case 't':
text = 1;
break;
case '?':
err = 1;
break;
}
}
if (err || (optind != argc - 1))
err_quit("usage: print [-t] filename");
if ((fd = open(argv[optind], O_RDONLY)) < 0)
err_sys("print: can't open %s", argv[optind]);
if (fstat(fd, &sbuf) < 0)
err_sys("print: can't stat %s", argv[optind]);
if (!S_ISREG(sbuf.st_mode))
err_quit("print: %s must be a regular file", argv[optind]);
/*
* Get the hostname of the host acting as the print server.
*/
if ((host = get_printserver()) == NULL)
err_quit("print: no print server defined");
if ((err = getaddrlist(host, "print", &ailist)) != 0)
err_quit("print: getaddrinfo error: %s", gai_strerror(err));
for (aip = ailist; aip != NULL; aip = aip->ai_next) {
if ((sfd = connect_retry(AF_INET, SOCK_STREAM, 0,
aip->ai_addr, aip->ai_addrlen)) < 0) {
err = errno;
} else {
submit_file(fd, sfd, argv[optind], sbuf.st_size, text);
exit(0);
}
}
err_exit(err, "print: can't contact %s", host);
}
/*
* Send a file to the printer daemon.
*/
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];
/*
* First build the header.
*/
if ((pwd = getpwuid(geteuid())) == NULL) {
strcpy(req.usernm, "unknown");
} else {
strncpy(req.usernm, pwd->pw_name, USERNM_MAX-1);
req.usernm[USERNM_MAX-1] = '\0';
}
req.size = htonl(nbytes);
if (text)
req.flags = htonl(PR_TEXT);
else
req.flags = 0;
if ((len = strlen(fname)) >= JOBNM_MAX) {
/*
* Truncate the filename (+-5 accounts for the leading
* four characters and the terminating null).
*/
strcpy(req.jobnm, "... ");
strncat(req.jobnm, &fname[len-JOBNM_MAX+5], JOBNM_MAX-5);
} else {
strcpy(req.jobnm, fname);
}
/*
* Send the header to the server.
*/
nw = writen(sockfd, &req, sizeof(struct printreq));
if (nw != sizeof(struct printreq)) {
if (nw < 0)
err_sys("can't write to print server");
else
err_quit("short write (%d/%d) to print server",
nw, sizeof(struct printreq));
}
/*
* Now send the file.
*/
while ((nr = read(fd, buf, IOBUFSZ)) != 0) {
nw = writen(sockfd, buf, nr);
if (nw != nr) {
if (nw < 0)
err_sys("can't write to print server");
else
err_quit("short write (%d/%d) to print server",
nw, nr);
}
}
/*
* Read the response.
*/
if ((nr = readn(sockfd, &res, sizeof(struct printresp))) !=
sizeof(struct printresp))
err_sys("can't read response from server");
if (res.retcode != 0) {
printf("rejected: %s\n", res.msg);
exit(1);
} else {
printf("job ID %ld\n", (long)ntohl(res.jobid));
}
}