]> git.sesse.net Git - vlc/blob - src/misc/configuration.c
* ./plugins/aa: aalib output plugin courtesy of Sigmund Augdal.
[vlc] / src / misc / configuration.c
1 /*****************************************************************************
2  * configuration.c management of the modules configuration
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: configuration.c,v 1.7 2002/03/19 14:00:50 sam Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include <stdio.h>                                              /* sprintf() */
25 #include <stdlib.h>                                      /* free(), strtol() */
26 #include <string.h>                                              /* strdup() */
27 #include <unistd.h>                                              /* getuid() */
28
29 #include <videolan/vlc.h>
30
31 #if defined(HAVE_GETPWUID) || defined(HAVE_GETPWUID_R)
32 #include <pwd.h>                                               /* getpwuid() */
33 #endif
34
35 #include <sys/stat.h>
36 #include <sys/types.h>
37
38 /*****************************************************************************
39  * Local prototypes
40  *****************************************************************************/
41 static char *GetHomeDir( void );
42
43 /*****************************************************************************
44  * config_GetIntVariable: get the value of an int variable
45  *****************************************************************************
46  * This function is used to get the value of variables which are internally
47  * represented by an integer (MODULE_CONFIG_ITEM_INTEGER and
48  * MODULE_CONFIG_ITEM_BOOL).
49  *****************************************************************************/
50 int config_GetIntVariable( const char *psz_name )
51 {
52     module_config_t *p_config;
53
54     p_config = config_FindConfig( psz_name );
55
56     /* sanity checks */
57     if( !p_config )
58     {
59         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
60         return -1;
61     }
62     if( (p_config->i_type!=MODULE_CONFIG_ITEM_INTEGER) &&
63         (p_config->i_type!=MODULE_CONFIG_ITEM_BOOL) )
64     {
65         intf_ErrMsg( "config error: option %s doesn't refer to an int",
66                      psz_name );
67         return -1;
68     }
69
70     return p_config->i_value;
71 }
72
73 /*****************************************************************************
74  * config_GetPszVariable: get the string value of a string variable
75  *****************************************************************************
76  * This function is used to get the value of variables which are internally
77  * represented by a string (MODULE_CONFIG_ITEM_STRING, MODULE_CONFIG_ITEM_FILE,
78  * and MODULE_CONFIG_ITEM_PLUGIN).
79  *
80  * Important note: remember to free() the returned char* because it a duplicate
81  *   of the actual value. It isn't safe to return a pointer to the actual value
82  *   as it can be modified at any time.
83  *****************************************************************************/
84 char * config_GetPszVariable( const char *psz_name )
85 {
86     module_config_t *p_config;
87     char *psz_value = NULL;
88
89     p_config = config_FindConfig( psz_name );
90
91     /* sanity checks */
92     if( !p_config )
93     {
94         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
95         return NULL;
96     }
97     if( (p_config->i_type!=MODULE_CONFIG_ITEM_STRING) &&
98         (p_config->i_type!=MODULE_CONFIG_ITEM_FILE) &&
99         (p_config->i_type!=MODULE_CONFIG_ITEM_PLUGIN) )
100     {
101         intf_ErrMsg( "config error: option %s doesn't refer to a string",
102                      psz_name );
103         return NULL;
104     }
105
106     /* return a copy of the string */
107     vlc_mutex_lock( p_config->p_lock );
108     if( p_config->psz_value ) psz_value = strdup( p_config->psz_value );
109     vlc_mutex_unlock( p_config->p_lock );
110
111     return psz_value;
112 }
113
114 /*****************************************************************************
115  * config_PutPszVariable: set the string value of a string variable
116  *****************************************************************************
117  * This function is used to set the value of variables which are internally
118  * represented by a string (MODULE_CONFIG_ITEM_STRING, MODULE_CONFIG_ITEM_FILE,
119  * and MODULE_CONFIG_ITEM_PLUGIN).
120  *****************************************************************************/
121 void config_PutPszVariable( const char *psz_name, char *psz_value )
122 {
123     module_config_t *p_config;
124
125     p_config = config_FindConfig( psz_name );
126
127     /* sanity checks */
128     if( !p_config )
129     {
130         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
131         return;
132     }
133     if( (p_config->i_type!=MODULE_CONFIG_ITEM_STRING) &&
134         (p_config->i_type!=MODULE_CONFIG_ITEM_FILE) &&
135         (p_config->i_type!=MODULE_CONFIG_ITEM_PLUGIN) )
136     {
137         intf_ErrMsg( "config error: option %s doesn't refer to a string",
138                      psz_name );
139         return;
140     }
141
142     vlc_mutex_lock( p_config->p_lock );
143
144     /* free old string */
145     if( p_config->psz_value ) free( p_config->psz_value );
146
147     if( psz_value ) p_config->psz_value = strdup( psz_value );
148     else p_config->psz_value = NULL;
149
150     vlc_mutex_unlock( p_config->p_lock );
151
152 }
153
154 /*****************************************************************************
155  * config_PutIntVariable: set the integer value of an int variable
156  *****************************************************************************
157  * This function is used to set the value of variables which are internally
158  * represented by an integer (MODULE_CONFIG_ITEM_INTEGER and
159  * MODULE_CONFIG_ITEM_BOOL).
160  *****************************************************************************/
161 void config_PutIntVariable( const char *psz_name, int i_value )
162 {
163     module_config_t *p_config;
164
165     p_config = config_FindConfig( psz_name );
166
167     /* sanity checks */
168     if( !p_config )
169     {
170         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
171         return;
172     }
173     if( (p_config->i_type!=MODULE_CONFIG_ITEM_INTEGER) &&
174         (p_config->i_type!=MODULE_CONFIG_ITEM_BOOL) )
175     {
176         intf_ErrMsg( "config error: option %s doesn't refer to an int",
177                      psz_name );
178         return;
179     }
180
181     p_config->i_value = i_value;
182 }
183
184 /*****************************************************************************
185  * config_FindConfig: find the config structure associated with an option.
186  *****************************************************************************
187  * FIXME: This function really needs to be optimized.
188  *****************************************************************************/
189 module_config_t *config_FindConfig( const char *psz_name )
190 {
191     module_t *p_module;
192     int i;
193
194     if( !psz_name ) return NULL;
195
196     for( p_module = p_module_bank->first ;
197          p_module != NULL ;
198          p_module = p_module->next )
199     {
200         for( i = 0; i < p_module->i_config_lines; i++ )
201         {
202             if( p_module->p_config[i].i_type & MODULE_CONFIG_HINT )
203                 /* ignore hints */
204                 continue;
205             if( !strcmp( psz_name, p_module->p_config[i].psz_name ) )
206                 return &p_module->p_config[i];
207         }
208     }
209
210     return NULL;
211 }
212
213 /*****************************************************************************
214  * config_Duplicate: creates a duplicate of a module's configuration data.
215  *****************************************************************************
216  * Unfortunatly we cannot work directly with the module's config data as
217  * this module might be unloaded from memory at any time (remember HideModule).
218  * This is why we need to create an exact copy of the config data.
219  *****************************************************************************/
220 module_config_t *config_Duplicate( module_t *p_module )
221 {
222     int i;
223     module_config_t *p_config;
224
225     /* allocate memory */
226     p_config = (module_config_t *)malloc( sizeof(module_config_t)
227                                           * p_module->i_config_lines );
228     if( p_config == NULL )
229     {
230         intf_ErrMsg( "config error: can't duplicate p_config" );
231         return( NULL );
232     }
233
234     for( i = 0; i < p_module->i_config_lines ; i++ )
235     {
236         p_config[i].i_type = p_module->p_config_orig[i].i_type;
237         p_config[i].i_value = p_module->p_config_orig[i].i_value;
238         p_config[i].b_dirty = p_module->p_config_orig[i].b_dirty;
239         p_config[i].p_lock = &p_module->config_lock;
240         if( p_module->p_config_orig[i].psz_name )
241             p_config[i].psz_name =
242                 strdup( p_module->p_config_orig[i].psz_name );
243         else p_config[i].psz_name = NULL;
244         if( p_module->p_config_orig[i].psz_text )
245             p_config[i].psz_text =
246                 strdup( p_module->p_config_orig[i].psz_text );
247         else p_config[i].psz_text = NULL;
248         if( p_module->p_config_orig[i].psz_longtext )
249             p_config[i].psz_longtext =
250                 strdup( p_module->p_config_orig[i].psz_longtext );
251         else p_config[i].psz_longtext = NULL;
252         if( p_module->p_config_orig[i].psz_value )
253             p_config[i].psz_value =
254                 strdup( p_module->p_config_orig[i].psz_value );
255         else p_config[i].psz_value = NULL;
256
257         /* the callback pointer is only valid when the module is loaded so this
258          * value is set in ActivateModule() and reset in DeactivateModule() */
259         p_config[i].p_callback = NULL;
260     }
261
262     return p_config;
263 }
264
265 /*****************************************************************************
266  * config_LoadConfigFile: loads the configuration file.
267  *****************************************************************************
268  * This function is called to load the config options stored in the config
269  * file.
270  *****************************************************************************/
271 int config_LoadConfigFile( const char *psz_module_name )
272 {
273     module_t *p_module;
274     FILE *file;
275     char line[1024];
276     char *p_index, *psz_option_name, *psz_option_value;
277     int i;
278     char *psz_filename, *psz_homedir;
279
280     /* Acquire config file lock */
281     vlc_mutex_lock( &p_main->config_lock );
282
283     psz_homedir = GetHomeDir();
284     if( !psz_homedir )
285     {
286         intf_ErrMsg( "config error: GetHomeDir failed" );
287         vlc_mutex_unlock( &p_main->config_lock );
288         return -1;
289     }
290     psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
291                                    strlen(psz_homedir) + 1 );
292     if( !psz_filename )
293     {
294         intf_ErrMsg( "config error: couldn't malloc psz_filename" );
295         free( psz_homedir );
296         vlc_mutex_unlock( &p_main->config_lock );
297         return -1;
298     }
299     sprintf( psz_filename, "%s/" CONFIG_DIR "/" CONFIG_FILE, psz_homedir );
300     free( psz_homedir );
301
302     intf_WarnMsg( 5, "config: opening config file %s", psz_filename );
303
304     file = fopen( psz_filename, "r" );
305     if( !file )
306     {
307         intf_WarnMsg( 1, "config: couldn't open config file %s for reading",
308                          psz_filename );
309         free( psz_filename );
310         vlc_mutex_unlock( &p_main->config_lock );
311         return -1;
312     }
313
314     /* Look for the selected module, if NULL then save everything */
315     for( p_module = p_module_bank->first ; p_module != NULL ;
316          p_module = p_module->next )
317     {
318
319         if( psz_module_name && strcmp( psz_module_name, p_module->psz_name ) )
320             continue;
321
322         /* The config file is organized in sections, one per module. Look for
323          * the interesting section ( a section is of the form [foo] ) */
324         rewind( file );
325         while( fgets( line, 1024, file ) )
326         {
327             if( (line[0] == '[') && (p_index = strchr(line,']')) &&
328                 (p_index - &line[1] == strlen(p_module->psz_name) ) &&
329                 !memcmp( &line[1], p_module->psz_name,
330                          strlen(p_module->psz_name) ) )
331             {
332                 intf_WarnMsg( 5, "config: loading config for module <%s>",
333                                  p_module->psz_name );
334
335                 break;
336             }
337         }
338         /* either we found the section or we're at the EOF */
339
340         /* Now try to load the options in this section */
341         while( fgets( line, 1024, file ) )
342         {
343             if( line[0] == '[' ) break; /* end of section */
344
345             /* ignore comments or empty lines */
346             if( (line[0] == '#') || (line[0] == (char)0) ) continue;
347
348             /* get rid of line feed */
349             if( line[strlen(line)-1] == '\n' )
350                 line[strlen(line)-1] = (char)0;
351
352             /* look for option name */
353             psz_option_name = line;
354             psz_option_value = NULL;
355             p_index = strchr( line, '=' );
356             if( !p_index ) break; /* this ain't an option!!! */
357
358             *p_index = (char)0;
359             psz_option_value = p_index + 1;
360
361             /* try to match this option with one of the module's options */
362             for( i = 0; i < p_module->i_config_lines; i++ )
363             {
364                 if( p_module->p_config[i].i_type & MODULE_CONFIG_HINT )
365                     /* ignore hints */
366                     continue;
367                 if( !strcmp( p_module->p_config[i].psz_name,
368                              psz_option_name ) )
369                 {
370                     /* We found it */
371                     switch( p_module->p_config[i].i_type )
372                     {
373                     case MODULE_CONFIG_ITEM_BOOL:
374                     case MODULE_CONFIG_ITEM_INTEGER:
375                         p_module->p_config[i].i_value =
376                             atoi( psz_option_value);
377                         intf_WarnMsg( 7, "config: found <%s> option %s=%i",
378                                       p_module->psz_name,
379                                       p_module->p_config[i].psz_name,
380                                       p_module->p_config[i].i_value );
381                         break;
382
383                     default:
384                         vlc_mutex_lock( p_module->p_config[i].p_lock );
385
386                         /* free old string */
387                         if( p_module->p_config[i].psz_value )
388                             free( p_module->p_config[i].psz_value );
389
390                         p_module->p_config[i].psz_value =
391                             strdup( psz_option_value );
392
393                         vlc_mutex_unlock( p_module->p_config[i].p_lock );
394
395                         intf_WarnMsg( 7, "config: found <%s> option %s=%s",
396                                       p_module->psz_name,
397                                       p_module->p_config[i].psz_name,
398                                       p_module->p_config[i].psz_value );
399                         break;
400                     }
401                 }
402             }
403         }
404
405     }
406     
407     fclose( file );
408     free( psz_filename );
409
410     vlc_mutex_unlock( &p_main->config_lock );
411
412     return 0;
413 }
414
415 /*****************************************************************************
416  * config_SaveConfigFile: Save a module's config options.
417  *****************************************************************************
418  * This will save the specified module's config options to the config file.
419  * If psz_module_name is NULL then we save all the modules config options.
420  * It's no use to save the config options that kept their default values, so
421  * we'll try to be a bit clever here.
422  *
423  * When we save we mustn't delete the config options of the plugins that
424  * haven't been loaded. So we cannot just create a new config file with the
425  * config structures we've got in memory. 
426  * I don't really know how to deal with this nicely, so I will use a completly
427  * dumb method ;-)
428  * I will load the config file in memory, but skipping all the sections of the
429  * modules we want to save. Then I will create a brand new file, dump the file
430  * loaded in memory and then append the sections of the modules we want to
431  * save.
432  * Really stupid no ?
433  *****************************************************************************/
434 int config_SaveConfigFile( const char *psz_module_name )
435 {
436     module_t *p_module;
437     FILE *file;
438     char p_line[1024], *p_index2;
439     int i, i_sizebuf = 0;
440     char *p_bigbuffer, *p_index;
441     boolean_t b_backup;
442     char *psz_filename, *psz_homedir;
443
444     /* Acquire config file lock */
445     vlc_mutex_lock( &p_main->config_lock );
446
447     psz_homedir = GetHomeDir();
448     if( !psz_homedir )
449     {
450         intf_ErrMsg( "config error: GetHomeDir failed" );
451         vlc_mutex_unlock( &p_main->config_lock );
452         return -1;
453     }
454     psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
455                                    strlen(psz_homedir) + 1 );
456     if( !psz_filename )
457     {
458         intf_ErrMsg( "config error: couldn't malloc psz_filename" );
459         free( psz_homedir );
460         vlc_mutex_unlock( &p_main->config_lock );
461         return -1;
462     }
463     sprintf( psz_filename, "%s/" CONFIG_DIR, psz_homedir );
464     free( psz_homedir );
465 #ifndef WIN32
466     mkdir( psz_filename, 0755 );
467 #else
468     mkdir( psz_filename );
469 #endif
470     strcat( psz_filename, "/" CONFIG_FILE );
471
472
473     intf_WarnMsg( 5, "config: opening config file %s", psz_filename );
474
475     file = fopen( psz_filename, "r" );
476     if( !file )
477     {
478         intf_WarnMsg( 1, "config: couldn't open config file %s for reading",
479                          psz_filename );
480     }
481     else
482     {
483         /* look for file size */
484         fseek( file, 0, SEEK_END );
485         i_sizebuf = ftell( file );
486         rewind( file );
487     }
488
489     p_bigbuffer = p_index = malloc( i_sizebuf+1 );
490     if( !p_bigbuffer )
491     {
492         intf_ErrMsg( "config error: couldn't malloc bigbuffer" );
493         if( file ) fclose( file );
494         free( psz_filename );
495         vlc_mutex_unlock( &p_main->config_lock );
496         return -1;
497     }
498     p_bigbuffer[0] = 0;
499
500     /* backup file into memory, we only need to backup the sections we won't
501      * save later on */
502     b_backup = 0;
503     while( file && fgets( p_line, 1024, file ) )
504     {
505         if( (p_line[0] == '[') && (p_index2 = strchr(p_line,']')))
506         {
507             /* we found a section, check if we need to do a backup */
508             for( p_module = p_module_bank->first; p_module != NULL;
509                  p_module = p_module->next )
510             {
511                 if( ((p_index2 - &p_line[1]) == strlen(p_module->psz_name) ) &&
512                     !memcmp( &p_line[1], p_module->psz_name,
513                              strlen(p_module->psz_name) ) )
514                 {
515                     if( !psz_module_name )
516                         break;
517                     else if( !strcmp( psz_module_name, p_module->psz_name ) )
518                         break;
519                 }
520             }
521
522             if( !p_module )
523             {
524                 /* we don't have this section in our list so we need to back
525                  * it up */
526                 *p_index2 = 0;
527                 intf_WarnMsg( 5, "config: backing up config for "
528                                  "unknown module <%s>", &p_line[1] );
529                 *p_index2 = ']';
530
531                 b_backup = 1;
532             }
533             else
534             {
535                 b_backup = 0;
536             }
537         }
538
539         /* save line if requested and line is valid (doesn't begin with a
540          * space, tab, or eol) */
541         if( b_backup && (p_line[0] != '\n') && (p_line[0] != ' ')
542             && (p_line[0] != '\t') )
543         {
544             strcpy( p_index, p_line );
545             p_index += strlen( p_line );
546         }
547     }
548     if( file ) fclose( file );
549
550
551     /*
552      * Save module config in file
553      */
554
555     file = fopen( psz_filename, "w" );
556     if( !file )
557     {
558         intf_WarnMsg( 1, "config: couldn't open config file %s for writing",
559                          psz_filename );
560         free( psz_filename );
561         vlc_mutex_unlock( &p_main->config_lock );
562         return -1;
563     }
564
565     fprintf( file, "###\n###  " COPYRIGHT_MESSAGE "\n###\n\n" );
566
567     /* Look for the selected module, if NULL then save everything */
568     for( p_module = p_module_bank->first ; p_module != NULL ;
569          p_module = p_module->next )
570     {
571
572         if( psz_module_name && strcmp( psz_module_name, p_module->psz_name ) )
573             continue;
574
575         if( !p_module->i_config_items )
576             continue;
577
578         intf_WarnMsg( 5, "config: saving config for module <%s>",
579                          p_module->psz_name );
580
581         fprintf( file, "[%s]\n", p_module->psz_name );
582
583         if( p_module->psz_longname )
584             fprintf( file, "###\n###  %s\n###\n", p_module->psz_longname );
585
586         for( i = 0; i < p_module->i_config_lines; i++ )
587         {
588             if( p_module->p_config[i].i_type & MODULE_CONFIG_HINT )
589                 /* ignore hints */
590                 continue;
591
592             switch( p_module->p_config[i].i_type )
593             {
594             case MODULE_CONFIG_ITEM_BOOL:
595             case MODULE_CONFIG_ITEM_INTEGER:
596                 if( p_module->p_config[i].psz_text )
597                     fprintf( file, "# %s\n", p_module->p_config[i].psz_text );
598                 fprintf( file, "%s=%i\n", p_module->p_config[i].psz_name,
599                          p_module->p_config[i].i_value );
600                 break;
601
602             default:
603                 if( p_module->p_config[i].psz_value )
604                 {
605                     if( p_module->p_config[i].psz_text )
606                         fprintf( file, "# %s\n",
607                                  p_module->p_config[i].psz_text );
608                     fprintf( file, "%s=%s\n", p_module->p_config[i].psz_name,
609                              p_module->p_config[i].psz_value );
610                 }
611             }
612         }
613
614         fprintf( file, "\n" );
615     }
616
617
618     /*
619      * Restore old settings from the config in file
620      */
621     fputs( p_bigbuffer, file );
622     free( p_bigbuffer );
623
624     fclose( file );
625     free( psz_filename );
626     vlc_mutex_unlock( &p_main->config_lock );
627
628     return 0;
629 }
630
631 /* Following functions are local. */
632
633 /*****************************************************************************
634  * GetHomeDir: find the user's home directory.
635  *****************************************************************************
636  * This function will try by different ways to find the user's home path.
637  *****************************************************************************/
638 static char *GetHomeDir( void )
639 {
640     char *p_tmp, *p_homedir = NULL;
641
642 #if defined(HAVE_GETPWUID_R) || defined(HAVE_GETPWUID)
643     struct passwd *p_pw = NULL;
644 #endif
645
646 #if defined(HAVE_GETPWUID)
647     if( ( p_pw = getpwuid( getuid() ) ) == NULL )
648 #elif defined(HAVE_GETPWUID_R)
649     int ret;
650     struct passwd pwd;
651     char *p_buffer = NULL;
652     int bufsize = 128;
653
654     p_buffer = (char *)malloc( bufsize );
655
656     if( ( ret = getpwuid_r( getuid(), &pwd, p_buffer, bufsize, &p_pw ) ) < 0 )
657 #endif
658     {
659         if( ( p_tmp = getenv( "HOME" ) ) == NULL )
660         {
661             intf_ErrMsg( "config error: unable to get home directory, "
662                          "using /tmp instead" );
663             p_homedir = strdup( "/tmp" );
664         }
665         else p_homedir = strdup( p_tmp );
666     }
667 #if defined(HAVE_GETPWUID_R) || defined(HAVE_GETPWUID)
668     else
669     {
670         if( p_pw ) p_homedir = strdup( p_pw->pw_dir );
671     }
672 #endif
673
674 #if !defined(HAVE_GETPWUID) && defined(HAVE_GETPWUID_R)
675     if( p_buffer ) free( p_buffer );
676 #endif
677
678     return p_homedir;
679 }