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