Coverage Report

Created: 2025-08-26 06:55

/src/glib/glib/giounix.c
Line
Count
Source (jump to first uncovered line)
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
0
{
129
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
130
0
  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
131
132
0
  *timeout = -1;
133
134
  /* Only return TRUE here if _all_ bits in watch->condition will be set
135
   */
136
0
  return ((watch->condition & buffer_condition) == watch->condition);
137
0
}
138
139
static gboolean 
140
g_io_unix_check (GSource  *source)
141
0
{
142
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
143
0
  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
144
0
  GIOCondition poll_condition = watch->pollfd.revents;
145
146
0
  return ((poll_condition | buffer_condition) & watch->condition);
147
0
}
148
149
static gboolean
150
g_io_unix_dispatch (GSource     *source,
151
        GSourceFunc  callback,
152
        gpointer     user_data)
153
154
0
{
155
0
  GIOFunc func = (GIOFunc)callback;
156
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
157
0
  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
158
159
0
  if (!func)
160
0
    {
161
0
      g_warning ("IO watch dispatched without callback. "
162
0
     "You must call g_source_connect().");
163
0
      return FALSE;
164
0
    }
165
  
166
0
  return (*func) (watch->channel,
167
0
      (watch->pollfd.revents | buffer_condition) & watch->condition,
168
0
      user_data);
169
0
}
170
171
static void 
172
g_io_unix_finalize (GSource *source)
173
0
{
174
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
175
176
0
  g_io_channel_unref (watch->channel);
177
0
}
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
0
{
186
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
187
0
  gssize result;
188
189
0
  if (count > SSIZE_MAX) /* At least according to the Debian manpage for read */
190
0
    count = SSIZE_MAX;
191
192
0
 retry:
193
0
  result = read (unix_channel->fd, buf, count);
194
195
0
  if (result < 0)
196
0
    {
197
0
      int errsv = errno;
198
0
      *bytes_read = 0;
199
200
0
      switch (errsv)
201
0
        {
202
0
#ifdef EINTR
203
0
          case EINTR:
204
0
            goto retry;
205
0
#endif
206
0
#ifdef EAGAIN
207
0
          case EAGAIN:
208
0
            return G_IO_STATUS_AGAIN;
209
0
#endif
210
0
          default:
211
0
            g_set_error_literal (err, G_IO_CHANNEL_ERROR,
212
0
                                 g_io_channel_error_from_errno (errsv),
213
0
                                 g_strerror (errsv));
214
0
            return G_IO_STATUS_ERROR;
215
0
        }
216
0
    }
217
218
0
  *bytes_read = result;
219
220
0
  return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
221
0
}
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
0
{
230
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
231
0
  gssize result;
232
233
0
 retry:
234
0
  result = write (unix_channel->fd, buf, count);
235
236
0
  if (result < 0)
237
0
    {
238
0
      int errsv = errno;
239
0
      *bytes_written = 0;
240
241
0
      switch (errsv)
242
0
        {
243
0
#ifdef EINTR
244
0
          case EINTR:
245
0
            goto retry;
246
0
#endif
247
0
#ifdef EAGAIN
248
0
          case EAGAIN:
249
0
            return G_IO_STATUS_AGAIN;
250
0
#endif
251
0
          default:
252
0
            g_set_error_literal (err, G_IO_CHANNEL_ERROR,
253
0
                                 g_io_channel_error_from_errno (errsv),
254
0
                                 g_strerror (errsv));
255
0
            return G_IO_STATUS_ERROR;
256
0
        }
257
0
    }
258
259
0
  *bytes_written = result;
260
261
0
  return G_IO_STATUS_NORMAL;
262
0
}
263
264
static GIOStatus
265
g_io_unix_seek (GIOChannel *channel,
266
    gint64      offset, 
267
    GSeekType   type,
268
                GError    **err)
269
0
{
270
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
271
0
  int whence;
272
0
  off_t tmp_offset;
273
0
  off_t result;
274
275
0
  switch (type)
276
0
    {
277
0
    case G_SEEK_SET:
278
0
      whence = SEEK_SET;
279
0
      break;
280
0
    case G_SEEK_CUR:
281
0
      whence = SEEK_CUR;
282
0
      break;
283
0
    case G_SEEK_END:
284
0
      whence = SEEK_END;
285
0
      break;
286
0
    default:
287
0
      whence = -1; /* Shut the compiler up */
288
0
      g_assert_not_reached ();
289
0
    }
290
291
0
  tmp_offset = offset;
292
0
  if (tmp_offset != offset)
293
0
    {
294
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
295
0
                           g_io_channel_error_from_errno (EINVAL),
296
0
                           g_strerror (EINVAL));
297
0
      return G_IO_STATUS_ERROR;
298
0
    }
299
  
300
0
  result = lseek (unix_channel->fd, tmp_offset, whence);
301
302
0
  if (result < 0)
303
0
    {
304
0
      int errsv = errno;
305
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
306
0
                           g_io_channel_error_from_errno (errsv),
307
0
                           g_strerror (errsv));
