~ubuntu-branches/ubuntu/oneiric/gconf/oneiric-proposed

« back to all changes in this revision

Viewing changes to gconf/gconf-internals.c

  • Committer: Bazaar Package Importer
  • Author(s): Takuo KITAME
  • Date: 2002-03-17 01:51:39 UTC
  • Revision ID: james.westby@ubuntu.com-20020317015139-z4f8fdg1hoe049g0
Tags: upstream-1.0.9
ImportĀ upstreamĀ versionĀ 1.0.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/* GConf
 
3
 * Copyright (C) 1999, 2000 Red Hat Inc.
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Library General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Library General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Library General Public
 
16
 * License along with this library; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
#include "gconf-internals.h"
 
23
#include "gconf-backend.h"
 
24
#include "gconf-schema.h"
 
25
#include "gconf.h"
 
26
#include <orb/orbit.h>
 
27
#include <liboaf/liboaf.h>
 
28
#include <string.h>
 
29
#include <sys/stat.h>
 
30
#include <sys/types.h>
 
31
#include <unistd.h>
 
32
#include <stdlib.h>
 
33
#include <stdio.h>
 
34
#include <fcntl.h>
 
35
#include <errno.h>
 
36
#include <ctype.h>
 
37
#include <locale.h>
 
38
#include <time.h>
 
39
#include <math.h>
 
40
 
 
41
#define g_utf8_skip gconf_g_utf8_skip
 
42
 
 
43
typedef void (* GSpawnChildSetupFunc) (gpointer user_data);
 
44
 
 
45
typedef enum
 
46
{
 
47
  G_SPAWN_LEAVE_DESCRIPTORS_OPEN = 1 << 0,
 
48
  G_SPAWN_DO_NOT_REAP_CHILD      = 1 << 1,
 
49
  /* look for argv[0] in the path i.e. use execvp() */
 
50
  G_SPAWN_SEARCH_PATH            = 1 << 2,
 
51
  /* Dump output to /dev/null */
 
52
  G_SPAWN_STDOUT_TO_DEV_NULL     = 1 << 3,
 
53
  G_SPAWN_STDERR_TO_DEV_NULL     = 1 << 4,
 
54
  G_SPAWN_CHILD_INHERITS_STDIN   = 1 << 5,
 
55
  G_SPAWN_FILE_AND_ARGV_ZERO     = 1 << 6
 
56
} GSpawnFlags;
 
57
 
 
58
static gboolean g_spawn_async (const gchar           *working_directory,
 
59
                               gchar                **argv,
 
60
                               gchar                **envp,
 
61
                               GSpawnFlags            flags,
 
62
                               GSpawnChildSetupFunc   child_setup,
 
63
                               gpointer               user_data,
 
64
                               gint                  *child_pid,
 
65
                               GError               **error);
 
66
 
 
67
gboolean gconf_log_debug_messages = FALSE;
 
68
 
 
69
static gboolean gconf_daemon_mode = FALSE;
 
70
static gchar* daemon_ior = NULL;
 
71
 
 
72
void
 
73
gconf_set_daemon_mode(gboolean setting)
 
74
{
 
75
  gconf_daemon_mode = setting;
 
76
}
 
77
 
 
78
gboolean
 
79
gconf_in_daemon_mode(void)
 
80
{
 
81
  return gconf_daemon_mode;
 
82
}
 
83
 
 
84
void
 
85
gconf_set_daemon_ior(const gchar* ior)
 
86
{
 
87
  if (daemon_ior != NULL)
 
88
    {
 
89
      g_free(daemon_ior);
 
90
      daemon_ior = NULL;
 
91
    }
 
92
      
 
93
  if (ior != NULL)
 
94
    daemon_ior = g_strdup(ior);
 
95
}
 
96
 
 
97
const gchar*
 
98
gconf_get_daemon_ior(void)
 
99
{
 
100
  return daemon_ior;
 
101
}
 
102
 
 
103
gchar*
 
104
gconf_key_directory  (const gchar* key)
 
105
{
 
106
  const gchar* end;
 
107
  gchar* retval;
 
108
  int len;
 
109
 
 
110
  end = strrchr(key, '/');
 
111
 
 
112
  if (end == NULL)
 
113
    {
 
114
      gconf_log(GCL_ERR, _("No '/' in key `%s'"), key);
 
115
      return NULL;
 
116
    }
 
117
 
 
118
  len = end-key+1;
 
119
 
 
120
  if (len == 1)
 
121
    {
 
122
      /* Root directory */
 
123
      retval = g_strdup("/");
 
124
    }
 
125
  else 
 
126
    {
 
127
      retval = g_malloc(len);
 
128
      
 
129
      strncpy(retval, key, len);
 
130
      
 
131
      retval[len-1] = '\0';
 
132
    }
 
133
 
 
134
  return retval;
 
135
}
 
136
 
 
137
const gchar*
 
138
gconf_key_key        (const gchar* key)
 
139
{
 
140
  const gchar* end;
 
141
  
 
142
  end = strrchr(key, '/');
 
143
 
 
144
  ++end;
 
145
 
 
146
  return end;
 
147
}
 
148
 
 
149
/*
 
150
 *  Random stuff 
 
151
 */
 
152
 
 
153
gboolean
 
154
gconf_file_exists (const gchar* filename)
 
155
{
 
156
  struct stat s;
 
157
  
 
158
  g_return_val_if_fail (filename != NULL,FALSE);
 
159
  
 
160
  return stat (filename, &s) == 0;
 
161
}
 
162
 
 
163
gboolean
 
164
gconf_file_test(const gchar* filename, int test)
 
165
{
 
166
  struct stat s;
 
167
  if(stat (filename, &s) != 0)
 
168
    return FALSE;
 
169
  if(!(test & GCONF_FILE_ISFILE) && S_ISREG(s.st_mode))
 
170
    return FALSE;
 
171
  if(!(test & GCONF_FILE_ISLINK) && S_ISLNK(s.st_mode))
 
172
    return FALSE;
 
173
  if(!(test & GCONF_FILE_ISDIR) && S_ISDIR(s.st_mode))
 
174
    return FALSE;
 
175
  return TRUE;
 
176
}
 
177
 
 
178
GConfValue* 
 
179
gconf_value_from_corba_value(const ConfigValue* value)
 
180
{
 
181
  GConfValue* gval;
 
182
  GConfValueType type = GCONF_VALUE_INVALID;
 
183
  
 
184
  switch (value->_d)
 
185
    {
 
186
    case InvalidVal:
 
187
      return NULL;
 
188
      break;
 
189
    case IntVal:
 
190
      type = GCONF_VALUE_INT;
 
191
      break;
 
192
    case StringVal:
 
193
      type = GCONF_VALUE_STRING;
 
194
      break;
 
195
    case FloatVal:
 
196
      type = GCONF_VALUE_FLOAT;
 
197
      break;
 
198
    case BoolVal:
 
199
      type = GCONF_VALUE_BOOL;
 
200
      break;
 
201
    case SchemaVal:
 
202
      type = GCONF_VALUE_SCHEMA;
 
203
      break;
 
204
    case ListVal:
 
205
      type = GCONF_VALUE_LIST;
 
206
      break;
 
207
    case PairVal:
 
208
      type = GCONF_VALUE_PAIR;
 
209
      break;
 
210
    default:
 
211
      gconf_log(GCL_DEBUG, "Invalid type in %s", G_GNUC_FUNCTION);
 
212
      return NULL;
 
213
    }
 
214
 
 
215
  g_assert(GCONF_VALUE_TYPE_VALID(type));
 
216
  
 
217
  gval = gconf_value_new(type);
 
218
 
 
219
  switch (gval->type)
 
220
    {
 
221
    case GCONF_VALUE_INT:
 
222
      gconf_value_set_int(gval, value->_u.int_value);
 
223
      break;
 
224
    case GCONF_VALUE_STRING:
 
225
      if (!g_utf8_validate (value->_u.string_value, -1, NULL))
 
226
        {
 
227
          gconf_log (GCL_ERR, _("Invalid UTF-8 in string value in '%s'"),
 
228
                     value->_u.string_value); 
 
229
        }
 
230
      else
 
231
        {
 
232
          gconf_value_set_string(gval, value->_u.string_value);
 
233
        }
 
234
      break;
 
235
    case GCONF_VALUE_FLOAT:
 
236
      gconf_value_set_float(gval, value->_u.float_value);
 
237
      break;
 
238
    case GCONF_VALUE_BOOL:
 
239
      gconf_value_set_bool(gval, value->_u.bool_value);
 
240
      break;
 
241
    case GCONF_VALUE_SCHEMA:
 
242
      gconf_value_set_schema_nocopy(gval, 
 
243
                                    gconf_schema_from_corba_schema(&(value->_u.schema_value)));
 
244
      break;
 
245
    case GCONF_VALUE_LIST:
 
246
      {
 
247
        GSList* list = NULL;
 
248
        guint i = 0;
 
249
        
 
250
        switch (value->_u.list_value.list_type)
 
251
          {
 
252
          case BIntVal:
 
253
            gconf_value_set_list_type(gval, GCONF_VALUE_INT);
 
254
            break;
 
255
          case BBoolVal:
 
256
            gconf_value_set_list_type(gval, GCONF_VALUE_BOOL);
 
257
            break;
 
258
          case BFloatVal:
 
259
            gconf_value_set_list_type(gval, GCONF_VALUE_FLOAT);
 
260
            break;
 
261
          case BStringVal:
 
262
            gconf_value_set_list_type(gval, GCONF_VALUE_STRING);
 
263
            break;
 
264
          case BInvalidVal:
 
265
            break;
 
266
          default:
 
267
            g_warning("Bizarre list type in %s", G_GNUC_FUNCTION);
 
268
            break;
 
269
          }
 
270
 
 
271
        if (gconf_value_get_list_type(gval) != GCONF_VALUE_INVALID)
 
272
          {
 
273
            i = 0;
 
274
            while (i < value->_u.list_value.seq._length)
 
275
              {
 
276
                GConfValue* val;
 
277
                
 
278
                /* This is a bit dubious; we cast a ConfigBasicValue to ConfigValue
 
279
                   because they have the same initial members, but by the time
 
280
                   the CORBA and C specs kick in, not sure we are guaranteed
 
281
                   to be able to do this.
 
282
                */
 
283
                val = gconf_value_from_corba_value((ConfigValue*)&value->_u.list_value.seq._buffer[i]);
 
284
                
 
285
                if (val == NULL)
 
286
                  gconf_log(GCL_ERR, _("Couldn't interpret CORBA value for list element"));
 
287
                else if (val->type != gconf_value_get_list_type(gval))
 
288
                  gconf_log(GCL_ERR, _("Incorrect type for list element in %s"), G_GNUC_FUNCTION);
 
289
                else
 
290
                  list = g_slist_prepend(list, val);
 
291
                
 
292
                ++i;
 
293
              }
 
294
        
 
295
            list = g_slist_reverse(list);
 
296
            
 
297
            gconf_value_set_list_nocopy(gval, list);
 
298
          }
 
299
        else
 
300
          {
 
301
            gconf_log(GCL_ERR, _("Received list from gconfd with a bad list type"));
 
302
          }
 
303
      }
 
304
      break;
 
305
    case GCONF_VALUE_PAIR:
 
306
      {
 
307
        g_return_val_if_fail(value->_u.pair_value._length == 2, gval);
 
308
        
 
309
        gconf_value_set_car_nocopy(gval,
 
310
                                   gconf_value_from_corba_value((ConfigValue*)&value->_u.list_value.seq._buffer[0]));
 
311
 
 
312
        gconf_value_set_cdr_nocopy(gval,
 
313
                                   gconf_value_from_corba_value((ConfigValue*)&value->_u.list_value.seq._buffer[1]));
 
314
      }
 
315
      break;
 
316
    default:
 
317
      g_assert_not_reached();
 
318
      break;
 
319
    }
 
320
  
 
321
  return gval;
 
322
}
 
323
 
 
324
void          
 
325
fill_corba_value_from_gconf_value(GConfValue* value, 
 
326
                                   ConfigValue* cv)
 
327
{
 
328
  if (value == NULL)
 
329
    {
 
330
      cv->_d = InvalidVal;
 
331
      return;
 
332
    }
 
333
 
 
334
  switch (value->type)
 
335
    {
 
336
    case GCONF_VALUE_INT:
 
337
      cv->_d = IntVal;
 
338
      cv->_u.int_value = gconf_value_get_int(value);
 
339
      break;
 
340
    case GCONF_VALUE_STRING:
 
341
      cv->_d = StringVal;
 
342
      cv->_u.string_value = CORBA_string_dup((char*)gconf_value_get_string(value));
 
343
      break;
 
344
    case GCONF_VALUE_FLOAT:
 
345
      cv->_d = FloatVal;
 
346
      cv->_u.float_value = gconf_value_get_float(value);
 
347
      break;
 
348
    case GCONF_VALUE_BOOL:
 
349
      cv->_d = BoolVal;
 
350
      cv->_u.bool_value = gconf_value_get_bool(value);
 
351
      break;
 
352
    case GCONF_VALUE_SCHEMA:
 
353
      cv->_d = SchemaVal;
 
354
      fill_corba_schema_from_gconf_schema(gconf_value_get_schema(value),
 
355
                                           &cv->_u.schema_value);
 
356
      break;
 
357
    case GCONF_VALUE_LIST:
 
358
      {
 
359
        guint n, i;
 
360
        GSList* list;
 
361
        
 
362
        cv->_d = ListVal;
 
363
 
 
364
        list = gconf_value_get_list(value);
 
365
 
 
366
        n = g_slist_length(list);
 
367
 
 
368
        cv->_u.list_value.seq._buffer =
 
369
          CORBA_sequence_ConfigBasicValue_allocbuf(n);
 
370
        cv->_u.list_value.seq._length = n;
 
371
        cv->_u.list_value.seq._maximum = n;
 
372
        CORBA_sequence_set_release(&cv->_u.list_value.seq, TRUE);
 
373
        
 
374
        switch (gconf_value_get_list_type(value))
 
375
          {
 
376
          case GCONF_VALUE_INT:
 
377
            cv->_u.list_value.list_type = BIntVal;
 
378
            break;
 
379
 
 
380
          case GCONF_VALUE_BOOL:
 
381
            cv->_u.list_value.list_type = BBoolVal;
 
382
            break;
 
383
            
 
384
          case GCONF_VALUE_STRING:
 
385
            cv->_u.list_value.list_type = BStringVal;
 
386
            break;
 
387
 
 
388
          case GCONF_VALUE_FLOAT:
 
389
            cv->_u.list_value.list_type = BFloatVal;
 
390
            break;
 
391
 
 
392
          case GCONF_VALUE_SCHEMA:
 
393
            cv->_u.list_value.list_type = BSchemaVal;
 
394
            break;
 
395
            
 
396
          default:
 
397
            cv->_u.list_value.list_type = BInvalidVal;
 
398
            gconf_log(GCL_DEBUG, "Invalid list type in %s", G_GNUC_FUNCTION);
 
399
            break;
 
400
          }
 
401
        
 
402
        i= 0;
 
403
        while (list != NULL)
 
404
          {
 
405
            /* That dubious ConfigBasicValue->ConfigValue cast again */
 
406
            fill_corba_value_from_gconf_value((GConfValue*)list->data,
 
407
                                               (ConfigValue*)&cv->_u.list_value.seq._buffer[i]);
 
408
 
 
409
            list = g_slist_next(list);
 
410
            ++i;
 
411
          }
 
412
      }
 
413
      break;
 
414
    case GCONF_VALUE_PAIR:
 
415
      {
 
416
        cv->_d = PairVal;
 
417
 
 
418
        cv->_u.pair_value._buffer =
 
419
          CORBA_sequence_ConfigBasicValue_allocbuf(2);
 
420
        cv->_u.pair_value._length = 2;
 
421
        cv->_u.pair_value._maximum = 2;
 
422
        CORBA_sequence_set_release(&cv->_u.pair_value, TRUE);
 
423
        
 
424
        /* dubious cast */
 
425
        fill_corba_value_from_gconf_value(gconf_value_get_car(value),
 
426
                                           (ConfigValue*)&cv->_u.pair_value._buffer[0]);
 
427
        fill_corba_value_from_gconf_value(gconf_value_get_cdr(value),
 
428
                                           (ConfigValue*)&cv->_u.pair_value._buffer[1]);
 
429
      }
 
430
      break;
 
431
      
 
432
    case GCONF_VALUE_INVALID:
 
433
      cv->_d = InvalidVal;
 
434
      break;
 
435
    default:
 
436
      cv->_d = InvalidVal;
 
437
      gconf_log(GCL_DEBUG, "Unknown type in %s", G_GNUC_FUNCTION);
 
438
      break;
 
439
    }
 
440
}
 
441
 
 
442
ConfigValue*  
 
443
corba_value_from_gconf_value(GConfValue* value)
 
444
{
 
445
  ConfigValue* cv;
 
446
 
 
447
  cv = ConfigValue__alloc();
 
448
 
 
449
  fill_corba_value_from_gconf_value(value, cv);
 
450
 
 
451
  return cv;
 
452
}
 
453
 
 
454
ConfigValue*  
 
455
invalid_corba_value()
 
456
{
 
457
  ConfigValue* cv;
 
458
 
 
459
  cv = ConfigValue__alloc();
 
460
 
 
461
  cv->_d = InvalidVal;
 
462
 
 
463
  return cv;
 
464
}
 
465
 
 
466
gchar*
 
467
gconf_object_to_string (CORBA_Object obj,
 
468
                        GError **err)
 
469
{
 
470
  CORBA_Environment ev;
 
471
  gchar *ior;
 
472
  gchar *retval;
 
473
  
 
474
  CORBA_exception_init (&ev);
 
475
 
 
476
  ior = CORBA_ORB_object_to_string (gconf_orb_get (), obj, &ev);
 
477
 
 
478
  if (ior == NULL)
 
479
    {
 
480
      gconf_set_error (err,
 
481
                       GCONF_ERROR_FAILED,
 
482
                       _("Failed to convert object to IOR"));
 
483
 
 
484
      return NULL;
 
485
    }
 
486
 
 
487
  retval = g_strdup (ior);
 
488
 
 
489
  CORBA_free (ior);
 
490
 
 
491
  return retval;
 
492
}
 
493
 
 
494
static ConfigValueType
 
495
corba_type_from_gconf_type(GConfValueType type)
 
496
{
 
497
  switch (type)
 
498
    {
 
499
    case GCONF_VALUE_INT:
 
500
      return IntVal;
 
501
    case GCONF_VALUE_BOOL:
 
502
      return BoolVal;
 
503
    case GCONF_VALUE_FLOAT:
 
504
      return FloatVal;
 
505
    case GCONF_VALUE_INVALID:
 
506
      return InvalidVal;
 
507
    case GCONF_VALUE_STRING:
 
508
      return StringVal;
 
509
    case GCONF_VALUE_SCHEMA:
 
510
      return SchemaVal;
 
511
    case GCONF_VALUE_LIST:
 
512
      return ListVal;
 
513
    case GCONF_VALUE_PAIR:
 
514
      return PairVal;
 
515
    default:
 
516
      g_assert_not_reached();
 
517
      return InvalidVal;
 
518
    }
 
519
}
 
520
 
 
521
static GConfValueType
 
522
gconf_type_from_corba_type(ConfigValueType type)
 
523
{
 
524
  switch (type)
 
525
    {
 
526
    case InvalidVal:
 
527
      return GCONF_VALUE_INVALID;
 
528
    case StringVal:
 
529
      return GCONF_VALUE_STRING;
 
530
    case IntVal:
 
531
      return GCONF_VALUE_INT;
 
532
    case FloatVal:
 
533
      return GCONF_VALUE_FLOAT;
 
534
    case SchemaVal:
 
535
      return GCONF_VALUE_SCHEMA;
 
536
    case BoolVal:
 
537
      return GCONF_VALUE_BOOL;
 
538
    case ListVal:
 
539
      return GCONF_VALUE_LIST;
 
540
    case PairVal:
 
541
      return GCONF_VALUE_PAIR;
 
542
    default:
 
543
      g_assert_not_reached();
 
544
      return GCONF_VALUE_INVALID;
 
545
    }
 
546
}
 
547
 
 
548
void          
 
549
fill_corba_schema_from_gconf_schema(GConfSchema* sc, 
 
550
                                     ConfigSchema* cs)
 
