1 | /* GLIB - Library of useful routines for C programming |
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | * |
4 | * giounix.c: IO Channels using unix file descriptors |
5 | * Copyright 1998 Owen Taylor |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | /* |
22 | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
23 | * file for a list of people on the GLib Team. See the ChangeLog |
24 | * files for a list of changes. These files are distributed with |
25 | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
26 | */ |
27 | |
28 | /* |
29 | * MT safe |
30 | */ |
31 | |
32 | #include "config.h" |
33 | |
34 | #define _POSIX_SOURCE /* for SSIZE_MAX */ |
35 | |
36 | #include <sys/types.h> |
37 | #include <sys/stat.h> |
38 | #include <stdio.h> |
39 | #include <unistd.h> |
40 | #include <errno.h> |
41 | #include <string.h> |
42 | #include <fcntl.h> |
43 | #include <glib/gstdio.h> |
44 | |
45 | #include "giochannel.h" |
46 | |
47 | #include "gerror.h" |
48 | #include "gfileutils.h" |
49 | #include "gstrfuncs.h" |
50 | #include "gtestutils.h" |
51 | |
52 | /* |
53 | * Unix IO Channels |
54 | */ |
55 | |
56 | typedef struct _GIOUnixChannel GIOUnixChannel; |
57 | typedef struct _GIOUnixWatch GIOUnixWatch; |
58 | |
59 | struct _GIOUnixChannel |
60 | { |
61 | GIOChannel channel; |
62 | gint fd; |
63 | }; |
64 | |
65 | struct _GIOUnixWatch |
66 | { |
67 | GSource source; |
68 | GPollFD pollfd; |
69 | GIOChannel *channel; |
70 | GIOCondition condition; |
71 | }; |
72 | |
73 | |
74 | static GIOStatus g_io_unix_read (GIOChannel *channel, |
75 | gchar *buf, |
76 | gsize count, |
77 | gsize *bytes_read, |
78 | GError **err); |
79 | static GIOStatus g_io_unix_write (GIOChannel *channel, |
80 | const gchar *buf, |
81 | gsize count, |
82 | gsize *bytes_written, |
83 | GError **err); |
84 | static GIOStatus g_io_unix_seek (GIOChannel *channel, |
85 | gint64 offset, |
86 | GSeekType type, |
87 | GError **err); |
88 | static GIOStatus g_io_unix_close (GIOChannel *channel, |
89 | GError **err); |
90 | static void g_io_unix_free (GIOChannel *channel); |
91 | static GSource* g_io_unix_create_watch (GIOChannel *channel, |
92 | GIOCondition condition); |
93 | static GIOStatus g_io_unix_set_flags (GIOChannel *channel, |
94 | GIOFlags flags, |
95 | GError **err); |
96 | static GIOFlags g_io_unix_get_flags (GIOChannel *channel); |
97 | |
98 | static gboolean g_io_unix_prepare (GSource *source, |
99 | gint *timeout); |
100 | static gboolean g_io_unix_check (GSource *source); |
101 | static gboolean g_io_unix_dispatch (GSource *source, |
102 | GSourceFunc callback, |
103 | gpointer user_data); |
104 | static void g_io_unix_finalize (GSource *source); |
105 | |
106 | GSourceFuncs g_io_watch_funcs = { |
107 | g_io_unix_prepare, |
108 | g_io_unix_check, |
109 | g_io_unix_dispatch, |
110 | g_io_unix_finalize, |
111 | NULL, NULL |
112 | }; |
113 | |
114 | static GIOFuncs unix_channel_funcs = { |
115 | g_io_unix_read, |
116 | g_io_unix_write, |
117 | g_io_unix_seek, |
118 | g_io_unix_close, |
119 | g_io_unix_create_watch, |
120 | g_io_unix_free, |
121 | g_io_unix_set_flags, |
122 | g_io_unix_get_flags, |
123 | }; |
124 | |
125 | static gboolean |
126 | g_io_unix_prepare (GSource *source, |
127 | gint *timeout) |
128 | { |
129 | GIOUnixWatch *watch = (GIOUnixWatch *)source; |
130 | GIOCondition buffer_condition = g_io_channel_get_buffer_condition (channel: watch->channel); |
131 | |
132 | *timeout = -1; |
133 | |
134 | /* Only return TRUE here if _all_ bits in watch->condition will be set |
135 | */ |
136 | return ((watch->condition & buffer_condition) == watch->condition); |
137 | } |
138 | |
139 | static gboolean |
140 | g_io_unix_check (GSource *source) |
141 | { |
142 | GIOUnixWatch *watch = (GIOUnixWatch *)source; |
143 | GIOCondition buffer_condition = g_io_channel_get_buffer_condition (channel: watch->channel); |
144 | GIOCondition poll_condition = watch->pollfd.revents; |
145 | |
146 | return ((poll_condition | buffer_condition) & watch->condition); |
147 | } |
148 | |
149 | static gboolean |
150 | g_io_unix_dispatch (GSource *source, |
151 | GSourceFunc callback, |
152 | gpointer user_data) |
153 | |
154 | { |
155 | GIOFunc func = (GIOFunc)callback; |
156 | GIOUnixWatch *watch = (GIOUnixWatch *)source; |
157 | GIOCondition buffer_condition = g_io_channel_get_buffer_condition (channel: watch->channel); |
158 | |
159 | if (!func) |
160 | { |
161 | g_warning ("IO watch dispatched without callback. " |
162 | "You must call g_source_connect()." ); |
163 | return FALSE; |
164 | } |
165 | |
166 | return (*func) (watch->channel, |
167 | (watch->pollfd.revents | buffer_condition) & watch->condition, |
168 | user_data); |
169 | } |
170 | |
171 | static void |
172 | g_io_unix_finalize (GSource *source) |
173 | { |
174 | GIOUnixWatch *watch = (GIOUnixWatch *)source; |
175 | |
176 | g_io_channel_unref (channel: watch->channel); |
177 | } |
178 | |
179 | static GIOStatus |
180 | g_io_unix_read (GIOChannel *channel, |
181 | gchar *buf, |
182 | gsize count, |
183 | gsize *bytes_read, |
184 | GError **err) |
185 | { |
186 | GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel; |
187 | gssize result; |
188 | |
189 | if (count > SSIZE_MAX) /* At least according to the Debian manpage for read */ |
190 | count = SSIZE_MAX; |
191 | |
192 | retry: |
193 | result = read (fd: unix_channel->fd, buf: buf, nbytes: count); |
194 | |
195 | if (result < 0) |
196 | { |
197 | int errsv = errno; |
198 | *bytes_read = 0; |
199 | |
200 | switch (errsv) |
201 | { |
202 | #ifdef EINTR |
203 | case EINTR: |
204 | goto retry; |
205 | #endif |
206 | #ifdef EAGAIN |
207 | case EAGAIN: |
208 | return G_IO_STATUS_AGAIN; |
209 | #endif |
210 | default: |
211 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
212 | code: g_io_channel_error_from_errno (en: errsv), |
213 | message: g_strerror (errnum: errsv)); |
214 | return G_IO_STATUS_ERROR; |
215 | } |
216 | } |
217 | |
218 | *bytes_read = result; |
219 | |
220 | return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; |
221 | } |
222 | |
223 | static GIOStatus |
224 | g_io_unix_write (GIOChannel *channel, |
225 | const gchar *buf, |
226 | gsize count, |
227 | gsize *bytes_written, |
228 | GError **err) |
229 | { |
230 | GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel; |
231 | gssize result; |
232 | |
233 | retry: |
234 | result = write (fd: unix_channel->fd, buf: buf, n: count); |
235 | |
236 | if (result < 0) |
237 | { |
238 | int errsv = errno; |
239 | *bytes_written = 0; |
240 | |
241 | switch (errsv) |
242 | { |
243 | #ifdef EINTR |
244 | case EINTR: |
245 | goto retry; |
246 | #endif |
247 | #ifdef EAGAIN |
248 | case EAGAIN: |
249 | return G_IO_STATUS_AGAIN; |
250 | #endif |
251 | default: |
252 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
253 | code: g_io_channel_error_from_errno (en: errsv), |
254 | message: g_strerror (errnum: errsv)); |
255 | return G_IO_STATUS_ERROR; |
256 | } |
257 | } |
258 | |
259 | *bytes_written = result; |
260 | |
261 | return G_IO_STATUS_NORMAL; |
262 | } |
263 | |
264 | static GIOStatus |
265 | g_io_unix_seek (GIOChannel *channel, |
266 | gint64 offset, |
267 | GSeekType type, |
268 | GError **err) |
269 | { |
270 | GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel; |
271 | int whence; |
272 | off_t tmp_offset; |
273 | off_t result; |
274 | |
275 | switch (type) |
276 | { |
277 | case G_SEEK_SET: |
278 | whence = SEEK_SET; |
279 | break; |
280 | case G_SEEK_CUR: |
281 | whence = SEEK_CUR; |
282 | break; |
283 | case G_SEEK_END: |
284 | whence = SEEK_END; |
285 | break; |
286 | default: |
287 | whence = -1; /* Shut the compiler up */ |
288 | g_assert_not_reached (); |
289 | } |
290 | |
291 | tmp_offset = offset; |
292 | if (tmp_offset != offset) |
293 | { |
294 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
295 | code: g_io_channel_error_from_errno (EINVAL), |
296 | message: g_strerror (EINVAL)); |
297 | return G_IO_STATUS_ERROR; |
298 | } |
299 | |
300 | result = lseek (fd: unix_channel->fd, offset: tmp_offset, whence: whence); |
301 | |
302 | if (result < 0) |
303 | { |
304 | int errsv = errno; |
305 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
306 | code: g_io_channel_error_from_errno (en: errsv), |
307 | message: g_strerror (errnum: errsv)); |
308 | return G_IO_STATUS_ERROR; |
309 | } |
310 | |
311 | return G_IO_STATUS_NORMAL; |
312 | } |
313 | |
314 | |
315 | static GIOStatus |
316 | g_io_unix_close (GIOChannel *channel, |
317 | GError **err) |
318 | { |
319 | GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel; |
320 | |
321 | if (close (fd: unix_channel->fd) < 0) |
322 | { |
323 | int errsv = errno; |
324 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
325 | code: g_io_channel_error_from_errno (en: errsv), |
326 | message: g_strerror (errnum: errsv)); |
327 | return G_IO_STATUS_ERROR; |
328 | } |
329 | |
330 | return G_IO_STATUS_NORMAL; |
331 | } |
332 | |
333 | static void |
334 | g_io_unix_free (GIOChannel *channel) |
335 | { |
336 | GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel; |
337 | |
338 | g_free (mem: unix_channel); |
339 | } |
340 | |
341 | static GSource * |
342 | g_io_unix_create_watch (GIOChannel *channel, |
343 | GIOCondition condition) |
344 | { |
345 | GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel; |
346 | GSource *source; |
347 | GIOUnixWatch *watch; |
348 | |
349 | |
350 | source = g_source_new (source_funcs: &g_io_watch_funcs, struct_size: sizeof (GIOUnixWatch)); |
351 | g_source_set_name (source, name: "GIOChannel (Unix)" ); |
352 | watch = (GIOUnixWatch *)source; |
353 | |
354 | watch->channel = channel; |
355 | g_io_channel_ref (channel); |
356 | |
357 | watch->condition = condition; |
358 | |
359 | watch->pollfd.fd = unix_channel->fd; |
360 | watch->pollfd.events = condition; |
361 | |
362 | g_source_add_poll (source, fd: &watch->pollfd); |
363 | |
364 | return source; |
365 | } |
366 | |
367 | static GIOStatus |
368 | g_io_unix_set_flags (GIOChannel *channel, |
369 | GIOFlags flags, |
370 | GError **err) |
371 | { |
372 | glong fcntl_flags; |
373 | GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel; |
374 | |
375 | fcntl_flags = 0; |
376 | |
377 | if (flags & G_IO_FLAG_APPEND) |
378 | fcntl_flags |= O_APPEND; |
379 | if (flags & G_IO_FLAG_NONBLOCK) |
380 | #ifdef O_NONBLOCK |
381 | fcntl_flags |= O_NONBLOCK; |
382 | #else |
383 | fcntl_flags |= O_NDELAY; |
384 | #endif |
385 | |
386 | if (fcntl (fd: unix_channel->fd, F_SETFL, fcntl_flags) == -1) |
387 | { |
388 | int errsv = errno; |
389 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
390 | code: g_io_channel_error_from_errno (en: errsv), |
391 | message: g_strerror (errnum: errsv)); |
392 | return G_IO_STATUS_ERROR; |
393 | } |
394 | |
395 | return G_IO_STATUS_NORMAL; |
396 | } |
397 | |
398 | static GIOFlags |
399 | g_io_unix_get_flags (GIOChannel *channel) |
400 | { |
401 | GIOFlags flags = 0; |
402 | glong fcntl_flags; |
403 | GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel; |
404 | |
405 | fcntl_flags = fcntl (fd: unix_channel->fd, F_GETFL); |
406 | |
407 | if (fcntl_flags == -1) |
408 | { |
409 | int err = errno; |
410 | g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)" , |
411 | g_strerror (err), err); |
412 | return 0; |
413 | } |
414 | |
415 | if (fcntl_flags & O_APPEND) |
416 | flags |= G_IO_FLAG_APPEND; |
417 | #ifdef O_NONBLOCK |
418 | if (fcntl_flags & O_NONBLOCK) |
419 | #else |
420 | if (fcntl_flags & O_NDELAY) |
421 | #endif |
422 | flags |= G_IO_FLAG_NONBLOCK; |
423 | |
424 | switch (fcntl_flags & (O_RDONLY | O_WRONLY | O_RDWR)) |
425 | { |
426 | case O_RDONLY: |
427 | channel->is_readable = TRUE; |
428 | channel->is_writeable = FALSE; |
429 | break; |
430 | case O_WRONLY: |
431 | channel->is_readable = FALSE; |
432 | channel->is_writeable = TRUE; |
433 | break; |
434 | case O_RDWR: |
435 | channel->is_readable = TRUE; |
436 | channel->is_writeable = TRUE; |
437 | break; |
438 | default: |
439 | g_assert_not_reached (); |
440 | } |
441 | |
442 | return flags; |
443 | } |
444 | |
445 | GIOChannel * |
446 | g_io_channel_new_file (const gchar *filename, |
447 | const gchar *mode, |
448 | GError **error) |
449 | { |
450 | int fid, flags; |
451 | mode_t create_mode; |
452 | GIOChannel *channel; |
453 | enum { /* Cheesy hack */ |
454 | MODE_R = 1 << 0, |
455 | MODE_W = 1 << 1, |
456 | MODE_A = 1 << 2, |
457 | MODE_PLUS = 1 << 3, |
458 | MODE_R_PLUS = MODE_R | MODE_PLUS, |
459 | MODE_W_PLUS = MODE_W | MODE_PLUS, |
460 | MODE_A_PLUS = MODE_A | MODE_PLUS |
461 | } mode_num; |
462 | struct stat buffer; |
463 | |
464 | g_return_val_if_fail (filename != NULL, NULL); |
465 | g_return_val_if_fail (mode != NULL, NULL); |
466 | g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL); |
467 | |
468 | switch (mode[0]) |
469 | { |
470 | case 'r': |
471 | mode_num = MODE_R; |
472 | break; |
473 | case 'w': |
474 | mode_num = MODE_W; |
475 | break; |
476 | case 'a': |
477 | mode_num = MODE_A; |
478 | break; |
479 | default: |
480 | g_warning ("Invalid GIOFileMode %s." , mode); |
481 | return NULL; |
482 | } |
483 | |
484 | switch (mode[1]) |
485 | { |
486 | case '\0': |
487 | break; |
488 | case '+': |
489 | if (mode[2] == '\0') |
490 | { |
491 | mode_num |= MODE_PLUS; |
492 | break; |
493 | } |
494 | G_GNUC_FALLTHROUGH; |
495 | default: |
496 | g_warning ("Invalid GIOFileMode %s." , mode); |
497 | return NULL; |
498 | } |
499 | |
500 | switch (mode_num) |
501 | { |
502 | case MODE_R: |
503 | flags = O_RDONLY; |
504 | break; |
505 | case MODE_W: |
506 | flags = O_WRONLY | O_TRUNC | O_CREAT; |
507 | break; |
508 | case MODE_A: |
509 | flags = O_WRONLY | O_APPEND | O_CREAT; |
510 | break; |
511 | case MODE_R_PLUS: |
512 | flags = O_RDWR; |
513 | break; |
514 | case MODE_W_PLUS: |
515 | flags = O_RDWR | O_TRUNC | O_CREAT; |
516 | break; |
517 | case MODE_A_PLUS: |
518 | flags = O_RDWR | O_APPEND | O_CREAT; |
519 | break; |
520 | case MODE_PLUS: |
521 | default: |
522 | g_assert_not_reached (); |
523 | flags = 0; |
524 | } |
525 | |
526 | create_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; |
527 | |
528 | fid = g_open (file: filename, oflag: flags, create_mode); |
529 | if (fid == -1) |
530 | { |
531 | int err = errno; |
532 | g_set_error_literal (err: error, G_FILE_ERROR, |
533 | code: g_file_error_from_errno (err_no: err), |
534 | message: g_strerror (errnum: err)); |
535 | return (GIOChannel *)NULL; |
536 | } |
537 | |
538 | if (fstat (fd: fid, buf: &buffer) == -1) /* In case someone opens a FIFO */ |
539 | { |
540 | int err = errno; |
541 | close (fd: fid); |
542 | g_set_error_literal (err: error, G_FILE_ERROR, |
543 | code: g_file_error_from_errno (err_no: err), |
544 | message: g_strerror (errnum: err)); |
545 | return (GIOChannel *)NULL; |
546 | } |
547 | |
548 | channel = (GIOChannel *) g_new (GIOUnixChannel, 1); |
549 | |
550 | channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode) |
551 | || S_ISBLK (buffer.st_mode); |
552 | |
553 | switch (mode_num) |
554 | { |
555 | case MODE_R: |
556 | channel->is_readable = TRUE; |
557 | channel->is_writeable = FALSE; |
558 | break; |
559 | case MODE_W: |
560 | case MODE_A: |
561 | channel->is_readable = FALSE; |
562 | channel->is_writeable = TRUE; |
563 | break; |
564 | case MODE_R_PLUS: |
565 | case MODE_W_PLUS: |
566 | case MODE_A_PLUS: |
567 | channel->is_readable = TRUE; |
568 | channel->is_writeable = TRUE; |
569 | break; |
570 | case MODE_PLUS: |
571 | default: |
572 | g_assert_not_reached (); |
573 | } |
574 | |
575 | g_io_channel_init (channel); |
576 | channel->close_on_unref = TRUE; /* must be after g_io_channel_init () */ |
577 | channel->funcs = &unix_channel_funcs; |
578 | |
579 | ((GIOUnixChannel *) channel)->fd = fid; |
580 | return channel; |
581 | } |
582 | |
583 | /** |
584 | * g_io_channel_unix_new: |
585 | * @fd: a file descriptor. |
586 | * |
587 | * Creates a new #GIOChannel given a file descriptor. On UNIX systems |
588 | * this works for plain files, pipes, and sockets. |
589 | * |
590 | * The returned #GIOChannel has a reference count of 1. |
591 | * |
592 | * The default encoding for #GIOChannel is UTF-8. If your application |
593 | * is reading output from a command using via pipe, you may need to set |
594 | * the encoding to the encoding of the current locale (see |
595 | * g_get_charset()) with the g_io_channel_set_encoding() function. |
596 | * By default, the fd passed will not be closed when the final reference |
597 | * to the #GIOChannel data structure is dropped. |
598 | * |
599 | * If you want to read raw binary data without interpretation, then |
600 | * call the g_io_channel_set_encoding() function with %NULL for the |
601 | * encoding argument. |
602 | * |
603 | * This function is available in GLib on Windows, too, but you should |
604 | * avoid using it on Windows. The domain of file descriptors and |
605 | * sockets overlap. There is no way for GLib to know which one you mean |
606 | * in case the argument you pass to this function happens to be both a |
607 | * valid file descriptor and socket. If that happens a warning is |
608 | * issued, and GLib assumes that it is the file descriptor you mean. |
609 | * |
610 | * Returns: a new #GIOChannel. |
611 | **/ |
612 | GIOChannel * |
613 | g_io_channel_unix_new (gint fd) |
614 | { |
615 | struct stat buffer; |
616 | GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1); |
617 | GIOChannel *channel = (GIOChannel *)unix_channel; |
618 | |
619 | g_io_channel_init (channel); |
620 | channel->funcs = &unix_channel_funcs; |
621 | |
622 | unix_channel->fd = fd; |
623 | |
624 | /* I'm not sure if fstat on a non-file (e.g., socket) works |
625 | * it should be safe to say if it fails, the fd isn't seekable. |
626 | */ |
627 | /* Newer UNIX versions support S_ISSOCK(), fstat() will probably |
628 | * succeed in most cases. |
629 | */ |
630 | if (fstat (fd: unix_channel->fd, buf: &buffer) == 0) |
631 | channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode) |
632 | || S_ISBLK (buffer.st_mode); |
633 | else /* Assume not seekable */ |
634 | channel->is_seekable = FALSE; |
635 | |
636 | g_io_unix_get_flags (channel); /* Sets is_readable, is_writeable */ |
637 | |
638 | return channel; |
639 | } |
640 | |
641 | /** |
642 | * g_io_channel_unix_get_fd: |
643 | * @channel: a #GIOChannel, created with g_io_channel_unix_new(). |
644 | * |
645 | * Returns the file descriptor of the #GIOChannel. |
646 | * |
647 | * On Windows this function returns the file descriptor or socket of |
648 | * the #GIOChannel. |
649 | * |
650 | * Returns: the file descriptor of the #GIOChannel. |
651 | **/ |
652 | gint |
653 | g_io_channel_unix_get_fd (GIOChannel *channel) |
654 | { |
655 | GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel; |
656 | return unix_channel->fd; |
657 | } |
658 | |