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