551
{
 
552
  cs->value_type = corba_type_from_gconf_type(sc->type);
 
553
  cs->value_list_type = corba_type_from_gconf_type(sc->list_type);
 
554
  cs->value_car_type = corba_type_from_gconf_type(sc->car_type);
 
555
  cs->value_cdr_type = corba_type_from_gconf_type(sc->cdr_type);
 
556
 
 
557
  cs->locale = CORBA_string_dup(sc->locale ? sc->locale : "");
 
558
  cs->short_desc = CORBA_string_dup(sc->short_desc ? sc->short_desc : "");
 
559
  cs->long_desc = CORBA_string_dup(sc->long_desc ? sc->long_desc : "");
 
560
  cs->owner = CORBA_string_dup(sc->owner ? sc->owner : "");
 
561
 
 
562
  {
 
563
    gchar* encoded;
 
564
    GConfValue* default_val;
 
565
 
 
566
    default_val = gconf_schema_get_default_value(sc);
 
567
 
 
568
    if (default_val)
 
569
      {
 
570
        encoded = gconf_value_encode(default_val);
 
571
 
 
572
        g_assert(encoded != NULL);
 
573
 
 
574
        cs->encoded_default_value = CORBA_string_dup(encoded);
 
575
 
 
576
        g_free(encoded);
 
577
      }
 
578
    else
 
579
      cs->encoded_default_value = CORBA_string_dup("");
 
580
  }
 
581
}
 
582
 
 
583
ConfigSchema* 
 
584
corba_schema_from_gconf_schema(GConfSchema* sc)
 
585
{
 
586
  ConfigSchema* cs;
 
587
 
 
588
  cs = ConfigSchema__alloc();
 
589
 
 
590
  fill_corba_schema_from_gconf_schema(sc, cs);
 
591
 
 
592
  return cs;
 
593
}
 
594
 
 
595
GConfSchema*  
 
596
gconf_schema_from_corba_schema(const ConfigSchema* cs)
 
597
{
 
598
  GConfSchema* sc;
 
599
  GConfValueType type = GCONF_VALUE_INVALID;
 
600
  GConfValueType list_type = GCONF_VALUE_INVALID;
 
601
  GConfValueType car_type = GCONF_VALUE_INVALID;
 
602
  GConfValueType cdr_type = GCONF_VALUE_INVALID;
 
603
 
 
604
  type = gconf_type_from_corba_type(cs->value_type);
 
605
  list_type = gconf_type_from_corba_type(cs->value_list_type);
 
606
  car_type = gconf_type_from_corba_type(cs->value_car_type);
 
607
  cdr_type = gconf_type_from_corba_type(cs->value_cdr_type);
 
608
 
 
609
  sc = gconf_schema_new();
 
610
 
 
611
  gconf_schema_set_type(sc, type);
 
612
  gconf_schema_set_list_type(sc, list_type);
 
613
  gconf_schema_set_car_type(sc, car_type);
 
614
  gconf_schema_set_cdr_type(sc, cdr_type);
 
615
 
 
616
  if (*cs->locale != '\0')
 
617
    {
 
618
      if (!g_utf8_validate (cs->locale, -1, NULL))
 
619
        gconf_log (GCL_ERR, _("Invalid UTF-8 in locale for schema"));
 
620
      else
 
621
        gconf_schema_set_locale(sc, cs->locale);
 
622
    }
 
623
 
 
624
  if (*cs->short_desc != '\0')
 
625
    {
 
626
      if (!g_utf8_validate (cs->short_desc, -1, NULL))
 
627
        gconf_log (GCL_ERR, _("Invalid UTF-8 in short description for schema"));
 
628
      else
 
629
        gconf_schema_set_short_desc(sc, cs->short_desc);
 
630
    }
 
631
 
 
632
  if (*cs->long_desc != '\0')
 
633
    {
 
634
      if (!g_utf8_validate (cs->long_desc, -1, NULL))
 
635
        gconf_log (GCL_ERR, _("Invalid UTF-8 in long description for schema"));
 
636
      else
 
637
        gconf_schema_set_long_desc(sc, cs->long_desc);
 
638
    }
 
639
 
 
640
  if (*cs->owner != '\0')
 
641
    {
 
642
      if (!g_utf8_validate (cs->owner, -1, NULL))
 
643
        gconf_log (GCL_ERR, _("Invalid UTF-8 in owner for schema"));
 
644
      else
 
645
        gconf_schema_set_owner(sc, cs->owner);
 
646
    }
 
647
      
 
648
  {
 
649
    GConfValue* val;
 
650
 
 
651
    val = gconf_value_decode(cs->encoded_default_value);
 
652
 
 
653
    if (val)
 
654
      gconf_schema_set_default_value_nocopy(sc, val);
 
655
  }
 
656
  
 
657
  return sc;
 
658
}
 
659
 
 
660
const gchar* 
 
661
gconf_value_type_to_string(GConfValueType type)
 
662
{
 
663
  switch (type)
 
664
    {
 
665
    case GCONF_VALUE_INT:
 
666
      return "int";
 
667
      break;
 
668
    case GCONF_VALUE_STRING:
 
669
      return "string";
 
670
      break;
 
671
    case GCONF_VALUE_FLOAT:
 
672
      return "float";
 
673
      break;
 
674
    case GCONF_VALUE_BOOL:
 
675
      return "bool";
 
676
      break;
 
677
    case GCONF_VALUE_SCHEMA:
 
678
      return "schema";
 
679
      break;
 
680
    case GCONF_VALUE_LIST:
 
681
      return "list";
 
682
      break;
 
683
    case GCONF_VALUE_PAIR:
 
684
      return "pair";
 
685
      break;
 
686
    case GCONF_VALUE_INVALID:
 
687
      return "*invalid*";
 
688
      break;
 
689
    default:
 
690
      g_assert_not_reached();
 
691
      return NULL; /* for warnings */
 
692
      break;
 
693
    }
 
694
}
 
695
 
 
696
GConfValueType 
 
697
gconf_value_type_from_string(const gchar* type_str)
 
698
{
 
699
  if (strcmp(type_str, "int") == 0)
 
700
    return GCONF_VALUE_INT;
 
701
  else if (strcmp(type_str, "float") == 0)
 
702
    return GCONF_VALUE_FLOAT;
 
703
  else if (strcmp(type_str, "string") == 0)
 
704
    return GCONF_VALUE_STRING;
 
705
  else if (strcmp(type_str, "bool") == 0)
 
706
    return GCONF_VALUE_BOOL;
 
707
  else if (strcmp(type_str, "schema") == 0)
 
708
    return GCONF_VALUE_SCHEMA;
 
709
  else if (strcmp(type_str, "list") == 0)
 
710
    return GCONF_VALUE_LIST;
 
711
  else if (strcmp(type_str, "pair") == 0)
 
712
    return GCONF_VALUE_PAIR;
 
713
  else
 
714
    return GCONF_VALUE_INVALID;
 
715
}
 
716
 
 
717
/*
 
718
 * Config files (yikes! we can't store our config in GConf!)
 
719
 */
 
720
 
 
721
static gchar*
 
722
unquote_string(gchar* s)
 
723
{
 
724
  gchar* end;
 
725
 
 
726
  /* Strip whitespace and first quote from front of string */
 
727
  while (*s && (isspace(*s) || (*s == '"')))
 
728
    ++s;
 
729
 
 
730
  end = s;
 
731
  while (*end)
 
732
    ++end;
 
733
 
 
734
  --end; /* one back from '\0' */
 
735
 
 
736
  /* Strip whitespace and last quote from end of string */
 
737
  while ((end > s) && (isspace(*end) || (*end == '"')))
 
738
    {
 
739
      *end = '\0';
 
740
      --end;
 
741
    }
 
742
 
 
743
  return s;
 
744
}
 
745
 
 
746
static const gchar*
 
747
get_variable(const gchar* varname)
 
748
{
 
749
  /* These first two DO NOT use environment variables, which
 
750
     makes things a bit more "secure" in some sense
 
751
  */
 
752
  if (strcmp(varname, "HOME") == 0)
 
753
    {
 
754
      return g_get_home_dir();
 
755
    }
 
756
  else if (strcmp(varname, "USER") == 0)
 
757
    {
 
758
      return g_get_user_name();
 
759
    }
 
760
  else if (varname[0] == 'E' &&
 
761
           varname[1] == 'N' &&
 
762
           varname[2] == 'V' &&
 
763
           varname[3] == '_')
 
764
    {
 
765
      /* This is magic: if a variable called ENV_FOO is used,
 
766
         then the environment variable FOO is checked */
 
767
      gchar* envvar = getenv(&varname[4]);
 
768
 
 
769
      if (envvar)
 
770
        return envvar;
 
771
      else
 
772
        return "";
 
773
    }
 
774
  else
 
775
    return "";
 
776
}
 
777
 
 
778
static gchar*
 
779
subst_variables(const gchar* src)
 
780
{
 
781
  const gchar* iter;
 
782
  gchar* retval;
 
783
  guint retval_len;
 
784
  guint pos;
 
785
  
 
786
  g_return_val_if_fail(src != NULL, NULL);
 
787
 
 
788
  retval_len = strlen(src) + 1;
 
789
  pos = 0;
 
790
  
 
791
  retval = g_malloc0(retval_len+3); /* add 3 just to avoid off-by-one
 
792
                                       segvs - yeah I know it bugs
 
793
                                       you, but C sucks */
 
794
  
 
795
  iter = src;
 
796
 
 
797
  while (*iter)
 
798
    {
 
799
      gboolean performed_subst = FALSE;
 
800
      
 
801
      if (pos >= retval_len)
 
802
        {
 
803
          retval_len *= 2;
 
804
          retval = g_realloc(retval, retval_len+3); /* add 3 for luck */
 
805
        }
 
806
      
 
807
      if (*iter == '$' && *(iter+1) == '(')
 
808
        {
 
809
          const gchar* varstart = iter + 2;
 
810
          const gchar* varend   = strchr(varstart, ')');
 
811
 
 
812
          if (varend != NULL)
 
813
            {
 
814
              char* varname;
 
815
              const gchar* varval;
 
816
              guint varval_len;
 
817
 
 
818
              performed_subst = TRUE;
 
819
 
 
820
              varname = g_strndup(varstart, varend - varstart);
 
821
              
 
822
              varval = get_variable(varname);
 
823
              g_free(varname);
 
824
 
 
825
              varval_len = strlen(varval);
 
826
 
 
827
              if ((retval_len - pos) < varval_len)
 
828
                {
 
829
                  retval_len *= 2;
 
830
                  retval = g_realloc(retval, retval_len+3);
 
831
                }
 
832
              
 
833
              strcpy(&retval[pos], varval);
 
834
              pos += varval_len;
 
835
 
 
836
              iter = varend + 1;
 
837
            }
 
838
        }
 
839
 
 
840
      if (!performed_subst)
 
841
        {
 
842
          retval[pos] = *iter;
 
843
          ++pos;
 
844
          ++iter;
 
845
        }
 
846
    }
 
847
  retval[pos] = '\0';
 
848
 
 
849
  return retval;
 
850
}
 
851
 
 
852
gchar**       
 
853
gconf_load_source_path(const gchar* filename, GError** err)
 
854
{
 
855
  FILE* f;
 
856
  GSList* l = NULL;
 
857
  gchar** addresses;
 
858
  gchar buf[512];
 
859
  GSList* tmp;
 
860
  guint n;
 
861
 
 
862
  f = fopen(filename, "r");
 
863
 
 
864
  if (f == NULL)
 
865
    {
 
866
      if (err)
 
867
        *err = gconf_error_new(GCONF_ERROR_FAILED,
 
868
                               _("Couldn't open path file `%s': %s\n"), 
 
869
                               filename, 
 
870
                               strerror(errno));
 
871
      return NULL;
 
872
    }
 
873
 
 
874
  while (fgets(buf, 512, f) != NULL)
 
875
    {
 
876
      gchar* s = buf;
 
877
      
 
878
      while (*s && isspace(*s))
 
879
        ++s;
 
880
 
 
881
      if (*s == '#')
 
882
        {
 
883
          /* Allow comments, why not */
 
884
        }
 
885
      else if (*s == '\0')
 
886
        {
 
887
          /* Blank line */
 
888
        }
 
889
      else if (strncmp("include", s, 7) == 0)
 
890
        {
 
891
          gchar* unq;
 
892
          gchar** included;
 
893
          gchar *varsubst;
 
894
          
 
895
          s += 7;
 
896
 
 
897
          unq = unquote_string(s);
 
898
 
 
899
          varsubst = subst_variables (unq);
 
900
          
 
901
          included = gconf_load_source_path (varsubst, NULL);
 
902
 
 
903
          g_free (varsubst);
 
904
          
 
905
          if (included != NULL)
 
906
            {
 
907
              gchar** iter = included;
 
908
 
 
909
              while (*iter)
 
910
                {
 
911
                  l = g_slist_prepend(l, *iter); /* Note that we won't free *included */
 
912
                  ++iter;
 
913
                }
 
914
 
 
915
              g_free(included); /* Only the array, not the contained strings */
 
916
            }
 
917
        }
 
918
      else 
 
919
        {
 
920
          gchar* unq;
 
921
          gchar* varsubst;
 
922
          
 
923
          unq = unquote_string(buf);
 
924
          varsubst = subst_variables(unq);
 
925
          
 
926
          if (*varsubst != '\0') /* Drop lines with just two quote marks or something */
 
927
            {
 
928
              gconf_log(GCL_DEBUG, _("Adding source `%s'\n"), varsubst);
 
929
              l = g_slist_prepend(l, g_strdup(varsubst));
 
930
            }
 
931
          g_free(varsubst);
 
932
        }
 
933
    }
 
934
 
 
935
  if (ferror(f))
 
936
    {
 
937
      /* This should basically never happen */
 
938
      if (err)
 
939
        *err = gconf_error_new(GCONF_ERROR_FAILED,
 
940
                               _("Read error on file `%s': %s\n"), 
 
941
                               filename,
 
942
                               strerror(errno));
 
943
      /* don't return, we want to go ahead and return any 
 
944
         addresses we already loaded. */
 
945
    }
 
946
 
 
947
  fclose(f);  
 
948
 
 
949
  /* This will make sense if you realize that we reversed the list 
 
950
     as we loaded it, and are now reversing it to be correct again. 
 
951
  */
 
952
 
 
953
  if (l == NULL)
 
954
    return NULL;
 
955
 
 
956
  n = g_slist_length(l);
 
957
 
 
958
  g_assert(n > 0);
 
959
  
 
960
  addresses = g_malloc0(sizeof(gchar*) * (n+1));
 
961
 
 
962
  addresses[n] = NULL;
 
963
 
 
964
  --n;
 
965
  tmp = l;
 
966
 
 
967
  while (tmp != NULL)
 
968
    {
 
969
      addresses[n] = tmp->data;
 
970
 
 
971
      tmp = g_slist_next(tmp);
 
972
      --n;
 
973
    }
 
974
  
 
975
  g_assert(addresses[0] != NULL); /* since we used malloc0 this detects bad logic */
 
976
 
 
977
  return addresses;
 
978
}
 
979
 
 
980
/* This should also support concatting filesystem dirs and keys, 
 
981
   or dir and subdir.
 
982
*/
 
983
gchar*        
 
984
gconf_concat_dir_and_key(const gchar* dir, const gchar* key)
 
985
{
 
986
  guint dirlen;
 
987
  guint keylen;
 
988
  gchar* retval;
 
989
 
 
990
  g_return_val_if_fail(dir != NULL, NULL);
 
991
  g_return_val_if_fail(key != NULL, NULL);
 
992
  g_return_val_if_fail(*dir == '/', NULL);
 
993
 
 
994
  dirlen = strlen(dir);
 
995
  keylen = strlen(key);
 
996
 
 
997
  retval = g_malloc0(dirlen+keylen+3); /* auto-null-terminate */
 
998
 
 
999
  strcpy(retval, dir);
 
1000
 
 
1001
  if (dir[dirlen-1] == '/')
 
1002
    {
 
1003
      /* dir ends in slash, strip key slash if needed */
 
1004
      if (*key == '/')
 
1005
        ++key;
 
1006
 
 
1007
      strcpy((retval+dirlen), key);
 
1008
    }
 
1009
  else 
 
1010
    {
 
1011
      /* Dir doesn't end in slash, add slash if key lacks one. */
 
1012
      gchar* dest = retval + dirlen;
 
1013
 
 
1014
      if (*key != '/')
 
1015
        {
 
1016
          *dest = '/';
 
1017
          ++dest;
 
1018
        }
 
1019
      
 
1020
      strcpy(dest, key);
 
1021
    }
 
1022
  
 
1023
  return retval;
 
1024
}
 
1025
 
 
1026
gulong
 
1027
gconf_string_to_gulong(const gchar* str)
 
1028
{
 
1029
  gulong retval;
 
1030
  gchar *end;
 
1031
  errno = 0;
 
1032
  retval = strtoul(str, &end, 10);
 
1033
  if (end == str || errno != 0)
 
1034
    retval = 0;
 
1035
 
 
1036
  return retval;
 
1037
}
 
1038
 
 
1039
gboolean
 
1040
gconf_string_to_double(const gchar* str, gdouble* retloc)
 
1041
{
 
1042
  int res;
 
1043
  char *old_locale;
 
1044
 
 
1045
  /* make sure we write values to files in a consistent manner */
 
1046
  old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
 
1047
  setlocale (LC_NUMERIC, "C");
 
1048
 
 
1049
  *retloc = 0.0;
 
1050
  res = sscanf (str, "%lf", retloc);
 
1051
 
 
1052
  setlocale (LC_NUMERIC, old_locale);
 
1053
  g_free (old_locale);
 
1054
 
 
1055
  if (res == 1)
 
1056
    return TRUE;
 
1057
  else
 
1058
    return FALSE;
 
1059
}
 
1060
 
 
1061
gchar*
 
1062
gconf_double_to_string(gdouble val)
 
1063
{
 
1064
  char str[101 + DBL_DIG];
 
1065
  char *old_locale;
 
1066
 
 
1067
  /* make sure we write values to files in a consistent manner */
 
1068
  old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
 
1069
  setlocale (LC_NUMERIC, "C");
 
1070
  
 
1071
  if (fabs (val) < 1e9 && fabs (val) > 1e-5)
 
1072
    g_snprintf (str, 100 + DBL_DIG, "%.*g", DBL_DIG, val);
 
1073
  else
 
1074
    g_snprintf (str, 100 + DBL_DIG, "%f", val);
 
1075
 
 
1076
  setlocale (LC_NUMERIC, old_locale);
 
1077
  g_free (old_locale);
 
1078
  
 
1079
  return g_strdup(str);
 
1080
}
 
1081
 
 
1082
const gchar*
 
1083
gconf_current_locale(void)
 
1084
{
 
1085
#ifdef HAVE_LC_MESSAGES
 
1086
  return setlocale(LC_MESSAGES, NULL);
 
1087
#else
 
1088
  return setlocale(LC_CTYPE, NULL);
 
1089
#endif
 
1090
}
 
1091
 
 
1092
/*
 
1093
 * Log
 
1094
 */
 
1095
 
 
1096
gchar*
 
1097
gconf_quote_percents(const gchar* src)
 
1098
{
 
1099
  gchar* dest;
 
1100
  const gchar* s;
 
1101
  gchar* d;
 
1102
 
 
1103
  g_return_val_if_fail(src != NULL, NULL);
 
1104
  
 
1105
  /* waste memory! woo-hoo! */
 
1106
  dest = g_malloc0(strlen(src)*2+4);
 
1107
  
 
1108
  d = dest;
 
1109
  
 
1110
  s = src;
 
1111
  while (*s)
 
1112
    {
 
1113
      switch (*s)
 
1114
        {
 
1115
        case '%':
 
1116
          {
 
1117
            *d = '%';
 
1118
            ++d;
 
1119
            *d = '%';
 
1120
            ++d;
 
1121
          }
 
1122
          break;
 
1123
          
 
1124
        default:
 
1125
          {
 
1126
            *d = *s;
 
1127
            ++d;
 
1128
          }
 
1129
          break;
 
1130
        }
 
1131
      ++s;
 
1132
    }
 
1133
 
 
1134
  /* End with NULL */
 
1135
  *d = '\0';
 
1136
  
 
1137
  return dest;
 
1138
}
 
1139
 
 
1140
#include <syslog.h>
 
1141
 
 
1142
void
 
1143
gconf_log(GConfLogPriority pri, const gchar* fmt, ...)
 
