µOS++ IIIe Reference 7.0.0
The third edition of µOS++, a POSIX inspired open source framework, written in C++
Loading...
Searching...
No Matches
io.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ distribution.
3 * (https://github.com/micro-os-plus)
4 * Copyright (c) 2015 Liviu Ionescu.
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
35
37
38#include <cassert>
39#include <cerrno>
40#include <cstdarg>
41
42// ----------------------------------------------------------------------------
43
44#if defined(__clang__)
45#pragma clang diagnostic ignored "-Wc++98-compat"
46#endif
47
48// ----------------------------------------------------------------------------
49
50// Variadic calls are processed in two steps, first prepare a
51// va_list structure, then call implementation functions like doOpen()
52// doIoctl(), that use 'va_list args'.
53
54namespace os
55{
56 namespace posix
57 {
58 // ------------------------------------------------------------------------
59
60 io*
61 open (const char* path, int oflag, ...)
62 {
63 // Forward to the variadic version of the function.
64 std::va_list args;
65 va_start(args, oflag);
66 io* const ret = vopen (path, oflag, args);
67 va_end(args);
68
69 return ret;
70 }
71
77 io*
78 vopen (const char* path, int oflag, std::va_list args)
79 {
80#if defined(OS_TRACE_POSIX_IO_IO)
81 trace::printf ("io::%s(\"%s\")\n", __func__, path ? path : "");
82#endif
83
84 if (path == nullptr)
85 {
86 errno = EFAULT;
87 return nullptr;
88 }
89
90 if (*path == '\0')
91 {
92 errno = ENOENT;
93 return nullptr;
94 }
95
96 errno = 0;
97
99 while (true)
100 {
101 // Check if path is a device.
103 if (io != nullptr)
104 {
105 // If so, use the implementation to open the device.
106 int oret = static_cast<device*> (io)->vopen (path, oflag, args);
107 if (oret < 0)
108 {
109 // Open failed.
110 return nullptr;
111 }
112
113 // File descriptor already allocated by device.
114 break;
115 }
116
117 // Check if a regular file.
118 auto adjusted_path = path;
120 &adjusted_path);
121
122 // The manager will return null if there are no file systems
123 // registered, no need to check this condition separately.
124 if (fs == nullptr)
125 {
126 errno = EBADF;
127 return nullptr;
128 }
129
130 // Use the file system implementation to open the file, using
131 // the adjusted path (mount point prefix removed).
132 io = fs->vopen (adjusted_path, oflag, args);
133 if (io == nullptr)
134 {
135 // Open failed.
136 return nullptr;
137 }
138
139 break;
140 }
141
142 // Return a valid pointer to an object derived from io, or nullptr.
143
144#if defined(OS_TRACE_POSIX_IO_IO)
145 trace::printf ("io::%s(\"%s\")=%p fd=%d\n", __func__, path, io,
146 io->file_descriptor ());
147#endif
148 return io;
149 }
150
151 // ========================================================================
152
153 io::io (io_impl& impl, type t) :
154 impl_ (impl), //
155 type_ (t)
156 {
157#if defined(OS_TRACE_POSIX_IO_IO)
158 trace::printf ("io::%s()=%p\n", __func__, this);
159#endif
160
161 file_descriptor_ = no_file_descriptor;
162 }
163
165 {
166#if defined(OS_TRACE_POSIX_IO_IO)
167 trace::printf ("io::%s() @%p\n", __func__, this);
168#endif
169
170 file_descriptor_ = no_file_descriptor;
171 }
172
173 // ------------------------------------------------------------------------
174
175 int
177 {
178#if defined(OS_TRACE_POSIX_IO_IO)
179 trace::printf ("io::%s() @%p\n", __func__, this);
180#endif
181
182 if (!impl ().do_is_opened ())
183 {
184 errno = EBADF; // Not opened.
185 return -1;
186 }
187
188 errno = 0;
189
190 // Execute the implementation specific code.
191 int ret = impl ().do_close ();
192
193 // Remove this IO from the file descriptors registry.
194 file_descriptors_manager::deallocate (file_descriptor_);
195 file_descriptor_ = no_file_descriptor;
196
197 return ret;
198 }
199
200 io*
202 {
203#if defined(OS_TRACE_POSIX_IO_IO)
204 trace::printf ("io::%s() @%p\n", __func__, this);
205#endif
206
208 if (fd < 0)
209 {
210 // If allocation failed, close this object.
211 impl ().do_close ();
213 return nullptr;
214 }
215
216#if defined(OS_TRACE_POSIX_IO_IO)
217 trace::printf ("io::%s() @%p fd=%d\n", __func__, this, fd);
218#endif
219
220 // Return a valid pointer to an object derived from `io`.
221 return this;
222 }
223
224 // ------------------------------------------------------------------------
225
226 // All these wrappers are required to clear 'errno'.
227
228 ssize_t
229 io::read (void* buf, std::size_t nbyte)
230 {
231#if defined(OS_TRACE_POSIX_IO_IO)
232 trace::printf ("io::%s(0x0%X, %u) @%p\n", __func__, buf, nbyte, this);
233#endif
234
235 if (buf == nullptr)
236 {
237 errno = EFAULT;
238 return -1;
239 }
240
241 if (!impl ().do_is_opened ())
242 {
243 errno = EBADF; // Not opened.
244 return -1;
245 }
246
247 if (!impl ().do_is_connected ())
248 {
249 errno = EIO; // Not opened.
250 return -1;
251 }
252
253 errno = 0;
254
255 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html
256 // Before any action described below is taken, and if nbyte is zero,
257 // the read() function may detect and return errors as described below.
258 // In the absence of errors, or if error detection is not performed,
259 // the read() function shall return zero and have no other results.
260 if (nbyte == 0)
261 {
262 return 0; // Nothing to do.
263 }
264
265 // Execute the implementation specific code.
266 ssize_t ret = impl ().do_read (buf, nbyte);
267 if (ret >= 0)
268 {
269 impl ().offset_ += ret;
270 }
271
272#if defined(OS_TRACE_POSIX_IO_IO)
273 trace::printf ("io::%s(0x0%X, %u) @%p n=%d\n", __func__, buf, nbyte, this,
274 ret);
275#endif
276 return ret;
277 }
278
279 ssize_t
280 io::write (const void* buf, std::size_t nbyte)
281 {
282#if defined(OS_TRACE_POSIX_IO_IO)
283 trace::printf ("io::%s(0x0%X, %u) @%p\n", __func__, buf, nbyte, this);
284#endif
285
286 if (buf == nullptr)
287 {
288 errno = EFAULT;
289 return -1;
290 }
291
292 if (!impl ().do_is_opened ())
293 {
294 errno = EBADF; // Not opened.
295 return -1;
296 }
297
298 if (!impl ().do_is_connected ())
299 {
300 errno = EIO; // Not opened.
301 return -1;
302 }
303
304 errno = 0;
305
306 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html
307 // Before any action described below is taken, and if nbyte is zero
308 // and the file is a regular file, the write() function may detect and
309 // return errors as described below. In the absence of errors, or if
310 // error detection is not performed, the write() function shall return
311 // zero and have no other results. If nbyte is zero and the file is
312 // not a regular file, the results are unspecified.
313 if (nbyte == 0)
314 {
315 return 0; // Nothing to do.
316 }
317
318 // Execute the implementation specific code.
319 ssize_t ret = impl ().do_write (buf, nbyte);
320 if (ret >= 0)
321 {
322 impl ().offset_ += ret;
323 }
324
325#if defined(OS_TRACE_POSIX_IO_IO)
326 trace::printf ("io::%s(0x0%X, %u) @%p n=%d\n", __func__, buf, nbyte, this,
327 ret);
328#endif
329 return ret;
330 }
331
332 ssize_t
333 io::writev (const struct iovec* iov, int iovcnt)
334 {
335#if defined(OS_TRACE_POSIX_IO_IO)
336 trace::printf ("io::%s(0x0%X, %d) @%p\n", __func__, iov, iovcnt, this);
337#endif
338
339 if (iov == nullptr)
340 {
341 errno = EFAULT;
342 return -1;
343 }
344
345 if (iovcnt <= 0)
346 {
347 errno = EINVAL;
348 return -1;
349 }
350
351 if (!impl ().do_is_opened ())
352 {
353 errno = EBADF; // Not opened.
354 return -1;
355 }
356
357 if (!impl ().do_is_connected ())
358 {
359 errno = EIO; // Not opened.
360 return -1;
361 }
362
363 errno = 0;
364
365 // Execute the implementation specific code.
366 ssize_t ret = impl ().do_writev (iov, iovcnt);
367 if (ret >= 0)
368 {
369 impl ().offset_ += ret;
370 }
371 return ret;
372 }
373
374 int
375 io::fcntl (int cmd, ...)
376 {
377 // Forward to the variadic version of the function.
378 std::va_list args;
379 va_start(args, cmd);
380 int ret = vfcntl (cmd, args);
381 va_end(args);
382
383 return ret;
384 }
385
386 int
387 io::vfcntl (int cmd, std::va_list args)
388 {
389#if defined(OS_TRACE_POSIX_IO_IO)
390 trace::printf ("io::%s(%d) @%p\n", __func__, cmd, this);
391#endif
392
393 if (!impl ().do_is_opened ())
394 {
395 errno = EBADF; // Not opened.
396 return -1;
397 }
398
399 if (!impl ().do_is_connected ())
400 {
401 errno = EIO; // Not opened.
402 return -1;
403 }
404
405 errno = 0;
406
407 // Execute the implementation specific code.
408 return impl ().do_vfcntl (cmd, args);
409 }
410
411 int
413 {
414 errno = 0;
415
416 // Execute the implementation specific code.
417 return impl ().do_isatty ();
418 }
419
420 // fstat() on a socket returns a zero'd buffer.
421 int
422 io::fstat (struct stat* buf)
423 {
424#if defined(OS_TRACE_POSIX_IO_IO)
425 trace::printf ("io::%s(%p) @%p\n", __func__, buf, this);
426#endif
427
428 if (buf == nullptr)
429 {
430 errno = EFAULT;
431 return -1;
432 }
433
434 if (!impl ().do_is_opened ())
435 {
436 errno = EBADF; // Not opened.
437 return -1;
438 }
439
440 if (!impl ().do_is_connected ())
441 {
442 errno = EIO; // Not opened.
443 return -1;
444 }
445
446 errno = 0;
447
448 // Execute the implementation specific code.
449 return impl ().do_fstat (buf);
450 }
451
452 off_t
453 io::lseek (off_t offset, int whence)
454 {
455#if defined(OS_TRACE_POSIX_IO_IO)
456 trace::printf ("io::%s(%d, %d) @%p\n", __func__, offset, whence, this);
457#endif
458
459 if (!impl ().do_is_opened ())
460 {
461 errno = EBADF; // Not opened.
462 return -1;
463 }
464
465 errno = 0;
466
467 // Execute the implementation specific code.
468 return impl ().do_lseek (offset, whence);
469 }
470
471 // ========================================================================
472
474 {
475#if defined(OS_TRACE_POSIX_IO_IO)
476 trace::printf ("io_impl::%s()=%p\n", __func__, this);
477#endif
478 }
479
481 {
482#if defined(OS_TRACE_POSIX_IO_IO)
483 trace::printf ("io_impl::%s() @%p\n", __func__, this);
484#endif
485 }
486
487 void
489 {
490 return;
491 }
492
493 bool
495 {
496 return true;
497 }
498
499 ssize_t
500 io_impl::do_writev (const struct iovec* iov, int iovcnt)
501 {
502 ssize_t total = 0;
503
504 const struct iovec* p = iov;
505 for (int i = 0; i < iovcnt; ++i, ++p)
506 {
507 ssize_t ret = do_write (p->iov_base, p->iov_len);
508 if (ret < 0)
509 {
510 return ret;
511 }
512 total += ret;
513 }
514 return total;
515 }
516
517#pragma GCC diagnostic push
518#pragma GCC diagnostic ignored "-Wunused-parameter"
519
520 int
521 io_impl::do_vfcntl (int cmd, std::va_list args)
522 {
523 errno = ENOSYS; // Not implemented
524 return -1;
525 }
526
527 int
529 {
530 errno = ENOTTY; // By default, it is not a TTY.
531 return 0;
532 }
533
534 int
536 {
537 errno = ENOSYS; // Not implemented
538 return -1;
539 }
540
541#pragma GCC diagnostic pop
542
543 // ==========================================================================
544 } /* namespace posix */
545} /* namespace os */
546
547// ----------------------------------------------------------------------------
static value_type * identify_device(const char *path)
Base device class.
Definition device.h:78
static int deallocate(file_descriptor_t fildes)
static file_system * identify_mounted(const char **path1, const char **path2=nullptr)
virtual bool do_is_connected(void)
Definition io.cpp:494
virtual ssize_t do_writev(const struct iovec *iov, int iovcnt)
Definition io.cpp:500
virtual int do_close(void)=0
virtual int do_vfcntl(int cmd, std::va_list args)
Definition io.cpp:521
virtual int do_isatty(void)
Definition io.cpp:528
virtual ssize_t do_write(const void *buf, std::size_t nbyte)=0
virtual ~io_impl()
Definition io.cpp:480
virtual void do_deallocate(void)
Definition io.cpp:488
virtual ssize_t do_read(void *buf, std::size_t nbyte)=0
virtual int do_fstat(struct stat *buf)
Definition io.cpp:535
virtual off_t do_lseek(off_t offset, int whence)=0
Base I/O class.
Definition io.h:98
int isatty(void)
Definition io.cpp:412
file_descriptor_t file_descriptor(void) const
Definition io.h:441
io(io_impl &impl, type t)
Definition io.cpp:153
virtual off_t lseek(off_t offset, int whence)
Definition io.cpp:453
io * alloc_file_descriptor(void)
Definition io.cpp:201
io_impl & impl(void) const
Definition io.h:453
virtual int fstat(struct stat *buf)
Definition io.cpp:422
virtual ssize_t write(const void *buf, std::size_t nbyte)
Definition io.cpp:280
int fcntl(int cmd,...)
Definition io.cpp:375
virtual int close(void)
Definition io.cpp:176
void clear_file_descriptor(void)
Definition io.h:435
virtual ssize_t read(void *buf, std::size_t nbyte)
Definition io.cpp:229
virtual ~io()
Definition io.cpp:164
virtual ssize_t writev(const struct iovec *iov, int iovcnt)
Definition io.cpp:333
virtual int vfcntl(int cmd, std::va_list args)
Definition io.cpp:387
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:74
io * open(const char *path, int oflag,...)
Definition io.cpp:61
io * vopen(const char *path, int oflag, std::va_list args)
Definition io.cpp:78
int stat(const char *path, struct stat *buf)
constexpr file_descriptor_t no_file_descriptor
Definition types.h:61
System namespace.
Definition uio.h:56
void * iov_base
Definition uio.h:57
size_t iov_len
Definition uio.h:58