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