ecd32ecd339d0e6badbed4272e1b79e40b26a98a
[platform/upstream/glib.git] / glib / giounix.c
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 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, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GLib Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
28  */
29
30 /* 
31  * MT safe
32  */
33
34 #include "config.h"
35
36 #define _POSIX_SOURCE           /* for SSIZE_MAX */
37
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <string.h>
44 #include <fcntl.h>
45
46 #include "glib.h"
47
48 /*
49  * Unix IO Channels
50  */
51
52 typedef struct _GIOUnixChannel GIOUnixChannel;
53 typedef struct _GIOUnixWatch GIOUnixWatch;
54
55 struct _GIOUnixChannel
56 {
57   GIOChannel channel;
58   gint fd;
59 };
60
61 struct _GIOUnixWatch
62 {
63   GSource       source;
64   GPollFD       pollfd;
65   GIOChannel   *channel;
66   GIOCondition  condition;
67 };
68
69
70 static GIOStatus        g_io_unix_read          (GIOChannel   *channel,
71                                                  gchar        *buf,
72                                                  gsize         count,
73                                                  gsize        *bytes_read,
74                                                  GError      **err);
75 static GIOStatus        g_io_unix_write         (GIOChannel   *channel,
76                                                  const gchar  *buf,
77                                                  gsize         count,
78                                                  gsize        *bytes_written,
79                                                  GError      **err);
80 static GIOStatus        g_io_unix_seek          (GIOChannel   *channel,
81                                                  gint64        offset,
82                                                  GSeekType     type,
83                                                  GError      **err);
84 static GIOStatus        g_io_unix_close         (GIOChannel   *channel,
85                                                  GError      **err);
86 static void             g_io_unix_free          (GIOChannel   *channel);
87 static GSource*         g_io_unix_create_watch  (GIOChannel   *channel,
88                                                  GIOCondition  condition);
89 static GIOStatus        g_io_unix_set_flags     (GIOChannel   *channel,
90                                                  GIOFlags      flags,
91                                                  GError      **err);
92 static GIOFlags         g_io_unix_get_flags     (GIOChannel   *channel);
93
94 static gboolean g_io_unix_prepare  (GSource     *source,
95                                     gint        *timeout);
96 static gboolean g_io_unix_check    (GSource     *source);
97 static gboolean g_io_unix_dispatch (GSource     *source,
98                                     GSourceFunc  callback,
99                                     gpointer     user_data);
100 static void     g_io_unix_finalize (GSource     *source);
101
102 GSourceFuncs g_io_watch_funcs = {
103   g_io_unix_prepare,
104   g_io_unix_check,
105   g_io_unix_dispatch,
106   g_io_unix_finalize
107 };
108
109 static GIOFuncs unix_channel_funcs = {
110   g_io_unix_read,
111   g_io_unix_write,
112   g_io_unix_seek,
113   g_io_unix_close,
114   g_io_unix_create_watch,
115   g_io_unix_free,
116   g_io_unix_set_flags,
117   g_io_unix_get_flags,
118 };
119
120 static gboolean 
121 g_io_unix_prepare (GSource  *source,
122                    gint     *timeout)
123 {
124   GIOUnixWatch *watch = (GIOUnixWatch *)source;
125   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
126
127   *timeout = -1;
128
129   /* Only return TRUE here if _all_ bits in watch->condition will be set
130    */
131   return ((watch->condition & buffer_condition) == watch->condition);
132 }
133
134 static gboolean 
135 g_io_unix_check (GSource  *source)
136 {
137   GIOUnixWatch *watch = (GIOUnixWatch *)source;
138   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
139   GIOCondition poll_condition = watch->pollfd.revents;
140
141   return ((poll_condition | buffer_condition) & watch->condition);
142 }
143
144 static gboolean
145 g_io_unix_dispatch (GSource     *source,
146                     GSourceFunc  callback,
147                     gpointer     user_data)
148
149 {
150   GIOFunc func = (GIOFunc)callback;
151   GIOUnixWatch *watch = (GIOUnixWatch *)source;
152   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
153
154   if (!func)
155     {
156       g_warning ("IO watch dispatched without callback\n"
157                  "You must call g_source_connect().");
158       return FALSE;
159     }
160   
161   return (*func) (watch->channel,
162                   (watch->pollfd.revents | buffer_condition) & watch->condition,
163                   user_data);
164 }
165
166 static void 
167 g_io_unix_finalize (GSource *source)
168 {
169   GIOUnixWatch *watch = (GIOUnixWatch *)source;
170
171   g_io_channel_unref (watch->channel);
172 }
173
174 static GIOStatus
175 g_io_unix_read (GIOChannel *channel, 
176                 gchar      *buf, 
177                 gsize       count,
178                 gsize      *bytes_read,
179                 GError    **err)
180 {
181   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
182   gssize result;
183
184   if (count > SSIZE_MAX) /* At least according to the Debian manpage for read */
185     count = SSIZE_MAX;
186
187  retry:
188   result = read (unix_channel->fd, buf, count);
189
190   if (result < 0)
191     {
192       *bytes_read = 0;
193
194       switch (errno)
195         {
196 #ifdef EINTR
197           case EINTR:
198             goto retry;
199 #endif
200 #ifdef EAGAIN
201           case EAGAIN:
202             return G_IO_STATUS_AGAIN;
203 #endif
204           default:
205             g_set_error (err, G_IO_CHANNEL_ERROR,
206                          g_io_channel_error_from_errno (errno),
207                          g_strerror (errno));
208             return G_IO_STATUS_ERROR;
209         }
210     }
211
212   *bytes_read = result;
213
214   return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
215 }
216
217 static GIOStatus
218 g_io_unix_write (GIOChannel  *channel, 
219                  const gchar *buf, 
220                  gsize       count,
221                  gsize      *bytes_written,
222                  GError    **err)
223 {
224   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
225   gssize result;
226
227  retry:
228   result = write (unix_channel->fd, buf, count);
229
230   if (result < 0)
231     {
232       *bytes_written = 0;
233
234       switch (errno)
235         {
236 #ifdef EINTR
237           case EINTR:
238             goto retry;
239 #endif
240 #ifdef EAGAIN
241           case EAGAIN:
242             return G_IO_STATUS_AGAIN;
243 #endif
244           default:
245             g_set_error (err, G_IO_CHANNEL_ERROR,
246                          g_io_channel_error_from_errno (errno),
247                          g_strerror (errno));
248             return G_IO_STATUS_ERROR;
249         }
250     }
251
252   *bytes_written = result;
253
254   return G_IO_STATUS_NORMAL;
255 }
256
257 static GIOStatus
258 g_io_unix_seek (GIOChannel *channel,
259                 gint64      offset, 
260                 GSeekType   type,
261                 GError    **err)
262 {
263   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
264   int whence;
265   off_t tmp_offset;
266   off_t result;
267
268   switch (type)
269     {
270     case G_SEEK_SET:
271       whence = SEEK_SET;
272       break;
273     case G_SEEK_CUR:
274       whence = SEEK_CUR;
275       break;
276     case G_SEEK_END:
277       whence = SEEK_END;
278       break;
279     default:
280       whence = -1; /* Shut the compiler up */
281       g_assert_not_reached ();
282     }
283
284   tmp_offset = offset;
285   if (tmp_offset != offset)
286     {
287       g_set_error (err, G_IO_CHANNEL_ERROR,
288                    g_io_channel_error_from_errno (EINVAL),
289                    g_strerror (EINVAL));
290       return G_IO_STATUS_ERROR;
291     }
292   
293   result = lseek (unix_channel->fd, tmp_offset, whence);
294
295   if (result < 0)
296     {
297       g_set_error (err, G_IO_CHANNEL_ERROR,
298                    g_io_channel_error_from_errno (errno),
299                    g_strerror (errno));
300       return G_IO_STATUS_ERROR;
301     }
302
303   return G_IO_STATUS_NORMAL;
304 }
305
306
307 static GIOStatus
308 g_io_unix_close (GIOChannel *channel,
309                  GError    **err)
310 {
311   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
312
313   if (close (unix_channel->fd) < 0)
314     {
315       g_set_error (err, G_IO_CHANNEL_ERROR,
316                    g_io_channel_error_from_errno (errno),
317                    g_strerror (errno));
318       return G_IO_STATUS_ERROR;
319     }
320
321   return G_IO_STATUS_NORMAL;
322 }
323
324 static void 
325 g_io_unix_free (GIOChannel *channel)
326 {
327   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
328
329   g_free (unix_channel);
330 }
331
332 static GSource *
333 g_io_unix_create_watch (GIOChannel   *channel,
334                         GIOCondition  condition)
335 {
336   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
337   GSource *source;
338   GIOUnixWatch *watch;
339
340
341   source = g_source_new (&g_io_watch_funcs, sizeof (GIOUnixWatch));
342   watch = (GIOUnixWatch *)source;
343   
344   watch->channel = channel;
345   g_io_channel_ref (channel);
346   
347   watch->condition = condition;
348
349   watch->pollfd.fd = unix_channel->fd;
350   watch->pollfd.events = condition;
351
352   g_source_add_poll (source, &watch->pollfd);
353
354   return source;
355 }
356
357 static GIOStatus
358 g_io_unix_set_flags (GIOChannel *channel,
359                      GIOFlags    flags,
360                      GError    **err)
361 {
362   glong fcntl_flags;
363   GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
364
365   fcntl_flags = 0;
366
367   if (flags & G_IO_FLAG_APPEND)
368     fcntl_flags |= O_APPEND;
369   if (flags & G_IO_FLAG_NONBLOCK)
370 #ifdef O_NONBLOCK
371     fcntl_flags |= O_NONBLOCK;
372 #else
373     fcntl_flags |= O_NDELAY;
374 #endif
375
376   if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
377     {
378       g_set_error (err, G_IO_CHANNEL_ERROR,
379                    g_io_channel_error_from_errno (errno),
380                    g_strerror (errno));
381       return G_IO_STATUS_ERROR;
382     }
383
384   return G_IO_STATUS_NORMAL;
385 }
386
387 static GIOFlags
388 g_io_unix_get_flags (GIOChannel *channel)
389 {
390   GIOFlags flags = 0;
391   glong fcntl_flags;
392   GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
393
394   fcntl_flags = fcntl (unix_channel->fd, F_GETFL);
395
396   if (fcntl_flags == -1)
397     {
398       g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)\n",
399                  g_strerror (errno), errno);
400       return 0;
401     }
402
403   if (fcntl_flags & O_APPEND)
404     flags |= G_IO_FLAG_APPEND;
405 #ifdef O_NONBLOCK
406   if (fcntl_flags & O_NONBLOCK)
407 #else
408   if (fcntl_flags & O_NDELAY)
409 #endif
410     flags |= G_IO_FLAG_NONBLOCK;
411
412   switch (fcntl_flags & (O_RDONLY | O_WRONLY | O_RDWR))
413     {
414       case O_RDONLY:
415         channel->is_readable = TRUE;
416         channel->is_writeable = FALSE;
417         break;
418       case O_WRONLY:
419         channel->is_readable = FALSE;
420         channel->is_writeable = TRUE;
421         break;
422       case O_RDWR:
423         channel->is_readable = TRUE;
424         channel->is_writeable = TRUE;
425         break;
426       default:
427         g_assert_not_reached ();
428     }
429
430   return flags;
431 }
432
433 GIOChannel *
434 g_io_channel_new_file (const gchar *filename,
435                        const gchar *mode,
436                        GError     **error)
437 {
438   int fid, flags;
439   mode_t create_mode;
440   GIOChannel *channel;
441   enum { /* Cheesy hack */
442     MODE_R = 1 << 0,
443     MODE_W = 1 << 1,
444     MODE_A = 1 << 2,
445     MODE_PLUS = 1 << 3
446   } mode_num;
447   struct stat buffer;
448
449   g_return_val_if_fail (filename != NULL, NULL);
450   g_return_val_if_fail (mode != NULL, NULL);
451   g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
452
453   switch (mode[0])
454     {
455       case 'r':
456         mode_num = MODE_R;
457         break;
458       case 'w':
459         mode_num = MODE_W;
460         break;
461       case 'a':
462         mode_num = MODE_A;
463         break;
464       default:
465         g_warning ("Invalid GIOFileMode %s.\n", mode);
466         return NULL;
467     }
468
469   switch (mode[1])
470     {
471       case '\0':
472         break;
473       case '+':
474         if (mode[2] == '\0')
475           {
476             mode_num |= MODE_PLUS;
477             break;
478           }
479         /* Fall through */
480       default:
481         g_warning ("Invalid GIOFileMode %s.\n", mode);
482         return NULL;
483     }
484
485   switch (mode_num)
486     {
487       case MODE_R:
488         flags = O_RDONLY;
489         break;
490       case MODE_W:
491         flags = O_WRONLY | O_TRUNC | O_CREAT;
492         break;
493       case MODE_A:
494         flags = O_WRONLY | O_APPEND | O_CREAT;
495         break;
496       case MODE_R | MODE_PLUS:
497         flags = O_RDWR;
498         break;
499       case MODE_W | MODE_PLUS:
500         flags = O_RDWR | O_TRUNC | O_CREAT;
501         break;
502       case MODE_A | MODE_PLUS:
503         flags = O_RDWR | O_APPEND | O_CREAT;
504         break;
505       default:
506         g_assert_not_reached ();
507         flags = 0;
508     }
509
510   create_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
511   fid = open (filename, flags, create_mode);
512   if (fid == -1)
513     {
514       g_set_error (error, G_FILE_ERROR,
515                    g_file_error_from_errno (errno),
516                    g_strerror (errno));
517       return (GIOChannel *)NULL;
518     }
519
520   if (fstat (fid, &buffer) == -1) /* In case someone opens a FIFO */
521     {
522       close (fid);
523       g_set_error (error, G_FILE_ERROR,
524                    g_file_error_from_errno (errno),
525                    g_strerror (errno));
526       return (GIOChannel *)NULL;
527     }
528
529   channel = (GIOChannel *) g_new (GIOUnixChannel, 1);
530
531   channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
532                          || S_ISBLK (buffer.st_mode);
533
534   switch (mode_num)
535     {
536       case MODE_R:
537         channel->is_readable = TRUE;
538         channel->is_writeable = FALSE;
539         break;
540       case MODE_W:
541       case MODE_A:
542         channel->is_readable = FALSE;
543         channel->is_writeable = TRUE;
544         break;
545       case MODE_R | MODE_PLUS:
546       case MODE_W | MODE_PLUS:
547       case MODE_A | MODE_PLUS:
548         channel->is_readable = TRUE;
549         channel->is_writeable = TRUE;
550         break;
551       default:
552         g_assert_not_reached ();
553     }
554
555   g_io_channel_init (channel);
556   channel->close_on_unref = TRUE; /* must be after g_io_channel_init () */
557   channel->funcs = &unix_channel_funcs;
558
559   ((GIOUnixChannel *) channel)->fd = fid;
560   return channel;
561 }
562
563 GIOChannel *
564 g_io_channel_unix_new (gint fd)
565 {
566   struct stat buffer;
567   GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
568   GIOChannel *channel = (GIOChannel *)unix_channel;
569
570   g_io_channel_init (channel);
571   channel->funcs = &unix_channel_funcs;
572
573   unix_channel->fd = fd;
574
575   /* I'm not sure if fstat on a non-file (e.g., socket) works
576    * it should be safe to say if it fails, the fd isn't seekable.
577    */
578   /* Newer UNIX versions support S_ISSOCK(), fstat() will probably
579    * succeed in most cases.
580    */
581   if (fstat (unix_channel->fd, &buffer) == 0)
582     channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
583                            || S_ISBLK (buffer.st_mode);
584   else /* Assume not seekable */
585     channel->is_seekable = FALSE;
586
587   g_io_unix_get_flags (channel); /* Sets is_readable, is_writeable */
588
589   return channel;
590 }
591
592 gint
593 g_io_channel_unix_get_fd (GIOChannel *channel)
594 {
595   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
596   return unix_channel->fd;
597 }