fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 262 lines 5.3 kB view raw
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}