1 /*
2 * MOC - music on console
3 * Copyright (C) 2004-2005 Damian Pietras <daper@daper.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 */
11
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/wait.h>
22 #include <sys/time.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <getopt.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <locale.h>
31 #include <assert.h>
32
33 #ifdef HAVE_UNAME_SYSCALL
34 #include <sys/utsname.h>
35 #endif
36
37 #include "common.h"
38 #include "server.h"
39 #include "interface.h"
40 #include "options.h"
41 #include "protocol.h"
42 #include "log.h"
43 #include "compat.h"
44 #include "decoder.h"
45 #include "lists.h"
46 #include "files.h"
47 #include "rcc.h"
48
49 struct parameters
50 {
51 char *config_file;
52 int debug;
53 int only_server;
54 int foreground;
55 int append;
56 int enqueue;
57 int clear;
58 int play;
59 int dont_run_iface;
60 int stop;
61 int exit;
62 int pause;
63 int unpause;
64 int next;
65 int previous;
66 int get_file_info;
67 int toggle_pause;
68 int playit;
69 int seek_by;
70 char jump_type;
71 int jump_to;
72 char *formatted_into_param;
73 int get_formatted_info;
74 char *adj_volume;
75 char *toggle;
76 char *on;
77 char *off;
78 };
79
80
81 /* Connect to the server, return fd of the socket or -1 on error. */
server_connect()82 static int server_connect ()
83 {
84 struct sockaddr_un sock_name;
85 int sock;
86
87 /* Create a socket */
88 if ((sock = socket (PF_LOCAL, SOCK_STREAM, 0)) == -1)
89 return -1;
90
91 sock_name.sun_family = AF_LOCAL;
92 strcpy (sock_name.sun_path, socket_name());
93
94 if (connect(sock, (struct sockaddr *)&sock_name,
95 SUN_LEN(&sock_name)) == -1) {
96 close (sock);
97 return -1;
98 }
99
100 return sock;
101 }
102
103 /* Ping the server.
104 * Return 1 if the server responds with EV_PONG, otherwise 1. */
ping_server(int sock)105 static int ping_server (int sock)
106 {
107 int event;
108
109 send_int(sock, CMD_PING); /* ignore errors - the server could have
110 already closed the connection and sent
111 EV_BUSY */
112 if (!get_int(sock, &event))
113 fatal ("Error when receiving pong response!");
114 return event == EV_PONG ? 1 : 0;
115 }
116
117 /* Check if a directory ./.moc exists and create if needed. */
check_moc_dir()118 static void check_moc_dir ()
119 {
120 char *dir_name = create_file_name ("");
121 struct stat file_stat;
122
123 /* strip trailing slash */
124 dir_name[strlen(dir_name)-1] = 0;
125
126 if (stat (dir_name, &file_stat) == -1) {
127 if (errno == ENOENT) {
128 if (mkdir (dir_name, 0700) == -1)
129 fatal ("Can't create directory %s: %s",
130 dir_name, strerror (errno));
131 }
132 else
133 fatal ("Error trying to check for "CONFIG_DIR" directory: %s",
134 strerror (errno));
135 }
136 else {
137 if (!S_ISDIR(file_stat.st_mode) || access (dir_name, W_OK))
138 fatal ("%s is not a writable directory!", dir_name);
139 }
140 }
141
sig_chld(int sig ATTR_UNUSED)142 static void sig_chld (int sig ATTR_UNUSED)
143 {
144 int saved_errno;
145 pid_t rc;
146
147 log_signal (sig);
148
149 saved_errno = errno;
150 do {
151 rc = waitpid (-1, NULL, WNOHANG);
152 } while (rc > 0);
153 errno = saved_errno;
154 }
155
156 /* Run client and the server if needed. */
start_moc(const struct parameters * params,lists_t_strs * args)157 static void start_moc (const struct parameters *params, lists_t_strs *args)
158 {
159 int list_sock;
160 int server_sock = -1;
161
162 if (!params->foreground && (server_sock = server_connect()) == -1) {
163 int notify_pipe[2];
164 int i = 0;
165 ssize_t rc;
166
167 printf ("Running the server...\n");
168
169 /* To notify the client that the server socket is ready */
170 if (pipe(notify_pipe))
171 fatal ("pipe() failed: %s", strerror(errno));
172
173 switch (fork()) {
174 case 0: /* child - start server */
175 set_me_server ();
176 list_sock = server_init (params->debug, params->foreground);
177 rc = write (notify_pipe[1], &i, sizeof(i));
178 if (rc < 0)
179 fatal ("write() to notify pipe failed: %s",
180 strerror(errno));
181 close (notify_pipe[0]);
182 close (notify_pipe[1]);
183 signal (SIGCHLD, sig_chld);
184 server_loop (list_sock);
185 options_free ();
186 decoder_cleanup ();
187 io_cleanup ();
188 files_cleanup ();
189 rcc_cleanup ();
190 compat_cleanup ();
191 exit (EXIT_SUCCESS);
192 case -1:
193 fatal ("fork() failed: %s", strerror(errno));
194 default:
195 close (notify_pipe[1]);
196 if (read(notify_pipe[0], &i, sizeof(i)) != sizeof(i))
197 fatal ("Server exited!");
198 close (notify_pipe[0]);
199 if ((server_sock = server_connect()) == -1) {
200 perror ("server_connect()");
201 fatal ("Can't connect to the server!");
202 }
203 }
204 }
205 else if (!params->foreground && params->only_server)
206 fatal ("Server is already running!");
207 else if (params->foreground && params->only_server) {
208 set_me_server ();
209 list_sock = server_init (params->debug, params->foreground);
210 signal (SIGCHLD, sig_chld);
211 server_loop (list_sock);
212 }
213
214 if (!params->only_server) {
215 signal (SIGPIPE, SIG_IGN);
216 if (ping_server(server_sock)) {
217 if (!params->dont_run_iface) {
218 init_interface (server_sock, params->debug, args);
219 interface_loop ();
220 interface_end ();
221 server_sock = -1;
222 }
223 }
224 else
225 fatal ("Can't connect to the server!");
226 }
227
228 if (!params->foreground && params->only_server)
229 send_int (server_sock, CMD_DISCONNECT);
230
231 if (server_sock != -1) {
232 close (server_sock);
233 server_sock = -1;
234 }
235 }
236
show_version()237 static void show_version ()
238 {
239 #ifdef HAVE_UNAME_SYSCALL
240 int rc;
241 struct utsname uts;
242 #endif
243
244 putchar ('\n');
245 printf (" This is : %s\n", PACKAGE_NAME);
246 printf (" Version : %s\n", PACKAGE_VERSION);
247
248 #ifdef PACKAGE_REVISION
249 printf (" Revision : %s\n", PACKAGE_REVISION);
250 #endif
251
252 /* Show build time */
253 #ifdef __DATE__
254 printf (" Built : %s", __DATE__);
255 # ifdef __TIME__
256 printf (" %s", __TIME__);
257 # endif
258 putchar ('\n');
259 #endif
260
261 /* Show compiled-in components */
262 printf (" Compiled with :");
263 #ifdef HAVE_OSS
264 printf (" OSS");
265 #endif
266 #ifdef HAVE_SNDIO
267 printf (" SNDIO");
268 #endif
269 #ifdef HAVE_ALSA
270 printf (" ALSA");
271 #endif
272 #ifdef HAVE_JACK
273 printf (" JACK");
274 #endif
275 #ifndef NDEBUG
276 printf (" DEBUG");
277 #endif
278 #ifdef HAVE_CURL
279 printf (" Network streams");
280 #endif
281 #ifdef HAVE_SAMPLERATE
282 printf (" resample");
283 #endif
284 putchar ('\n');
285
286 #ifdef HAVE_UNAME_SYSCALL
287 rc = uname (&uts);
288 if (rc == 0)
289 printf (" Running on : %s %s %s\n", uts.sysname, uts.release,
290 uts.machine);
291 #endif
292
293 printf (" Author : Damian Pietras\n");
294 printf (" Homepage : %s\n", PACKAGE_URL);
295 printf (" E-Mail : %s\n", PACKAGE_BUGREPORT);
296 printf (" Copyright : (C) 2003-2016 Damian Pietras and others\n");
297 printf (" License : GNU General Public License, version 2 or later\n");
298 putchar ('\n');
299 }
300
301 /* Show program usage. */
show_usage(const char * prg_name)302 static void show_usage (const char *prg_name) {
303 printf ("%s (version %s", PACKAGE_NAME, PACKAGE_VERSION);
304 #ifdef PACKAGE_REVISION
305 printf (", revision %s", PACKAGE_REVISION);
306 #endif
307 printf (")\n");
308 printf ("Usage:\n %s [OPTIONS]... [FILE]...\n%s", prg_name,
309 "-V --version Print program version and exit\n"
310 "-h --help Print usage and exit\n"
311 #ifndef NDEBUG
312 "-D --debug Turn on logging to a file\n"
313 #endif
314 "-S --server Only run the server\n"
315 "-F --foreground Run server in foreground and log to stdout\n"
316 "-R --sound-driver LIST Use the first valid sound driver from LIST\n"
317 " (sndio, oss, alsa, jack, null)\n"
318 "-m --music-dir Start in MusicDir\n"
319 "-a --append Append the files/directories/playlists passed in\n"
320 " the command line to playlist and exit\n"
321 "-q --enqueue Add the files given on command line to the queue\n"
322 "-c --clear Clear the playlist and exit\n"
323 "-p --play Start playing from the first item on the playlist\n"
324 "-l --playit Play files given on the command line without modifying\n"
325 " the playlist\n"
326 "-s --stop Stop playing\n"
327 "-f --next Play the next song\n"
328 "-r --previous Play the previous song\n"
329 "-x --exit Shutdown the server\n"
330 "-T --theme theme Use the selected theme file (read from ~/.moc/themes\n"
331 " if the path is not absolute)\n"
332 "-C --config FILE Use the specified config file instead of the default\n"
333 "-O --set-option NAME=VALUE\n"
334 " Override the configuration option NAME with VALUE\n"
335 "-M --moc-dir DIR Use the specified MOC directory instead of the default\n"
336 "-P --pause Pause\n"
337 "-U --unpause Unpause\n"
338 "-G --toggle-pause Toggle between playing and paused\n"
339 "-v --volume (+/-)LEVEL Adjust the PCM volume\n"
340 "-y --sync Synchronize the playlist with other clients\n"
341 "-n --nosync Don't synchronize the playlist with other clients\n"
342 "-A --ascii Use ASCII characters to draw lines\n"
343 "-i --info Print information about the currently playing file\n"
344 "-Q --format FORMAT Print formatted information about the currently\n"
345 " playing file\n"
346 "-e --recursively Alias for -a\n"
347 "-k --seek N Seek by N seconds (can be negative)\n"
348 "-j --jump N{%,s} Jump to some position of the current track\n"
349 "-o --on <controls> Turn on a control (shuffle, autonext, repeat)\n"
350 "-u --off <controls> Turn off a control (shuffle, autonext, repeat)\n"
351 "-t --toggle <controls> Toggle a control (shuffle, autonext, repeat)\n");
352 }
353
354 /* Send commands requested in params to the server. */
server_command(struct parameters * params,lists_t_strs * args)355 static void server_command (struct parameters *params, lists_t_strs *args)
356 {
357 int sock;
358
359 if ((sock = server_connect()) == -1)
360 fatal ("The server is not running!");
361
362 signal (SIGPIPE, SIG_IGN);
363 if (ping_server(sock)) {
364 if (params->playit)
365 interface_cmdline_playit (sock, args);
366 if (params->clear)
367 interface_cmdline_clear_plist (sock);
368 if (params->append)
369 interface_cmdline_append (sock, args);
370 if (params->enqueue)
371 interface_cmdline_enqueue (sock, args);
372 if (params->play)
373 interface_cmdline_play_first (sock);
374 if (params->get_file_info)
375 interface_cmdline_file_info (sock);
376 if (params->seek_by)
377 interface_cmdline_seek_by (sock, params->seek_by);
378 if (params->jump_type=='%')
379 interface_cmdline_jump_to_percent (sock,params->jump_to);
380 if (params->jump_type=='s')
381 interface_cmdline_jump_to (sock,params->jump_to);
382 if (params->get_formatted_info)
383 interface_cmdline_formatted_info (sock,
384 params->formatted_into_param);
385 if (params->adj_volume)
386 interface_cmdline_adj_volume (sock, params->adj_volume);
387 if (params->toggle)
388 interface_cmdline_set (sock, params->toggle, 2);
389 if (params->on)
390 interface_cmdline_set (sock, params->on, 1);
391 if (params->off)
392 interface_cmdline_set (sock, params->off, 0);
393 if (params->exit) {
394 if (!send_int(sock, CMD_QUIT))
395 fatal ("Can't send command!");
396 }
397 else if (params->stop) {
398 if (!send_int(sock, CMD_STOP)
399 || !send_int(sock, CMD_DISCONNECT))
400 fatal ("Can't send commands!");
401 }
402 else if (params->pause) {
403 if (!send_int(sock, CMD_PAUSE)
404 || !send_int(sock, CMD_DISCONNECT))
405 fatal ("Can't send commands!");
406 }
407 else if (params->next) {
408 if (!send_int(sock, CMD_NEXT)
409 || !send_int(sock, CMD_DISCONNECT))
410 fatal ("Can't send commands!");
411 }
412 else if (params->previous) {
413 if (!send_int(sock, CMD_PREV)
414 || !send_int(sock, CMD_DISCONNECT))
415 fatal ("Can't send commands!");
416 }
417 else if (params->unpause) {
418 if (!send_int(sock, CMD_UNPAUSE)
419 || !send_int(sock, CMD_DISCONNECT))
420 fatal ("Can't send commands!");
421 }
422 else if (params->toggle_pause) {
423 int state;
424 int ev;
425 int cmd = -1;
426
427 if (!send_int(sock, CMD_GET_STATE))
428 fatal ("Can't send commands!");
429 if (!get_int(sock, &ev) || ev != EV_DATA
430 || !get_int(sock, &state))
431 fatal ("Can't get data from the server!");
432
433 if (state == STATE_PAUSE)
434 cmd = CMD_UNPAUSE;
435 else if (state == STATE_PLAY)
436 cmd = CMD_PAUSE;
437
438 if (cmd != -1 && !send_int(sock, cmd))
439 fatal ("Can't send commands!");
440 if (!send_int(sock, CMD_DISCONNECT))
441 fatal ("Can't send commands!");
442 }
443 }
444 else
445 fatal ("Can't connect to the server!");
446
447 close (sock);
448 }
449
get_num_param(const char * p,const char ** last)450 static long get_num_param (const char *p,const char ** last)
451 {
452 char *e;
453 long val;
454
455 val = strtol (p, &e, 10);
456 if ((*e&&last==NULL)||e==p)
457 fatal ("The parameter should be a number!");
458
459 if (last)
460 *last=e;
461 return val;
462 }
463
464 /* Log the command line which launched MOC. */
log_command_line(int argc,char * argv[])465 static void log_command_line (int argc, char *argv[])
466 {
467 lists_t_strs *cmdline;
468 char *str;
469
470 assert (argc >= 0);
471 assert (argv != NULL);
472 assert (argv[argc] == NULL);
473
474 cmdline = lists_strs_new (argc);
475 if (lists_strs_load (cmdline, argv) > 0)
476 str = lists_strs_fmt (cmdline, "%s ");
477 else
478 str = xstrdup ("No command line available");
479 logit ("%s", str);
480 free (str);
481 lists_strs_free (cmdline);
482 }
483
override_config_option(const char * optarg,lists_t_strs * deferred)484 static void override_config_option (const char *optarg, lists_t_strs *deferred)
485 {
486 int len;
487 bool append;
488 char *ptr, *name, *value;
489 enum option_type type;
490
491 assert (optarg != NULL);
492
493 ptr = strchr (optarg, '=');
494 if (ptr == NULL)
495 goto error;
496
497 /* Allow for list append operator ("+="). */
498 append = (ptr > optarg && *(ptr - 1) == '+');
499
500 name = trim (optarg, ptr - optarg - (append ? 1 : 0));
501 if (!name || !name[0])
502 goto error;
503 type = options_get_type (name);
504
505 if (type == OPTION_LIST) {
506 if (deferred) {
507 lists_strs_append (deferred, optarg);
508 free (name);
509 return;
510 }
511 }
512 else if (append)
513 goto error;
514
515 value = trim (ptr + 1, strlen (ptr + 1));
516 if (!value || !value[0])
517 goto error;
518
519 if (value[0] == '\'' || value[0] == '"') {
520 len = strlen (value);
521 if (value[0] != value[len - 1])
522 goto error;
523 if (strlen (value) < 2)
524 goto error;
525 memmove (value, value + 1, len - 2);
526 value[len - 2] = 0x00;
527 }
528
529 if (!options_set_pair (name, value, append))
530 goto error;
531 options_ignore_config (name);
532
533 free (name);
534 free (value);
535 return;
536
537 error:
538 fatal ("Malformed override option: %s", optarg);
539 }
540
process_deferred_overrides(lists_t_strs * deferred)541 static void process_deferred_overrides (lists_t_strs *deferred)
542 {
543 int ix;
544 bool cleared;
545 const char marker[] = "*Marker*";
546 char **config_decoders;
547 lists_t_strs *decoders_option;
548
549 /* We need to shuffle the PreferredDecoders list into the
550 * right order as we load any deferred overriding options. */
551
552 decoders_option = options_get_list ("PreferredDecoders");
553 lists_strs_reverse (decoders_option);
554 config_decoders = lists_strs_save (decoders_option);
555 lists_strs_clear (decoders_option);
556 lists_strs_append (decoders_option, marker);
557
558 for (ix = 0; ix < lists_strs_size (deferred); ix += 1)
559 override_config_option (lists_strs_at (deferred, ix), NULL);
560
561 cleared = lists_strs_empty (decoders_option) ||
562 strcmp (lists_strs_at (decoders_option, 0), marker) != 0;
563 lists_strs_reverse (decoders_option);
564 if (!cleared) {
565 char **override_decoders;
566
567 free (lists_strs_pop (decoders_option));
568 override_decoders = lists_strs_save (decoders_option);
569 lists_strs_clear (decoders_option);
570 lists_strs_load (decoders_option, config_decoders);
571 lists_strs_load (decoders_option, override_decoders);
572 free (override_decoders);
573 }
574 free (config_decoders);
575 }
576
577 /* Process the command line options and arguments. */
process_command_line(int argc,char * argv[],struct parameters * params,lists_t_strs * deferred)578 static lists_t_strs *process_command_line (int argc, char *argv[],
579 struct parameters *params,
580 lists_t_strs *deferred)
581 {
582 int ret, opt_index = 0;
583 const char *jump_type;
584 lists_t_strs *result;
585
586 struct option long_options[] = {
587 { "version", 0, NULL, 'V' },
588 { "help", 0, NULL, 'h' },
589 #ifndef NDEBUG
590 { "debug", 0, NULL, 'D' },
591 #endif
592 { "server", 0, NULL, 'S' },
593 { "foreground", 0, NULL, 'F' },
594 { "sound-driver", 1, NULL, 'R' },
595 { "music-dir", 0, NULL, 'm' },
596 { "append", 0, NULL, 'a' },
597 { "enqueue", 0, NULL, 'q' },
598 { "clear", 0, NULL, 'c' },
599 { "play", 0, NULL, 'p' },
600 { "playit", 0, NULL, 'l' },
601 { "stop", 0, NULL, 's' },
602 { "next", 0, NULL, 'f' },
603 { "previous", 0, NULL, 'r' },
604 { "exit", 0, NULL, 'x' },
605 { "theme", 1, NULL, 'T' },
606 { "config", 1, NULL, 'C' },
607 { "set-option", 1, NULL, 'O' },
608 { "moc-dir", 1, NULL, 'M' },
609 { "pause", 0, NULL, 'P' },
610 { "unpause", 0, NULL, 'U' },
611 { "toggle-pause", 0, NULL, 'G' },
612 { "sync", 0, NULL, 'y' },
613 { "nosync", 0, NULL, 'n' },
614 { "ascii", 0, NULL, 'A' },
615 { "info", 0, NULL, 'i' },
616 { "recursively", 0, NULL, 'e' },
617 { "seek", 1, NULL, 'k' },
618 { "jump", 1, NULL, 'j' },
619 { "format", 1, NULL, 'Q' },
620 { "volume", 1, NULL, 'v' },
621 { "toggle", 1, NULL, 't' },
622 { "on", 1, NULL, 'o' },
623 { "off", 1, NULL, 'u' },
624 { 0, 0, 0, 0 }
625 };
626
627 assert (argc >= 0);
628 assert (argv != NULL);
629 assert (argv[argc] == NULL);
630 assert (params != NULL);
631 assert (deferred != NULL);
632
633 while ((ret = getopt_long(argc, argv,
634 "VhDSFR:macpsxT:C:O:M:PUynArfiGelk:j:v:t:o:u:Q:q",
635 long_options, &opt_index)) != -1) {
636 switch (ret) {
637 case 'V':
638 show_version ();
639 exit (EXIT_SUCCESS);
640 case 'h':
641 show_usage (argv[0]);
642 exit (EXIT_SUCCESS);
643 #ifndef NDEBUG
644 case 'D':
645 params->debug = 1;
646 break;
647 #endif
648 case 'S':
649 params->only_server = 1;
650 break;
651 case 'F':
652 params->foreground = 1;
653 params->only_server = 1;
654 break;
655 case 'R':
656 if (!options_check_list ("SoundDriver", optarg))
657 fatal ("No such sound driver: %s", optarg);
658 options_set_list ("SoundDriver", optarg, false);
659 options_ignore_config ("SoundDriver");
660 break;
661 case 'm':
662 options_set_int ("StartInMusicDir", 1);
663 options_ignore_config ("StartInMusicDir");
664 break;
665 case 'a':
666 case 'e':
667 params->append = 1;
668 params->dont_run_iface = 1;
669 break;
670 case 'q':
671 params->enqueue = 1;
672 params->dont_run_iface = 1;
673 break;
674 case 'c':
675 params->clear = 1;
676 params->dont_run_iface = 1;
677 break;
678 case 'i':
679 params->get_file_info = 1;
680 params->dont_run_iface = 1;
681 break;
682 case 'p':
683 params->play = 1;
684 params->dont_run_iface = 1;
685 break;
686 case 'l':
687 params->playit = 1;
688 params->dont_run_iface = 1;
689 break;
690 case 's':
691 params->stop = 1;
692 params->dont_run_iface = 1;
693 break;
694 case 'f':
695 params->next = 1;
696 params->dont_run_iface = 1;
697 break;
698 case 'r':
699 params->previous = 1;
700 params->dont_run_iface = 1;
701 break;
702 case 'x':
703 params->exit = 1;
704 params->dont_run_iface = 1;
705 break;
706 case 'P':
707 params->pause = 1;
708 params->dont_run_iface = 1;
709 break;
710 case 'U':
711 params->unpause = 1;
712 params->dont_run_iface = 1;
713 break;
714 case 'T':
715 options_set_str ("ForceTheme", optarg);
716 break;
717 case 'C':
718 params->config_file = xstrdup (optarg);
719 break;
720 case 'O':
721 override_config_option (optarg, deferred);
722 break;
723 case 'M':
724 options_set_str ("MOCDir", optarg);
725 options_ignore_config ("MOCDir");
726 break;
727 case 'y':
728 options_set_int ("SyncPlaylist", 1);
729 options_ignore_config ("SyncPlaylist");
730 break;
731 case 'n':
732 options_set_int ("SyncPlaylist", 0);
733 options_ignore_config ("SyncPlaylist");
734 break;
735 case 'A':
736 options_set_int ("ASCIILines", 1);
737 options_ignore_config ("ASCIILines");
738 break;
739 case 'G':
740 params->toggle_pause = 1;
741 params->dont_run_iface = 1;
742 break;
743 case 'k':
744 params->seek_by = get_num_param (optarg, NULL);
745 params->dont_run_iface = 1;
746 break;
747 case 'j':
748 params->jump_to = get_num_param (optarg, &jump_type);
749 if (*jump_type)
750 if (!jump_type[1])
751 if (*jump_type == '%' || tolower (*jump_type) == 's') {
752 params->jump_type = tolower (*jump_type);
753 params->dont_run_iface = 1;
754 break;
755 }
756 //TODO: Add message explaining the error
757 show_usage (argv[0]);
758 exit (EXIT_FAILURE);
759 case 'v' :
760 params->adj_volume = optarg;
761 params->dont_run_iface = 1;
762 break;
763 case 't' :
764 params->toggle = optarg;
765 params->dont_run_iface = 1;
766 break;
767 case 'o' :
768 params->on = optarg;
769 params->dont_run_iface = 1;
770 break;
771 case 'u' :
772 params->off = optarg;
773 params->dont_run_iface = 1;
774 break;
775 case 'Q':
776 params->formatted_into_param = optarg;
777 params->get_formatted_info = 1;
778 params->dont_run_iface = 1;
779 break;
780 default:
781 show_usage (argv[0]);
782 exit (EXIT_FAILURE);
783 }
784 }
785
786 result = lists_strs_new (argc - optind);
787 lists_strs_load (result, argv + optind);
788
789 return result;
790 }
791
main(int argc,char * argv[])792 int main (int argc, char *argv[])
793 {
794 struct parameters params;
795 lists_t_strs *deferred_overrides;
796 lists_t_strs *args;
797
798 #ifdef HAVE_UNAME_SYSCALL
799 int rc;
800 struct utsname uts;
801 #endif
802
803 #ifdef PACKAGE_REVISION
804 logit ("This is Music On Console (revision %s)", PACKAGE_REVISION);
805 #else
806 logit ("This is Music On Console (version %s)", PACKAGE_VERSION);
807 #endif
808
809 #ifdef CONFIGURATION
810 logit ("Configured:%s", CONFIGURATION);
811 #endif
812
813 #ifdef HAVE_UNAME_SYSCALL
814 rc = uname (&uts);
815 if (rc == 0)
816 logit ("Running on: %s %s %s", uts.sysname, uts.release, uts.machine);
817 #endif
818
819 log_command_line (argc, argv);
820
821 files_init ();
822
823 if (get_home () == NULL)
824 fatal ("Could not determine user's home directory!");
825
826 memset (¶ms, 0, sizeof(params));
827 options_init ();
828 deferred_overrides = lists_strs_new (4);
829
830 /* set locale according to the environment variables */
831 if (!setlocale(LC_ALL, ""))
832 logit ("Could not set locale!");
833
834 args = process_command_line (argc, argv, ¶ms, deferred_overrides);
835
836 if (params.dont_run_iface && params.only_server)
837 fatal ("-c, -a and -p options can't be used with --server!");
838
839 if (!params.config_file)
840 params.config_file = xstrdup (create_file_name ("config"));
841 options_parse (params.config_file);
842 if (params.config_file)
843 free (params.config_file);
844 params.config_file = NULL;
845
846 process_deferred_overrides (deferred_overrides);
847 lists_strs_free (deferred_overrides);
848 deferred_overrides = NULL;
849
850 check_moc_dir ();
851
852 io_init ();
853 rcc_init ();
854 decoder_init (params.debug);
855 srand (time(NULL));
856
857 if (!params.only_server && params.dont_run_iface)
858 server_command (¶ms, args);
859 else
860 start_moc (¶ms, args);
861
862 lists_strs_free (args);
863 options_free ();
864 decoder_cleanup ();
865 io_cleanup ();
866 rcc_cleanup ();
867 files_cleanup ();
868 compat_cleanup ();
869
870 return EXIT_SUCCESS;
871 }
872