1144
{
 
1145
  gchar* msg;
 
1146
  va_list args;
 
1147
  int syslog_pri = LOG_DEBUG;
 
1148
 
 
1149
  if (!gconf_log_debug_messages && 
 
1150
      pri == GCL_DEBUG)
 
1151
    return;
 
1152
  
 
1153
  va_start (args, fmt);
 
1154
  msg = g_strdup_vprintf(fmt, args);
 
1155
  va_end (args);
 
1156
 
 
1157
  if (gconf_daemon_mode)
 
1158
    {
 
1159
      switch (pri)
 
1160
        {
 
1161
        case GCL_EMERG:
 
1162
          syslog_pri = LOG_EMERG;
 
1163
          break;
 
1164
      
 
1165
        case GCL_ALERT:
 
1166
          syslog_pri = LOG_ALERT;
 
1167
          break;
 
1168
      
 
1169
        case GCL_CRIT:
 
1170
          syslog_pri = LOG_CRIT;
 
1171
          break;
 
1172
      
 
1173
        case GCL_ERR:
 
1174
          syslog_pri = LOG_ERR;
 
1175
          break;
 
1176
      
 
1177
        case GCL_WARNING:
 
1178
          syslog_pri = LOG_WARNING;
 
1179
          break;
 
1180
      
 
1181
        case GCL_NOTICE:
 
1182
          syslog_pri = LOG_NOTICE;
 
1183
          break;
 
1184
      
 
1185
        case GCL_INFO:
 
1186
          syslog_pri = LOG_INFO;
 
1187
          break;
 
1188
      
 
1189
        case GCL_DEBUG:
 
1190
          syslog_pri = LOG_DEBUG;
 
1191
          break;
 
1192
 
 
1193
        default:
 
1194
          g_assert_not_reached();
 
1195
          break;
 
1196
        }
 
1197
 
 
1198
      syslog(syslog_pri, "%s", msg);
 
1199
    }
 
1200
  else
 
1201
    {
 
1202
      switch (pri)
 
1203
        {
 
1204
        case GCL_EMERG:
 
1205
        case GCL_ALERT:
 
1206
        case GCL_CRIT:
 
1207
        case GCL_ERR:
 
1208
        case GCL_WARNING:
 
1209
          fprintf(stderr, "%s\n", msg);
 
1210
          break;
 
1211
      
 
1212
        case GCL_NOTICE:
 
1213
        case GCL_INFO:
 
1214
        case GCL_DEBUG:
 
1215
          printf("%s\n", msg);
 
1216
          break;
 
1217
 
 
1218
        default:
 
1219
          g_assert_not_reached();
 
1220
          break;
 
1221
        }
 
1222
    }
 
1223
  
 
1224
  g_free(msg);
 
1225
}
 
1226
 
 
1227
/*
 
1228
 * List/pair conversion
 
1229
 */
 
1230
 
 
1231
GConfValue*
 
1232
gconf_value_list_from_primitive_list(GConfValueType list_type, GSList* list,
 
1233
                                     GError **err)
 
1234
{
 
1235
  GSList* value_list;
 
1236
  GSList* tmp;
 
1237
 
 
1238
  g_return_val_if_fail(list_type != GCONF_VALUE_INVALID, NULL);
 
1239
  g_return_val_if_fail(list_type != GCONF_VALUE_LIST, NULL);
 
1240
  g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, NULL);
 
1241
  
 
1242
  value_list = NULL;
 
1243
 
 
1244
  tmp = list;
 
1245
 
 
1246
  while (tmp != NULL)
 
1247
    {
 
1248
      GConfValue* val;
 
1249
 
 
1250
      val = gconf_value_new(list_type);
 
1251
 
 
1252
      switch (list_type)
 
1253
        {
 
1254
        case GCONF_VALUE_INT:
 
1255
          gconf_value_set_int(val, GPOINTER_TO_INT(tmp->data));
 
1256
          break;
 
1257
 
 
1258
        case GCONF_VALUE_BOOL:
 
1259
          gconf_value_set_bool(val, GPOINTER_TO_INT(tmp->data));
 
1260
          break;
 
1261
 
 
1262
        case GCONF_VALUE_FLOAT:
 
1263
          gconf_value_set_float(val, *((gdouble*)tmp->data));
 
1264
          break;
 
1265
 
 
1266
        case GCONF_VALUE_STRING:
 
1267
          if (!g_utf8_validate (tmp->data, -1, NULL))
 
1268
            {
 
1269
              g_set_error (err, GCONF_ERROR,
 
1270
                           GCONF_ERROR_FAILED,
 
1271
                           _("Text contains invalid UTF-8"));
 
1272
              goto error;
 
1273
            }
 
1274
                     
 
1275
          gconf_value_set_string(val, tmp->data);
 
1276
          break;
 
1277
 
 
1278
        case GCONF_VALUE_SCHEMA:
 
1279
          if (!gconf_schema_validate (tmp->data, err))
 
1280
            goto error;
 
1281
          gconf_value_set_schema(val, tmp->data);
 
1282
          break;
 
1283
          
 
1284
        default:
 
1285
          g_assert_not_reached();
 
1286
          break;
 
1287
        }
 
1288
 
 
1289
      value_list = g_slist_prepend(value_list, val);
 
1290
 
 
1291
      tmp = g_slist_next(tmp);
 
1292
    }
 
1293
 
 
1294
  /* Get it in the right order. */
 
1295
  value_list = g_slist_reverse(value_list);
 
1296
 
 
1297
  {
 
1298
    GConfValue* value_with_list;
 
1299
    
 
1300
    value_with_list = gconf_value_new(GCONF_VALUE_LIST);
 
1301
    gconf_value_set_list_type(value_with_list, list_type);
 
1302
    gconf_value_set_list_nocopy(value_with_list, value_list);
 
1303
 
 
1304
    return value_with_list;
 
1305
  }
 
1306
 
 
1307
 error:
 
1308
  g_slist_foreach (value_list, (GFunc)gconf_value_free, NULL);
 
1309
  g_slist_free (value_list);
 
1310
  return NULL;
 
1311
}
 
1312
 
 
1313
 
 
1314
static GConfValue*
 
1315
from_primitive(GConfValueType type, gconstpointer address,
 
1316
               GError **err)
 
1317
{
 
1318
  GConfValue* val;
 
1319
 
 
1320
  val = gconf_value_new(type);
 
1321
 
 
1322
  switch (type)
 
1323
    {
 
1324
    case GCONF_VALUE_INT:
 
1325
      gconf_value_set_int(val, *((const gint*)address));
 
1326
      break;
 
1327
 
 
1328
    case GCONF_VALUE_BOOL:
 
1329
      gconf_value_set_bool(val, *((const gboolean*)address));
 
1330
      break;
 
1331
 
 
1332
    case GCONF_VALUE_STRING:
 
1333
      if (!g_utf8_validate (*((const gchar**)address), -1, NULL))
 
1334
        {
 
1335
          g_set_error (err, GCONF_ERROR,
 
1336
                       GCONF_ERROR_FAILED,
 
1337
                       _("Text contains invalid UTF-8"));
 
1338
          gconf_value_free (val);
 
1339
          return NULL;
 
1340
        }
 
1341
 
 
1342
      gconf_value_set_string(val, *((const gchar**)address));
 
1343
      break;
 
1344
 
 
1345
    case GCONF_VALUE_FLOAT:
 
1346
      gconf_value_set_float(val, *((const gdouble*)address));
 
1347
      break;
 
1348
 
 
1349
    case GCONF_VALUE_SCHEMA:
 
1350
      if (!gconf_schema_validate (*((GConfSchema**)address), err))
 
1351
        {
 
1352
          gconf_value_free (val);
 
1353
          return NULL;
 
1354
        }
 
1355
      
 
1356
      gconf_value_set_schema(val, *((GConfSchema**)address));
 
1357
      break;
 
1358
      
 
1359
    default:
 
1360
      g_assert_not_reached();
 
1361
      break;
 
1362
    }
 
1363
 
 
1364
  return val;
 
1365
}
 
1366
 
 
1367
GConfValue*
 
1368
gconf_value_pair_from_primitive_pair(GConfValueType car_type,
 
1369
                                     GConfValueType cdr_type,
 
1370
                                     gconstpointer address_of_car,
 
1371
                                     gconstpointer address_of_cdr,
 
1372
                                     GError       **err)
 
1373
{
 
1374
  GConfValue* pair;
 
1375
  GConfValue* car;
 
1376
  GConfValue* cdr;
 
1377
  
 
1378
  g_return_val_if_fail(car_type != GCONF_VALUE_INVALID, NULL);
 
1379
  g_return_val_if_fail(car_type != GCONF_VALUE_LIST, NULL);
 
1380
  g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, NULL);
 
1381
  g_return_val_if_fail(cdr_type != GCONF_VALUE_INVALID, NULL);
 
1382
  g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, NULL);
 
1383
  g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, NULL);
 
1384
  g_return_val_if_fail(address_of_car != NULL, NULL);
 
1385
  g_return_val_if_fail(address_of_cdr != NULL, NULL);
 
1386
  
 
1387
  car = from_primitive(car_type, address_of_car, err);
 
1388
  if (car == NULL)
 
1389
    return NULL;
 
1390
  cdr = from_primitive(cdr_type, address_of_cdr, err);
 
1391
  if (cdr == NULL)
 
1392
    {
 
1393
      gconf_value_free (car);
 
1394
      return NULL;
 
1395
    }
 
1396
  
 
1397
  pair = gconf_value_new(GCONF_VALUE_PAIR);
 
1398
  gconf_value_set_car_nocopy(pair, car);
 
1399
  gconf_value_set_cdr_nocopy(pair, cdr);
 
1400
 
 
1401
  return pair;
 
1402
}
 
1403
 
 
1404
 
 
1405
GSList*
 
1406
gconf_value_list_to_primitive_list_destructive(GConfValue* val,
 
1407
                                               GConfValueType list_type,
 
1408
                                               GError** err)
 
1409
{
 
1410
  GSList* retval;
 
1411
 
 
1412
  g_return_val_if_fail(val != NULL, NULL);
 
1413
  g_return_val_if_fail(list_type != GCONF_VALUE_INVALID, NULL);
 
1414
  g_return_val_if_fail(list_type != GCONF_VALUE_LIST, NULL);
 
1415
  g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, NULL);
 
1416
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
 
1417
  
 
1418
  if (val->type != GCONF_VALUE_LIST)
 
1419
    {
 
1420
      if (err)
 
1421
        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
 
1422
                               _("Expected list, got %s"),
 
1423
                               gconf_value_type_to_string(val->type));
 
1424
      gconf_value_free(val);
 
1425
      return NULL;
 
1426
    }
 
1427
 
 
1428
  if (gconf_value_get_list_type(val) != list_type)
 
1429
    {
 
1430
      if (err)
 
1431
        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
 
1432
                               _("Expected list of %s, got list of %s"),
 
1433
                               gconf_value_type_to_string(list_type),
 
1434
                               gconf_value_type_to_string(val->type));
 
1435
      gconf_value_free(val);
 
1436
      return NULL;
 
1437
    }
 
1438
 
 
1439
  g_assert(gconf_value_get_list_type(val) == list_type);
 
1440
      
 
1441
  retval = gconf_value_get_list(val);
 
1442
 
 
1443
  /* Cheating the API to avoid a list copy; set this to NULL to
 
1444
         avoid destroying the list */
 
1445
  val->d.list_data.list = NULL;
 
1446
      
 
1447
  gconf_value_free(val);
 
1448
  val = NULL;
 
1449
      
 
1450
  {
 
1451
    /* map (typeChange, retval) */
 
1452
    GSList* tmp;
 
1453
 
 
1454
    tmp = retval;
 
1455
 
 
1456
    while (tmp != NULL)
 
1457
      {
 
1458
        GConfValue* elem = tmp->data;
 
1459
 
 
1460
        g_assert(elem != NULL);
 
1461
        g_assert(elem->type == list_type);
 
1462
            
 
1463
        switch (list_type)
 
1464
          {
 
1465
          case GCONF_VALUE_INT:
 
1466
          case GCONF_VALUE_BOOL:
 
1467
            tmp->data = GINT_TO_POINTER(gconf_value_get_int(elem));
 
1468
            break;
 
1469
                
 
1470
          case GCONF_VALUE_FLOAT:
 
1471
            {
 
1472
              gdouble* d = g_new(gdouble, 1);
 
1473
              *d = gconf_value_get_float(elem);
 
1474
              tmp->data = d;
 
1475
            }
 
1476
            break;
 
1477
 
 
1478
          case GCONF_VALUE_STRING:
 
1479
            {
 
1480
              /* Cheat again, and steal the string from the value */
 
1481
              tmp->data = elem->d.string_data;
 
1482
              elem->d.string_data = NULL;
 
1483
            }
 
1484
            break;
 
1485
 
 
1486
          case GCONF_VALUE_SCHEMA:
 
1487
            {
 
1488
              /* and also steal the schema... */
 
1489
              tmp->data = elem->d.schema_data;
 
1490
              elem->d.schema_data = NULL;
 
1491
            }
 
1492
            break;
 
1493
                
 
1494
          default:
 
1495
            g_assert_not_reached();
 
1496
            break;
 
1497
          }
 
1498
 
 
1499
        /* Clean up the value */
 
1500
        gconf_value_free(elem);
 
1501
            
 
1502
        tmp = g_slist_next(tmp);
 
1503
      }
 
1504
  } /* list conversion block */
 
1505
      
 
1506
  return retval;
 
1507
}
 
1508
 
 
1509
 
 
1510
static void
 
1511
primitive_value(gpointer retloc, GConfValue* val)
 
1512
{
 
1513
  switch (val->type)
 
1514
    {
 
1515
    case GCONF_VALUE_INT:
 
1516
      *((gint*)retloc) = gconf_value_get_int(val);
 
1517
      break;
 
1518
 
 
1519
    case GCONF_VALUE_FLOAT:
 
1520
      *((gdouble*)retloc) = gconf_value_get_float(val);
 
1521
      break;
 
1522
 
 
1523
    case GCONF_VALUE_STRING:
 
1524
      {
 
1525
        *((gchar**)retloc) = val->d.string_data;
 
1526
        /* cheat and steal the string to avoid a copy */
 
1527
        val->d.string_data = NULL;
 
1528
      }
 
1529
      break;
 
1530
 
 
1531
    case GCONF_VALUE_BOOL:
 
1532
      *((gboolean*)retloc) = gconf_value_get_bool(val);
 
1533
      break;
 
1534
 
 
1535
    case GCONF_VALUE_SCHEMA:
 
1536
      *((GConfSchema**)retloc) = gconf_value_get_schema(val);
 
1537
      break;
 
1538
      
 
1539
    default:
 
1540
      g_assert_not_reached();
 
1541
      break;
 
1542
    }
 
1543
}
 
1544
 
 
1545
gboolean
 
1546
gconf_value_pair_to_primitive_pair_destructive(GConfValue* val,
 
1547
                                               GConfValueType car_type,
 
1548
                                               GConfValueType cdr_type,
 
1549
                                               gpointer car_retloc,
 
1550
                                               gpointer cdr_retloc,
 
1551
                                               GError** err)
 
1552
{
 
1553
  GConfValue* car;
 
1554
  GConfValue* cdr;
 
1555
 
 
1556
  g_return_val_if_fail(val != NULL, FALSE);
 
1557
  g_return_val_if_fail(car_type != GCONF_VALUE_INVALID, FALSE);
 
1558
  g_return_val_if_fail(car_type != GCONF_VALUE_LIST, FALSE);
 
1559
  g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, FALSE);
 
1560
  g_return_val_if_fail(cdr_type != GCONF_VALUE_INVALID, FALSE);
 
1561
  g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, FALSE);
 
1562
  g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, FALSE);
 
1563
  g_return_val_if_fail(car_retloc != NULL, FALSE);
 
1564
  g_return_val_if_fail(cdr_retloc != NULL, FALSE);
 
1565
  g_return_val_if_fail(err == NULL || *err == NULL, FALSE);  
 
1566
      
 
1567
  if (val->type != GCONF_VALUE_PAIR)
 
1568
    {
 
1569
      if (err)
 
1570
        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
 
1571
                               _("Expected pair, got %s"),
 
1572
                               gconf_value_type_to_string(val->type));
 
1573
      gconf_value_free(val);
 
1574
      return FALSE;
 
1575
    }
 
1576
 
 
1577
  car = gconf_value_get_car(val);
 
1578
  cdr = gconf_value_get_cdr(val);
 
1579
      
 
1580
  if (car == NULL ||
 
1581
      cdr == NULL)
 
1582
    {
 
1583
      if (err)
 
1584
        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH, 
 
1585
                               _("Expected (%s,%s) pair, got a pair with one or both values missing"),
 
1586
                               gconf_value_type_to_string(car_type),
 
1587
                               gconf_value_type_to_string(cdr_type));
 
1588
 
 
1589
      gconf_value_free(val);
 
1590
      return FALSE;
 
1591
    }
 
1592
 
 
1593
  g_assert(car != NULL);
 
1594
  g_assert(cdr != NULL);
 
1595
      
 
1596
  if (car->type != car_type ||
 
1597
      cdr->type != cdr_type)
 
1598
    {
 
1599
      if (err)
 
1600
        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
 
1601
                               _("Expected pair of type (%s,%s) got type (%s,%s)"),
 
1602
                               gconf_value_type_to_string(car_type),
 
1603
                               gconf_value_type_to_string(cdr_type),
 
1604
                               gconf_value_type_to_string(car->type),
 
1605
                               gconf_value_type_to_string(cdr->type));
 
1606
      gconf_value_free(val);
 
1607
      return FALSE;
 
1608
    }
 
1609
 
 
1610
  primitive_value(car_retloc, car);
 
1611
  primitive_value(cdr_retloc, cdr);
 
1612
 
 
1613
  gconf_value_free(val);
 
1614
 
 
1615
  return TRUE;
 
1616
}
 
1617
 
 
1618
 
 
1619
 
 
1620
/*
 
1621
 * Encode/decode
 
1622
 */
 
1623
 
 
1624
gchar*
 
1625
gconf_quote_string   (const gchar* src)
 
1626
{
 
1627
  gchar* dest;
 
1628
  const gchar* s;
 
1629
  gchar* d;
 
1630
 
 
1631
  g_return_val_if_fail(src != NULL, NULL);
 
1632
  
 
1633
  /* waste memory! woo-hoo! */
 
1634
  dest = g_malloc0(strlen(src)*2+4);
 
1635
  
 
1636
  d = dest;
 
1637
 
 
1638
  *d = '"';
 
1639
  ++d;
 
1640
  
 
1641
  s = src;
 
1642
  while (*s)
 
1643
    {
 
1644
      switch (*s)
 
1645
        {
 
1646
        case '"':
 
1647
          {
 
1648
            *d = '\\';
 
1649
            ++d;
 
1650
            *d = '"';
 
1651
            ++d;
 
1652
          }
 
1653
          break;
 
1654
          
 
1655
        case '\\':
 
1656
          {
 
1657
            *d = '\\';
 
1658
            ++d;
 
1659
            *d = '\\';
 
1660
            ++d;
 
1661
          }
 
1662
          break;
 
1663
          
 
1664
        default:
 
1665
          {
 
1666
            *d = *s;
 
1667
            ++d;
 
1668
          }
 
1669
          break;
 
1670
        }
 
1671
      ++s;
 
1672
    }
 
1673
 
 
1674
  /* End with quote mark and NULL */
 
1675
  *d = '"';
 
1676
  ++d;
 
1677
  *d = '\0';
 
1678
  
 
1679
  return dest;
 
1680
}
 
1681
 
 
1682
gchar*
 
1683
gconf_unquote_string (const gchar* str, const gchar** end, GError** err)
 
1684
{
 
1685
  gchar* unq;
 
1686
  gchar* unq_end = NULL;
 
1687
 
 
1688
  g_return_val_if_fail(end != NULL, NULL);
 
1689
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
 
1690
  g_return_val_if_fail(str != NULL, NULL);
 
1691
  
 
1692
  unq = g_strdup(str);
 
1693
 
 
1694
  gconf_unquote_string_inplace(unq, &unq_end, err);
 
1695
 
 
1696
  *end = (str + (unq_end - unq));
 
1697
 
 
1698
  return unq;
 
1699
}
 
1700
 
 
1701
void
 
1702
gconf_unquote_string_inplace (gchar* str, gchar** end, GError** err)
 
1703
{
 
1704
  gchar* dest;
 
1705
  gchar* s;
 
1706
 
 
1707
  g_return_if_fail(end != NULL);
 
1708
  g_return_if_fail(err == NULL || *err == NULL);
 
1709
  g_return_if_fail(str != NULL);
 
1710
  
 
1711
  dest = s = str;
 
1712
 
 
1713
  if (*s != '"')
 
1714
    {
 
1715
      if (err)
 
1716
        *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
 
1717
                               _("Quoted string doesn't begin with a quotation mark"));
 
1718
      *end = str;
 
1719
      return;
 
1720
    }
 
1721
 
 
1722
  /* Skip the initial quote mark */
 
1723
  ++s;
 
1724
  
 
1725
  while (*s)
 
