fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/drivers/char/char-posix.c *
7 * Created: 2009-03-10 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2009-2010 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <limits.h>
27
28#include <fcntl.h>
29#include <poll.h>
30#include <sys/stat.h>
31#include <unistd.h>
32
33#include <drivers/options.h>
34#include <drivers/char/char.h>
35#include <drivers/char/char-posix.h>
36
37
38static
39int chr_posix_check_fd (int fd, int rd, int wr)
40{
41 int r;
42 struct pollfd pfd[1];
43
44 if (fd < 0) {
45 return (1);
46 }
47
48 pfd[0].fd = fd;
49 pfd[0].events = (rd ? POLLIN : 0) | (wr ? POLLOUT : 0);
50
51 r = poll (pfd, 1, 0);
52
53 if (r < 0) {
54 return (1);
55 }
56
57 if ((pfd[0].revents & (POLLIN | POLLOUT)) == 0) {
58 return (1);
59 }
60
61 return (0);
62}
63
64static
65void chr_posix_close (char_drv_t *cdrv)
66{
67 char_posix_t *drv;
68
69 drv = cdrv->ext;
70
71 if (drv->fd_write > 2) {
72 close (drv->fd_write);
73 }
74
75 if ((drv->fd_read > 2) && (drv->fd_read != drv->fd_write)) {
76 close (drv->fd_read);
77 }
78
79 if (drv->name_write != NULL) {
80 free (drv->name_write);
81 }
82
83 if (drv->name_read != NULL) {
84 free (drv->name_read);
85 }
86
87 if (drv->name != NULL) {
88 free (drv->name);
89 }
90
91 free (drv);
92}
93
94static
95unsigned chr_posix_read (char_drv_t *cdrv, void *buf, unsigned cnt)
96{
97 char_posix_t *drv;
98 ssize_t r;
99
100 drv = cdrv->ext;
101
102 if (drv->fd_read < 0) {
103 return (0);
104 }
105
106 if (chr_posix_check_fd (drv->fd_read, 1, 0)) {
107 return (0);
108 }
109
110#if UINT_MAX > SSIZE_MAX
111 if (cnt > SSIZE_MAX) {
112 cnt = SSIZE_MAX;
113 }
114#endif
115
116 r = read (drv->fd_read, buf, cnt);
117
118 if (r <= 0) {
119 return (0);
120 }
121
122 return (r);
123}
124
125static
126unsigned chr_posix_write (char_drv_t *cdrv, const void *buf, unsigned cnt)
127{
128 char_posix_t *drv;
129 ssize_t r;
130
131 drv = cdrv->ext;
132
133 if (drv->fd_write < 0) {
134 return (cnt);
135 }
136
137 if (chr_posix_check_fd (drv->fd_write, 0, 1)) {
138 return (0);
139 }
140
141#if UINT_MAX > SSIZE_MAX
142 if (cnt > SSIZE_MAX) {
143 cnt = SSIZE_MAX;
144 }
145#endif
146
147 r = write (drv->fd_write, buf, cnt);
148
149 if (r <= 0) {
150 return (0);
151 }
152
153 return (r);
154}
155
156static
157int chr_posix_init (char_posix_t *drv, const char *name)
158{
159 chr_init (&drv->cdrv, drv);
160
161 drv->cdrv.close = chr_posix_close;
162 drv->cdrv.read = chr_posix_read;
163 drv->cdrv.write = chr_posix_write;
164
165 drv->name = NULL;
166 drv->name_read = NULL;
167 drv->name_write = NULL;
168
169 drv->fd_read = -1;
170 drv->fd_write = -1;
171
172 drv->name = drv_get_option (name, "file");
173
174 if (drv->name == NULL) {
175 drv->name_read = drv_get_option (name, "read");
176 drv->name_write = drv_get_option (name, "write");
177 }
178
179 if (drv->name != NULL) {
180 if (strcmp (drv->name, "-") == 0) {
181 drv->fd_read = 0;
182 drv->fd_write = 1;
183 }
184 else if (strcmp (drv->name, "--") == 0) {
185 drv->fd_read = 0;
186 drv->fd_write = 2;
187 }
188 else {
189 drv->fd_read = open (drv->name,
190 O_RDWR | O_CREAT | O_NOCTTY | O_TRUNC,
191 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
192 );
193
194 if (drv->fd_read < 0) {
195 return (1);
196 }
197
198 drv->fd_write = drv->fd_read;
199 }
200 }
201 else if ((drv->name_read != NULL) || (drv->name_write != NULL)) {
202 if (drv->name_read != NULL) {
203 if (strcmp (drv->name_read, "-") == 0) {
204 drv->fd_read = 0;
205 }
206 else {
207 drv->fd_read = open (drv->name_read,
208 O_RDONLY | O_NOCTTY, 0
209 );
210
211 if (drv->fd_read < 0) {
212 return (1);
213 }
214 }
215 }
216
217 if (drv->name_write != NULL) {
218 if (strcmp (drv->name_write, "-") == 0) {
219 drv->fd_write = 1;
220 }
221 else if (strcmp (drv->name_write, "--") == 0) {
222 drv->fd_write = 2;
223 }
224 else {
225 drv->fd_write = open (drv->name_write,
226 O_WRONLY | O_CREAT | O_NOCTTY | O_TRUNC,
227 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
228 );
229
230 if (drv->fd_write < 0) {
231 return (1);
232 }
233 }
234 }
235 }
236 else {
237 if (strncmp (name, "sercon", 6) == 0) {
238 drv->fd_read = 0;
239 drv->fd_write = 1;
240 }
241 }
242
243 return (0);
244}
245
246char_drv_t *chr_posix_open (const char *name)
247{
248 char_posix_t *drv;
249
250 drv = malloc (sizeof (char_posix_t));
251
252 if (drv == NULL) {
253 return (NULL);
254 }
255
256 if (chr_posix_init (drv, name)) {
257 chr_posix_close (&drv->cdrv);
258 return (NULL);
259 }
260
261 return (&drv->cdrv);
262}