308
0
      return G_IO_STATUS_ERROR;
309
0
    }
310
311
0
  return G_IO_STATUS_NORMAL;
312
0
}
313
314
315
static GIOStatus
316
g_io_unix_close (GIOChannel *channel,
317
     GError    **err)
318
0
{
319
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
320
321
0
  if (close (unix_channel->fd) < 0)
322
0
    {
323
0
      int errsv = errno;
324
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
325
0
                           g_io_channel_error_from_errno (errsv),
326
0
                           g_strerror (errsv));
327
0
      return G_IO_STATUS_ERROR;
328
0
    }
329
330
0
  return G_IO_STATUS_NORMAL;
331
0
}
332
333
static void 
334
g_io_unix_free (GIOChannel *channel)
335
0
{
336
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
337
338
0
  g_free (unix_channel);
339
0
}
340
341
static GSource *
342
g_io_unix_create_watch (GIOChannel   *channel,
343
      GIOCondition  condition)
344
0
{
345
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
346
0
  GSource *source;
347
0
  GIOUnixWatch *watch;
348
349
350
0
  source = g_source_new (&g_io_watch_funcs, sizeof (GIOUnixWatch));
351
0
  g_source_set_name (source, "GIOChannel (Unix)");
352
0
  watch = (GIOUnixWatch *)source;
353
  
354
0
  watch->channel = channel;
355
0
  g_io_channel_ref (channel);
356
  
357
0
  watch->condition = condition;
358
359
0
  watch->pollfd.fd = unix_channel->fd;
360
0
  watch->pollfd.events = condition;
361
362
0
  g_source_add_poll (source, &watch->pollfd);
363
364
0
  return source;
365
0
}
366
367
static GIOStatus
368
g_io_unix_set_flags (GIOChannel *channel,
369
                     GIOFlags    flags,
370
                     GError    **err)
371
0
{
372
0
  glong fcntl_flags;
373
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
374
375
0
  fcntl_flags = 0;
376
377
0
  if (flags & G_IO_FLAG_APPEND)
378
0
    fcntl_flags |= O_APPEND;
379
0
  if (flags & G_IO_FLAG_NONBLOCK)
380
0
#ifdef O_NONBLOCK
381
0
    fcntl_flags |= O_NONBLOCK;
382
#else
383
    fcntl_flags |= O_NDELAY;
384
#endif
385
386
0
  if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
387
0
    {
388
0
      int errsv = errno;
389
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
390
0
                           g_io_channel_error_from_errno (errsv),
391
0
                           g_strerror (errsv));
392
0
      return G_IO_STATUS_ERROR;
393
0
    }
394
395
0
  return G_IO_STATUS_NORMAL;
396
0
}
397
398
static GIOFlags
399
g_io_unix_get_flags (GIOChannel *channel)
400
0
{
401
0
  GIOFlags flags = 0;
402
0
  glong fcntl_flags;
403
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
404
405
0
  fcntl_flags = fcntl (unix_channel->fd, F_GETFL);
406
407
0
  if (fcntl_flags == -1)
408
0
    {
409
0
      int err = errno;
410
0
      g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)",
411
0
     g_strerror (err), err);
412
0
      return 0;
413
0
    }
414
415
0
  if (fcntl_flags & O_APPEND)
416
0
    flags |= G_IO_FLAG_APPEND;
417
0
#ifdef O_NONBLOCK
418
0
  if (fcntl_flags & O_NONBLOCK)
419
#else
420
  if (fcntl_flags & O_NDELAY)
421
#endif
422
0
    flags |= G_IO_FLAG_NONBLOCK;
423
424
0
  switch (fcntl_flags & (O_RDONLY | O_WRONLY | O_RDWR))
425
0
    {
426
0
      case O_RDONLY:
427
0
        channel->is_readable = TRUE;
428
0
        channel->is_writeable = FALSE;
429
0
        break;
430
0
      case O_WRONLY:
431
0
        channel->is_readable = FALSE;
432
0
        channel->is_writeable = TRUE;
433
0
        break;
434
0
      case O_RDWR:
435
0
        channel->is_readable = TRUE;
436
0
        channel->is_writeable = TRUE;
437
0
        break;
438
0
      default:
439
0
        g_assert_not_reached ();
440
0
    }
441
442
0
  return flags;
443
0
}
444
445
GIOChannel *
446
g_io_channel_new_file (const gchar *filename,
447
                       const gchar *mode,
448
                       GError     **error)
