PageRenderTime 23ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/lib/libast/common/sfio/sfpkrd.c

https://github.com/richlowe/illumos-gate
C | 291 lines | 236 code | 19 blank | 36 comment | 101 complexity | cd61b98ec2ba262bc402b778b8b8de7a MD5 | raw file
  1. /***********************************************************************
  2. * *
  3. * This software is part of the ast package *
  4. * Copyright (c) 1985-2010 AT&T Intellectual Property *
  5. * and is licensed under the *
  6. * Common Public License, Version 1.0 *
  7. * by AT&T Intellectual Property *
  8. * *
  9. * A copy of the License is available at *
  10. * http://www.opensource.org/licenses/cpl1.0.txt *
  11. * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
  12. * *
  13. * Information and Software Systems Research *
  14. * AT&T Research *
  15. * Florham Park NJ *
  16. * *
  17. * Glenn Fowler <gsf@research.att.com> *
  18. * David Korn <dgk@research.att.com> *
  19. * Phong Vo <kpv@research.att.com> *
  20. * *
  21. ***********************************************************************/
  22. #include "sfhdr.h"
  23. #if !_PACKAGE_ast
  24. #ifndef FIONREAD
  25. #if _sys_ioctl
  26. #include <sys/ioctl.h>
  27. #endif
  28. #endif
  29. #endif
  30. /* Read/Peek a record from an unseekable device
  31. **
  32. ** Written by Kiem-Phong Vo.
  33. */
  34. #define STREAM_PEEK 001
  35. #define SOCKET_PEEK 002
  36. #if __STD_C
  37. ssize_t sfpkrd(int fd, Void_t* argbuf, size_t n, int rc, long tm, int action)
  38. #else
  39. ssize_t sfpkrd(fd, argbuf, n, rc, tm, action)
  40. int fd; /* file descriptor */
  41. Void_t* argbuf; /* buffer to read data */
  42. size_t n; /* buffer size */
  43. int rc; /* record character */
  44. long tm; /* time-out */
  45. int action; /* >0: peeking, if rc>=0, get action records,
  46. <0: no peeking, if rc>=0, get -action records,
  47. =0: no peeking, if rc>=0, must get a single record
  48. */
  49. #endif
  50. {
  51. reg ssize_t r;
  52. reg int ntry, t;
  53. reg char *buf = (char*)argbuf, *endbuf;
  54. if(rc < 0 && tm < 0 && action <= 0)
  55. return sysreadf(fd,buf,n);
  56. t = (action > 0 || rc >= 0) ? (STREAM_PEEK|SOCKET_PEEK) : 0;
  57. #if !_stream_peek
  58. t &= ~STREAM_PEEK;
  59. #endif
  60. #if !_socket_peek
  61. t &= ~SOCKET_PEEK;
  62. #endif
  63. for(ntry = 0; ntry < 2; ++ntry)
  64. {
  65. r = -1;
  66. #if _stream_peek
  67. if((t&STREAM_PEEK) && (ntry == 1 || tm < 0) )
  68. {
  69. struct strpeek pbuf;
  70. pbuf.flags = 0;
  71. pbuf.ctlbuf.maxlen = -1;
  72. pbuf.ctlbuf.len = 0;
  73. pbuf.ctlbuf.buf = NIL(char*);
  74. pbuf.databuf.maxlen = n;
  75. pbuf.databuf.buf = buf;
  76. pbuf.databuf.len = 0;
  77. if((r = ioctl(fd,I_PEEK,&pbuf)) < 0)
  78. { if(errno == EINTR)
  79. return -1;
  80. t &= ~STREAM_PEEK;
  81. }
  82. else
  83. { t &= ~SOCKET_PEEK;
  84. if(r > 0 && (r = pbuf.databuf.len) <= 0)
  85. { if(action <= 0) /* read past eof */
  86. r = sysreadf(fd,buf,1);
  87. return r;
  88. }
  89. if(r == 0)
  90. r = -1;
  91. else if(r > 0)
  92. break;
  93. }
  94. }
  95. #endif /* stream_peek */
  96. if(ntry == 1)
  97. break;
  98. /* poll or select to see if data is present. */
  99. while(tm >= 0 || action > 0 ||
  100. /* block until there is data before peeking again */
  101. ((t&STREAM_PEEK) && rc >= 0) ||
  102. /* let select be interrupted instead of recv which autoresumes */
  103. (t&SOCKET_PEEK) )
  104. { r = -2;
  105. #if _lib_poll
  106. if(r == -2)
  107. {
  108. struct pollfd po;
  109. po.fd = fd;
  110. po.events = POLLIN;
  111. po.revents = 0;
  112. if((r = SFPOLL(&po,1,tm)) < 0)
  113. { if(errno == EINTR)
  114. return -1;
  115. else if(errno == EAGAIN)
  116. { errno = 0;
  117. continue;
  118. }
  119. else r = -2;
  120. }
  121. else r = (po.revents&POLLIN) ? 1 : -1;
  122. }
  123. #endif /*_lib_poll*/
  124. #if _lib_select
  125. if(r == -2)
  126. {
  127. #if _hpux_threads && vt_threaded
  128. #define fd_set int
  129. #endif
  130. fd_set rd;
  131. struct timeval tmb, *tmp;
  132. FD_ZERO(&rd);
  133. FD_SET(fd,&rd);
  134. if(tm < 0)
  135. tmp = NIL(struct timeval*);
  136. else
  137. { tmp = &tmb;
  138. tmb.tv_sec = tm/SECOND;
  139. tmb.tv_usec = (tm%SECOND)*SECOND;
  140. }
  141. r = select(fd+1,&rd,NIL(fd_set*),NIL(fd_set*),tmp);
  142. if(r < 0)
  143. { if(errno == EINTR)
  144. return -1;
  145. else if(errno == EAGAIN)
  146. { errno = 0;
  147. continue;
  148. }
  149. else r = -2;
  150. }
  151. else r = FD_ISSET(fd,&rd) ? 1 : -1;
  152. }
  153. #endif /*_lib_select*/
  154. if(r == -2)
  155. {
  156. #if !_lib_poll && !_lib_select /* both poll and select can't be used */
  157. #ifdef FIONREAD /* quick and dirty check for availability */
  158. long nsec = tm < 0 ? 0 : (tm+999)/1000;
  159. while(nsec > 0 && r < 0)
  160. { long avail = -1;
  161. if((r = ioctl(fd,FIONREAD,&avail)) < 0)
  162. { if(errno == EINTR)
  163. return -1;
  164. else if(errno == EAGAIN)
  165. { errno = 0;
  166. continue;
  167. }
  168. else /* ioctl failed completely */
  169. { r = -2;
  170. break;
  171. }
  172. }
  173. else r = avail <= 0 ? -1 : (ssize_t)avail;
  174. if(r < 0 && nsec-- > 0)
  175. sleep(1);
  176. }
  177. #endif
  178. #endif
  179. }
  180. if(r > 0) /* there is data now */
  181. { if(action <= 0 && rc < 0)
  182. return sysreadf(fd,buf,n);
  183. else r = -1;
  184. }
  185. else if(tm >= 0) /* timeout exceeded */
  186. return -1;
  187. else r = -1;
  188. break;
  189. }
  190. #if _socket_peek
  191. if(t&SOCKET_PEEK)
  192. {
  193. #if __MACH__ && __APPLE__
  194. /*
  195. * work around macos 10.4 recv(MSG_PEEK) bug that consumes pipe() data
  196. */
  197. struct stat st;
  198. static int recv_peek_ok;
  199. if (!recv_peek_ok)
  200. {
  201. int fds[2];
  202. char tst[2];
  203. tst[0] = 'a';
  204. tst[1] = 'z';
  205. recv_peek_ok = (!pipe(fds) && write(fds[1], tst, 2) && recv(fds[0], tst, 1, MSG_PEEK) == 1 && tst[0] == 'a' && recv(fds[0], tst, 1, MSG_PEEK) == 1 && tst[0] == 'a') ? 1 : -1;
  206. close(fds[0]);
  207. close(fds[1]);
  208. }
  209. if (recv_peek_ok < 0 && !fstat(fd, &st) && !S_ISSOCK(st.st_mode))
  210. {
  211. r = -1;
  212. t &= ~SOCKET_PEEK;
  213. }
  214. else
  215. #endif
  216. while((r = recv(fd,(char*)buf,n,MSG_PEEK)) < 0)
  217. { if(errno == EINTR)
  218. return -1;
  219. else if(errno == EAGAIN)
  220. { errno = 0;
  221. continue;
  222. }
  223. t &= ~SOCKET_PEEK;
  224. break;
  225. }
  226. if(r >= 0)
  227. { t &= ~STREAM_PEEK;
  228. if(r > 0)
  229. break;
  230. else /* read past eof */
  231. { if(action <= 0)
  232. r = sysreadf(fd,buf,1);
  233. return r;
  234. }
  235. }
  236. }
  237. #endif
  238. }
  239. if(r < 0)
  240. { if(tm >= 0 || action > 0)
  241. return -1;
  242. else /* get here means: tm < 0 && action <= 0 && rc >= 0 */
  243. { /* number of records read at a time */
  244. if((action = action ? -action : 1) > (int)n)
  245. action = n;
  246. r = 0;
  247. while((t = sysreadf(fd,buf,action)) > 0)
  248. { r += t;
  249. for(endbuf = buf+t; buf < endbuf;)
  250. if(*buf++ == rc)
  251. action -= 1;
  252. if(action == 0 || (int)(n-r) < action)
  253. break;
  254. }
  255. return r == 0 ? t : r;
  256. }
  257. }
  258. /* successful peek, find the record end */
  259. if(rc >= 0)
  260. { reg char* sp;
  261. t = action == 0 ? 1 : action < 0 ? -action : action;
  262. for(endbuf = (sp = buf)+r; sp < endbuf; )
  263. if(*sp++ == rc)
  264. if((t -= 1) == 0)
  265. break;
  266. r = sp - buf;
  267. }
  268. /* advance */
  269. if(action <= 0)
  270. r = sysreadf(fd,buf,r);
  271. return r;
  272. }