125
|
1 /*
|
|
2 * cfgparser.c : GeeXboX uShare config file parser.
|
|
3 * Originally developped for the GeeXboX project.
|
|
4 * Copyright (C) 2005-2007 Alexis Saettler <asbin@asbin.org>
|
|
5 *
|
|
6 * This program is free software; you can redistribute it and/or modify
|
|
7 * it under the terms of the GNU General Public License as published by
|
|
8 * the Free Software Foundation; either version 2 of the License, or
|
|
9 * (at your option) any later version.
|
|
10 *
|
|
11 * This program is distributed in the hope that it will be useful,
|
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 * GNU Library General Public License for more details.
|
|
15 *
|
|
16 * You should have received a copy of the GNU General Public License along
|
|
17 * with this program; if not, write to the Free Software Foundation,
|
|
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
19 */
|
|
20
|
|
21 #include <stdio.h>
|
|
22 #include <stdlib.h>
|
|
23 #include <string.h>
|
|
24 #include <getopt.h>
|
|
25 #include <stdbool.h>
|
|
26 #include <limits.h>
|
|
27
|
|
28 #include "config.h"
|
|
29 #include "gettext.h"
|
|
30 #include "cfgparser.h"
|
|
31 #include "ushare.h"
|
|
32 #include "trace.h"
|
|
33 #include "osdep.h"
|
|
34
|
|
35 #define USHARE_DIR_DELIM ","
|
|
36
|
|
37 static bool
|
|
38 ignore_line (const char *line)
|
|
39 {
|
|
40 int i;
|
|
41 size_t len;
|
|
42
|
|
43 /* commented line */
|
|
44 if (line[0] == '#' )
|
|
45 return true;
|
|
46
|
|
47 len = strlen (line);
|
|
48
|
|
49 for (i = 0 ; i < (int) len ; i++ )
|
|
50 if (line[i] != ' ' && line[i] != '\t' && line[i] != '\n')
|
|
51 return false;
|
|
52
|
|
53 return true;
|
|
54 }
|
|
55
|
|
56 static char *
|
|
57 strdup_trim (const char *s)
|
|
58 {
|
|
59 size_t begin, end;
|
|
60 char *r = NULL;
|
|
61
|
|
62 if (!s)
|
|
63 return NULL;
|
|
64
|
|
65 end = strlen (s) - 1;
|
|
66
|
|
67 for (begin = 0 ; begin < end ; begin++)
|
|
68 if (s[begin] != ' ' && s[begin] != '\t' && s[begin] != '"')
|
|
69 break;
|
|
70
|
|
71 for (; begin < end ; end--)
|
|
72 if (s[end] != ' ' && s[end] != '\t' && s[end] != '"' && s[end] != '\n')
|
|
73 break;
|
|
74
|
|
75 r = strndup (s + begin, end - begin + 1);
|
|
76
|
|
77 return r;
|
|
78 }
|
|
79
|
|
80 static void
|
|
81 ushare_set_name (struct ushare_t *ut, const char *name)
|
|
82 {
|
|
83 if (!ut || !name)
|
|
84 return;
|
|
85
|
|
86 if (ut->name)
|
|
87 {
|
|
88 free (ut->name);
|
|
89 ut->name = NULL;
|
|
90 }
|
|
91
|
|
92 ut->name = strdup_trim (name);
|
|
93 }
|
|
94
|
|
95 static void
|
|
96 ushare_set_interface (struct ushare_t *ut, const char *iface)
|
|
97 {
|
|
98 if (!ut || !iface)
|
|
99 return;
|
|
100
|
|
101 if (ut->interface)
|
|
102 {
|
|
103 free (ut->interface);
|
|
104 ut->interface = NULL;
|
|
105 }
|
|
106
|
|
107 ut->interface = strdup_trim (iface);
|
|
108 }
|
|
109
|
|
110 static void
|
|
111 ushare_add_contentdir (struct ushare_t *ut, const char *dir)
|
|
112 {
|
|
113 if (!ut || !dir)
|
|
114 return;
|
|
115
|
|
116 ut->contentlist = content_add (ut->contentlist, dir);
|
|
117 }
|
|
118
|
|
119 static void
|
|
120 ushare_set_cfg_file (struct ushare_t *ut, const char *file)
|
|
121 {
|
|
122 if (!ut || !file)
|
|
123 return;
|
|
124
|
|
125 ut->cfg_file = strdup (file);
|
|
126 }
|
|
127
|
|
128 static void
|
|
129 ushare_set_dir (struct ushare_t *ut, const char *dirlist)
|
|
130 {
|
|
131 char *x = NULL, *token = NULL;
|
|
132 char *m_buffer = NULL, *buffer;
|
|
133
|
|
134 if (!ut || !dirlist)
|
|
135 return;
|
|
136
|
|
137 x = strdup_trim (dirlist);
|
|
138 if (x)
|
|
139 {
|
|
140 m_buffer = (char*) malloc (strlen (x) * sizeof (char));
|
|
141 if (m_buffer)
|
|
142 {
|
|
143 buffer = m_buffer;
|
|
144 token = strtok_r (x, USHARE_DIR_DELIM, &buffer);
|
|
145 while (token)
|
|
146 {
|
|
147 ushare_add_contentdir (ut, token);
|
|
148 token = strtok_r (NULL, USHARE_DIR_DELIM, &buffer);
|
|
149 }
|
|
150 free (m_buffer);
|
|
151 }
|
|
152 free (x);
|
|
153 }
|
|
154 }
|
|
155
|
|
156 static void
|
|
157 ushare_set_port (struct ushare_t *ut, const char *port)
|
|
158 {
|
|
159 if (!ut || !port)
|
|
160 return;
|
|
161
|
|
162 ut->port = atoi (port);
|
|
163 if (ut->port < 49152)
|
|
164 {
|
|
165 fprintf (stderr,
|
|
166 _("Warning: port doesn't fit IANA port assignements.\n"));
|
|
167
|
|
168 fprintf (stderr, _("Warning: Only Dynamic or Private Ports can be used "
|
|
169 "(from 49152 through 65535)\n"));
|
|
170 ut->port = 0;
|
|
171 }
|
|
172 }
|
|
173
|
|
174 static void
|
|
175 ushare_set_telnet_port (struct ushare_t *ut, const char *port)
|
|
176 {
|
|
177 if (!ut || !port)
|
|
178 return;
|
|
179
|
|
180 ut->telnet_port = atoi (port);
|
|
181 }
|
|
182
|
|
183 static void
|
|
184 ushare_use_web (struct ushare_t *ut, const char *val)
|
|
185 {
|
|
186 if (!ut || !val)
|
|
187 return;
|
|
188
|
|
189 ut->use_presentation = (!strcmp (val, "yes")) ? true : false;
|
|
190 }
|
|
191
|
|
192 static void
|
|
193 ushare_use_telnet (struct ushare_t *ut, const char *val)
|
|
194 {
|
|
195 if (!ut || !val)
|
|
196 return;
|
|
197
|
|
198 ut->use_telnet = (!strcmp (val, "yes")) ? true : false;
|
|
199 }
|
|
200
|
|
201 static void
|
|
202 ushare_use_xbox (struct ushare_t *ut, const char *val)
|
|
203 {
|
|
204 if (!ut || !val)
|
|
205 return;
|
|
206
|
|
207 ut->xbox360 = (!strcmp (val, "yes")) ? true : false;
|
|
208 }
|
|
209
|
|
210 static void
|
|
211 ushare_use_dlna (struct ushare_t *ut, const char *val)
|
|
212 {
|
|
213 if (!ut || !val)
|
|
214 return;
|
|
215
|
|
216 #ifdef HAVE_DLNA
|
|
217 ut->dlna_enabled = (!strcmp (val, "yes")) ? true : false;
|
|
218 #endif /* HAVE_DLNA */
|
|
219 }
|
|
220
|
|
221 static void
|
|
222 ushare_set_override_iconv_err (struct ushare_t *ut, const char *arg)
|
|
223 {
|
|
224 if (!ut)
|
|
225 return;
|
|
226
|
|
227 ut->override_iconv_err = false;
|
|
228
|
|
229 if (!strcasecmp (arg, "yes")
|
|
230 || !strcasecmp (arg, "true")
|
|
231 || !strcmp (arg, "1"))
|
|
232 ut->override_iconv_err = true;
|
|
233 }
|
|
234
|
|
235 static u_configline_t configline[] = {
|
|
236 { USHARE_NAME, ushare_set_name },
|
|
237 { USHARE_IFACE, ushare_set_interface },
|
|
238 { USHARE_PORT, ushare_set_port },
|
|
239 { USHARE_TELNET_PORT, ushare_set_telnet_port },
|
|
240 { USHARE_DIR, ushare_set_dir },
|
|
241 { USHARE_OVERRIDE_ICONV_ERR, ushare_set_override_iconv_err },
|
|
242 { USHARE_ENABLE_WEB, ushare_use_web },
|
|
243 { USHARE_ENABLE_TELNET, ushare_use_telnet },
|
|
244 { USHARE_ENABLE_XBOX, ushare_use_xbox },
|
|
245 { USHARE_ENABLE_DLNA, ushare_use_dlna },
|
|
246 { NULL, NULL },
|
|
247 };
|
|
248
|
|
249 static void
|
|
250 parse_config_line (struct ushare_t *ut, const char *line,
|
|
251 u_configline_t *configline)
|
|
252 {
|
|
253 char *s = NULL;
|
|
254
|
|
255 s = strchr (line, '=');
|
|
256 if (s && s[1] != '\0')
|
|
257 {
|
|
258 int i;
|
|
259 for (i=0 ; configline[i].name ; i++)
|
|
260 {
|
|
261 if (!strncmp (line, configline[i].name, strlen (configline[i].name)))
|
|
262 {
|
|
263 configline[i].set_var (ut, s + 1);
|
|
264 break;
|
|
265 }
|
|
266 }
|
|
267 }
|
|
268 }
|
|
269
|
|
270 int
|
|
271 parse_config_file (struct ushare_t *ut)
|
|
272 {
|
|
273 char filename[PATH_MAX];
|
|
274 FILE *conffile;
|
|
275 char *line = NULL;
|
|
276 size_t size = 0;
|
|
277 ssize_t read;
|
|
278
|
|
279 if (!ut)
|
|
280 return -1;
|
|
281
|
|
282 if (!ut->cfg_file)
|
|
283 snprintf (filename, PATH_MAX, "%s/%s", SYSCONFDIR, USHARE_CONFIG_FILE);
|
|
284 else
|
|
285 snprintf (filename, PATH_MAX, "%s", ut->cfg_file);
|
|
286
|
|
287 conffile = fopen (filename, "r");
|
|
288 if (!conffile)
|
|
289 return -1;
|
|
290
|
|
291 while ((read = getline (&line, &size, conffile)) != -1)
|
|
292 {
|
|
293 if (ignore_line (line))
|
|
294 continue;
|
|
295
|
|
296 if (line[read-1] == '\n')
|
|
297 line[read-1] = '\0';
|
|
298
|
|
299 while (line[0] == ' ' || line[0] == '\t')
|
|
300 line++;
|
|
301
|
|
302 parse_config_line (ut, line, configline);
|
|
303 }
|
|
304
|
|
305 fclose (conffile);
|
|
306
|
|
307 if (line)
|
|
308 free (line);
|
|
309
|
|
310 return 0;
|
|
311 }
|
|
312
|
|
313 inline static void
|
|
314 display_usage (void)
|
|
315 {
|
|
316 display_headers ();
|
|
317 printf ("\n");
|
|
318 printf (_("Usage: ushare [-n name] [-i interface] [-p port] [-c directory] [[-c directory]...]\n"));
|
|
319 printf (_("Options:\n"));
|
|
320 printf (_(" -n, --name=NAME\tSet UPnP Friendly Name (default is '%s')\n"),
|
|
321 DEFAULT_USHARE_NAME);
|
|
322 printf (_(" -i, --interface=IFACE\tUse IFACE Network Interface (default is '%s')\n"),
|
|
323 DEFAULT_USHARE_IFACE);
|
|
324 printf (_(" -f, --cfg=FILE\t\tConfig file to be used\n"));
|
|
325 printf (_(" -p, --port=PORT\tForces the HTTP server to run on PORT\n"));
|
|
326 printf (_(" -q, --telnet-port=PORT\tForces the TELNET server to run on PORT\n"));
|
|
327 printf (_(" -c, --content=DIR\tShare the content of DIR directory\n"));
|
|
328 printf (_(" -w, --no-web\t\tDisable the control web page (enabled by default)\n"));
|
|
329 printf (_(" -t, --no-telnet\tDisable the TELNET control (enabled by default)\n"));
|
|
330 printf (_(" -o, --override-iconv-err\tIf iconv fails parsing name, still add to media contents (hoping the renderer can handle it)\n"));
|
|
331 printf (_(" -v, --verbose\t\tSet verbose display\n"));
|
|
332 printf (_(" -x, --xbox\t\tUse XboX 360 compliant profile\n"));
|
|
333 #ifdef HAVE_DLNA
|
|
334 printf (_(" -d, --dlna\t\tUse DLNA compliant profile (PlayStation3 needs this)\n"));
|
|
335 #endif /* HAVE_DLNA */
|
|
336 printf (_(" -D, --daemon\t\tRun as a daemon\n"));
|
|
337 printf (_(" -V, --version\t\tDisplay the version of uShare and exit\n"));
|
|
338 printf (_(" -h, --help\t\tDisplay this help\n"));
|
|
339 }
|
|
340
|
|
341 int
|
|
342 parse_command_line (struct ushare_t *ut, int argc, char **argv)
|
|
343 {
|
|
344 int c, index;
|
|
345 char short_options[] = "VhvDowtxdn:i:p:q:c:f:";
|
|
346 struct option long_options [] = {
|
|
347 {"version", no_argument, 0, 'V' },
|
|
348 {"help", no_argument, 0, 'h' },
|
|
349 {"verbose", no_argument, 0, 'v' },
|
|
350 {"daemon", no_argument, 0, 'D' },
|
|
351 {"override-iconv-err", no_argument, 0, 'o' },
|
|
352 {"name", required_argument, 0, 'n' },
|
|
353 {"interface", required_argument, 0, 'i' },
|
|
354 {"port", required_argument, 0, 'p' },
|
|
355 {"telnet-port", required_argument, 0, 'q' },
|
|
356 {"content", required_argument, 0, 'c' },
|
|
357 {"no-web", no_argument, 0, 'w' },
|
|
358 {"no-telnet", no_argument, 0, 't' },
|
|
359 {"xbox", no_argument, 0, 'x' },
|
|
360 #ifdef HAVE_DLNA
|
|
361 {"dlna", no_argument, 0, 'd' },
|
|
362 #endif /* HAVE_DLNA */
|
|
363 {"cfg", required_argument, 0, 'f' },
|
|
364 {0, 0, 0, 0 }
|
|
365 };
|
|
366
|
|
367 /* command line argument processing */
|
|
368 while (true)
|
|
369 {
|
|
370 c = getopt_long (argc, argv, short_options, long_options, &index);
|
|
371
|
|
372 if (c == EOF)
|
|
373 break;
|
|
374
|
|
375 switch (c)
|
|
376 {
|
|
377 case 0:
|
|
378 /* opt = long_options[index].name; */
|
|
379 break;
|
|
380
|
|
381 case '?':
|
|
382 case 'h':
|
|
383 display_usage ();
|
|
384 return -1;
|
|
385
|
|
386 case 'V':
|
|
387 display_headers ();
|
|
388 return -1;
|
|
389
|
|
390 case 'v':
|
|
391 ut->verbose = true;
|
|
392 break;
|
|
393
|
|
394 case 'D':
|
|
395 ut->daemon = true;
|
|
396 break;
|
|
397
|
|
398 case 'o':
|
|
399 ut->override_iconv_err = true;
|
|
400 break;
|
|
401
|
|
402 case 'n':
|
|
403 ushare_set_name (ut, optarg);
|
|
404 break;
|
|
405
|
|
406 case 'i':
|
|
407 ushare_set_interface (ut, optarg);
|
|
408 break;
|
|
409
|
|
410 case 'p':
|
|
411 ushare_set_port (ut, optarg);
|
|
412 break;
|
|
413
|
|
414 case 'q':
|
|
415 ushare_set_telnet_port (ut, optarg);
|
|
416 break;
|
|
417
|
|
418 case 'c':
|
|
419 ushare_add_contentdir (ut, optarg);
|
|
420 break;
|
|
421
|
|
422 case 'w':
|
|
423 ut->use_presentation = false;
|
|
424 break;
|
|
425
|
|
426 case 't':
|
|
427 ut->use_telnet = false;
|
|
428 break;
|
|
429
|
|
430 case 'x':
|
|
431 ut->xbox360 = true;
|
|
432 break;
|
|
433
|
|
434 #ifdef HAVE_DLNA
|
|
435 case 'd':
|
|
436 ut->dlna_enabled = true;
|
|
437 break;
|
|
438 #endif /* HAVE_DLNA */
|
|
439
|
|
440 case 'f':
|
|
441 ushare_set_cfg_file (ut, optarg);
|
|
442 break;
|
|
443
|
|
444 default:
|
|
445 break;
|
|
446 }
|
|
447 }
|
|
448
|
|
449 return 0;
|
|
450 }
|