1726
    {
 
1727
      g_assert(s > dest); /* loop invariant */
 
1728
      
 
1729
      switch (*s)
 
1730
        {
 
1731
        case '"':
 
1732
          /* End of the string, return now */
 
1733
          *dest = '\0';
 
1734
          ++s;
 
1735
          *end = s;
 
1736
          return;
 
1737
          break;
 
1738
 
 
1739
        case '\\':
 
1740
          /* Possible escaped quote or \ */
 
1741
          ++s;
 
1742
          if (*s == '"')
 
1743
            {
 
1744
              *dest = *s;
 
1745
              ++s;
 
1746
              ++dest;
 
1747
            }
 
1748
          else if (*s == '\\')
 
1749
            {
 
1750
              *dest = *s;
 
1751
              ++s;
 
1752
              ++dest;
 
1753
            }
 
1754
          else
 
1755
            {
 
1756
              /* not an escaped char */
 
1757
              *dest = '\\';
 
1758
              ++dest;
 
1759
              /* ++s already done. */
 
1760
            }
 
1761
          break;
 
1762
 
 
1763
        default:
 
1764
          *dest = *s;
 
1765
          ++dest;
 
1766
          ++s;
 
1767
          break;
 
1768
        }
 
1769
 
 
1770
      g_assert(s > dest); /* loop invariant */
 
1771
    }
 
1772
  
 
1773
  /* If we reach here this means the close quote was never encountered */
 
1774
 
 
1775
  *dest = '\0';
 
1776
  
 
1777
  if (err)
 
1778
    *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
 
1779
                           _("Quoted string doesn't end with a quotation mark"));
 
1780
  *end = s;
 
1781
  return;
 
1782
}
 
1783
 
 
1784
/* The encoding format
 
1785
 
 
1786
   The first byte of the encoded string is the type of the value:
 
1787
 
 
1788
    i  int
 
1789
    b  bool
 
1790
    f  float
 
1791
    s  string
 
1792
    c  schema
 
1793
    p  pair
 
1794
    l  list
 
1795
    v  invalid
 
1796
 
 
1797
    For int, the rest of the encoded value is the integer to be parsed with atoi()
 
1798
    For bool, the rest is 't' or 'f'
 
1799
    For float, the rest is a float to parse with g_strtod()
 
1800
    For string, the rest is the string (not quoted)
 
1801
    For schema, the encoding is complicated; see below.
 
1802
    For pair, the rest is two primitive encodings (ibcfs), quoted, separated by a comma,
 
1803
              car before cdr
 
1804
    For list, first character is type, the rest is primitive encodings, quoted,
 
1805
              separated by commas
 
1806
 
 
1807
    Schema:
 
1808
 
 
1809
    After the 'c' indicating schema, the second character is a byte indicating
 
1810
    the type the schema expects. Then a comma, and the quoted locale, or "" for none.
 
1811
    comma, and quoted short description; comma, quoted long description; comma, default
 
1812
    value in the encoded format given above, quoted.
 
1813
*/
 
1814
 
 
1815
static gchar type_byte(GConfValueType type)
 
1816
{
 
1817
  switch (type)
 
1818
    {
 
1819
    case GCONF_VALUE_INT:
 
1820
      return 'i';
 
1821
      break;
 
1822
        
 
1823
    case GCONF_VALUE_BOOL:
 
1824
      return 'b';
 
1825
      break;
 
1826
 
 
1827
    case GCONF_VALUE_FLOAT:
 
1828
      return 'f';
 
1829
      break;
 
1830
 
 
1831
    case GCONF_VALUE_STRING:
 
1832
      return 's';
 
1833
      break;
 
1834
 
 
1835
    case GCONF_VALUE_SCHEMA:
 
1836
      return 'c';
 
1837
      break;
 
1838
 
 
1839
    case GCONF_VALUE_LIST:
 
1840
      return 'l';
 
1841
      break;
 
1842
 
 
1843
    case GCONF_VALUE_PAIR:
 
1844
      return 'p';
 
1845
      break;
 
1846
 
 
1847
    case GCONF_VALUE_INVALID:
 
1848
      return 'v';
 
1849
      break;
 
1850
      
 
1851
    default:
 
1852
      g_assert_not_reached();
 
1853
      return '\0';
 
1854
      break;
 
1855
    }
 
1856
}
 
1857
 
 
1858
GConfValueType
 
1859
byte_type(gchar byte)
 
1860
{
 
1861
  switch (byte)
 
1862
    {
 
1863
    case 'i':
 
1864
      return GCONF_VALUE_INT;
 
1865
      break;
 
1866
 
 
1867
    case 'b':
 
1868
      return GCONF_VALUE_BOOL;
 
1869
      break;
 
1870
 
 
1871
    case 's':
 
1872
      return GCONF_VALUE_STRING;
 
1873
      break;
 
1874
 
 
1875
    case 'c':
 
1876
      return GCONF_VALUE_SCHEMA;
 
1877
      break;
 
1878
 
 
1879
    case 'f':
 
1880
      return GCONF_VALUE_FLOAT;
 
1881
      break;
 
1882
 
 
1883
    case 'l':
 
1884
      return GCONF_VALUE_LIST;
 
1885
      break;
 
1886
 
 
1887
    case 'p':
 
1888
      return GCONF_VALUE_PAIR;
 
1889
      break;
 
1890
      
 
1891
    case 'v':
 
1892
      return GCONF_VALUE_INVALID;
 
1893
      break;
 
1894
 
 
1895
    default:
 
1896
      return GCONF_VALUE_INVALID;
 
1897
      break;
 
1898
    }
 
1899
}
 
1900
 
 
1901
GConfValue*
 
1902
gconf_value_decode (const gchar* encoded)
 
1903
{
 
1904
  GConfValueType type;
 
1905
  GConfValue* val;
 
1906
  const gchar* s;
 
1907
  
 
1908
  type = byte_type(*encoded);
 
1909
 
 
1910
  if (type == GCONF_VALUE_INVALID)
 
1911
    return NULL;
 
1912
 
 
1913
  if (!g_utf8_validate (encoded, -1, NULL))
 
1914
    {
 
1915
      gconf_log (GCL_ERR, _("Encoded value is not valid UTF-8"));
 
1916
      return NULL;
 
1917
    }
 
1918
  
 
1919
  val = gconf_value_new(type);
 
1920
 
 
1921
  s = encoded + 1;
 
1922
  
 
1923
  switch (val->type)
 
1924
    {
 
1925
    case GCONF_VALUE_INT:
 
1926
      gconf_value_set_int(val, atoi(s));
 
1927
      break;
 
1928
        
 
1929
    case GCONF_VALUE_BOOL:
 
1930
      gconf_value_set_bool(val, *s == 't' ? TRUE : FALSE);
 
1931
      break;
 
1932
 
 
1933
    case GCONF_VALUE_FLOAT:
 
1934
      {
 
1935
        double d;
 
1936
        gchar* endptr = NULL;
 
1937
        
 
1938
        d = g_strtod(s, &endptr);
 
1939
        if (endptr == s)
 
1940
          g_warning("Failure converting string to double in %s", G_GNUC_FUNCTION);
 
1941
        gconf_value_set_float(val, d);
 
1942
      }
 
1943
      break;
 
1944
 
 
1945
    case GCONF_VALUE_STRING:
 
1946
      {
 
1947
        gconf_value_set_string(val, s);
 
1948
      }
 
1949
      break;
 
1950
 
 
1951
    case GCONF_VALUE_SCHEMA:
 
1952
      {
 
1953
        GConfSchema* sc = gconf_schema_new();
 
1954
        const gchar* end = NULL;
 
1955
        gchar* unquoted;
 
1956
        
 
1957
        gconf_value_set_schema(val, sc);
 
1958
 
 
1959
        gconf_schema_set_type(sc, byte_type(*s));
 
1960
        ++s;
 
1961
        gconf_schema_set_list_type(sc, byte_type(*s));
 
1962
        ++s;
 
1963
        gconf_schema_set_car_type(sc, byte_type(*s));
 
1964
        ++s;
 
1965
        gconf_schema_set_cdr_type(sc, byte_type(*s));
 
1966
        ++s;
 
1967
 
 
1968
        /* locale */
 
1969
        unquoted = gconf_unquote_string(s, &end, NULL);
 
1970
 
 
1971
        gconf_schema_set_locale(sc, unquoted);
 
1972
 
 
1973
        g_free(unquoted);
 
1974
        
 
1975
        if (*end != ',')
 
1976
          g_warning("no comma after locale in schema");
 
1977
 
 
1978
        ++end;
 
1979
        s = end;
 
1980
 
 
1981
        /* short */
 
1982
        unquoted = gconf_unquote_string(s, &end, NULL);
 
1983
 
 
1984
        gconf_schema_set_short_desc(sc, unquoted);
 
1985
 
 
1986
        g_free(unquoted);
 
1987
        
 
1988
        if (*end != ',')
 
1989
          g_warning("no comma after short desc in schema");
 
1990
 
 
1991
        ++end;
 
1992
        s = end;
 
1993
 
 
1994
 
 
1995
        /* long */
 
1996
        unquoted = gconf_unquote_string(s, &end, NULL);
 
1997
 
 
1998
        gconf_schema_set_long_desc(sc, unquoted);
 
1999
 
 
2000
        g_free(unquoted);
 
2001
        
 
2002
        if (*end != ',')
 
2003
          g_warning("no comma after long desc in schema");
 
2004
 
 
2005
        ++end;
 
2006
        s = end;
 
2007
        
 
2008
        
 
2009
        /* default value */
 
2010
        unquoted = gconf_unquote_string(s, &end, NULL);
 
2011
 
 
2012
        gconf_schema_set_default_value_nocopy(sc, gconf_value_decode(unquoted));
 
2013
 
 
2014
        g_free(unquoted);
 
2015
        
 
2016
        if (*end != '\0')
 
2017
          g_warning("trailing junk after encoded schema");
 
2018
      }
 
2019
      break;
 
2020
 
 
2021
    case GCONF_VALUE_LIST:
 
2022
      {
 
2023
        GSList* value_list = NULL;
 
2024
 
 
2025
        gconf_value_set_list_type(val, byte_type(*s));
 
2026
        ++s;
 
2027
 
 
2028
        while (*s)
 
2029
          {
 
2030
            gchar* unquoted;
 
2031
            const gchar* end;
 
2032
            
 
2033
            GConfValue* elem;
 
2034
            
 
2035
            unquoted = gconf_unquote_string(s, &end, NULL);            
 
2036
 
 
2037
            elem = gconf_value_decode(unquoted);
 
2038
 
 
2039
            g_free(unquoted);
 
2040
            
 
2041
            if (elem)
 
2042
              value_list = g_slist_prepend(value_list, elem);
 
2043
            
 
2044
            s = end;
 
2045
            if (*s == ',')
 
2046
              ++s;
 
2047
            else if (*s != '\0')
 
2048
              {
 
2049
                g_warning("weird character in encoded list");
 
2050
                break; /* error */
 
2051
              }
 
2052
          }
 
2053
 
 
2054
        value_list = g_slist_reverse(value_list);
 
2055
 
 
2056
        gconf_value_set_list_nocopy(val, value_list);
 
2057
      }
 
2058
      break;
 
2059
 
 
2060
    case GCONF_VALUE_PAIR:
 
2061
      {
 
2062
        gchar* unquoted;
 
2063
        const gchar* end;
 
2064
        
 
2065
        GConfValue* car;
 
2066
        GConfValue* cdr;
 
2067
        
 
2068
        unquoted = gconf_unquote_string(s, &end, NULL);            
 
2069
        
 
2070
        car = gconf_value_decode(unquoted);
 
2071
 
 
2072
        g_free(unquoted);
 
2073
        
 
2074
        s = end;
 
2075
        if (*s == ',')
 
2076
          ++s;
 
2077
        else
 
2078
          {
 
2079
            g_warning("weird character in encoded pair");
 
2080
          }
 
2081
        
 
2082
        unquoted = gconf_unquote_string(s, &end, NULL);
 
2083
        
 
2084
        cdr = gconf_value_decode(unquoted);
 
2085
        g_free(unquoted);
 
2086
 
 
2087
 
 
2088
        gconf_value_set_car_nocopy(val, car);
 
2089
        gconf_value_set_cdr_nocopy(val, cdr);
 
2090
      }
 
2091
      break;
 
2092
 
 
2093
    default:
 
2094
      g_assert_not_reached();
 
2095
      break;
 
2096
    }
 
2097
 
 
2098
  return val;
 
2099
}
 
2100
 
 
2101
gchar*
 
2102
gconf_value_encode (GConfValue* val)
 
2103
{
 
2104
  gchar* retval = NULL;
 
2105
  
 
2106
  g_return_val_if_fail(val != NULL, NULL);
 
2107
 
 
2108
  switch (val->type)
 
2109
    {
 
2110
    case GCONF_VALUE_INT:
 
2111
      retval = g_strdup_printf("i%d", gconf_value_get_int(val));
 
2112
      break;
 
2113
        
 
2114
    case GCONF_VALUE_BOOL:
 
2115
      retval = g_strdup_printf("b%c", gconf_value_get_bool(val) ? 't' : 'f');
 
2116
      break;
 
2117
 
 
2118
    case GCONF_VALUE_FLOAT:
 
2119
      retval = g_strdup_printf("f%g", gconf_value_get_float(val));
 
2120
      break;
 
2121
 
 
2122
    case GCONF_VALUE_STRING:
 
2123
      retval = g_strdup_printf("s%s", gconf_value_get_string(val));
 
2124
      break;
 
2125
 
 
2126
    case GCONF_VALUE_SCHEMA:
 
2127
      {
 
2128
        gchar* tmp;
 
2129
        gchar* retval;
 
2130
        gchar* quoted;
 
2131
        gchar* encoded;
 
2132
        GConfSchema* sc;
 
2133
 
 
2134
        sc = gconf_value_get_schema(val);
 
2135
        
 
2136
        tmp = g_strdup_printf("c%c%c%c%c,",
 
2137
                              type_byte(gconf_schema_get_type(sc)),
 
2138
                              type_byte(gconf_schema_get_list_type(sc)),
 
2139
                              type_byte(gconf_schema_get_car_type(sc)),
 
2140
                              type_byte(gconf_schema_get_cdr_type(sc)));
 
2141
 
 
2142
        quoted = gconf_quote_string(gconf_schema_get_locale(sc) ?
 
2143
                                    gconf_schema_get_locale(sc) : "");
 
2144
        retval = g_strconcat(tmp, quoted, ",", NULL);
 
2145
 
 
2146
        g_free(tmp);
 
2147
        g_free(quoted);
 
2148
 
 
2149
        tmp = retval;
 
2150
        quoted = gconf_quote_string(gconf_schema_get_short_desc(sc) ?
 
2151
                                    gconf_schema_get_short_desc(sc) : "");
 
2152
 
 
2153
        retval = g_strconcat(tmp, quoted, ",", NULL);
 
2154
 
 
2155
        g_free(tmp);
 
2156
        g_free(quoted);
 
2157
 
 
2158
 
 
2159
        tmp = retval;
 
2160
        quoted = gconf_quote_string(gconf_schema_get_long_desc(sc) ?
 
2161
                                    gconf_schema_get_long_desc(sc) : "");
 
2162
 
 
2163
        retval = g_strconcat(tmp, quoted, ",", NULL);
 
2164
 
 
2165
        g_free(tmp);
 
2166
        g_free(quoted);
 
2167
        
 
2168
 
 
2169
        if (gconf_schema_get_default_value(sc) != NULL)
 
2170
          encoded = gconf_value_encode(gconf_schema_get_default_value(sc));
 
2171
        else
 
2172
          encoded = g_strdup("");
 
2173
 
 
2174
        tmp = retval;
 
2175
          
 
2176
        quoted = gconf_quote_string(encoded);
 
2177
 
 
2178
        retval = g_strconcat(tmp, quoted, NULL);
 
2179
 
 
2180
        g_free(tmp);
 
2181
        g_free(quoted);
 
2182
        g_free(encoded);
 
2183
      }
 
2184
      break;
 
2185
 
 
2186
    case GCONF_VALUE_LIST:
 
2187
      {
 
2188
        GSList* tmp;
 
2189
 
 
2190
        retval = g_strdup_printf("l%c", type_byte(gconf_value_get_list_type(val)));
 
2191
        
 
2192
        tmp = gconf_value_get_list(val);
 
2193
 
 
2194
        while (tmp != NULL)
 
2195
          {
 
2196
            GConfValue* elem = tmp->data;
 
2197
            gchar* encoded;
 
2198
            gchar* quoted;
 
2199
            
 
2200
            g_assert(elem != NULL);
 
2201
 
 
2202
            encoded = gconf_value_encode(elem);
 
2203
 
 
2204
            quoted = gconf_quote_string(encoded);
 
2205
 
 
2206
            g_free(encoded);
 
2207
 
 
2208
            {
 
2209
              gchar* free_me;
 
2210
              free_me = retval;
 
2211
              
 
2212
              retval = g_strconcat(retval, ",", quoted, NULL);
 
2213
              
 
2214
              g_free(quoted);
 
2215
              g_free(free_me);
 
2216
            }
 
2217
            
 
2218
            tmp = g_slist_next(tmp);
 
2219
          }
 
2220
      }
 
2221
      break;
 
2222
 
 
2223
    case GCONF_VALUE_PAIR:
 
2224
      {
 
2225
        gchar* car_encoded;
 
2226
        gchar* cdr_encoded;
 
2227
        gchar* car_quoted;
 
2228
        gchar* cdr_quoted;
 
2229
 
 
2230
        car_encoded = gconf_value_encode(gconf_value_get_car(val));
 
2231
        cdr_encoded = gconf_value_encode(gconf_value_get_cdr(val));
 
2232
 
 
2233
        car_quoted = gconf_quote_string(car_encoded);
 
2234
        cdr_quoted = gconf_quote_string(cdr_encoded);
 
2235
 
 
2236
        retval = g_strconcat("p", car_quoted, ",", cdr_quoted, NULL);
 
2237
 
 
2238
        g_free(car_encoded);
 
2239
        g_free(cdr_encoded);
 
2240
        g_free(car_quoted);
 
2241
        g_free(cdr_quoted);
 
2242
      }
 
2243
      break;
 
2244
 
 
2245
    default:
 
2246
      g_assert_not_reached();
 
2247
      break;
 
2248
      
 
2249
    }
 
2250
 
 
2251
  return retval;
 
2252
}
 
2253
 
 
2254
gboolean
 
2255
gconf_handle_oaf_exception(CORBA_Environment* ev, GError** err)
 
2256
{
 
2257
  switch (ev->_major)
 
2258
    {
 
2259
    case CORBA_NO_EXCEPTION:
 
2260
      CORBA_exception_free(ev);
 
2261
      return FALSE;
 
2262
      break;
 
2263
    case CORBA_SYSTEM_EXCEPTION:
 
2264
      if (err)
 
2265
        *err = gconf_error_new (GCONF_ERROR_NO_SERVER, _("CORBA error: %s"),
 
2266
                                CORBA_exception_id (ev));
 
2267
      CORBA_exception_free (ev);
 
2268
      return TRUE;
 
2269
      break;
 
2270
 
 
2271
    case CORBA_USER_EXCEPTION:
 
2272
      {
 
2273
        const gchar* id = CORBA_exception_id(ev);
 
2274
 
 
2275
        if (strcmp(id, "IDL:OAF/GeneralError:1.0") == 0)
 
2276
          {
 
2277
            OAF_GeneralError* ge = CORBA_exception_value(ev);
 
2278
 
 
2279
            if (err)
 
2280
              *err = gconf_error_new (GCONF_ERROR_OAF_ERROR,
 
2281
                                      _("OAF problem description: '%s'"),
 
2282
                                      ge->description);
 
2283
          }
 
2284
        else if (strcmp (id,"IDL:OAF/ActivationContext/NotListed:1.0" ) == 0)
 
2285
          {
 
2286
            if (err)
 
2287
              *err = gconf_error_new(GCONF_ERROR_OAF_ERROR, _("attempt to remove not-listed OAF object directory"));
 
2288
          }
 
2289
        else if (strcmp (id,"IDL:OAF/ActivationContext/AlreadyListed:1.0" ) == 0)
 
2290
          {
 
2291
            if (err)
 
2292
              *err = gconf_error_new(GCONF_ERROR_OAF_ERROR, _("attempt to add already-listed OAF directory")); 
 
2293
          }
 
2294
        else if (strcmp (id,"IDL:OAF/ActivationContext/ParseFailed:1.0") == 0)
 
2295
          {
 
2296
            OAF_ActivationContext_ParseFailed* pe = CORBA_exception_value(ev);
 
2297
            
 
2298
            if (err)
 
2299
              *err = gconf_error_new(GCONF_ERROR_OAF_ERROR, _("OAF parse error: %s"), pe->description);
 
2300
          }
 
2301
        else
 
2302
          {
 
2303
            if (err)
 
2304
              *err = gconf_error_new(GCONF_ERROR_OAF_ERROR, _("Unknown OAF error"));
 
2305
          }
 
2306
        
 
2307
        CORBA_exception_free(ev);
 
2308
        return TRUE;
 
2309
      }
 
2310
      break;
 
2311
    default:
 
2312
      g_assert_not_reached();
 
2313
      return TRUE;
 
2314
      break;
 
2315
    }
 
2316
}
 
