[daemon-fix] Fixed sending daemon match rules for kdbus broadcasts
[platform/upstream/dbus.git] / bus / desktop-file.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* desktop-file.c  .desktop file parser
3  *
4  * Copyright (C) 2003  CodeFactory AB
5  * Copyright (C) 2003  Red Hat Inc.
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #include <config.h>
26 #include <dbus/dbus-sysdeps.h>
27 #include <dbus/dbus-internals.h>
28 #include "desktop-file.h"
29 #include "utils.h"
30
31 typedef struct
32 {
33   char *key;
34   char *value;
35 } BusDesktopFileLine;
36
37 typedef struct
38 {
39   char *section_name;
40   
41   int n_lines;
42   BusDesktopFileLine *lines;
43   int n_allocated_lines;  
44 } BusDesktopFileSection;
45
46 struct BusDesktopFile
47 {
48   int n_sections;
49   BusDesktopFileSection *sections;
50   int n_allocated_sections;
51 };
52
53 /**
54  * Parser for service files.
55  */
56 typedef struct
57 {
58   DBusString data; /**< The data from the file */
59
60   BusDesktopFile *desktop_file; /**< The resulting object */
61   int current_section;    /**< The current section being parsed */
62   
63   int pos;          /**< Current position */
64   int len;          /**< Length */
65   int line_num;     /**< Current line number */
66   
67 } BusDesktopFileParser;
68
69 #define VALID_KEY_CHAR 1
70 #define VALID_LOCALE_CHAR 2
71 static unsigned char valid[256] = { 
72    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
73    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
74    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x3 , 0x2 , 0x0 , 
75    0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
76    0x0 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 
77    0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , 
78    0x0 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 
79    0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
80    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
81    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
82    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
83    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
84    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
85    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
86    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
87    0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 
88 };
89
90 static void report_error (BusDesktopFileParser *parser,
91                           char                 *message,
92                           const char           *error_name,
93                           DBusError            *error);
94
95 static void
96 parser_free (BusDesktopFileParser *parser)
97 {
98   bus_desktop_file_free (parser->desktop_file);
99   
100   _dbus_string_free (&parser->data);
101 }
102
103 static void
104 bus_desktop_file_line_free (BusDesktopFileLine *line)
105 {
106   dbus_free (line->key);
107   dbus_free (line->value);
108 }
109
110 static void
111 bus_desktop_file_section_free (BusDesktopFileSection *section)
112 {
113   int i;
114
115   for (i = 0; i < section->n_lines; i++)
116     bus_desktop_file_line_free (&section->lines[i]);
117
118   dbus_free (section->lines);
119   dbus_free (section->section_name);
120 }
121
122 void
123 bus_desktop_file_free (BusDesktopFile *desktop_file)
124 {
125   int i;
126
127   for (i = 0; i < desktop_file->n_sections; i++)
128     bus_desktop_file_section_free (&desktop_file->sections[i]);
129   dbus_free (desktop_file->sections);
130
131   dbus_free (desktop_file);
132 }
133
134 static dbus_bool_t
135 grow_lines_in_section (BusDesktopFileSection *section)
136 {
137   BusDesktopFileLine *lines;
138   
139   int new_n_lines;
140
141   if (section->n_allocated_lines == 0)
142     new_n_lines = 1;
143   else
144     new_n_lines = section->n_allocated_lines*2;
145
146   lines = dbus_realloc (section->lines,
147                         sizeof (BusDesktopFileLine) * new_n_lines);
148
149   if (lines == NULL)
150     return FALSE;
151   
152   section->lines = lines;
153   section->n_allocated_lines = new_n_lines;
154
155   return TRUE;
156 }
157
158 static dbus_bool_t
159 grow_sections (BusDesktopFile *desktop_file)
160 {
161   int new_n_sections;
162   BusDesktopFileSection *sections;
163   
164   if (desktop_file->n_allocated_sections == 0)
165     new_n_sections = 1;
166   else
167     new_n_sections = desktop_file->n_allocated_sections*2;
168
169   sections = dbus_realloc (desktop_file->sections,
170                            sizeof (BusDesktopFileSection) * new_n_sections);
171   if (sections == NULL)
172     return FALSE;
173   
174   desktop_file->sections = sections;
175   
176   desktop_file->n_allocated_sections = new_n_sections;
177
178   return TRUE;
179 }
180
181 static char *
182 unescape_string (BusDesktopFileParser *parser,
183                  const DBusString     *str,
184                  int                   pos,
185                  int                   end_pos,
186                  DBusError            *error)
187 {
188   char *retval, *q;
189
190   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
191   
192   /* len + 1 is enough, because unescaping never makes the
193    * string longer
194    */
195   retval = dbus_malloc (end_pos - pos + 1);
196   if (retval == NULL)
197     {
198       BUS_SET_OOM (error);
199       return NULL;
200     }
201
202   q = retval;
203   
204   while (pos < end_pos)
205     {
206       if (_dbus_string_get_byte (str, pos) == 0)
207         {
208           /* Found an embedded null */
209           dbus_free (retval);
210           report_error (parser, "Text to be unescaped contains embedded nul",
211                         BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
212           return NULL;
213         }
214
215       if (_dbus_string_get_byte (str, pos) == '\\')
216         {
217           pos ++;
218
219           if (pos >= end_pos)
220             {
221               /* Escape at end of string */
222               dbus_free (retval);
223               report_error (parser, "Text to be unescaped ended in \\",
224                             BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
225               return NULL;
226             }
227
228           switch (_dbus_string_get_byte (str, pos))
229             {
230             case 's':
231               *q++ = ' ';
232               break;
233            case 't':
234               *q++ = '\t';
235               break;
236            case 'n':
237               *q++ = '\n';
238               break;
239            case 'r':
240               *q++ = '\r';
241               break;
242            case '\\':
243               *q++ = '\\';
244               break;
245            default:
246              /* Invalid escape code */
247              dbus_free (retval);
248              report_error (parser, "Text to be unescaped had invalid escape sequence",
249                            BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
250              return NULL;
251             }
252           pos++;
253         }
254       else
255         {
256           *q++ =_dbus_string_get_byte (str, pos);
257
258           pos++;
259         }
260     }
261
262   *q = 0;
263
264   return retval;
265 }
266
267 static BusDesktopFileSection* 
268 new_section (BusDesktopFile *desktop_file,
269              const char     *name)
270 {
271   int n;
272   char *name_copy;
273   
274   if (desktop_file->n_allocated_sections == desktop_file->n_sections)
275     {
276       if (!grow_sections (desktop_file))
277         return NULL;
278     }
279
280   name_copy = _dbus_strdup (name);
281   if (name_copy == NULL)
282     return NULL;
283
284   n = desktop_file->n_sections;
285   desktop_file->sections[n].section_name = name_copy;
286
287   desktop_file->sections[n].n_lines = 0;
288   desktop_file->sections[n].lines = NULL;
289   desktop_file->sections[n].n_allocated_lines = 0;
290
291   if (!grow_lines_in_section (&desktop_file->sections[n]))
292     {
293       dbus_free (desktop_file->sections[n].section_name);
294       desktop_file->sections[n].section_name = NULL;
295       return NULL;
296     }
297
298   desktop_file->n_sections += 1;
299   
300   return &desktop_file->sections[n];  
301 }
302
303 static BusDesktopFileSection* 
304 open_section (BusDesktopFileParser *parser,
305               char                 *name)
306 {  
307   BusDesktopFileSection *section;
308
309   section = new_section (parser->desktop_file, name);
310   if (section == NULL)
311     return NULL;
312   
313   parser->current_section = parser->desktop_file->n_sections - 1;
314   _dbus_assert (&parser->desktop_file->sections[parser->current_section] == section);
315   
316   return section;
317 }
318
319 static BusDesktopFileLine *
320 new_line (BusDesktopFileParser *parser)
321 {
322   BusDesktopFileSection *section;
323   BusDesktopFileLine *line;
324   
325   section = &parser->desktop_file->sections[parser->current_section];
326
327   if (section->n_allocated_lines == section->n_lines)
328     {
329       if (!grow_lines_in_section (section))
330         return NULL;
331     }
332
333   line = &section->lines[section->n_lines++];
334
335   _DBUS_ZERO(*line);
336     
337   return line;
338 }
339
340 static dbus_bool_t
341 is_blank_line (BusDesktopFileParser *parser)
342 {
343   int p;
344   char c;
345   
346   p = parser->pos;
347
348   c = _dbus_string_get_byte (&parser->data, p);
349
350   while (c && c != '\n')
351     {
352       if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'))
353         return FALSE;
354       
355       p++;
356       c = _dbus_string_get_byte (&parser->data, p);
357     }
358
359   return TRUE;
360 }
361
362 static void
363 parse_comment_or_blank (BusDesktopFileParser *parser)
364 {
365   int line_end, eol_len;
366   
367   if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len))
368     line_end = parser->len;
369
370   if (line_end == parser->len)
371     parser->pos = parser->len;
372   else
373     parser->pos = line_end + eol_len;
374   
375   parser->line_num += 1;
376 }
377
378 static dbus_bool_t
379 is_valid_section_name (const char *name)
380 {
381   /* 5. Group names may contain all ASCII characters except for control characters and '[' and ']'. */
382
383   while (*name)
384     {
385       if (!((*name >= 'A' && *name <= 'Z') || (*name >= 'a' || *name <= 'z') ||
386             *name == '\n' || *name == '\t'))
387         return FALSE;
388       
389       name++;
390     }
391
392   return TRUE;
393 }
394
395 static dbus_bool_t
396 parse_section_start (BusDesktopFileParser *parser, DBusError *error)
397 {
398   int line_end, eol_len;
399   char *section_name;
400
401   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
402     
403   if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len))
404     line_end = parser->len;
405   
406   if (line_end - parser->pos <= 2 ||
407       _dbus_string_get_byte (&parser->data, line_end - 1) != ']')
408     {
409       report_error (parser, "Invalid syntax for section header", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error);
410       parser_free (parser);
411       return FALSE;
412     }
413
414   section_name = unescape_string (parser,
415                                   &parser->data, parser->pos + 1, line_end - 1,
416                                   error);
417
418   if (section_name == NULL)
419     {
420       parser_free (parser);
421       return FALSE;
422     }
423
424   if (!is_valid_section_name (section_name))
425     {
426       report_error (parser, "Invalid characters in section name", BUS_DESKTOP_PARSE_ERROR_INVALID_CHARS, error);
427       parser_free (parser);
428       dbus_free (section_name);
429       return FALSE;
430     }
431
432   if (open_section (parser, section_name) == NULL)
433     {
434       dbus_free (section_name);
435       parser_free (parser);
436       BUS_SET_OOM (error);
437       return FALSE;
438     }
439
440   if (line_end == parser->len)
441     parser->pos = parser->len;
442   else
443     parser->pos = line_end + eol_len;
444   
445   parser->line_num += 1;
446
447   dbus_free (section_name);
448   
449   return TRUE;
450 }
451
452 static dbus_bool_t
453 parse_key_value (BusDesktopFileParser *parser, DBusError *error)
454 {
455   int line_end, eol_len;
456   int key_start, key_end;
457   int value_start;
458   int p;
459   char *value, *tmp;
460   DBusString key;
461   BusDesktopFileLine *line;
462
463   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
464   
465   if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len))
466     line_end = parser->len;
467   
468   p = parser->pos;
469   key_start = p;
470   while (p < line_end &&
471          (valid[_dbus_string_get_byte (&parser->data, p)] & VALID_KEY_CHAR))
472     p++;
473   key_end = p;
474   
475   if (key_start == key_end)
476     {
477       report_error (parser, "Empty key name", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error);
478       parser_free (parser);
479       return FALSE;
480     }
481
482   /* We ignore locales for now */
483   if (p < line_end && _dbus_string_get_byte (&parser->data, p) == '[')
484     {
485       if (line_end == parser->len)
486         parser->pos = parser->len;
487       else
488         parser->pos = line_end + eol_len;
489           
490       parser->line_num += 1;
491
492       return TRUE;
493     }
494   
495   /* Skip space before '=' */
496   while (p < line_end && _dbus_string_get_byte (&parser->data, p) == ' ')
497     p++;
498
499   if (p < line_end && _dbus_string_get_byte (&parser->data, p) != '=')
500     {
501       report_error (parser, "Invalid characters in key name", BUS_DESKTOP_PARSE_ERROR_INVALID_CHARS, error);
502       parser_free (parser);
503       return FALSE;
504     }
505
506   if (p == line_end)
507     {
508       report_error (parser, "No '=' in key/value pair", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error);
509       parser_free (parser);
510       return FALSE;
511     }
512
513   /* Skip the '=' */
514   p++;
515
516   /* Skip space after '=' */
517   while (p < line_end && _dbus_string_get_byte (&parser->data, p) == ' ')
518     p++;
519
520   value_start = p;
521   
522   value = unescape_string (parser, &parser->data, value_start, line_end, error);
523   if (value == NULL)
524     {
525       parser_free (parser);
526       return FALSE;
527     }
528
529   line = new_line (parser);
530   if (line == NULL)
531     {
532       dbus_free (value);
533       parser_free (parser);
534       BUS_SET_OOM (error);
535       return FALSE;
536     }
537   
538   if (!_dbus_string_init (&key))
539     {
540       dbus_free (value);
541       parser_free (parser);
542       BUS_SET_OOM (error);
543       return FALSE;
544     }
545   
546   if (!_dbus_string_copy_len (&parser->data, key_start, key_end - key_start,
547                               &key, 0))
548     {
549       _dbus_string_free (&key);
550       dbus_free (value);
551       parser_free (parser);
552       BUS_SET_OOM (error);
553       return FALSE;
554     }
555   
556   if (!_dbus_string_steal_data (&key, &tmp))
557     {
558       _dbus_string_free (&key);
559       dbus_free (value);
560       parser_free (parser);
561       BUS_SET_OOM (error);
562       return FALSE;
563     }
564   
565   _dbus_string_free (&key);
566   
567   line->key = tmp;
568   line->value = value;
569
570   if (line_end == parser->len)
571     parser->pos = parser->len;
572   else
573     parser->pos = line_end + eol_len;
574   
575   parser->line_num += 1;
576
577   return TRUE;
578 }
579
580 static void
581 report_error (BusDesktopFileParser *parser,
582               char                 *message,
583               const char           *error_name,
584               DBusError            *error)
585 {
586   const char *section_name = NULL;
587
588   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
589   
590   if (parser->current_section != -1)
591     section_name = parser->desktop_file->sections[parser->current_section].section_name;
592
593   if (section_name)
594     dbus_set_error (error, error_name,
595                     "Error in section %s at line %d: %s\n", section_name, parser->line_num, message);
596   else
597     dbus_set_error (error, error_name,
598                     "Error at line %d: %s\n", parser->line_num, message);
599 }
600
601 #if 0
602 static void
603 dump_desktop_file (BusDesktopFile *file)
604 {
605   int i;
606
607   for (i = 0; i < file->n_sections; i++)
608     {
609       int j;
610       
611       printf ("[%s]\n", file->sections[i].section_name);
612
613       for (j = 0; j < file->sections[i].n_lines; j++)
614         {
615           printf ("%s=%s\n", file->sections[i].lines[j].key,
616                   file->sections[i].lines[j].value);
617         }
618     }
619 }
620 #endif
621
622 BusDesktopFile*
623 bus_desktop_file_load (DBusString *filename,
624                        DBusError  *error)
625 {
626   DBusString str;
627   BusDesktopFileParser parser;
628   DBusStat sb;
629
630   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
631   
632   /* Clearly there's a race here, but it's just to make it unlikely
633    * that we do something silly, we still handle doing it below.
634    */
635   if (!_dbus_stat (filename, &sb, error))
636     return NULL;
637
638   if (sb.size > _DBUS_ONE_KILOBYTE * 128)
639     {
640       dbus_set_error (error, DBUS_ERROR_FAILED,
641                       "Desktop file size (%ld bytes) is too large", (long) sb.size);
642       return NULL;
643     }
644   
645   if (!_dbus_string_init (&str))
646     {
647       BUS_SET_OOM (error);
648       return NULL;
649     }
650   
651   if (!_dbus_file_get_contents (&str, filename, error))
652     {
653       _dbus_string_free (&str);
654       return NULL;
655     }
656
657   if (!_dbus_string_validate_utf8 (&str, 0, _dbus_string_get_length (&str)))
658     {
659       _dbus_string_free (&str);
660       dbus_set_error (error, DBUS_ERROR_FAILED,
661                       "invalid UTF-8");   
662       return NULL;
663     }
664   
665   parser.desktop_file = dbus_new0 (BusDesktopFile, 1);
666   if (parser.desktop_file == NULL)
667     {
668       _dbus_string_free (&str);
669       BUS_SET_OOM (error);
670       return NULL;
671     }
672   
673   parser.data = str;
674   parser.line_num = 1;
675   parser.pos = 0;
676   parser.len = _dbus_string_get_length (&parser.data);
677   parser.current_section = -1;
678
679   while (parser.pos < parser.len)
680     {
681       if (_dbus_string_get_byte (&parser.data, parser.pos) == '[')
682         {
683           if (!parse_section_start (&parser, error))
684             {
685               return NULL;
686             }
687         }
688       else if (is_blank_line (&parser) ||
689                _dbus_string_get_byte (&parser.data, parser.pos) == '#')
690         parse_comment_or_blank (&parser);
691       else if (parser.current_section < 0)
692         {
693            dbus_set_error(error, DBUS_ERROR_FAILED,
694                           "invalid service file: key=value before [Section]");
695            return NULL;
696         }
697       else
698         {
699           if (!parse_key_value (&parser, error))
700             {
701               return NULL;
702             }
703         }
704     }
705
706   _dbus_string_free (&parser.data);
707
708   return parser.desktop_file;
709 }
710
711 static BusDesktopFileSection *
712 lookup_section (BusDesktopFile *desktop_file,
713                 const char     *section_name)
714 {
715   BusDesktopFileSection *section;
716   int i;
717   
718   if (section_name == NULL)
719     return NULL;
720   
721   for (i = 0; i < desktop_file->n_sections; i ++)
722     {
723       section = &desktop_file->sections[i];
724
725       if (strcmp (section->section_name, section_name) == 0)
726         return section;
727     }
728   
729   return NULL;
730 }
731
732 static BusDesktopFileLine *
733 lookup_line (BusDesktopFile        *desktop_file,
734              BusDesktopFileSection *section,
735              const char            *keyname)
736 {
737   BusDesktopFileLine *line;
738   int i;
739
740   for (i = 0; i < section->n_lines; i++)
741     {
742       line = &section->lines[i];
743       
744       if (strcmp (line->key, keyname) == 0)
745         return line;
746     }
747   
748   return NULL;
749 }
750
751 dbus_bool_t
752 bus_desktop_file_get_raw (BusDesktopFile  *desktop_file,
753                           const char      *section_name,
754                           const char      *keyname,
755                           const char     **val)
756 {
757   BusDesktopFileSection *section;
758   BusDesktopFileLine *line;
759
760   *val = NULL;
761
762   section = lookup_section (desktop_file, section_name);
763   
764   if (!section)
765     return FALSE;
766
767   line = lookup_line (desktop_file,
768                       section,
769                       keyname);
770
771   if (!line)
772     return FALSE;
773   
774   *val = line->value;
775   
776   return TRUE;
777 }
778
779 dbus_bool_t
780 bus_desktop_file_get_string (BusDesktopFile  *desktop_file,
781                              const char      *section,
782                              const char      *keyname,
783                              char           **val,
784                              DBusError       *error)
785 {
786   const char *raw;
787  
788   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
789
790   *val = NULL;
791   
792   if (!bus_desktop_file_get_raw (desktop_file, section, keyname, &raw))
793     {
794       dbus_set_error (error, DBUS_ERROR_FAILED,
795                       "No \"%s\" key in .service file\n", keyname);
796       return FALSE;
797     }
798
799   *val = _dbus_strdup (raw);
800
801   if (*val == NULL)
802     {
803       BUS_SET_OOM (error);
804       return FALSE;
805     }
806   
807   return TRUE;
808 }