2002-12-12 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-sysdeps.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation)
3  * 
4  * Copyright (C) 2002  Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-sysdeps.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #ifdef HAVE_WRITEV
37 #include <sys/uio.h>
38 #endif
39
40
41 /**
42  * @addtogroup DBusInternalsUtils
43  * @{
44  */
45 /**
46  * Aborts the program with SIGABRT (dumping core).
47  */
48 void
49 _dbus_abort (void)
50 {
51   abort ();
52   _exit (1); /* in case someone manages to ignore SIGABRT */
53 }
54
55 /**
56  * Wrapper for getenv().
57  *
58  * @param varname name of environment variable
59  * @returns value of environment variable or #NULL if unset
60  */
61 const char*
62 _dbus_getenv (const char *varname)
63 {  
64   return getenv (varname);
65 }
66
67 /**
68  * Thin wrapper around the read() system call that appends
69  * the data it reads to the DBusString buffer. It appends
70  * up to the given count, and returns the same value
71  * and same errno as read(). The only exception is that
72  * _dbus_read() handles EINTR for you.
73  *
74  * @param fd the file descriptor to read from
75  * @param buffer the buffer to append data to
76  * @param count the amount of data to read
77  * @returns the number of bytes read or -1
78  */
79 int
80 _dbus_read (int               fd,
81             DBusString       *buffer,
82             int               count)
83 {
84   int bytes_read;
85   int start;
86   char *data;
87
88   _dbus_assert (count >= 0);
89   
90   start = _dbus_string_get_length (buffer);
91
92   if (!_dbus_string_lengthen (buffer, count))
93     {
94       errno = ENOMEM;
95       return -1;
96     }
97
98   _dbus_string_get_data_len (buffer, &data, start, count);
99
100  again:
101   
102   bytes_read = read (fd, data, count);
103
104   if (bytes_read < 0)
105     {
106       if (errno == EINTR)
107         goto again;
108       else
109         {
110           /* put length back (note that this doesn't actually realloc anything) */
111           _dbus_string_set_length (buffer, start);
112           return -1;
113         }
114     }
115   else
116     {
117       /* put length back (doesn't actually realloc) */
118       _dbus_string_set_length (buffer, start + bytes_read);
119       return bytes_read;
120     }
121 }
122
123 /**
124  * Thin wrapper around the write() system call that writes a part of a
125  * DBusString and handles EINTR for you.
126  * 
127  * @param fd the file descriptor to write
128  * @param buffer the buffer to write data from
129  * @param start the first byte in the buffer to write
130  * @param len the number of bytes to try to write
131  * @returns the number of bytes written or -1 on error
132  */
133 int
134 _dbus_write (int               fd,
135              const DBusString *buffer,
136              int               start,
137              int               len)
138 {
139   const char *data;
140   int bytes_written;
141   
142   _dbus_string_get_const_data_len (buffer, &data, start, len);
143   
144  again:
145
146   bytes_written = write (fd, data, len);
147
148   if (errno == EINTR)
149     goto again;
150
151   return bytes_written;
152 }
153
154 /**
155  * Like _dbus_write() but will use writev() if possible
156  * to write both buffers in sequence. The return value
157  * is the number of bytes written in the first buffer,
158  * plus the number written in the second. If the first
159  * buffer is written successfully and an error occurs
160  * writing the second, the number of bytes in the first
161  * is returned (i.e. the error is ignored), on systems that
162  * don't have writev. Handles EINTR for you.
163  * The second buffer may be #NULL.
164  *
165  * @param fd the file descriptor
166  * @param buffer1 first buffer
167  * @param start1 first byte to write in first buffer
168  * @param len1 number of bytes to write from first buffer
169  * @param buffer2 second buffer, or #NULL
170  * @param start2 first byte to write in second buffer
171  * @param len2 number of bytes to write in second buffer
172  * @returns total bytes written from both buffers, or -1 on error
173  */
174 int
175 _dbus_write_two (int               fd,
176                  const DBusString *buffer1,
177                  int               start1,
178                  int               len1,
179                  const DBusString *buffer2,
180                  int               start2,
181                  int               len2)
182 {
183   _dbus_assert (buffer1 != NULL);
184   _dbus_assert (start1 >= 0);
185   _dbus_assert (start2 >= 0);
186   _dbus_assert (len1 >= 0);
187   _dbus_assert (len2 >= 0);
188   
189 #ifdef HAVE_WRITEV
190   {
191     struct iovec vectors[2];
192     const char *data1;
193     const char *data2;
194     int bytes_written;
195
196     _dbus_string_get_const_data_len (buffer1, &data1, start1, len1);
197
198     if (buffer2 != NULL)
199       _dbus_string_get_const_data_len (buffer2, &data2, start2, len2);
200     else
201       {
202         data2 = NULL;
203         start2 = 0;
204         len2 = 0;
205       }
206    
207     vectors[0].iov_base = (char*) data1;
208     vectors[0].iov_len = len1;
209     vectors[1].iov_base = (char*) data2;
210     vectors[1].iov_len = len2;
211
212   again:
213    
214     bytes_written = writev (fd,
215                             vectors,
216                             data2 ? 2 : 1);
217
218     if (errno == EINTR)
219       goto again;
220    
221     return bytes_written;
222   }
223 #else /* HAVE_WRITEV */
224   {
225     int ret1;
226     
227     ret1 = _dbus_write (fd, buffer1, start1, len1);
228     if (ret1 == len1 && buffer2 != NULL)
229       {
230         ret2 = _dbus_write (fd, buffer2, start2, len2);
231         if (ret2 < 0)
232           ret2 = 0; /* we can't report an error as the first write was OK */
233        
234         return ret1 + ret2;
235       }
236     else
237       return ret1;
238   }
239 #endif /* !HAVE_WRITEV */   
240 }
241
242 /**
243  * Creates a socket and connects it to the UNIX domain socket at the
244  * given path.  The connection fd is returned, and is set up as
245  * nonblocking.
246  *
247  * @param path the path to UNIX domain socket
248  * @param result return location for error code
249  * @returns connection file descriptor or -1 on error
250  */
251 int
252 _dbus_connect_unix_socket (const char     *path,
253                            DBusResultCode *result)
254 {
255   int fd;
256   struct sockaddr_un addr;  
257   
258   fd = socket (AF_LOCAL, SOCK_STREAM, 0);
259
260   if (fd < 0)
261     {
262       dbus_set_result (result,
263                        _dbus_result_from_errno (errno));
264       
265       _dbus_verbose ("Failed to create socket: %s\n",
266                      _dbus_strerror (errno)); 
267       
268       return -1;
269     }
270
271   _DBUS_ZERO (addr);
272   addr.sun_family = AF_LOCAL;
273   strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
274   addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH] = '\0';
275   
276   if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
277     {      
278       dbus_set_result (result,
279                        _dbus_result_from_errno (errno));
280
281       _dbus_verbose ("Failed to connect to socket %s: %s\n",
282                      path, _dbus_strerror (errno));
283
284       close (fd);
285       fd = -1;
286       
287       return -1;
288     }
289
290   if (!_dbus_set_fd_nonblocking (fd, result))
291     {
292       close (fd);
293       fd = -1;
294
295       return -1;
296     }
297
298   return fd;
299 }
300
301 /**
302  * Creates a socket and binds it to the given path,
303  * then listens on the socket. The socket is
304  * set to be nonblocking. 
305  *
306  * @param path the socket name
307  * @param result return location for errors
308  * @returns the listening file descriptor or -1 on error
309  */
310 int
311 _dbus_listen_unix_socket (const char     *path,
312                           DBusResultCode *result)
313 {
314   int listen_fd;
315   struct sockaddr_un addr;
316
317   listen_fd = socket (AF_LOCAL, SOCK_STREAM, 0);
318
319   if (listen_fd < 0)
320     {
321       dbus_set_result (result, _dbus_result_from_errno (errno));
322       _dbus_verbose ("Failed to create socket \"%s\": %s\n",
323                      path, _dbus_strerror (errno));
324       return -1;
325     }
326
327   _DBUS_ZERO (addr);
328   addr.sun_family = AF_LOCAL;
329   strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
330   addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH] = '\0';
331   
332   if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0)
333     {
334       dbus_set_result (result, _dbus_result_from_errno (errno));
335       _dbus_verbose ("Failed to bind socket \"%s\": %s\n",
336                      path, _dbus_strerror (errno));
337       close (listen_fd);
338       return -1;
339     }
340
341   if (listen (listen_fd, 30 /* backlog */) < 0)
342     {
343       dbus_set_result (result, _dbus_result_from_errno (errno));      
344       _dbus_verbose ("Failed to listen on socket \"%s\": %s\n",
345                      path, _dbus_strerror (errno));
346       close (listen_fd);
347       return -1;
348     }
349
350   if (!_dbus_set_fd_nonblocking (listen_fd, result))
351     {
352       close (listen_fd);
353       return -1;
354     }
355   
356   return listen_fd;
357 }
358
359 /**
360  * Accepts a connection on a listening UNIX socket.
361  * Specific to UNIX domain sockets because we might
362  * add extra args to this function later to get client
363  * credentials. Handles EINTR for you.
364  *
365  * @param listen_fd the listen file descriptor
366  * @returns the connection fd of the client, or -1 on error
367  */
368 int
369 _dbus_accept_unix_socket  (int listen_fd)
370 {
371   int client_fd;
372   
373  retry:
374   client_fd = accept (listen_fd, NULL, NULL);
375   
376   if (client_fd < 0)
377     {
378       if (errno == EINTR)
379         goto retry;
380     }
381
382   return client_fd;
383 }
384
385 /** @} */
386
387 /**
388  * @addtogroup DBusString
389  *
390  * @{
391  */
392 /**
393  * Appends an integer to a DBusString.
394  * 
395  * @param str the string
396  * @param value the integer value
397  * @returns #FALSE if not enough memory or other failure.
398  */
399 dbus_bool_t
400 _dbus_string_append_int (DBusString *str,
401                          long        value)
402 {
403   /* this calculation is from comp.lang.c faq */
404 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
405   int orig_len;
406   int i;
407   char *buf;
408   
409   orig_len = _dbus_string_get_length (str);
410
411   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
412     return FALSE;
413
414   _dbus_string_get_data_len (str, &buf, orig_len, MAX_LONG_LEN);
415
416   snprintf (buf, MAX_LONG_LEN, "%ld", value);
417
418   i = 0;
419   while (*buf)
420     {
421       ++buf;
422       ++i;
423     }
424   
425   _dbus_string_shorten (str, MAX_LONG_LEN - i);
426   
427   return TRUE;
428 }
429
430 /**
431  * Appends a double to a DBusString.
432  * 
433  * @param str the string
434  * @param value the floating point value
435  * @returns #FALSE if not enough memory or other failure.
436  */
437 dbus_bool_t
438 _dbus_string_append_double (DBusString *str,
439                             double      value)
440 {
441 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
442   int orig_len;
443   char *buf;
444   int i;
445   
446   orig_len = _dbus_string_get_length (str);
447
448   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
449     return FALSE;
450
451   _dbus_string_get_data_len (str, &buf, orig_len, MAX_DOUBLE_LEN);
452
453   snprintf (buf, MAX_LONG_LEN, "%g", value);
454
455   i = 0;
456   while (*buf)
457     {
458       ++buf;
459       ++i;
460     }
461   
462   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
463   
464   return TRUE;
465 }
466
467 /**
468  * Parses an integer contained in a DBusString. Either return parameter
469  * may be #NULL if you aren't interested in it. The integer is parsed
470  * and stored in value_return. Return parameters are not initialized
471  * if the function returns #FALSE.
472  *
473  * @param str the string
474  * @param start the byte index of the start of the integer
475  * @param value_return return location of the integer value or #NULL
476  * @param end_return return location of the end of the integer, or #NULL
477  * @returns #TRUE on success
478  */
479 dbus_bool_t
480 _dbus_string_parse_int (const DBusString *str,
481                         int               start,
482                         long             *value_return,
483                         int              *end_return)
484 {
485   long v;
486   const char *p;
487   char *end;
488
489   _dbus_string_get_const_data_len (str, &p, start,
490                                    _dbus_string_get_length (str) - start);
491
492   end = NULL;
493   errno = 0;
494   v = strtol (p, &end, 0);
495   if (end == NULL || end == p || errno != 0)
496     return FALSE;
497
498   if (value_return)
499     *value_return = v;
500   if (end_return)
501     *end_return = (end - p);
502
503   return TRUE;
504 }
505
506 /**
507  * Parses a floating point number contained in a DBusString. Either
508  * return parameter may be #NULL if you aren't interested in it. The
509  * integer is parsed and stored in value_return. Return parameters are
510  * not initialized if the function returns #FALSE.
511  *
512  * @todo this function is currently locale-dependent. Should
513  * ask alexl to relicense g_ascii_strtod() code and put that in
514  * here instead, so it's locale-independent.
515  *
516  * @param str the string
517  * @param start the byte index of the start of the float
518  * @param value_return return location of the float value or #NULL
519  * @param end_return return location of the end of the float, or #NULL
520  * @returns #TRUE on success
521  */
522 dbus_bool_t
523 _dbus_string_parse_double (const DBusString *str,
524                            int               start,
525                            double           *value_return,
526                            int              *end_return)
527 {
528   double v;
529   const char *p;
530   char *end;
531
532   _dbus_warn ("_dbus_string_parse_double() needs to be made locale-independent\n");
533   
534   _dbus_string_get_const_data_len (str, &p, start,
535                                    _dbus_string_get_length (str) - start);
536
537   end = NULL;
538   errno = 0;
539   v = strtod (p, &end);
540   if (end == NULL || end == p || errno != 0)
541     return FALSE;
542
543   if (value_return)
544     *value_return = v;
545   if (end_return)
546     *end_return = (end - p);
547
548   return TRUE;
549 }
550
551 /** @} end of DBusString */