2317
 
 
2318
/*
 
2319
 * Locks
 
2320
 */
 
2321
 
 
2322
/*
 
2323
 * Locks works as follows. We have a lock directory to hold the locking
 
2324
 * mess, and we have an IOR file inside the lock directory with the
 
2325
 * gconfd IOR, and we have an fcntl() lock on the IOR file. The IOR
 
2326
 * file is created atomically using a temporary file, then link()
 
2327
 */
 
2328
 
 
2329
struct _GConfLock {
 
2330
  gchar *lock_directory;
 
2331
  gchar *iorfile;
 
2332
  int    lock_fd;
 
2333
};
 
2334
 
 
2335
static void
 
2336
gconf_lock_destroy (GConfLock* lock)
 
2337
{
 
2338
  if (lock->lock_fd >= 0)
 
2339
    close (lock->lock_fd);
 
2340
  g_free (lock->iorfile);
 
2341
  g_free (lock->lock_directory);
 
2342
  g_free (lock);
 
2343
}
 
2344
 
 
2345
static void
 
2346
set_close_on_exec (int fd)
 
2347
{
 
2348
  int val;
 
2349
 
 
2350
  val = fcntl (fd, F_GETFD, 0);
 
2351
  if (val < 0)
 
2352
    {
 
2353
      gconf_log (GCL_DEBUG, "couldn't F_GETFD: %s\n", g_strerror (errno));
 
2354
      return;
 
2355
    }
 
2356
 
 
2357
  val |= FD_CLOEXEC;
 
2358
 
 
2359
  if (fcntl (fd, F_SETFD, val) < 0)
 
2360
    gconf_log (GCL_DEBUG, "couldn't F_SETFD: %s\n", g_strerror (errno));
 
2361
}
 
2362
 
 
2363
/* Your basic Stevens cut-and-paste */
 
2364
static int
 
2365
lock_reg (int fd, int cmd, int type, off_t offset, int whence, off_t len)
 
2366
{
 
2367
  struct flock lock;
 
2368
 
 
2369
  lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
 
2370
  lock.l_start = offset; /* byte offset relative to whence */
 
2371
  lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
 
2372
  lock.l_len = len; /* #bytes, 0 for eof */
 
2373
 
 
2374
  return fcntl (fd, cmd, &lock);
 
2375
}
 
2376
 
 
2377
#define lock_entire_file(fd) \
 
2378
  lock_reg ((fd), F_SETLK, F_WRLCK, 0, SEEK_SET, 0)
 
2379
#define unlock_entire_file(fd) \
 
2380
  lock_reg ((fd), F_SETLK, F_UNLCK, 0, SEEK_SET, 0)
 
2381
 
 
2382
static gboolean
 
2383
file_locked_by_someone_else (int fd)
 
2384
{
 
2385
  struct flock lock;
 
2386
 
 
2387
  lock.l_type = F_WRLCK;
 
2388
  lock.l_start = 0;
 
2389
  lock.l_whence = SEEK_SET;
 
2390
  lock.l_len = 0;
 
2391
 
 
2392
  if (fcntl (fd, F_GETLK, &lock) < 0)
 
2393
    return TRUE; /* pretend it's locked */
 
2394
 
 
2395
  if (lock.l_type == F_UNLCK)
 
2396
    return FALSE; /* we have the lock */
 
2397
  else
 
2398
    return TRUE; /* someone else has it */
 
2399
}
 
2400
 
 
2401
static char*
 
2402
unique_filename (const char *directory)
 
2403
{
 
2404
  char *guid;
 
2405
  char *uniquefile;
 
2406
  
 
2407
  guid = gconf_unique_key ();
 
2408
  uniquefile = g_strconcat (directory, "/", guid, NULL);
 
2409
  g_free (guid);
 
2410
 
 
2411
  return uniquefile;
 
2412
}
 
2413
 
 
2414
static int
 
2415
create_new_locked_file (const gchar *directory,
 
2416
                        const gchar *filename,
 
2417
                        GError     **err)
 
2418
{
 
2419
  int fd;
 
2420
  char *uniquefile;
 
2421
  gboolean got_lock;
 
2422
  
 
2423
  got_lock = FALSE;
 
2424
  
 
2425
  uniquefile = unique_filename (directory);
 
2426
 
 
2427
  fd = open (uniquefile, O_WRONLY | O_CREAT, 0700);
 
2428
 
 
2429
  /* Lock our temporary file, lock hopefully applies to the
 
2430
   * inode and so also counts once we link it to the new name
 
2431
   */
 
2432
  if (lock_entire_file (fd) < 0)
 
2433
    {
 
2434
      g_set_error (err,
 
2435
                   GCONF_ERROR,
 
2436
                   GCONF_ERROR_LOCK_FAILED,
 
2437
                   _("Could not lock temporary file '%s': %s"),
 
2438
                   uniquefile, g_strerror (errno));
 
2439
      goto out;
 
2440
    }
 
2441
  
 
2442
  /* Create lockfile as a link to unique file */
 
2443
  if (link (uniquefile, filename) == 0)
 
2444
    {
 
2445
      /* filename didn't exist before, and open succeeded, and we have the lock */
 
2446
      got_lock = TRUE;
 
2447
      goto out;
 
2448
    }
 
2449
  else
 
2450
    {
 
2451
      /* see if the link really succeeded */
 
2452
      struct stat sb;
 
2453
      if (stat (uniquefile, &sb) == 0 &&
 
2454
          sb.st_nlink == 2)
 
2455
        {
 
2456
          got_lock = TRUE;
 
2457
          goto out;
 
2458
        }
 
2459
      else
 
2460
        {
 
2461
          g_set_error (err,
 
2462
                       GCONF_ERROR,
 
2463
                       GCONF_ERROR_LOCK_FAILED,
 
2464
                       _("Could not create file '%s', probably because it already exists"),
 
2465
                       filename);
 
2466
          goto out;
 
2467
        }
 
2468
    }
 
2469
  
 
2470
 out:
 
2471
  if (got_lock)
 
2472
    set_close_on_exec (fd);
 
2473
  
 
2474
  unlink (uniquefile);
 
2475
  g_free (uniquefile);
 
2476
 
 
2477
  if (!got_lock)
 
2478
    {
 
2479
      if (fd >= 0)
 
2480
        close (fd);
 
2481
      fd = -1;
 
2482
    }
 
2483
  
 
2484
  return fd;
 
2485
}
 
2486
 
 
2487
static int
 
2488
open_empty_locked_file (const gchar *directory,
 
2489
                        const gchar *filename,
 
2490
                        GError     **err)
 
2491
{
 
2492
  int fd;
 
2493
 
 
2494
  fd = create_new_locked_file (directory, filename, NULL);
 
2495
 
 
2496
  if (fd >= 0)
 
2497
    return fd;
 
2498
  
 
2499
  /* We failed to create the file, most likely because it already
 
2500
   * existed; try to get the lock on the existing file, and if we can
 
2501
   * get that lock, delete it, then start over.
 
2502
   */
 
2503
  fd = open (filename, O_RDWR, 0700);
 
2504
  if (fd < 0)
 
2505
    {
 
2506
      /* File has gone away? */
 
2507
      g_set_error (err,
 
2508
                   GCONF_ERROR,
 
2509
                   GCONF_ERROR_LOCK_FAILED,
 
2510
                   _("Failed to create or open '%s'"),
 
2511
                   filename);
 
2512
      return -1;
 
2513
    }
 
2514
 
 
2515
  if (lock_entire_file (fd) < 0)
 
2516
    {
 
2517
      g_set_error (err,
 
2518
                   GCONF_ERROR,
 
2519
                   GCONF_ERROR_LOCK_FAILED,
 
2520
                   _("Failed to lock '%s': probably another process has the lock, or your operating system has NFS file locking misconfigured, or a hard NFS client crash caused a stale lock (%s)"),
 
2521
                   filename, strerror (errno));
 
2522
      close (fd);
 
2523
      return -1;
 
2524
    }
 
2525
 
 
2526
  /* We have the lock on filename, so delete it */
 
2527
  unlink (filename);
 
2528
  close (fd);
 
2529
  fd = -1;
 
2530
 
 
2531
  /* Now retry creating our file */
 
2532
  fd = create_new_locked_file (directory, filename, err);
 
2533
  
 
2534
  return fd;
 
2535
}
 
2536
 
 
2537
static ConfigServer
 
2538
read_current_server (const gchar *iorfile,
 
2539
                     gboolean     warn_if_fail)
 
2540
{
 
2541
  FILE *fp;
 
2542
  
 
2543
  fp = fopen (iorfile, "r");
 
2544
          
 
2545
  if (fp == NULL)
 
2546
    {
 
2547
      if (warn_if_fail)
 
2548
        gconf_log (GCL_WARNING, _("IOR file '%s' not opened successfully, no gconfd located: %s"),
 
2549
                   iorfile, g_strerror (errno));
 
2550
 
 
2551
      return CORBA_OBJECT_NIL;
 
2552
    }
 
2553
  else /* successfully opened IOR file */
 
2554
    {
 
2555
      char buf[2048] = { '\0' };
 
2556
      const char *str = NULL;
 
2557
 
 
2558
      fgets (buf, sizeof (buf) - 2, fp);
 
2559
      fclose (fp);
 
2560
 
 
2561
      /* The lockfile format is <pid>:<ior> for gconfd
 
2562
       * or <pid>:none for gconftool
 
2563
       */
 
2564
      str = buf;
 
2565
      while (isdigit(*str))
 
2566
        ++str;
 
2567
 
 
2568
      if (*str == ':')
 
2569
        ++str;
 
2570
          
 
2571
      if (str[0] == 'n' &&
 
2572
          str[1] == 'o' &&
 
2573
          str[2] == 'n' &&
 
2574
          str[3] == 'e')
 
2575
        {
 
2576
          if (warn_if_fail)
 
2577
            gconf_log (GCL_WARNING,
 
2578
                       _("gconftool or other non-gconfd process has the lock file '%s'"),
 
2579
                       iorfile);          
 
2580
        }
 
2581
      else /* file contains daemon IOR */
 
2582
        {
 
2583
          CORBA_ORB orb;
 
2584
          CORBA_Environment ev;
 
2585
          ConfigServer server;
 
2586
          
 
2587
          CORBA_exception_init (&ev);
 
2588
                  
 
2589
          orb = gconf_orb_get ();
 
2590
 
 
2591
          if (orb == NULL)
 
2592
            {
 
2593
              if (warn_if_fail)
 
2594
                gconf_log (GCL_WARNING,
 
2595
                           _("couldn't contact ORB to resolve existing gconfd object reference"));
 
2596
              return CORBA_OBJECT_NIL;
 
2597
            }
 
2598
                  
 
2599
          server = CORBA_ORB_string_to_object (orb, (char*) str, &ev);
 
2600
          CORBA_exception_free (&ev);
 
2601
 
 
2602
          return server;
 
2603
        }
 
2604
 
 
2605
      return CORBA_OBJECT_NIL;
 
2606
    }
 
2607
}
 
2608
 
 
2609
GConfLock*
 
2610
gconf_get_lock_or_current_holder (const gchar  *lock_directory,
 
2611
                                  ConfigServer *current_server,
 
2612
                                  GError      **err)
 
2613
{
 
2614
  ConfigServer server;
 
2615
  GConfLock* lock;
 
2616
  
 
2617
  g_return_val_if_fail(lock_directory != NULL, NULL);
 
2618
 
 
2619
  if (current_server)
 
2620
    *current_server = CORBA_OBJECT_NIL;
 
2621
  
 
2622
  if (mkdir (lock_directory, 0700) < 0 &&
 
2623
      errno != EEXIST)
 
2624
    {
 
2625
      gconf_set_error (err,
 
2626
                       GCONF_ERROR_LOCK_FAILED,
 
2627
                       _("couldn't create directory `%s': %s"),
 
2628
                       lock_directory, g_strerror (errno));
 
2629
 
 
2630
      return NULL;
 
2631
    }
 
2632
 
 
2633
  server = CORBA_OBJECT_NIL;
 
2634
    
 
2635
  lock = g_new0 (GConfLock, 1);
 
2636
 
 
2637
  lock->lock_directory = g_strdup (lock_directory);
 
2638
 
 
2639
  lock->iorfile = g_strconcat (lock->lock_directory, "/ior", NULL);
 
2640
 
 
2641
  /* Check the current IOR file and ping its daemon */
 
2642
  
 
2643
  lock->lock_fd = open_empty_locked_file (lock->lock_directory,
 
2644
                                          lock->iorfile,
 
2645
                                          err);
 
2646
  
 
2647
  if (lock->lock_fd < 0)
 
2648
    {
 
2649
      /* We didn't get the lock. Read the old server, and provide
 
2650
       * it to the caller. Error is already set.
 
2651
       */
 
2652
      if (current_server)
 
2653
        *current_server = read_current_server (lock->iorfile, TRUE);
 
2654
 
 
2655
      gconf_lock_destroy (lock);
 
2656
      
 
2657
      return NULL;
 
2658
    }
 
2659
  else
 
2660
    {
 
2661
      /* Write IOR to lockfile */
 
2662
      const gchar* ior;
 
2663
      int retval;
 
2664
      gchar* s;
 
2665
      
 
2666
      s = g_strdup_printf ("%u:", (guint) getpid ());
 
2667
        
 
2668
      retval = write (lock->lock_fd, s, strlen (s));
 
2669
 
 
2670
      g_free (s);
 
2671
        
 
2672
      if (retval >= 0)
 
2673
        {
 
2674
          ior = gconf_get_daemon_ior();
 
2675
            
 
2676
          if (ior == NULL)
 
2677
            retval = write (lock->lock_fd, "none", 4);
 
2678
          else
 
2679
            retval = write (lock->lock_fd, ior, strlen (ior));
 
2680
        }
 
2681
 
 
2682
      if (retval < 0)
 
2683
        {
 
2684
          gconf_set_error (err,
 
2685
                           GCONF_ERROR_LOCK_FAILED,
 
2686
                           _("Can't write to file `%s': %s"),
 
2687
                           lock->iorfile, g_strerror (errno));
 
2688
 
 
2689
          unlink (lock->iorfile);
 
2690
          gconf_lock_destroy (lock);
 
2691
 
 
2692
          return NULL;
 
2693
        }
 
2694
    }
 
2695
 
 
2696
  return lock;
 
2697
}
 
2698
 
 
2699
GConfLock*
 
2700
gconf_get_lock (const gchar *lock_directory,
 
2701
                GError     **err)
 
2702
{
 
2703
  return gconf_get_lock_or_current_holder (lock_directory, NULL, err);
 
2704
}
 
2705
 
 
2706
gboolean
 
2707
gconf_release_lock (GConfLock *lock,
 
2708
                    GError   **err)
 
2709
{
 
2710
  gboolean retval;
 
2711
  char *uniquefile;
 
2712
  
 
2713
  retval = FALSE;
 
2714
  uniquefile = NULL;
 
2715
  
 
2716
  /* A paranoia check to avoid disaster if e.g.
 
2717
   * some random client code opened and closed the
 
2718
   * lockfile (maybe Nautilus checking its MIME type or
 
2719
   * something)
 
2720
   */
 
2721
  if (lock->lock_fd < 0 ||
 
2722
      file_locked_by_someone_else (lock->lock_fd))
 
2723
    {
 
2724
      g_set_error (err,
 
2725
                   GCONF_ERROR,
 
2726
                   GCONF_ERROR_FAILED,
 
2727
                   _("We didn't have the lock on file `%s', but we should have"),
 
2728
                   lock->iorfile);
 
2729
      goto out;
 
2730
    }
 
2731
 
 
2732
  /* To avoid annoying .nfs3435314513453145 files on unlink, which keep us
 
2733
   * from removing the lock directory, we don't want to hold the
 
2734
   * lockfile open after removing all links to it. But we can't
 
2735
   * close it then unlink, because then we would be unlinking without
 
2736
   * holding the lock. So, we create a unique filename and link it too
 
2737
   * the locked file, then unlink the locked file, then drop our locks
 
2738
   * and close file descriptors, then unlink the unique filename
 
2739
   */
 
2740
  
 
2741
  uniquefile = unique_filename (lock->lock_directory);
 
2742
 
 
2743
  if (link (lock->iorfile, uniquefile) < 0)
 
2744
    {
 
2745
      g_set_error (err,
 
2746
                   GCONF_ERROR,
 
2747
                   GCONF_ERROR_FAILED,
 
2748
                   _("Failed to link '%s' to '%s': %s"),
 
2749
                   uniquefile, lock->iorfile, g_strerror (errno));
 
2750
 
 
2751
      goto out;
 
2752
    }
 
2753
  
 
2754
  /* Note that we unlink while still holding the lock to avoid races */
 
2755
  if (unlink (lock->iorfile) < 0)
 
2756
    {
 
2757
      g_set_error (err,
 
2758
                   GCONF_ERROR,
 
2759
                   GCONF_ERROR_FAILED,
 
2760
                   _("Failed to remove lock file `%s': %s"),
 
2761
                   lock->iorfile,
 
2762
                   g_strerror (errno));
 
2763
      goto out;
 
2764
    }
 
2765
 
 
2766
  /* Now drop our lock */
 
2767
  if (lock->lock_fd >= 0)
 
2768
    {
 
2769
      close (lock->lock_fd);
 
2770
      lock->lock_fd = -1;
 
2771
    }
 
2772
 
 
2773
  /* Now remove the temporary link we used to avoid .nfs351453 garbage */
 
2774
  if (unlink (uniquefile) < 0)
 
2775
    {
 
2776
      g_set_error (err,
 
2777
                   GCONF_ERROR,
 
2778
                   GCONF_ERROR_FAILED,
 
2779
                   _("Failed to clean up file '%s': %s"),
 
2780
                   uniquefile, g_strerror (errno));
 
2781
 
 
2782
      goto out;
 
2783
    }
 
2784
 
 
2785
  /* And finally clean up the directory - this would have failed if
 
2786
   * we had .nfs323423423 junk
 
2787
   */
 
2788
  if (rmdir (lock->lock_directory) < 0)
 
2789
    {
 
2790
      g_set_error (err,
 
2791
                   GCONF_ERROR,
 
2792
                   GCONF_ERROR_FAILED,
 
2793
                   _("Failed to remove lock directory `%s': %s"),
 
2794
                   lock->lock_directory,
 
2795
                   g_strerror (errno));
 
2796
      goto out;
 
2797
    }
 
2798
 
 
2799
  retval = TRUE;
 
2800
  
 
2801
 out:
 
2802
 
 
2803
  g_free (uniquefile);
 
2804
  gconf_lock_destroy (lock);
 
2805
  return retval;
 
2806
}
 
2807
 
 
2808
/* This function doesn't try to see if the lock is valid or anything
 
2809
 * of the sort; it just reads it. It does do the object_to_string
 
2810
 */
 
2811
ConfigServer
 
2812
gconf_get_current_lock_holder  (const gchar *lock_directory)
 
2813
{
 
2814
  char *iorfile;
 
2815
  ConfigServer server;
 
2816
 
 
2817
  iorfile = g_strconcat (lock_directory, "/ior", NULL);
 
2818
  server = read_current_server (iorfile, FALSE);
 
2819
  g_free (iorfile);
 
2820
  return server;
 
2821
}
 
2822
 
 
2823
/* Copied from OAF */
 
2824
#ifndef ORBIT_USES_GLIB_MAIN_LOOP
 
2825
 
 
2826
static gboolean
 
2827
orb_handle_connection (GIOChannel * source, GIOCondition cond,
 
2828
                       GIOPConnection * cnx)
 
2829
{
 
2830
        /* The best way to know about an fd exception is if select()/poll()
 
2831
         * tells you about it, so we just relay that information on to ORBit
 
2832
         * if possible
 
2833
         */
 
2834
 
 
2835
        if (cond & (G_IO_HUP | G_IO_NVAL | G_IO_ERR))
 
2836
                giop_main_handle_connection_exception (cnx);
 
2837
        else
 
2838
                giop_main_handle_connection (cnx);
 
2839
 
 
2840
        return TRUE;
 
2841
}
 
2842
 
 
2843
static void
 
