fed88144b2942db3d33da420e5fa5a4ca4e1a08b
[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
120 #if 0
121       if (bytes_read > 0)
122         _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
123 #endif
124       
125       return bytes_read;
126     }
127 }
128
129 /**
130  * Thin wrapper around the write() system call that writes a part of a
131  * DBusString and handles EINTR for you.
132  * 
133  * @param fd the file descriptor to write
134  * @param buffer the buffer to write data from
135  * @param start the first byte in the buffer to write
136  * @param len the number of bytes to try to write
137  * @returns the number of bytes written or -1 on error
138  */
139 int
140 _dbus_write (int               fd,
141              const DBusString *buffer,
142              int               start,
143              int               len)
144 {
145   const char *data;
146   int bytes_written;
147   
148   _dbus_string_get_const_data_len (buffer, &data, start, len);
149   
150  again:
151
152   bytes_written = write (fd, data, len);
153
154   if (errno == EINTR)
155     goto again;
156
157 #if 0
158   if (bytes_written > 0)
159     _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
160 #endif
161   
162   return bytes_written;
163 }
164
165 /**
166  * Like _dbus_write() but will use writev() if possible
167  * to write both buffers in sequence. The return value
168  * is the number of bytes written in the first buffer,
169  * plus the number written in the second. If the first
170  * buffer is written successfully and an error occurs
171  * writing the second, the number of bytes in the first
172  * is returned (i.e. the error is ignored), on systems that
173  * don't have writev. Handles EINTR for you.
174  * The second buffer may be #NULL.
175  *
176  * @param fd the file descriptor
177  * @param buffer1 first buffer
178  * @param start1 first byte to write in first buffer
179  * @param len1 number of bytes to write from first buffer
180  * @param buffer2 second buffer, or #NULL
181  * @param start2 first byte to write in second buffer
182  * @param len2 number of bytes to write in second buffer
183  * @returns total bytes written from both buffers, or -1 on error
184  */
185 int
186 _dbus_write_two (int               fd,
187                  const DBusString *buffer1,
188                  int               start1,
189                  int               len1,
190                  const DBusString *buffer2,
191                  int               start2,
192                  int               len2)
193 {
194   _dbus_assert (buffer1 != NULL);
195   _dbus_assert (start1 >= 0);
196   _dbus_assert (start2 >= 0);
197   _dbus_assert (len1 >= 0);
198   _dbus_assert (len2 >= 0);
199   
200 #ifdef HAVE_WRITEV
201   {
202     struct iovec vectors[2];
203     const char *data1;
204     const char *data2;
205     int bytes_written;
206
207     _dbus_string_get_const_data_len (buffer1, &data1, start1, len1);
208
209     if (buffer2 != NULL)
210       _dbus_string_get_const_data_len (buffer2, &data2, start2, len2);
211     else
212       {
213         data2 = NULL;
214         start2 = 0;
215         len2 = 0;
216       }
217    
218     vectors[0].iov_base = (char*) data1;
219     vectors[0].iov_len = len1;
220     vectors[1].iov_base = (char*) data2;
221     vectors[1].iov_len = len2;
222
223   again:
224    
225     bytes_written = writev (fd,
226                             vectors,
227                             data2 ? 2 : 1);
228
229     if (errno == EINTR)
230       goto again;
231    
232     return bytes_written;
233   }
234 #else /* HAVE_WRITEV */
235   {
236     int ret1;
237     
238     ret1 = _dbus_write (fd, buffer1, start1, len1);
239     if (ret1 == len1 && buffer2 != NULL)
240       {
241         ret2 = _dbus_write (fd, buffer2, start2, len2);
242         if (ret2 < 0)
243           ret2 = 0; /* we can't report an error as the first write was OK */
244        
245         return ret1 + ret2;
246       }
247     else
248       return ret1;
249   }
250 #endif /* !HAVE_WRITEV */   
251 }
252
253 /**
254  * Creates a socket and connects it to the UNIX domain socket at the
255  * given path.  The connection fd is returned, and is set up as
256  * nonblocking.
257  *
258  * @param path the path to UNIX domain socket
259  * @param result return location for error code
260  * @returns connection file descriptor or -1 on error
261  */
262 int
263 _dbus_connect_unix_socket (const char     *path,
264                            DBusResultCode *result)
265 {
266   int fd;
267   struct sockaddr_un addr;  
268   
269   fd = socket (AF_LOCAL, SOCK_STREAM, 0);
270
271   if (fd < 0)
272     {
273       dbus_set_result (result,
274                        _dbus_result_from_errno (errno));
275       
276       _dbus_verbose ("Failed to create socket: %s\n",
277                      _dbus_strerror (errno)); 
278       
279       return -1;
280     }
281
282   _DBUS_ZERO (addr);
283   addr.sun_family = AF_LOCAL;
284   strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
285   addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH] = '\0';
286   
287   if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
288     {      
289       dbus_set_result (result,
290                        _dbus_result_from_errno (errno));
291
292       _dbus_verbose ("Failed to connect to socket %s: %s\n",
293                      path, _dbus_strerror (errno));
294
295       close (fd);
296       fd = -1;
297       
298       return -1;
299     }
300
301   if (!_dbus_set_fd_nonblocking (fd, result))
302     {
303       close (fd);
304       fd = -1;
305
306       return -1;
307     }
308
309   return fd;
310 }
311
312 /**
313  * Creates a socket and binds it to the given path,
314  * then listens on the socket. The socket is
315  * set to be nonblocking. 
316  *
317  * @param path the socket name
318  * @param result return location for errors
319  * @returns the listening file descriptor or -1 on error
320  */
321 int
322 _dbus_listen_unix_socket (const char     *path,
323                           DBusResultCode *result)
324 {
325   int listen_fd;
326   struct sockaddr_un addr;
327
328   listen_fd = socket (AF_LOCAL, SOCK_STREAM, 0);
329
330   if (listen_fd < 0)
331     {
332       dbus_set_result (result, _dbus_result_from_errno (errno));
333       _dbus_verbose ("Failed to create socket \"%s\": %s\n",
334                      path, _dbus_strerror (errno));
335       return -1;
336     }
337
338   _DBUS_ZERO (addr);
339   addr.sun_family = AF_LOCAL;
340   strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
341   addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH] = '\0';
342   
343   if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0)
344     {
345       dbus_set_result (result, _dbus_result_from_errno (errno));
346       _dbus_verbose ("Failed to bind socket \"%s\": %s\n",
347                      path, _dbus_strerror (errno));
348       close (listen_fd);
349       return -1;
350     }
351
352   if (listen (listen_fd, 30 /* backlog */) < 0)
353     {
354       dbus_set_result (result, _dbus_result_from_errno (errno));      
355       _dbus_verbose ("Failed to listen on socket \"%s\": %s\n",
356                      path, _dbus_strerror (errno));
357       close (listen_fd);
358       return -1;
359     }
360
361   if (!_dbus_set_fd_nonblocking (listen_fd, result))
362     {
363       close (listen_fd);
364       return -1;
365     }
366   
367   return listen_fd;
368 }
369
370 /**
371  * Accepts a connection on a listening UNIX socket.
372  * Specific to UNIX domain sockets because we might
373  * add extra args to this function later to get client
374  * credentials. Handles EINTR for you.
375  *
376  * @param listen_fd the listen file descriptor
377  * @returns the connection fd of the client, or -1 on error
378  */
379 int
380 _dbus_accept_unix_socket  (int listen_fd)
381 {
382   int client_fd;
383   
384  retry:
385   client_fd = accept (listen_fd, NULL, NULL);
386   
387   if (client_fd < 0)
388     {
389       if (errno == EINTR)
390         goto retry;
391     }
392
393   return client_fd;
394 }
395
396 /** @} */
397
398 /**
399  * @addtogroup DBusString
400  *
401  * @{
402  */
403 /**
404  * Appends an integer to a DBusString.
405  * 
406  * @param str the string
407  * @param value the integer value
408  * @returns #FALSE if not enough memory or other failure.
409  */
410 dbus_bool_t
411 _dbus_string_append_int (DBusString *str,
412                          long        value)
413 {
414   /* this calculation is from comp.lang.c faq */
415 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
416   int orig_len;
417   int i;
418   char *buf;
419   
420   orig_len = _dbus_string_get_length (str);
421
422   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
423     return FALSE;
424
425   _dbus_string_get_data_len (str, &buf, orig_len, MAX_LONG_LEN);
426
427   snprintf (buf, MAX_LONG_LEN, "%ld", value);
428
429   i = 0;
430   while (*buf)
431     {
432       ++buf;
433       ++i;
434     }
435   
436   _dbus_string_shorten (str, MAX_LONG_LEN - i);
437   
438   return TRUE;
439 }
440
441 /**
442  * Appends a double to a DBusString.
443  * 
444  * @param str the string
445  * @param value the floating point value
446  * @returns #FALSE if not enough memory or other failure.
447  */
448 dbus_bool_t
449 _dbus_string_append_double (DBusString *str,
450                             double      value)
451 {
452 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
453   int orig_len;
454   char *buf;
455   int i;
456   
457   orig_len = _dbus_string_get_length (str);
458
459   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
460     return FALSE;
461
462   _dbus_string_get_data_len (str, &buf, orig_len, MAX_DOUBLE_LEN);
463
464   snprintf (buf, MAX_LONG_LEN, "%g", value);
465
466   i = 0;
467   while (*buf)
468     {
469       ++buf;
470       ++i;
471     }
472   
473   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
474   
475   return TRUE;
476 }
477
478 /**
479  * Parses an integer contained in a DBusString. Either return parameter
480  * may be #NULL if you aren't interested in it. The integer is parsed
481  * and stored in value_return. Return parameters are not initialized
482  * if the function returns #FALSE.
483  *
484  * @param str the string
485  * @param start the byte index of the start of the integer
486  * @param value_return return location of the integer value or #NULL
487  * @param end_return return location of the end of the integer, or #NULL
488  * @returns #TRUE on success
489  */
490 dbus_bool_t
491 _dbus_string_parse_int (const DBusString *str,
492                         int               start,
493                         long             *value_return,
494                         int              *end_return)
495 {
496   long v;
497   const char *p;
498   char *end;
499
500   _dbus_string_get_const_data_len (str, &p, start,
501                                    _dbus_string_get_length (str) - start);
502
503   end = NULL;
504   errno = 0;
505   v = strtol (p, &end, 0);
506   if (end == NULL || end == p || errno != 0)
507     return FALSE;
508
509   if (value_return)
510     *value_return = v;
511   if (end_return)
512     *end_return = (end - p);
513
514   return TRUE;
515 }
516
517 /**
518  * Parses a floating point number contained in a DBusString. Either
519  * return parameter may be #NULL if you aren't interested in it. The
520  * integer is parsed and stored in value_return. Return parameters are
521  * not initialized if the function returns #FALSE.
522  *
523  * @todo this function is currently locale-dependent. Should
524  * ask alexl to relicense g_ascii_strtod() code and put that in
525  * here instead, so it's locale-independent.
526  *
527  * @param str the string
528  * @param start the byte index of the start of the float
529  * @param value_return return location of the float value or #NULL
530  * @param end_return return location of the end of the float, or #NULL
531  * @returns #TRUE on success
532  */
533 dbus_bool_t
534 _dbus_string_parse_double (const DBusString *str,
535                            int               start,
536                            double           *value_return,
537                            int              *end_return)
538 {
539   double v;
540   const char *p;
541   char *end;
542
543   _dbus_warn ("_dbus_string_parse_double() needs to be made locale-independent\n");
544   
545   _dbus_string_get_const_data_len (str, &p, start,
546                                    _dbus_string_get_length (str) - start);
547
548   end = NULL;
549   errno = 0;
550   v = strtod (p, &end);
551   if (end == NULL || end == p || errno != 0)
552     return FALSE;
553
554   if (value_return)
555     *value_return = v;
556   if (end_return)
557     *end_return = (end - p);
558
559   return TRUE;
560 }
561
562 /** @} end of DBusString */