449
0
{
450
0
  int fid, flags;
451
0
  mode_t create_mode;
452
0
  GIOChannel *channel;
453
0
  enum { /* Cheesy hack */
454
0
    MODE_R = 1 << 0,
455
0
    MODE_W = 1 << 1,
456
0
    MODE_A = 1 << 2,
457
0
    MODE_PLUS = 1 << 3,
458
0
    MODE_R_PLUS = MODE_R | MODE_PLUS,
459
0
    MODE_W_PLUS = MODE_W | MODE_PLUS,
460
0
    MODE_A_PLUS = MODE_A | MODE_PLUS
461
0
  } mode_num;
462
0
  struct stat buffer;
463
464
0
  g_return_val_if_fail (filename != NULL, NULL);
465
0
  g_return_val_if_fail (mode != NULL, NULL);
466
0
  g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
467
468
0
  switch (mode[0])
469
0
    {
470
0
      case 'r':
471
0
        mode_num = MODE_R;
472
0
        break;
473
0
      case 'w':
474
0
        mode_num = MODE_W;
475
0
        break;
476
0
      case 'a':
477
0
        mode_num = MODE_A;
478
0
        break;
479
0
      default:
480
0
        g_warning ("Invalid GIOFileMode %s.", mode);
481
0
        return NULL;
482
0
    }
483
484
0
  switch (mode[1])
485
0
    {
486
0
      case '\0':
487
0
        break;
488
0
      case '+':
489
0
        if (mode[2] == '\0')
490
0
          {
491
0
            mode_num |= MODE_PLUS;
492
0
            break;
493
0
          }
494
0
        G_GNUC_FALLTHROUGH;
495
0
      default:
496
0
        g_warning ("Invalid GIOFileMode %s.", mode);
497
0
        return NULL;
498
0
    }
499
500
0
  switch (mode_num)
501
0
    {
502
0
      case MODE_R:
503
0
        flags = O_RDONLY;
504
0
        break;
505
0
      case MODE_W:
506
0
        flags = O_WRONLY | O_TRUNC | O_CREAT;
507
0
        break;
508
0
      case MODE_A:
509
0
        flags = O_WRONLY | O_APPEND | O_CREAT;
510
0
        break;
511
0
      case MODE_R_PLUS:
512
0
        flags = O_RDWR;
513
0
        break;
514
0
      case MODE_W_PLUS:
515
0
        flags = O_RDWR | O_TRUNC | O_CREAT;
516
0
        break;
517
0
      case MODE_A_PLUS:
518
0
        flags = O_RDWR | O_APPEND | O_CREAT;
519
0
        break;
520
0
      case MODE_PLUS:
521
0
      default:
522
0
        g_assert_not_reached ();
523
0
        flags = 0;
524
0
    }
525
526
0
  create_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
527
528
0
  fid = g_open (filename, flags, create_mode);
529
0
  if (fid == -1)
530
0
    {
531
0
      int err = errno;
532
0
      g_set_error_literal (error, G_FILE_ERROR,
533
0
                           g_file_error_from_errno (err),
534
0
                           g_strerror (err));
535
0
      return (GIOChannel *)NULL;
536
0
    }
537
538
0
  if (fstat (fid, &buffer) == -1) /* In case someone opens a FIFO */
539
0
    {
540
0
      int err = errno;
541
0
      close (fid);
542
0
      g_set_error_literal (error, G_FILE_ERROR,
543
0
                           g_file_error_from_errno (err),
544
0
                           g_strerror (err));
545
0
      return (GIOChannel *)NULL;
546
0
    }
547
548
0
  channel = (GIOChannel *) g_new (GIOUnixChannel, 1);
549
550
0
  channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
551
0
                         || S_ISBLK (buffer.st_mode);
552
553
0
  switch (mode_num)
554
0
    {
555
0
      case MODE_R:
556
0
        channel->is_readable = TRUE;
557
0
        channel->is_writeable = FALSE;
558
0
        break;
559
0
      case MODE_W:
560
0
      case MODE_A:
561
0
        channel->is_readable = FALSE;
562
0
        channel->is_writeable = TRUE;
563
0
        break;
564
0
      case MODE_R_PLUS:
565
0
      case MODE_W_PLUS:
566
0
      case MODE_A_PLUS:
567
0
        channel->is_readable = TRUE;
568
0
        channel->is_writeable = TRUE;
569
0
        break;
570
0
      case MODE_PLUS:
571
0
      default:
572
0
        g_assert_not_reached ();
573
0
    }
574
575
0
  g_io_channel_init (channel);
576
0
  channel->close_on_unref = TRUE; /* must be after g_io_channel_init () */
577
0
  channel->funcs = &unix_channel_funcs;
578
579
0
  ((GIOUnixChannel *) channel)->fd = fid;
580
0
  return channel;
581
0
}
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
0
{
615
0
  struct stat buffer;
616
0
  GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
617
0
  GIOChannel *channel = (GIOChannel *)unix_channel;
618
619
0
  g_io_channel_init (channel);
620
0
  channel->funcs = &unix_channel_funcs;
621
622
0
  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
0
  if (fstat (unix_channel->fd, &buffer) == 0)
631
0
    channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
632
0
                           || S_ISBLK (buffer.st_mode);
633
0
  else /* Assume not seekable */
634
0
    channel->is_seekable = FALSE;
635
636
0
  g_io_unix_get_flags (channel); /* Sets is_readable, is_writeable */
637
638
0
  return channel;
639
0
}
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
0
{
655
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
656
0
  return unix_channel->fd;
657
0
}