2844
orb_add_connection (GIOPConnection * cnx)
 
2845
{
 
2846
        int tag;
 
2847
        GIOChannel *channel;
 
2848
 
 
2849
        channel = g_io_channel_unix_new (GIOP_CONNECTION_GET_FD (cnx));
 
2850
        tag = g_io_add_watch_full (channel, G_PRIORITY_LOW,
 
2851
                                   G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
 
2852
                                   (GIOFunc) orb_handle_connection,
 
2853
                                   cnx, NULL);
 
2854
        g_io_channel_unref (channel);
 
2855
 
 
2856
        cnx->user_data = GUINT_TO_POINTER (tag);
 
2857
}
 
2858
 
 
2859
static void
 
2860
orb_remove_connection (GIOPConnection * cnx)
 
2861
{
 
2862
        g_source_remove (GPOINTER_TO_UINT (cnx->user_data));
 
2863
        cnx->user_data = GINT_TO_POINTER (-1);
 
2864
}
 
2865
 
 
2866
#endif /* !ORBIT_USES_GLIB_MAIN_LOOP */
 
2867
 
 
2868
 
 
2869
#include <netinet/in.h>
 
2870
#include <netdb.h>
 
2871
#include <arpa/inet.h>
 
2872
const char *
 
2873
get_hostname (void)
 
2874
{
 
2875
        static char *hostname = NULL;
 
2876
        char hn_tmp[65], ha_tmp[4];
 
2877
        struct hostent *hent;
 
2878
 
 
2879
        if (!hostname) {
 
2880
                gethostname (hn_tmp, sizeof (hn_tmp) - 1);
 
2881
 
 
2882
                hent = gethostbyname (hn_tmp);
 
2883
                if (hent) {
 
2884
                        memcpy (ha_tmp, hent->h_addr, 4);
 
2885
                        hent = gethostbyaddr (ha_tmp, 4, AF_INET);
 
2886
                        if (hent)
 
2887
                                hostname = g_strdup (hent->h_name);
 
2888
                        else
 
2889
                                hostname =
 
2890
                                        g_strdup (inet_ntoa
 
2891
                                                  (*
 
2892
                                                   ((struct in_addr *)
 
2893
                                                    ha_tmp)));
 
2894
                } else
 
2895
                        hostname = g_strdup (hn_tmp);
 
2896
        }
 
2897
 
 
2898
        return hostname;
 
2899
}
 
2900
 
 
2901
CORBA_ORB
 
2902
gconf_orb_get (void)
 
2903
{
 
2904
  if (gconf_in_daemon_mode ())
 
2905
    {
 
2906
      static CORBA_ORB gconf_orb = CORBA_OBJECT_NIL;      
 
2907
 
 
2908
      if (gconf_orb == CORBA_OBJECT_NIL)
 
2909
        {
 
2910
          CORBA_Environment ev;
 
2911
          int argc = 1;
 
2912
          char *argv[] = { "gconf", NULL };
 
2913
          CORBA_Context context;
 
2914
          const char *hostname;
 
2915
          
 
2916
#ifndef ORBIT_USES_GLIB_MAIN_LOOP
 
2917
          IIOPAddConnectionHandler = orb_add_connection;
 
2918
          IIOPRemoveConnectionHandler = orb_remove_connection;
 
2919
#endif /* !ORBIT_USES_GLIB_MAIN_LOOP */
 
2920
      
 
2921
          CORBA_exception_init (&ev);
 
2922
      
 
2923
          gconf_orb = CORBA_ORB_init (&argc, argv, "orbit-local-orb", &ev);
 
2924
          g_assert (ev._major == CORBA_NO_EXCEPTION);
 
2925
 
 
2926
          /* Set values in default context */
 
2927
          CORBA_ORB_get_default_context (gconf_orb, &context, &ev);
 
2928
          g_assert (ev._major == CORBA_NO_EXCEPTION);
 
2929
          
 
2930
          hostname = get_hostname ();
 
2931
          CORBA_Context_set_one_value (context, "hostname",
 
2932
                                       (char *) hostname, &ev);
 
2933
          CORBA_Context_set_one_value (context, "domain", "user", &ev);
 
2934
          CORBA_Context_set_one_value (context, "username",
 
2935
                                       g_get_user_name (), &ev);
 
2936
          
 
2937
          CORBA_exception_free (&ev);
 
2938
        }
 
2939
      
 
2940
      return gconf_orb;
 
2941
    }
 
2942
  else
 
2943
    {
 
2944
      return oaf_orb_get ();
 
2945
    }
 
2946
}
 
2947
 
 
2948
char*
 
2949
gconf_get_daemon_dir (void)
 
2950
{
 
2951
  return g_strconcat (g_get_home_dir (), "/.gconfd", NULL);
 
2952
}
 
2953
 
 
2954
char*
 
2955
gconf_get_lock_dir (void)
 
2956
{
 
2957
  char *gconfd_dir;
 
2958
  char *lock_dir;
 
2959
  
 
2960
  gconfd_dir = gconf_get_daemon_dir ();
 
2961
  lock_dir = g_strconcat (gconfd_dir, "/lock", NULL);
 
2962
 
 
2963
  g_free (gconfd_dir);
 
2964
  return lock_dir;
 
2965
}
 
2966
 
 
2967
 
 
2968
static void set_cloexec (gint fd);
 
2969
 
 
2970
static void
 
2971
close_fd_func (gpointer data)
 
2972
{
 
2973
  int *pipes = data;
 
2974
  
 
2975
  gint open_max;
 
2976
  gint i;
 
2977
  
 
2978
  open_max = sysconf (_SC_OPEN_MAX);
 
2979
  for (i = 3; i < open_max; i++)
 
2980
    {
 
2981
      /* don't close our write pipe */
 
2982
      if (i != pipes[1])
 
2983
        set_cloexec (i);
 
2984
    }
 
2985
}
 
2986
 
 
2987
ConfigServer
 
2988
gconf_activate_server (gboolean  start_if_not_found,
 
2989
                       GError  **error)
 
2990
{
 
2991
  ConfigServer server;
 
2992
  int p[2] = { -1, -1 };
 
2993
  char buf[1];
 
2994
  GError *tmp_err;
 
2995
  char *argv[3];
 
2996
  char *gconfd_dir;
 
2997
  char *lock_dir;
 
2998
  CORBA_Environment ev;
 
2999
  
 
3000
  gconfd_dir = gconf_get_daemon_dir ();
 
3001
  
 
3002
  if (mkdir (gconfd_dir, 0700) < 0 && errno != EEXIST)
 
3003
    gconf_log (GCL_WARNING, _("Failed to create %s: %s"),
 
3004
               gconfd_dir, g_strerror (errno));
 
3005
 
 
3006
  g_free (gconfd_dir);
 
3007
  
 
3008
  lock_dir = gconf_get_lock_dir ();
 
3009
  server = gconf_get_current_lock_holder (lock_dir);
 
3010
  g_free (lock_dir);
 
3011
 
 
3012
  /* Confirm server exists */
 
3013
  CORBA_exception_init (&ev);
 
3014
 
 
3015
  if (!CORBA_Object_is_nil (server, &ev))
 
3016
    {
 
3017
      ConfigServer_ping (server, &ev);
 
3018
      
 
3019
      if (ev._major != CORBA_NO_EXCEPTION)
 
3020
        server = CORBA_OBJECT_NIL;
 
3021
    }
 
3022
 
 
3023
  CORBA_exception_free (&ev);  
 
3024
 
 
3025
  if (server != CORBA_OBJECT_NIL)
 
3026
    return server;
 
3027
  
 
3028
  if (start_if_not_found)
 
3029
    {
 
3030
      /* Spawn server */
 
3031
      if (pipe (p) < 0)
 
3032
        {
 
3033
          g_set_error (error,
 
3034
                       GCONF_ERROR,
 
3035
                       GCONF_ERROR_NO_SERVER,
 
3036
                       _("Failed to create pipe for communicating with spawned gconf daemon: %s\n"),
 
3037
                       g_strerror (errno));
 
3038
          goto out;
 
3039
        }
 
3040
 
 
3041
      if (gconf_file_exists (GCONF_BINDIR"/gconfd-2"))
 
3042
        argv[0] = g_strconcat (GCONF_BINDIR, "/gconfd-2", NULL);
 
3043
      else
 
3044
        argv[0] = g_strconcat (GCONF_BINDIR, "/" GCONFD, NULL);
 
3045
 
 
3046
      argv[1] = g_strdup_printf ("%d", p[1]);
 
3047
      argv[2] = NULL;
 
3048
  
 
3049
      tmp_err = NULL;
 
3050
      if (!g_spawn_async (NULL,
 
3051
                          argv,
 
3052
                          NULL,
 
3053
                          G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
 
3054
                          close_fd_func,
 
3055
                          p,
 
3056
                          NULL,
 
3057
                          &tmp_err))
 
3058
        {
 
3059
          g_free (argv[0]);
 
3060
          g_free (argv[1]);
 
3061
          g_set_error (error,
 
3062
                       GCONF_ERROR,
 
3063
                       GCONF_ERROR_NO_SERVER,
 
3064
                       _("Failed to launch configuration server: %s\n"),
 
3065
                       tmp_err->message);
 
3066
          g_error_free (tmp_err);
 
3067
          goto out;
 
3068
        }
 
3069
      
 
3070
      g_free (argv[0]);
 
3071
      g_free (argv[1]);
 
3072
  
 
3073
      /* Block until server starts up */
 
3074
      read (p[0], buf, 1);
 
3075
 
 
3076
      lock_dir = gconf_get_lock_dir ();
 
3077
      server = gconf_get_current_lock_holder (lock_dir);
 
3078
      g_free (lock_dir);
 
3079
    }
 
3080
  
 
3081
 out:
 
3082
  if (server == CORBA_OBJECT_NIL &&
 
3083
      error &&
 
3084
      *error == NULL)
 
3085
    g_set_error (error,
 
3086
                 GCONF_ERROR,
 
3087
                 GCONF_ERROR_NO_SERVER,
 
3088
                 _("Failed to contact configuration server (a likely cause of this is that you have an existing configuration server (gconfd) running, but it isn't reachable from here - if you're logged in from two machines at once, you may need to enable TCP networking for ORBit)\n"));
 
3089
 
 
3090
  close (p[0]);
 
3091
  close (p[1]);
 
3092
  
 
3093
  return server;
 
3094
}
 
3095
 
 
3096
/* g_spawn cut-and-paste, changed to make all symbols static */
 
3097
 
 
3098
/* gspawn.h - Process launching
 
3099
 *
 
3100
 *  Copyright 2000 Red Hat, Inc.
 
3101
 *
 
3102
 * GLib is free software; you can redistribute it and/or
 
3103
 * modify it under the terms of the GNU Lesser General Public License as
 
3104
 * published by the Free Software Foundation; either version 2 of the
 
3105
 * License, or (at your option) any later version.
 
3106
 *
 
3107
 * GLib is distributed in the hope that it will be useful,
 
3108
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
3109
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
3110
 * Lesser General Public License for more details.
 
3111
 *
 
3112
 * You should have received a copy of the GNU Lesser General Public
 
3113
 * License along with GLib; see the file COPYING.LIB.  If not, write
 
3114
 * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
3115
 * Boston, MA 02111-1307, USA.
 
3116
 */
 
3117
 
 
3118
#ifndef __G_SPAWN_H__
 
3119
#define __G_SPAWN_H__
 
3120
 
 
3121
/* I'm not sure I remember our proposed naming convention here. */
 
3122
#define G_SPAWN_ERROR g_spawn_error_quark ()
 
3123
 
 
3124
typedef enum
 
3125
{
 
3126
  G_SPAWN_ERROR_FORK,   /* fork failed due to lack of memory */
 
3127
  G_SPAWN_ERROR_READ,   /* read or select on pipes failed */
 
3128
  G_SPAWN_ERROR_CHDIR,  /* changing to working dir failed */
 
3129
  G_SPAWN_ERROR_ACCES,  /* execv() returned EACCES */
 
3130
  G_SPAWN_ERROR_PERM,   /* execv() returned EPERM */
 
3131
  G_SPAWN_ERROR_2BIG,   /* execv() returned E2BIG */
 
3132
  G_SPAWN_ERROR_NOEXEC, /* execv() returned ENOEXEC */
 
3133
  G_SPAWN_ERROR_NAMETOOLONG, /* ""  "" ENAMETOOLONG */
 
3134
  G_SPAWN_ERROR_NOENT,       /* ""  "" ENOENT */
 
3135
  G_SPAWN_ERROR_NOMEM,       /* ""  "" ENOMEM */
 
3136
  G_SPAWN_ERROR_NOTDIR,      /* ""  "" ENOTDIR */
 
3137
  G_SPAWN_ERROR_LOOP,        /* ""  "" ELOOP   */
 
3138
  G_SPAWN_ERROR_TXTBUSY,     /* ""  "" ETXTBUSY */
 
3139
  G_SPAWN_ERROR_IO,          /* ""  "" EIO */
 
3140
  G_SPAWN_ERROR_NFILE,       /* ""  "" ENFILE */
 
3141
  G_SPAWN_ERROR_MFILE,       /* ""  "" EMFLE */
 
3142
  G_SPAWN_ERROR_INVAL,       /* ""  "" EINVAL */
 
3143
  G_SPAWN_ERROR_ISDIR,       /* ""  "" EISDIR */
 
3144
  G_SPAWN_ERROR_LIBBAD,      /* ""  "" ELIBBAD */
 
3145
  G_SPAWN_ERROR_FAILED       /* other fatal failure, error->message
 
3146
                              * should explain
 
3147
                              */
 
3148
} GSpawnError;
 
3149
 
 
3150
static GQuark g_spawn_error_quark (void);
 
3151
 
 
3152
static gboolean g_spawn_async (const gchar           *working_directory,
 
3153
                               gchar                **argv,
 
3154
                               gchar                **envp,
 
3155
                               GSpawnFlags            flags,
 
3156
                               GSpawnChildSetupFunc   child_setup,
 
3157
                               gpointer               user_data,
 
3158
                               gint                  *child_pid,
 
3159
                               GError               **error);
 
3160
 
 
3161
 
 
3162
/* Opens pipes for non-NULL standard_output, standard_input, standard_error,
 
3163
 * and returns the parent's end of the pipes.
 
3164
 */
 
3165
static gboolean g_spawn_async_with_pipes (const gchar          *working_directory,
 
3166
                                          gchar               **argv,
 
3167
                                          gchar               **envp,
 
3168
                                          GSpawnFlags           flags,
 
3169
                                          GSpawnChildSetupFunc  child_setup,
 
3170
                                          gpointer              user_data,
 
3171
                                          gint                 *child_pid,
 
3172
                                          gint                 *standard_input,
 
3173
                                          gint                 *standard_output,
 
3174
                                          gint                 *standard_error,
 
3175
                                          GError              **error);
 
3176
 
 
3177
 
 
3178
#endif /* __G_SPAWN_H__ */
 
3179
 
 
3180
 
 
3181
 
 
3182
 
 
3183
/* gspawn.c - Process launching
 
3184
 *
 
3185
 *  Copyright 2000 Red Hat, Inc.
 
3186
 *  g_execvpe implementation based on GNU libc execvp:
 
3187
 *   Copyright 1991, 92, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
 
3188
 *
 
3189
 * GLib is free software; you can redistribute it and/or
 
3190
 * modify it under the terms of the GNU Lesser General Public License as
 
3191
 * published by the Free Software Foundation; either version 2 of the
 
3192
 * License, or (at your option) any later version.
 
3193
 *
 
3194
 * GLib is distributed in the hope that it will be useful,
 
3195
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
3196
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
3197
 * Lesser General Public License for more details.
 
3198
 *
 
3199
 * You should have received a copy of the GNU Lesser General Public
 
3200
 * License along with GLib; see the file COPYING.LIB.  If not, write
 
3201
 * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
3202
 * Boston, MA 02111-1307, USA.
 
3203
 */
 
3204
 
 
3205
#include "glib.h"
 
3206
#include <sys/time.h>
 
3207
#include <sys/types.h>
 
3208
#include <sys/wait.h>
 
3209
#include <unistd.h>
 
3210
#include <errno.h>
 
3211
#include <fcntl.h>
 
3212
#include <signal.h>
 
3213
#include <string.h>
 
3214
 
 
3215
#ifdef HAVE_SYS_SELECT_H
 
3216
#include <sys/select.h>
 
3217
#endif /* HAVE_SYS_SELECT_H */
 
3218
 
 
3219
static gint g_execute (const gchar  *file,
 
3220
                       gchar **argv,
 
3221
                       gchar **envp,
 
3222
                       gboolean search_path);
 
3223
 
 
3224
static gboolean make_pipe            (gint                  p[2],
 
3225
                                      GError              **error);
 
3226
static gboolean fork_exec_with_pipes (gboolean              intermediate_child,
 
3227
                                      const gchar          *working_directory,
 
3228
                                      gchar               **argv,
 
3229
                                      gchar               **envp,
 
3230
                                      gboolean              close_descriptors,
 
3231
                                      gboolean              search_path,
 
3232
                                      gboolean              stdout_to_null,
 
3233
                                      gboolean              stderr_to_null,
 
3234
                                      gboolean              child_inherits_stdin,
 
3235
                                      gboolean              file_and_argv_zero,
 
3236
                                      GSpawnChildSetupFunc  child_setup,
 
3237
                                      gpointer              user_data,
 
3238
                                      gint                 *child_pid,
 
3239
                                      gint                 *standard_input,
 
3240
                                      gint                 *standard_output,
 
3241
                                      gint                 *standard_error,
 
3242
                                      GError              **error);
 
3243
 
 
3244
GQuark
 
3245
g_spawn_error_quark (void)
 
3246
{
 
3247
  static GQuark quark = 0;
 
3248
  if (quark == 0)
 
3249
    quark = g_quark_from_static_string ("g-exec-error-quark");
 
3250
  return quark;
 
3251
}
 
3252
 
 
3253
/**
 
3254
 * g_spawn_async:
 
3255
 * @working_directory: child's current working directory, or NULL to inherit parent's
 
3256
 * @argv: child's argument vector
 
3257
 * @envp: child's environment, or NULL to inherit parent's
 
3258
 * @flags: flags from #GSpawnFlags
 
3259
 * @child_setup: function to run in the child just before exec()
 
3260
 * @user_data: user data for @child_setup
 
3261
 * @child_pid: return location for child process ID, or NULL
 
3262
 * @error: return location for error
 
3263
 * 
 
3264
 * See g_spawn_async_with_pipes() for a full description; this function
 
3265
 * simply calls the g_spawn_async_with_pipes() without any pipes.
 
3266
 * 
 
3267
 * Return value: TRUE on success, FALSE if error is set
 
3268
 **/
 
3269
static gboolean
 
3270
g_spawn_async (const gchar          *working_directory,
 
3271
               gchar               **argv,
 
3272
               gchar               **envp,
 
3273
               GSpawnFlags           flags,
 
3274
               GSpawnChildSetupFunc  child_setup,
 
3275
               gpointer              user_data,
 
3276
               gint                 *child_pid,
 
3277
               GError              **error)
 
3278
{
 
3279
  g_return_val_if_fail (argv != NULL, FALSE);
 
3280
  
 
3281
  return g_spawn_async_with_pipes (working_directory,
 
3282
                                   argv, envp,
 
3283
                                   flags,
 
3284
                                   child_setup,
 
3285
                                   user_data,
 
3286
                                   child_pid,
 
3287
                                   NULL, NULL, NULL,
 
3288
                                   error);
 
3289
}
 
3290
 
 
3291
/* Avoids a danger in threaded situations (calling close()
 
3292
 * on a file descriptor twice, and another thread has
 
3293
 * re-opened it since the first close)
 
3294
 */
 
3295
static gint
 
3296
close_and_invalidate (gint *fd)
 
3297
{
 
3298
  gint ret;
 
3299
 
 
3300
  ret = close (*fd);
 
3301
  *fd = -1;
 
3302
 
 
3303
  return ret;
 
3304
}
 
3305
 
 
3306
typedef enum
 
3307
{
 
3308
  READ_FAILED = 0, /* FALSE */
 
3309
  READ_OK,
 
3310
  READ_EOF
 
3311
} ReadResult;
 
3312
 
 
3313
/**
 
3314
 * g_spawn_async_with_pipes:
 
3315
 * @working_directory: child's current working directory, or NULL to inherit parent's
 
3316
 * @argv: child's argument vector
 
3317
 * @envp: child's environment, or NULL to inherit parent's
 
3318
 * @flags: flags from #GSpawnFlags
 
3319
 * @child_setup: function to run in the child just before exec()
 
3320
 * @user_data: user data for @child_setup
 
3321
 * @child_pid: return location for child process ID, or NULL
 
3322
 * @standard_input: return location for file descriptor to write to child's stdin, or NULL
 
3323
 * @standard_output: return location for file descriptor to read child's stdout, or NULL
 
3324
 * @standard_error: return location for file descriptor to read child's stderr, or NULL
 
3325
 * @error: return location for error
 
3326
 *
 
3327
 * Executes a child program asynchronously (your program will not
 
3328
 * block waiting for the child to exit). The child program is
 
3329
 * specified by the only argument that must be provided, @argv. @argv
 
3330
 * should be a NULL-terminated array of strings, to be passed as the
 
3331
 * argument vector for the child. The first string in @argv is of
 
3332
 * course the name of the program to execute. By default, the name of
 
3333
 * the program must be a full path; the PATH shell variable will only
 
3334
 * be searched if you pass the %G_SPAWN_SEARCH_PATH flag.
 
3335
 *
 
3336
 * @envp is a NULL-terminated array of strings, where each string
 
3337
 * has the form <literal>KEY=VALUE</literal>. This will become
 
3338
 * the child's environment. If @envp is NULL, the child inherits its
 
3339
 * parent's environment.
 
3340
 *
 
3341
 * @flags should be the bitwise OR of any flags you want to affect the
 
3342
 * function's behavior. The %G_SPAWN_DO_NOT_REAP_CHILD means that the
 
3343
 * child will not be automatically reaped; you must call waitpid() or
 
3344
 * handle SIGCHLD yourself, or the child will become a zombie.
 
3345
 * %G_SPAWN_LEAVE_DESCRIPTORS_OPEN means that the parent's open file
 
3346
 * descriptors will be inherited by the child; otherwise all
 
3347
 * descriptors except stdin/stdout/stderr will be closed before
 
3348
 * calling exec() in the child. %G_SPAWN_SEARCH_PATH means that
 
3349
 * <literal>argv[0]</literal> need not be an absolute path, it
 
3350
 * will be looked for in the user's PATH. %G_SPAWN_STDOUT_TO_DEV_NULL
 
3351
 * means that the child's standad output will be discarded, instead
 
3352
 * of going to the same location as the parent's standard output.
 
3353
 * %G_SPAWN_STDERR_TO_DEV_NULL means that the child's standard error
 
3354
 * will be discarded. %G_SPAWN_CHILD_INHERITS_STDIN means that
 
3355
 * the child will inherit the parent's standard input (by default,
 
3356
 * the child's standard input is attached to /dev/null).
 
3357
 * %G_SPAWN_FILE_AND_ARGV_ZERO means that the first element of @argv is
 
3358
 * the file to execute, while the remaining elements are the
 
3359
 * actual argument vector to pass to the file. Normally
 
3360
 * g_spawn_async_with_pipes() uses @argv[0] as the file to execute, and
 
3361
 * passes all of @argv to the child.
 
3362
 *
 
3363
 * @child_setup and @user_data are a function and user data to be
 
3364
 * called in the child after GLib has performed all the setup it plans
 
3365
 * to perform (including creating pipes, closing file descriptors,
 
3366
 * etc.) but before calling exec(). That is, @child_setup is called
 
3367
 * just before calling exec() in the child. Obviously actions taken in
 
3368
 * this function will only affect the child, not the parent. 
 
3369
 *
 
3370
 * If non-NULL, @child_pid will be filled with the child's process
 
3371
 * ID. You can use the process ID to send signals to the child, or
 
3372
 * to waitpid() if you specified the %G_SPAWN_DO_NOT_REAP_CHILD flag.
 
3373
 *
 
3374
 * If non-NULL, the @standard_input, @standard_output, @standard_error
 
3375
 * locations will be filled with file descriptors for writing to the child's
 
3376
 * standard input or reading from its standard output or standard error.
 
3377
 * The caller of g_spawn_async_with_pipes() must close these file descriptors
 
3378
 * when they are no longer in use. If these parameters are NULL, the
 
3379
 * corresponding pipe won't be created.
 
3380
 *
 
3381
 * @error can be NULL to ignore errors, or non-NULL to report errors.
 
3382
 * If an error is set, the function returns FALSE. Errors
 
3383
 * are reported even if they occur in the child (for example if the
 
3384
 * executable in <literal>argv[0]</literal> is not found). Typically
 
3385
 * the <literal>message</literal> field of returned errors should be displayed
 
3386
 * to users. Possible errors are those from the #G_SPAWN_ERROR domain.
 
3387
 *
 
3388
 * If an error occurs, @child_pid, @standard_input, @standard_output,
 
3389
 * and @standard_error will not be filled with valid values.
 
3390
 * 
 
3391
 * Return value: TRUE on success, FALSE if an error was set
 
3392
 **/
 
3393
static gboolean
 
3394
g_spawn_async_with_pipes (const gchar          *working_directory,
 
3395
                          gchar               **argv,
 
3396
                          gchar               **envp,
 
3397
                          GSpawnFlags           flags,
 
3398
                          GSpawnChildSetupFunc  child_setup,
 
3399
                          gpointer              user_data,
 
3400
                          gint                 *child_pid,
 
3401
                          gint                 *standard_input,
 
3402
                          gint                 *standard_output,
 
3403
                          gint                 *standard_error,
 
3404
                          GError              **error)
 
3405
{
 
3406
  g_return_val_if_fail (argv != NULL, FALSE);
 
3407
  g_return_val_if_fail (standard_output == NULL ||
 
3408
                        !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
 
3409
  g_return_val_if_fail (standard_error == NULL ||
 
3410
                        !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
 
3411
  /* can't inherit stdin if we have an input pipe. */
 
3412
  g_return_val_if_fail (standard_input == NULL ||
 
3413
                        !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
 
3414
  
 
3415
  return fork_exec_with_pipes (!(flags & G_SPAWN_DO_NOT_REAP_CHILD),
 
3416
                               working_directory,
 
3417
                               argv,
 
3418
                               envp,
 
3419
                               !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
 
3420
                               (flags & G_SPAWN_SEARCH_PATH) != 0,
 
3421
                               (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
 
3422
                               (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
 
3423
                               (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
 
3424
                               (flags & G_SPAWN_FILE_AND_ARGV_ZERO) != 0,
 
3425
                               child_setup,
 
3426
                               user_data,
 
3427
                               child_pid,
 
3428
                               standard_input,
 
3429
                               standard_output,
 
3430
                               standard_error,
 
3431
                               error);
 
3432
}
 
3433
 
 
3434
static gint
 
3435
exec_err_to_g_error (gint en)
 
3436
{
 
3437
  switch (en)
 
3438
    {
 
3439
#ifdef EACCES
 
3440
    case EACCES:
 
3441
      return G_SPAWN_ERROR_ACCES;
 
3442
      break;
 
3443
#endif
 
3444
 
 
3445
#ifdef EPERM
 
3446
    case EPERM:
 
3447
      return G_SPAWN_ERROR_PERM;
 
3448
      break;
 
3449
#endif
 
3450
 
 
3451
#ifdef E2BIG
 
3452
    case E2BIG:
 
3453
      return G_SPAWN_ERROR_2BIG;
 
3454
      break;
 
3455
#endif
 
3456
 
 
3457
#ifdef ENOEXEC
 
3458
    case ENOEXEC:
 
3459
      return G_SPAWN_ERROR_NOEXEC;
 
3460
      break;
 
3461
#endif
 
3462
 
 
3463
#ifdef ENAMETOOLONG
 
3464
    case ENAMETOOLONG:
 
3465
      return G_SPAWN_ERROR_NAMETOOLONG;
 
3466
      break;
 
3467
#endif
 
3468
 
 
3469
#ifdef ENOENT
 
3470
    case ENOENT:
 
3471
      return G_SPAWN_ERROR_NOENT;
 
3472
      break;
 
3473
#endif
 
3474
 
 
3475
#ifdef ENOMEM
 
3476
    case ENOMEM:
 
3477
      return G_SPAWN_ERROR_NOMEM;
 
3478
      break;
 
3479
#endif
 
3480
 
 
3481
#ifdef ENOTDIR
 
3482
    case ENOTDIR:
 
3483
      return G_SPAWN_ERROR_NOTDIR;
 
3484
      break;
 
3485
#endif
 
3486
 
 
3487
#ifdef ELOOP
 
3488
    case ELOOP:
 
3489
      return G_SPAWN_ERROR_LOOP;
 
3490
      break;
 
3491
#endif
 
3492
      
 
3493
#ifdef ETXTBUSY
 
3494
    case ETXTBUSY:
 
3495
      return G_SPAWN_ERROR_TXTBUSY;
 
3496
      break;
 
3497
#endif
 
3498
 
 
3499
#ifdef EIO
 
3500
    case EIO:
 
3501
      return G_SPAWN_ERROR_IO;
 
3502
      break;
 
3503
#endif
 
3504
 
 
3505
#ifdef ENFILE
 
3506
    case ENFILE:
 
3507
      return G_SPAWN_ERROR_NFILE;
 
3508
      break;
 
3509
#endif
 
3510
 
 
3511
#ifdef EMFILE
 
3512
    case EMFILE:
 
3513
      return G_SPAWN_ERROR_MFILE;
 
3514
      break;
 
3515
#endif
 
3516
 
 
3517
#ifdef EINVAL
 
3518
    case EINVAL:
 
3519
      return G_SPAWN_ERROR_INVAL;
 
3520
      break;
 
3521
#endif
 
3522
 
 
3523
#ifdef EISDIR
 
3524
    case EISDIR:
 
3525
      return G_SPAWN_ERROR_ISDIR;
 
3526
      break;
 
3527
#endif
 
3528
 
 
3529
#ifdef ELIBBAD
 
3530
    case ELIBBAD:
 
3531
      return G_SPAWN_ERROR_LIBBAD;
 
3532
      break;
 
3533
#endif
 
3534
      
 
3535
    default:
 
3536
      return G_SPAWN_ERROR_FAILED;
 
3537
      break;
 
3538
    }
 
3539
}
 
3540
 
 
3541
static void
 
3542
write_err_and_exit (gint fd, gint msg)
 
3543
{
 
3544
  gint en = errno;
 
3545
  
 
3546
  write (fd, &msg, sizeof(msg));
 
3547
  write (fd, &en, sizeof(en));
 
3548
  
 
3549
  _exit (1);
 
3550
}
 
3551
 
 
3552
static void
 
3553
set_cloexec (gint fd)
 
3554
{
 
3555
  fcntl (fd, F_SETFD, FD_CLOEXEC);
 
3556
}
 
3557
 
 
3558
static gint
 
3559
sane_dup2 (gint fd1, gint fd2)
 
3560
{
 
3561
  gint ret;
 
3562
 
 
3563
 retry:
 
3564
  ret = dup2 (fd1, fd2);
 
3565
  if (ret < 0 && errno == EINTR)
 
3566
    goto retry;
 
3567
 
 
3568
  return ret;
 
3569
}
 
3570
 
 
3571
enum
 
3572
{
 
3573
  CHILD_CHDIR_FAILED,
 
3574
  CHILD_EXEC_FAILED,
 
3575
  CHILD_DUP2_FAILED,
 
3576
  CHILD_FORK_FAILED
 
3577
};
 
3578
 
 
3579
static void
 
3580
do_exec (gint                  child_err_report_fd,
 
3581
         gint                  stdin_fd,
 
3582
         gint                  stdout_fd,
 
3583
         gint                  stderr_fd,
 
3584
         const gchar          *working_directory,
 
3585
         gchar               **argv,
 
3586
         gchar               **envp,
 
3587
         gboolean              close_descriptors,
 
3588
         gboolean              search_path,
 
3589
         gboolean              stdout_to_null,
 
3590
         gboolean              stderr_to_null,
 
3591
         gboolean              child_inherits_stdin,
 
3592
         gboolean              file_and_argv_zero,
 
3593
         GSpawnChildSetupFunc  child_setup,
 
3594
         gpointer              user_data)
 
3595
{
 
3596
  if (working_directory && chdir (working_directory) < 0)
 
3597
    write_err_and_exit (child_err_report_fd,
 
3598
                        CHILD_CHDIR_FAILED);
 
3599
 
 
3600
  /* Close all file descriptors but stdin stdout and stderr as
 
3601
   * soon as we exec. Note that this includes
 
3602
   * child_err_report_fd, which keeps the parent from blocking
 
3603
   * forever on the other end of that pipe.
 
3604
   */
 
3605
  if (close_descriptors)
 
3606
    {
 
3607
      gint open_max;
 
3608
      gint i;
 
3609
      
 
3610
      open_max = sysconf (_SC_OPEN_MAX);
 
3611
      for (i = 3; i < open_max; i++)
 
3612
        set_cloexec (i);
 
3613
    }
 
3614
  else
 
3615
    {
 
3616
      /* We need to do child_err_report_fd anyway */
 
3617
      set_cloexec (child_err_report_fd);
 
3618
    }
 
3619
  
 
3620
  /* Redirect pipes as required */
 
3621
  
 
3622
  if (stdin_fd >= 0)
 
3623
    {
 
3624
      /* dup2 can't actually fail here I don't think */
 
3625
          
 
3626
      if (sane_dup2 (stdin_fd, 0) < 0)
 
3627
        write_err_and_exit (child_err_report_fd,
 
3628
                            CHILD_DUP2_FAILED);
 
3629
 
 
3630
      /* ignore this if it doesn't work */
 
3631
      close_and_invalidate (&stdin_fd);
 
3632
    }
 
3633
  else if (!child_inherits_stdin)
 
3634
    {
 
3635
      /* Keep process from blocking on a read of stdin */
 
3636
      gint read_null = open ("/dev/null", O_RDONLY);
 
3637
      sane_dup2 (read_null, 0);
 
3638
      close_and_invalidate (&read_null);
 
3639
    }
 
3640
 
 
3641
  if (stdout_fd >= 0)
 
3642
    {
 
3643
      /* dup2 can't actually fail here I don't think */
 
3644
          
 
3645
      if (sane_dup2 (stdout_fd, 1) < 0)
 
3646
        write_err_and_exit (child_err_report_fd,
 
3647
                            CHILD_DUP2_FAILED);
 
3648
 
 
3649
      /* ignore this if it doesn't work */
 
3650
      close_and_invalidate (&stdout_fd);
 
3651
    }
 
3652
  else if (stdout_to_null)
 
3653
    {
 
3654
      gint write_null = open ("/dev/null", O_WRONLY);
 
3655
      sane_dup2 (write_null, 1);
 
3656
      close_and_invalidate (&write_null);
 
3657
    }
 
3658
 
 
3659
  if (stderr_fd >= 0)
 
3660
    {
 
3661
      /* dup2 can't actually fail here I don't think */
 
3662
          
 
3663
      if (sane_dup2 (stderr_fd, 2) < 0)
 
3664
        write_err_and_exit (child_err_report_fd,
 
3665
                            CHILD_DUP2_FAILED);
 
3666
 
 
3667
      /* ignore this if it doesn't work */
 
3668
      close_and_invalidate (&stderr_fd);
 
3669
    }
 
3670
  else if (stderr_to_null)
 
3671
    {
 
3672
      gint write_null = open ("/dev/null", O_WRONLY);
 
3673
      sane_dup2 (write_null, 2);
 
3674
      close_and_invalidate (&write_null);
 
3675
    }
 
3676
  
 
3677
  /* Call user function just before we exec */
 
3678
  if (child_setup)
 
3679
    {
 
3680
      (* child_setup) (user_data);
 
3681
    }
 
3682
 
 
3683
  g_execute (argv[0],
 
3684
             file_and_argv_zero ? argv + 1 : argv,
 
3685
             envp, search_path);
 
3686
 
 
3687
  /* Exec failed */
 
3688
  write_err_and_exit (child_err_report_fd,
 
3689
                      CHILD_EXEC_FAILED);
 
3690
}
 
3691
 
 
3692
static gboolean
 
3693
read_ints (int      fd,
 
3694
           gint*    buf,
 
3695
           gint     n_ints_in_buf,    
 
3696
           gint    *n_ints_read,      
 
3697
           GError **error)
 
3698
{
 
3699
  gsize bytes = 0;    
 
3700
  
 
3701
  while (TRUE)
 
3702
    {
 
3703
      gssize chunk;    
 
3704
 
 
3705
      if (bytes >= sizeof(gint)*2)
 
3706
        break; /* give up, who knows what happened, should not be
 
3707
                * possible.
 
3708
                */
 
3709
          
 
3710
    again:
 
3711
      chunk = read (fd,
 
3712
                    ((gchar*)buf) + bytes,
 
3713
                    sizeof(gint) * n_ints_in_buf - bytes);
 
3714
      if (chunk < 0 && errno == EINTR)
 
3715
        goto again;
 
3716
          
 
3717
      if (chunk < 0)
 
3718
        {
 
3719
          /* Some weird shit happened, bail out */
 
3720
              
 
3721
          g_set_error (error,
 
3722
                       G_SPAWN_ERROR,
 
3723
                       G_SPAWN_ERROR_FAILED,
 
3724
                       _("Failed to read from child pipe (%s)"),
 
3725
                       g_strerror (errno));
 
3726
 
 
3727
          return FALSE;
 
3728
        }
 
3729
      else if (chunk == 0)
 
3730
        break; /* EOF */
 
3731
      else /* chunk > 0 */
 
3732
        bytes += chunk;
 
3733
    }
 
3734
 
 
3735
  *n_ints_read = (gint)(bytes / sizeof(gint));
 
3736
 
 
3737
  return TRUE;
 
3738
}
 
3739
 
 
3740
static gboolean
 
3741
fork_exec_with_pipes (gboolean              intermediate_child,
 
3742
                      const gchar          *working_directory,
 
3743
                      gchar               **argv,
 
3744
                      gchar               **envp,
 
3745
                      gboolean              close_descriptors,
 
3746
                      gboolean              search_path,
 
3747
                      gboolean              stdout_to_null,
 
3748
                      gboolean              stderr_to_null,
 
3749
                      gboolean              child_inherits_stdin,
 
3750
                      gboolean              file_and_argv_zero,
 
3751
                      GSpawnChildSetupFunc  child_setup,
 
3752
                      gpointer              user_data,
 
3753
                      gint                 *child_pid,
 
3754
                      gint                 *standard_input,
 
3755
                      gint                 *standard_output,
 
3756
                      gint                 *standard_error,
 
3757
                      GError              **error)     
 
3758
{
 
3759
  gint pid;
 
3760
  gint stdin_pipe[2] = { -1, -1 };
 
3761
  gint stdout_pipe[2] = { -1, -1 };
 
3762
  gint stderr_pipe[2] = { -1, -1 };
 
3763
  gint child_err_report_pipe[2] = { -1, -1 };
 
3764
  gint child_pid_report_pipe[2] = { -1, -1 };
 
3765
  gint status;
 
3766
  
 
3767
  if (!make_pipe (child_err_report_pipe, error))
 
3768
    return FALSE;
 
3769
 
 
3770
  if (intermediate_child && !make_pipe (child_pid_report_pipe, error))
 
3771
    goto cleanup_and_fail;
 
3772
  
 
3773
  if (standard_input && !make_pipe (stdin_pipe, error))
 
3774
    goto cleanup_and_fail;
 
3775
  
 
3776
  if (standard_output && !make_pipe (stdout_pipe, error))
 
3777
    goto cleanup_and_fail;
 
3778
 
 
3779
  if (standard_error && !make_pipe (stderr_pipe, error))
 
3780
    goto cleanup_and_fail;
 
3781
 
 
3782
  pid = fork ();
 
3783
 
 
3784
  if (pid < 0)
 
3785
    {      
 
3786
      g_set_error (error,
 
3787
                   G_SPAWN_ERROR,
 
3788
                   G_SPAWN_ERROR_FORK,
 
3789
                   _("Failed to fork (%s)"),
 
3790
                   g_strerror (errno));
 
3791
 
 
3792
      goto cleanup_and_fail;
 
3793
    }
 
3794
  else if (pid == 0)
 
3795
    {
 
3796
      /* Immediate child. This may or may not be the child that
 
3797
       * actually execs the new process.
 
3798
       */
 
3799
      
 
3800
      /* Be sure we crash if the parent exits
 
3801
       * and we write to the err_report_pipe
 
3802
       */
 
3803
      signal (SIGPIPE, SIG_DFL);
 
3804
 
 
3805
      /* Close the parent's end of the pipes;
 
3806
       * not needed in the close_descriptors case,
 
3807
       * though
 
3808
       */
 
3809
      close_and_invalidate (&child_err_report_pipe[0]);
 
3810
      close_and_invalidate (&child_pid_report_pipe[0]);
 
3811
      close_and_invalidate (&stdin_pipe[1]);
 
3812
      close_and_invalidate (&stdout_pipe[0]);
 
3813
      close_and_invalidate (&stderr_pipe[0]);
 
3814
      
 
3815
      if (intermediate_child)
 
3816
        {
 
3817
          /* We need to fork an intermediate child that launches the
 
3818
           * final child. The purpose of the intermediate child
 
3819
           * is to exit, so we can waitpid() it immediately.
 
3820
           * Then the grandchild will not become a zombie.
 
3821
           */
 
3822
          gint grandchild_pid;
 
3823
 
 
3824
          grandchild_pid = fork ();
 
3825
 
 
3826
          if (grandchild_pid < 0)
 
3827
            {
 
3828
              /* report -1 as child PID */
 
3829
              write (child_pid_report_pipe[1], &grandchild_pid,
 
3830
                     sizeof(grandchild_pid));
 
3831
              
 
3832
              write_err_and_exit (child_err_report_pipe[1],
 
3833
                                  CHILD_FORK_FAILED);              
 
3834
            }
 
3835
          else if (grandchild_pid == 0)
 
3836
            {
 
3837
              do_exec (child_err_report_pipe[1],
 
3838
                       stdin_pipe[0],
 
3839
                       stdout_pipe[1],
 
3840
                       stderr_pipe[1],
 
3841
                       working_directory,
 
3842
                       argv,
 
3843
                       envp,
 
3844
                       close_descriptors,
 
3845
                       search_path,
 
3846
                       stdout_to_null,
 
3847
                       stderr_to_null,
 
3848
                       child_inherits_stdin,
 
3849
                       file_and_argv_zero,
 
3850
                       child_setup,
 
3851
                       user_data);
 
3852
            }
 
3853
          else
 
3854
            {
 
3855
              write (child_pid_report_pipe[1], &grandchild_pid, sizeof(grandchild_pid));
 
3856
              close_and_invalidate (&child_pid_report_pipe[1]);
 
3857
              
 
3858
              _exit (0);
 
3859
            }
 
3860
        }
 
3861
      else
 
3862
        {
 
3863
          /* Just run the child.
 
3864
           */
 
3865
 
 
3866
          do_exec (child_err_report_pipe[1],
 
3867
                   stdin_pipe[0],
 
3868
                   stdout_pipe[1],
 
3869
                   stderr_pipe[1],
 
3870
                   working_directory,
 
3871
                   argv,
 
3872
                   envp,
 
3873
                   close_descriptors,
 
3874
                   search_path,
 
3875
                   stdout_to_null,
 
3876
                   stderr_to_null,
 
3877
                   child_inherits_stdin,
 
3878
                   file_and_argv_zero,
 
3879
                   child_setup,
 
3880
                   user_data);
 
3881
        }
 
3882
    }
 
3883
  else
 
3884
    {
 
3885
      /* Parent */
 
3886
      
 
3887
      gint buf[2];
 
3888
      gint n_ints = 0;    
 
3889
 
 
3890
      /* Close the uncared-about ends of the pipes */
 
3891
      close_and_invalidate (&child_err_report_pipe[1]);
 
3892
      close_and_invalidate (&child_pid_report_pipe[1]);
 
3893
      close_and_invalidate (&stdin_pipe[0]);
 
3894
      close_and_invalidate (&stdout_pipe[1]);
 
3895
      close_and_invalidate (&stderr_pipe[1]);
 
3896
 
 
3897
      /* If we had an intermediate child, reap it */
 
3898
      if (intermediate_child)
 
3899
        {
 
3900
        wait_again:
 
3901
          if (waitpid (pid, &status, 0) < 0)
 
3902
            {
 
3903
              if (errno == EINTR)
 
3904
                goto wait_again;
 
3905
              else if (errno == ECHILD)
 
3906
                ; /* do nothing, child already reaped */
 
3907
              else
 
3908
                g_warning ("waitpid() should not fail in "
 
3909
                           "'fork_exec_with_pipes'");
 
3910
            }
 
3911
        }
 
3912
      
 
3913
 
 
3914
      if (!read_ints (child_err_report_pipe[0],
 
3915
                      buf, 2, &n_ints,
 
3916
                      error))
 
3917
        goto cleanup_and_fail;
 
3918
        
 
3919
      if (n_ints >= 2)
 
3920
        {
 
3921
          /* Error from the child. */
 
3922
 
 
3923
          switch (buf[0])
 
3924
            {
 
3925
            case CHILD_CHDIR_FAILED:
 
3926
              g_set_error (error,
 
3927
                           G_SPAWN_ERROR,
 
3928
                           G_SPAWN_ERROR_CHDIR,
 
3929
                           _("Failed to change to directory '%s' (%s)"),
 
3930
                           working_directory,
 
3931
                           g_strerror (buf[1]));
 
3932
 
 
3933
              break;
 
3934
              
 
3935
            case CHILD_EXEC_FAILED:
 
3936
              g_set_error (error,
 
3937
                           G_SPAWN_ERROR,
 
3938
                           exec_err_to_g_error (buf[1]),
 
3939
                           _("Failed to execute child process (%s)"),
 
3940
                           g_strerror (buf[1]));
 
3941
 
 
3942
              break;
 
3943
              
 
3944
            case CHILD_DUP2_FAILED:
 
3945
              g_set_error (error,
 
3946
                           G_SPAWN_ERROR,
 
3947
                           G_SPAWN_ERROR_FAILED,
 
3948
                           _("Failed to redirect output or input of child process (%s)"),
 
3949
                           g_strerror (buf[1]));
 
3950
 
 
3951
              break;
 
3952
 
 
3953
            case CHILD_FORK_FAILED:
 
3954
              g_set_error (error,
 
3955
                           G_SPAWN_ERROR,
 
3956
                           G_SPAWN_ERROR_FORK,
 
3957
                           _("Failed to fork child process (%s)"),
 
3958
                           g_strerror (buf[1]));
 
3959
              break;
 
3960
              
 
3961
            default:
 
3962
              g_set_error (error,
 
3963
                           G_SPAWN_ERROR,
 
3964
                           G_SPAWN_ERROR_FAILED,
 
3965
                           _("Unknown error executing child process"));
 
3966
              break;
 
3967
            }
 
3968
 
 
3969
          goto cleanup_and_fail;
 
3970
        }
 
3971
 
 
3972
      /* Get child pid from intermediate child pipe. */
 
3973
      if (intermediate_child)
 
3974
        {
 
3975
          n_ints = 0;
 
3976
          
 
3977
          if (!read_ints (child_pid_report_pipe[0],
 
3978
                          buf, 1, &n_ints, error))
 
3979
            goto cleanup_and_fail;
 
3980
 
 
3981
          if (n_ints < 1)
 
3982
            {
 
3983
              g_set_error (error,
 
3984
                           G_SPAWN_ERROR,
 
3985
                           G_SPAWN_ERROR_FAILED,
 
3986
                           _("Failed to read enough data from child pid pipe (%s)"),
 
3987
                           g_strerror (errno));
 
3988
              goto cleanup_and_fail;
 
3989
            }
 
3990
          else
 
3991
            {
 
3992
              /* we have the child pid */
 
3993
              pid = buf[0];
 
3994
            }
 
3995
        }
 
3996
      
 
3997
      /* Success against all odds! return the information */
 
3998
      
 
3999
      if (child_pid)
 
4000
        *child_pid = pid;
 
4001
 
 
4002
      if (standard_input)
 
4003
        *standard_input = stdin_pipe[1];
 
4004
      if (standard_output)
 
4005
        *standard_output = stdout_pipe[0];
 
4006
      if (standard_error)
 
4007
        *standard_error = stderr_pipe[0];
 
4008
      
 
4009
      return TRUE;
 
4010
    }
 
4011
 
 
4012
 cleanup_and_fail:
 
4013
  close_and_invalidate (&child_err_report_pipe[0]);
 
4014
  close_and_invalidate (&child_err_report_pipe[1]);
 
4015
  close_and_invalidate (&child_pid_report_pipe[0]);
 
4016
  close_and_invalidate (&child_pid_report_pipe[1]);
 
4017
  close_and_invalidate (&stdin_pipe[0]);
 
4018
  close_and_invalidate (&stdin_pipe[1]);
 
4019
  close_and_invalidate (&stdout_pipe[0]);
 
4020
  close_and_invalidate (&stdout_pipe[1]);
 
4021
  close_and_invalidate (&stderr_pipe[0]);
 
4022
  close_and_invalidate (&stderr_pipe[1]);
 
4023
 
 
4024
  return FALSE;
 
4025
}
 
4026
 
 
4027
static gboolean
 
4028
make_pipe (gint     p[2],
 
4029
           GError **error)
 
4030
{
 
4031
  if (pipe (p) < 0)
 
4032
    {
 
4033
      g_set_error (error,
 
4034
                   G_SPAWN_ERROR,
 
4035
                   G_SPAWN_ERROR_FAILED,
 
4036
                   _("Failed to create pipe for communicating with child process (%s)"),
 
4037
                   g_strerror (errno));
 
4038
      return FALSE;
 
4039
    }
 
4040
  else
 
4041
    return TRUE;
 
4042
}
 
4043
 
 
4044
/* Based on execvp from GNU C Library */
 
4045
 
 
4046
static void
 
4047
script_execute (const gchar *file,
 
4048
                gchar      **argv,
 
4049
                gchar      **envp,
 
4050
                gboolean     search_path)
 
4051
{
 
4052
  /* Count the arguments.  */
 
4053
  int argc = 0;
 
4054
  while (argv[argc])
 
4055
    ++argc;
 
4056
  
 
4057
  /* Construct an argument list for the shell.  */
 
4058
  {
 
4059
    gchar **new_argv;
 
4060
 
 
4061
    new_argv = g_new0 (gchar*, argc + 1);
 
4062
    
 
4063
    new_argv[0] = (char *) "/bin/sh";
 
4064
    new_argv[1] = (char *) file;
 
4065
    while (argc > 1)
 
4066
      {
 
4067
        new_argv[argc] = argv[argc - 1];
 
4068
        --argc;
 
4069
      }
 
4070
 
 
4071
    /* Execute the shell. */
 
4072
    if (envp)
 
4073
      execve (new_argv[0], new_argv, envp);
 
4074
    else
 
4075
      execv (new_argv[0], new_argv);
 
4076
    
 
4077
    g_free (new_argv);
 
4078
  }
 
4079
}
 
4080
 
 
4081
static gchar*
 
4082
my_strchrnul (const gchar *str, gchar c)
 
4083
{
 
4084
  gchar *p = (gchar*) str;
 
4085
  while (*p && (*p != c))
 
4086
    ++p;
 
4087
 
 
4088
  return p;
 
4089
}
 
4090
 
 
4091
static gint
 
4092
g_execute (const gchar *file,
 
4093
           gchar      **argv,
 
4094
           gchar      **envp,
 
4095
           gboolean     search_path)
 
4096
{
 
4097
  if (*file == '\0')
 
4098
    {
 
4099
      /* We check the simple case first. */
 
4100
      errno = ENOENT;
 
4101
      return -1;
 
4102
    }
 
4103
 
 
4104
  if (!search_path || strchr (file, '/') != NULL)
 
4105
    {
 
4106
      /* Don't search when it contains a slash. */
 
4107
      if (envp)
 
4108
        execve (file, argv, envp);
 
4109
      else
 
4110
        execv (file, argv);
 
4111
      
 
4112
      if (errno == ENOEXEC)
 
4113
        script_execute (file, argv, envp, FALSE);
 
4114
    }
 
4115
  else
 
4116
    {
 
4117
      gboolean got_eacces = 0;
 
4118
      const gchar *path, *p;
 
4119
      gchar *name, *freeme;
 
4120
      size_t len;
 
4121
      size_t pathlen;
 
4122
 
 
4123
      path = g_getenv ("PATH");
 
4124
      if (path == NULL)
 
4125
        {
 
4126
          /* There is no `PATH' in the environment.  The default
 
4127
           * search path in libc is the current directory followed by
 
4128
           * the path `confstr' returns for `_CS_PATH'.
 
4129
           */
 
4130
 
 
4131
          /* In GLib we put . last, for security, and don't use the
 
4132
           * unportable confstr(); UNIX98 does not actually specify
 
4133
           * what to search if PATH is unset. POSIX may, dunno.
 
4134
           */
 
4135
          
 
4136
          path = "/bin:/usr/bin:.";
 
4137
        }
 
4138
 
 
4139
      len = strlen (file) + 1;
 
4140
      pathlen = strlen (path);
 
4141
      freeme = name = g_malloc (pathlen + len + 1);
 
4142
      
 
4143
      /* Copy the file name at the top, including '\0'  */
 
4144
      memcpy (name + pathlen + 1, file, len);
 
4145
      name = name + pathlen;
 
4146
      /* And add the slash before the filename  */
 
4147
      *name = '/';
 
4148
 
 
4149
      p = path;
 
4150
      do
 
4151
        {
 
4152
          char *startp;
 
4153
 
 
4154
          path = p;
 
4155
          p = my_strchrnul (path, ':');
 
4156
 
 
4157
          if (p == path)
 
4158
            /* Two adjacent colons, or a colon at the beginning or the end
 
4159
             * of `PATH' means to search the current directory.
 
4160
             */
 
4161
            startp = name + 1;
 
4162
          else
 
4163
            startp = memcpy (name - (p - path), path, p - path);
 
4164
 
 
4165
          /* Try to execute this name.  If it works, execv will not return.  */
 
4166
          if (envp)
 
4167
            execve (startp, argv, envp);
 
4168
          else
 
4169
            execv (startp, argv);
 
4170
          
 
4171
          if (errno == ENOEXEC)
 
4172
            script_execute (startp, argv, envp, search_path);
 
4173
 
 
4174
          switch (errno)
 
4175
            {
 
4176
            case EACCES:
 
4177
              /* Record the we got a `Permission denied' error.  If we end
 
4178
               * up finding no executable we can use, we want to diagnose
 
4179
               * that we did find one but were denied access.
 
4180
               */
 
4181
              got_eacces = TRUE;
 
4182
 
 
4183
              /* FALL THRU */
 
4184
              
 
4185
            case ENOENT:
 
4186
#ifdef ESTALE
 
4187
            case ESTALE:
 
4188
#endif
 
4189
#ifdef ENOTDIR
 
4190
            case ENOTDIR:
 
4191
#endif
 
4192
              /* Those errors indicate the file is missing or not executable
 
4193
               * by us, in which case we want to just try the next path
 
4194
               * directory.
 
4195
               */
 
4196
              break;
 
4197
 
 
4198
            default:
 
4199
              /* Some other error means we found an executable file, but
 
4200
               * something went wrong executing it; return the error to our
 
4201
               * caller.
 
4202
               */
 
4203
              g_free (freeme);
 
4204
              return -1;
 
4205
            }
 
4206
        }
 
4207
      while (*p++ != '\0');
 
4208
 
 
4209
      /* We tried every element and none of them worked.  */
 
4210
      if (got_eacces)
 
4211
        /* At least one failure was due to permissions, so report that
 
4212
         * error.
 
4213
         */
 
4214
        errno = EACCES;
 
4215
 
 
4216
      g_free (freeme);
 
4217
    }
 
4218
 
 
4219
  /* Return the error from the last attempt (probably ENOENT).  */
 
4220
  return -1;
 
4221
}
 
4222
 
 
4223
 
 
4224
 
 
4225
#define UTF8_COMPUTE(Char, Mask, Len)                                         \
 
4226
  if (Char < 128)                                                             \
 
4227
    {                                                                         \
 
4228
      Len = 1;                                                                \
 
4229
      Mask = 0x7f;                                                            \
 
4230
    }                                                                         \
 
4231
  else if ((Char & 0xe0) == 0xc0)                                             \
 
4232
    {                                                                         \
 
4233
      Len = 2;                                                                \
 
4234
      Mask = 0x1f;                                                            \
 
4235
    }                                                                         \
 
4236
  else if ((Char & 0xf0) == 0xe0)                                             \
 
4237
    {                                                                         \
 
4238
      Len = 3;                                                                \
 
4239
      Mask = 0x0f;                                                            \
 
4240
    }                                                                         \
 
4241
  else if ((Char & 0xf8) == 0xf0)                                             \
 
4242
    {                                                                         \
 
4243
      Len = 4;                                                                \
 
4244
      Mask = 0x07;                                                            \
 
4245
    }                                                                         \
 
4246
  else if ((Char & 0xfc) == 0xf8)                                             \
 
4247
    {                                                                         \
 
4248
      Len = 5;                                                                \
 
4249
      Mask = 0x03;                                                            \
 
4250
    }                                                                         \
 
4251
  else if ((Char & 0xfe) == 0xfc)                                             \
 
4252
    {                                                                         \
 
4253
      Len = 6;                                                                \
 
4254
      Mask = 0x01;                                                            \
 
4255
    }                                                                         \
 
4256
  else                                                                        \
 
4257
    Len = -1;
 
4258
 
 
4259
#define UTF8_LENGTH(Char)              \
 
4260
  ((Char) < 0x80 ? 1 :                 \
 
4261
   ((Char) < 0x800 ? 2 :               \
 
4262
    ((Char) < 0x10000 ? 3 :            \
 
4263
     ((Char) < 0x200000 ? 4 :          \
 
4264
      ((Char) < 0x4000000 ? 5 : 6)))))
 
4265
   
 
4266
 
 
4267
#define UTF8_GET(Result, Chars, Count, Mask, Len)                             \
 
4268
  (Result) = (Chars)[0] & (Mask);                                             \
 
4269
  for ((Count) = 1; (Count) < (Len); ++(Count))                               \
 
4270
    {                                                                         \
 
4271
      if (((Chars)[(Count)] & 0xc0) != 0x80)                                  \
 
4272
        {                                                                     \
 
4273
          (Result) = -1;                                                      \
 
4274
          break;                                                              \
 
4275
        }                                                                     \
 
4276
      (Result) <<= 6;                                                         \
 
4277
      (Result) |= ((Chars)[(Count)] & 0x3f);                                  \
 
4278
    }
 
4279
 
 
4280
#define UNICODE_VALID(Char)                   \
 
4281
    ((Char) < 0x110000 &&                     \
 
4282
     ((Char) < 0xD800 || (Char) >= 0xE000) && \
 
4283
     (Char) != 0xFFFE && (Char) != 0xFFFF)
 
4284
   
 
4285
     
 
4286
static const gchar utf8_skip_data[256] = {
 
4287
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
4288
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
4289
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
4290
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
4291
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
4292
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
4293
  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
 
4294
  3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0
 
4295
};
 
4296
 
 
4297
static const gchar * const gconf_g_utf8_skip = utf8_skip_data;
 
4298
 
 
4299
typedef guint32 gunichar;
 
4300
 
 
4301
gboolean
 
4302
gconf_g_utf8_validate (const gchar  *str,
 
4303
                       gssize        max_len,    
 
4304
                       const gchar **end)
 
4305
{
 
4306
 
 
4307
  const gchar *p;
 
4308
 
 
4309
  g_return_val_if_fail (str != NULL, FALSE);
 
4310
  
 
4311
  if (end)
 
4312
    *end = str;
 
4313
  
 
4314
  p = str;
 
4315
  
 
4316
  while ((max_len < 0 || (p - str) < max_len) && *p)
 
4317
    {
 
4318
      int i, mask = 0, len;
 
4319
      gunichar result;
 
4320
      unsigned char c = (unsigned char) *p;
 
4321
      
 
4322
      UTF8_COMPUTE (c, mask, len);
 
4323
 
 
4324
      if (len == -1)
 
4325
        break;
 
4326
 
 
4327
      /* check that the expected number of bytes exists in str */
 
4328
      if (max_len >= 0 &&
 
4329
          ((max_len - (p - str)) < len))
 
4330
        break;
 
4331
        
 
4332
      UTF8_GET (result, p, i, mask, len);
 
4333
 
 
4334
      if (UTF8_LENGTH (result) != len) /* Check for overlong UTF-8 */
 
4335
        break;
 
4336
 
 
4337
      if (result == (gunichar)-1)
 
4338
        break;
 
4339
 
 
4340
      if (!UNICODE_VALID (result))
 
4341
        break;
 
4342
      
 
4343
      p += len;
 
4344
    }
 
4345
 
 
4346
  if (end)
 
4347
    *end = p;
 
4348
 
 
4349
  /* See that we covered the entire length if a length was
 
4350
   * passed in, or that we ended on a nul if not
 
4351
   */
 
4352
  if (max_len >= 0 &&
 
4353
      p != (str + max_len))
 
4354
    return FALSE;
 
4355
  else if (max_len < 0 &&
 
4356
           *p != '\0')
 
4357
    return FALSE;
 
4358
  else
 
4359
    return TRUE;
 
4360
}