/* make state dir if not existing */ void hgd_mk_state_dir() { if (mkdir(state_path, S_IRWXU) != 0) { if (errno != EEXIST) { DPRINTF(HGD_D_ERROR, "%s: %s", state_path, SERROR); hgd_exit_nicely(); } } /* make filestore if not existing */ if (mkdir(filestore_path, S_IRWXU) != 0) { if (errno != EEXIST) { DPRINTF(HGD_D_ERROR, "%s:%s", filestore_path, SERROR); hgd_exit_nicely(); } } /* correct any insecure perms (user may think he knows better) */ if (chmod(filestore_path, S_IRWXU) != 0) DPRINTF(HGD_D_WARN, "Could not make filestore secure"); if (chmod(state_path, S_IRWXU) != 0) DPRINTF(HGD_D_WARN, "Could not make state dir secure"); }
int hgd_cmd_encrypt(struct hgd_session *sess, char **unused) { int ssl_err = 0, ret = -1; unused = unused; if (sess->ssl != NULL) { DPRINTF(HGD_D_WARN, "User tried to enable encyption twice"); return (HGD_FAIL); } if ((!ssl_capable) || (crypto_pref == HGD_CRYPTO_PREF_NEVER)) { DPRINTF(HGD_D_WARN, "User tried encrypt, when not possible"); hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|nossl"); return (HGD_FAIL); } DPRINTF(HGD_D_DEBUG, "New SSL for session"); sess->ssl = SSL_new(ctx); if (sess->ssl == NULL) { PRINT_SSL_ERR(HGD_D_ERROR, "SSL_new"); goto clean; } DPRINTF(HGD_D_DEBUG, "SSL_set_fd"); ssl_err = SSL_set_fd(sess->ssl, sess->sock_fd); if (ssl_err == 0) { PRINT_SSL_ERR(HGD_D_ERROR, "SSL_set_fd"); goto clean; } DPRINTF(HGD_D_DEBUG, "SSL_accept"); ssl_err = SSL_accept(sess->ssl); if (ssl_err != 1) { PRINT_SSL_ERR(HGD_D_ERROR, "SSL_accept"); goto clean; } /* This cannot fail so no error check */ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); ret = HGD_OK; /* all is well */ clean: if (ret == HGD_FAIL) { DPRINTF(HGD_D_INFO, "SSL connection failed"); hgd_exit_nicely(); /* be paranoid and kick client */ } else { DPRINTF(HGD_D_INFO, "SSL connection established"); hgd_sock_send_line(sess->sock_fd, sess->ssl, "ok"); } return (ret); }
void * xrealloc(void *old_p, size_t sz) { void *ptr; ptr = realloc(old_p, sz); if (!ptr) { DPRINTF(HGD_D_ERROR, "Could not reallocate"); hgd_exit_nicely(); } return (ptr); }
void * xcalloc(size_t sz, size_t size) { void *ptr; ptr = calloc(sz, size); if (!ptr) { DPRINTF(HGD_D_ERROR, "Could not allocate"); hgd_exit_nicely(); } return (ptr); }
int xasprintf(char **buf, char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = vasprintf(buf, fmt, ap); if (ret == -1) { DPRINTF(HGD_D_ERROR, "Can't allocate"); hgd_exit_nicely(); } return (ret); }
/* main loop that deals with network requests */ void hgd_listen_loop(void) { struct sockaddr_in addr, cli_addr; int cli_fd, child_pid = 0; socklen_t cli_addr_len; int sockopt = 1, data_ready; struct pollfd pfd; start: DPRINTF(HGD_D_DEBUG, "Setting up socket"); if ((svr_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { DPRINTF(HGD_D_ERROR, "socket(): %s", SERROR); hgd_exit_nicely(); } /* allow socket to be re-used right away after we exit */ if (setsockopt(svr_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) < 0) { DPRINTF(HGD_D_WARN, "Can't set SO_REUSEADDR"); } /* configure socket */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); if (bind(svr_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { DPRINTF(HGD_D_ERROR, "Bind to port %d: %s", port, SERROR); hgd_exit_nicely(); } if (listen(svr_fd, sock_backlog) < 0) { DPRINTF(HGD_D_ERROR, "Listen: %s", SERROR); hgd_exit_nicely(); } DPRINTF(HGD_D_INFO, "Socket ready and listening on port %d", port); /* setup signal handler */ signal(SIGCHLD, hgd_sigchld); while (1) { DPRINTF(HGD_D_INFO, "waiting for client connection"); /* spin until something is ready */ pfd.fd = svr_fd; pfd.events = POLLIN; data_ready = 0; while (!dying && !restarting && !data_ready) { data_ready = poll(&pfd, 1, INFTIM); if (data_ready == -1) { if (errno != EINTR) { DPRINTF(HGD_D_ERROR, "Poll error"); dying = 1; } data_ready = 0; } } if (dying || restarting) { if (restarting) exit_ok = 1; hgd_exit_nicely(); } cli_addr_len = sizeof(cli_addr); cli_fd = accept(svr_fd, (struct sockaddr *) &cli_addr, &cli_addr_len); if (cli_fd < 0) { DPRINTF(HGD_D_WARN, "Server failed to accept"); close(svr_fd); /* * accept will fail next time aswell :\ * it seems the fix is to re-initialise the socket */ goto start; } if (setsockopt(cli_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) < 0) { DPRINTF(HGD_D_WARN, "Can't set SO_REUSEADDR"); } /* ok, let's deal with that request then */ if (!single_client) child_pid = fork(); if (!child_pid) { /* turn off HUP handler */ //signal(SIGHUP, SIG_DFL); db = hgd_open_db(db_path, 0); if (db == NULL) hgd_exit_nicely(); hgd_service_client(cli_fd, &cli_addr); DPRINTF(HGD_D_DEBUG, "client service complete"); /* and we are done with this client */ if (shutdown(cli_fd, SHUT_RDWR) == -1) DPRINTF(HGD_D_WARN, "Can't shutdown socket"); close(cli_fd); close(svr_fd); svr_fd = -1; /* prevent shutdown of svr_fd */ exit_ok = 1; hgd_exit_nicely(); } /* child block ends */ close (cli_fd); DPRINTF(HGD_D_DEBUG, "client servicer PID = '%d'", child_pid); /* otherwise, back round for the next client */ } /* NOREACH */ }
int main(int argc, char **argv) { char *xdg_config_home; char *config_path[4] = {NULL, NULL, NULL, NULL}; int num_config = 2, ch; /* as early as possible */ HGD_INIT_SYSLOG_DAEMON(); config_path[0] = NULL; xasprintf(&config_path[1], "%s", HGD_GLOBAL_CFG_DIR HGD_SERV_CFG ); xdg_config_home = getenv("XDG_CONFIG_HOME"); if (xdg_config_home == NULL) { xasprintf(&config_path[2], "%s%s", getenv("HOME"), HGD_USR_CFG_DIR HGD_SERV_CFG ); } else { xasprintf(&config_path[2], "%s%s", xdg_config_home , "/hgd" HGD_SERV_CFG); } /* if killed, die nicely */ hgd_register_sig_handlers(); state_path = xstrdup(HGD_DFL_DIR); ssl_key_path = xstrdup(HGD_DFL_KEY_FILE); ssl_cert_path = xstrdup(HGD_DFL_CERT_FILE); DPRINTF(HGD_D_DEBUG, "Parsing options:1"); while ((ch = getopt(argc, argv, "Bc:Dd:EefF:hk:n:p:s:S:vx:y:")) != -1) { switch (ch) { case 'c': if (num_config < 3) { num_config++; DPRINTF(HGD_D_DEBUG, "added config %d %s", num_config, optarg); config_path[num_config] = optarg; } else { DPRINTF(HGD_D_WARN, "Too many config files specified"); hgd_exit_nicely(); } break; case 'x': hgd_debug = atoi(optarg); if (hgd_debug > 3) hgd_debug = 3; DPRINTF(HGD_D_DEBUG, "set debug to %d", hgd_debug); break; default: break; /* next getopt will catch errors */ } } RESET_GETOPT(); /* cache HUP info */ if (hgd_cache_exec_context(argv) != HGD_OK) hgd_exit_nicely(); hgd_read_config(config_path + num_config); DPRINTF(HGD_D_DEBUG, "Parsing options:2"); while ((ch = getopt(argc, argv, "Bc:Dd:EefF:hk:n:p:s:S:vx:y:")) != -1) { switch (ch) { case 'B': background = 0; DPRINTF(HGD_D_DEBUG, "Not \"backgrounding\" daemon."); break; case 'c': break; /* already handled */ case 'D': DPRINTF(HGD_D_DEBUG, "No client DNS lookups"); lookup_client_dns = 0; break; case 'd': free(state_path); state_path = xstrdup(optarg); DPRINTF(HGD_D_DEBUG, "Set hgd dir to '%s'", state_path); break; case 'e': crypto_pref = HGD_CRYPTO_PREF_ALWAYS; DPRINTF(HGD_D_DEBUG, "Server will insist on crypto"); break; case 'E': crypto_pref = HGD_CRYPTO_PREF_NEVER; DPRINTF(HGD_D_WARN, "Encryption disabled manually"); break; case 'f': single_client = 1; DPRINTF(HGD_D_DEBUG, "Single client debug mode on"); break; case 'F': flood_limit = atoi(optarg); DPRINTF(HGD_D_DEBUG, "Set flood limit to %d", flood_limit); break; case 'k': free(ssl_key_path); ssl_key_path = optarg; DPRINTF(HGD_D_DEBUG, "set ssl private key path to '%s'", ssl_key_path); break; case 'n': req_votes = atoi(optarg); DPRINTF(HGD_D_DEBUG, "Set required-votes to %d", req_votes); break; case 'p': port = atoi(optarg); DPRINTF(HGD_D_DEBUG, "Set port to %d", port); break; case 's': /* XXX overflow? */ max_upload_size = atoi(optarg) * HGD_MB; DPRINTF(HGD_D_DEBUG, "Set max upload size to %d", (int) max_upload_size); break; case 'S': free(ssl_cert_path); ssl_cert_path = optarg; DPRINTF(HGD_D_DEBUG, "set ssl cert path to '%s'", ssl_cert_path); break; case 'v': hgd_print_version(); exit_ok = 1; hgd_exit_nicely(); break; case 'x': DPRINTF(HGD_D_DEBUG, "set debug to %d", atoi(optarg)); hgd_debug = atoi(optarg); if (hgd_debug > 3) hgd_debug = 3; break; /* already set but over-rideable */ case 'y': free(vote_sound); vote_sound = optarg; DPRINTF(HGD_D_DEBUG, "set voteoff sound %s", vote_sound); break; case 'h': default: hgd_usage(); exit_ok = 1; hgd_exit_nicely(); break; }; } argc -= optind; argv += optind; /* set up paths */ xasprintf(&db_path, "%s/%s", state_path, HGD_DB_NAME); xasprintf(&filestore_path, "%s/%s", state_path, HGD_FILESTORE_NAME); umask(~S_IRWXU); hgd_mk_state_dir(); db = hgd_open_db(db_path, 0); if (db == NULL) hgd_exit_nicely(); sqlite3_close(db); /* re-opened later */ db = NULL; /* unless the user actively disables SSL, we try to be capable */ if (crypto_pref != HGD_CRYPTO_PREF_NEVER) { if (hgd_setup_ssl_ctx(&method, &ctx, 1, ssl_cert_path, ssl_key_path) == 0) { DPRINTF(HGD_D_INFO, "Server is SSL capable"); ssl_capable = 1; } else { DPRINTF(HGD_D_WARN, "Server is SSL incapable"); } } else { DPRINTF(HGD_D_INFO, "Server was forced SSL incapable"); } /* if -e, but something screwed up in the above, bail */ if ((crypto_pref == HGD_CRYPTO_PREF_ALWAYS) && (ssl_capable != 1)) { DPRINTF(HGD_D_ERROR, "Crypto was forced on, but server is incapable"); hgd_exit_nicely(); } /* alright, everything looks good, lets be a daemon and background */ if (background) hgd_daemonise(); hgd_listen_loop(); exit_ok = 1; hgd_exit_nicely(); return (EXIT_SUCCESS); /* NOREACH */ }
void hgd_service_client(int cli_fd, struct sockaddr_in *cli_addr) { struct hgd_session sess; char *recv_line; uint8_t exit, ssl_dead = 0; sess.cli_str = hgd_identify_client(cli_addr); sess.sock_fd = cli_fd; sess.cli_addr = cli_addr; sess.user = NULL; sess.ssl = NULL; if (sess.cli_str == NULL) xasprintf(&sess.cli_str, "unknown"); /* shouldn't happen */ DPRINTF(HGD_D_INFO, "Client connection: '%s'", sess.cli_str); /* oh hai */ hgd_sock_send_line(cli_fd, sess.ssl, HGD_GREET); /* main command recieve loop */ do { recv_line = hgd_sock_recv_line(sess.sock_fd, sess.ssl); exit = hgd_parse_line(&sess, recv_line); free(recv_line); if (num_bad_commands >= HGD_MAX_BAD_COMMANDS) { DPRINTF(HGD_D_WARN,"Client abused server, " "kicking '%s'", sess.cli_str); /* laters */ hgd_sock_send_line(cli_fd, sess.ssl, HGD_BYE_KICK); close(sess.sock_fd); exit_ok = 1; hgd_exit_nicely(); } } while (!exit && !dying && !restarting); /* * client service procs should not respawn as liesteners, * that would suck. This may need tweaking later, as the exit * message may be misinterpreted (?) Handling HUP is hard. */ if (restarting) { dying = 1; restarting = 0; exit_ok = 1; } /* laters */ hgd_sock_send_line(cli_fd, sess.ssl, HGD_BYE); /* free up the hgd_session members */ if (sess.cli_str != NULL) free(sess.cli_str); if (sess.ssl != NULL) { while (!ssl_dead) ssl_dead = SSL_shutdown(sess.ssl); SSL_free(sess.ssl); } if (sess.user) { if (sess.user->name) free(sess.user->name); free(sess.user); } }
int main(int argc, char **argv) { struct ui u; char *config_path[4] = {NULL, NULL, NULL, NULL}; int num_config = 2; memset(&u, 0, sizeof(u)); hgd_debug = 3; /* XXX config file or getopt */ host = xstrdup(HGD_DFL_HOST); #ifdef HAVE_LIBCONFIG config_path[0] = NULL; xasprintf(&config_path[1], "%s", HGD_GLOBAL_CFG_DIR HGD_CLI_CFG ); config_path[2] = hgd_get_XDG_userprefs_location(hgdc); #endif hgd_read_config(config_path + num_config); while(num_config > 0) { if (config_path[num_config] != NULL) { free (config_path[num_config]); config_path[num_config] = NULL; } num_config--; } if (init_log() != HGD_OK) hgd_exit_nicely(); /* XXX proper dialog box needed */ if (password == NULL) { password = xmalloc(HGD_MAX_PASS_SZ); if (readpassphrase("Password: "******"Can't read password"); hgd_exit_nicely(); } } hgd_register_sig_handlers(); initscr(); cbreak(); keypad(stdscr, TRUE); noecho(); if (has_colors()) { if (start_color() == ERR) DPRINTF(HGD_D_WARN, "Could not initialise colour terminal"); } /* XXX fall back implementations for B+W terms? */ init_pair(HGD_CPAIR_BARS, COLOR_YELLOW, COLOR_BLUE); init_pair(HGD_CPAIR_SELECTED, COLOR_BLACK, COLOR_WHITE); init_pair(HGD_CPAIR_DIALOG, COLOR_BLACK, COLOR_CYAN); init_pair(HGD_CPAIR_PBAR_BG, COLOR_YELLOW, COLOR_BLACK); /* initialise top and bottom bars */ if (hgd_init_titlebar(&u) != HGD_OK) hgd_exit_nicely(); if (hgd_init_statusbar(&u) != HGD_OK) hgd_exit_nicely(); /* and all content windows */ if (hgd_init_files_win(&u) != HGD_OK) hgd_exit_nicely(); if (hgd_init_console_win(&u) != HGD_OK) hgd_exit_nicely(); if (hgd_init_playlist_win(&u) != HGD_OK) hgd_exit_nicely(); /* start on the playlist */ hgd_switch_content(&u, HGD_WIN_PLAYLIST); if (user == NULL) user = getenv("USER"); /* XXX duplicated */ if (hgd_ui_connect(&u) != HGD_OK) hgd_exit_nicely(); /* main event loop */ DPRINTF(HGD_D_INFO, "nchgdc event loop starting"); hgd_event_loop(&u); DPRINTF(HGD_D_INFO, "Closing down"); hgd_free_content_win(&u, HGD_WIN_PLAYLIST); hgd_free_content_win(&u, HGD_WIN_FILES); hgd_free_content_win(&u, HGD_WIN_CONSOLE); delwin(u.status); delwin(u.title); exit_ok = 1; hgd_exit_nicely(); return 0; }
int main(int argc, char **argv) { char *config_path[4] = {NULL, NULL, NULL, NULL}; int num_config = 2, ch; /* syslog as early as possible */ HGD_INIT_SYSLOG(); #ifdef HAVE_LIBCONFIG config_path[0] = NULL; xasprintf(&config_path[1], "%s", HGD_GLOBAL_CFG_DIR HGD_SERV_CFG); config_path[2] = hgd_get_XDG_userprefs_location(hgdc); #endif hgd_register_sig_handlers(); state_path = xstrdup(HGD_DFL_DIR); DPRINTF(HGD_D_DEBUG, "Parsing options:1"); while ((ch = getopt(argc, argv, "c:d:hvx:" "c:x:")) != -1) { switch (ch) { case 'c': if (num_config < 3) { num_config++; DPRINTF(HGD_D_DEBUG, "added config %d %s", num_config, optarg); config_path[num_config] = optarg; } else { DPRINTF(HGD_D_WARN, "Too many config files specified"); hgd_exit_nicely(); } break; case 'x': hgd_debug = atoi(optarg); if (hgd_debug > 3) hgd_debug = 3; DPRINTF(HGD_D_DEBUG, "set debug level to %d", hgd_debug); break; default: break; /* next getopt will catch errors */ }; } hgd_read_config(config_path + num_config); while(num_config > 0) { if (config_path[num_config] != NULL) { free (config_path[num_config]); config_path[num_config] = NULL; } num_config--; } RESET_GETOPT(); DPRINTF(HGD_D_DEBUG, "Parsing options:2"); while ((ch = getopt(argc, argv, "c:d:hvx:" "c:x:")) != -1) { switch (ch) { case 'c': break; /* already handled */ case 'd': free(state_path); state_path = xstrdup(optarg); DPRINTF(HGD_D_DEBUG, "set hgd dir to '%s'", state_path); break; case 'v': hgd_print_version(); exit_ok = 1; hgd_exit_nicely(); break; case 'x': DPRINTF(HGD_D_DEBUG, "set debug to %d", atoi(optarg)); hgd_debug = atoi(optarg); if (hgd_debug > 3) hgd_debug = 3; break; /* already set but over-rideable */ case 'h': default: hgd_usage(); exit_ok = 1; hgd_exit_nicely(); break; }; } argc -= optind; argv += optind; xasprintf(&db_path, "%s/%s", state_path, HGD_DB_NAME); xasprintf(&filestore_path, "%s/%s", state_path, HGD_FILESTORE_NAME); umask(~S_IRWXU); hgd_mk_state_dir(); if (hgd_parse_command(argc, argv) == -1) hgd_exit_nicely(); exit_ok = 1; hgd_exit_nicely(); _exit (EXIT_SUCCESS); /* NOREACH */ }
/* * Please do not be tempted to move this to mplayer.c -- * This would cause hgd-admin and hgd-netd to pull in python */ int hgd_play_track(struct hgd_playlist_item *t, uint8_t purge_fs, uint8_t purge_db) { int status = 0, pid, ret = HGD_FAIL; char *ipc_path = 0, *pipe_arg = 0; FILE *ipc_file; struct stat st; DPRINTF(HGD_D_INFO, "Playing '%s' for '%s'", t->filename, t->user); if (hgd_mark_playing(t->id) == HGD_FAIL) goto clean; /* * We will write away the tid of the playing file * hgd-netd uses this to check the user is voting off the track * they think they are. */ xasprintf(&ipc_path, "%s/%s", state_path, HGD_PLAYING_FILE); /* first check the file is non-existent */ if (stat(ipc_path, &st) < 0) { if (errno != ENOENT) { DPRINTF(HGD_D_ERROR, "stale tid file: %s: %s", ipc_path, SERROR); goto clean; } } else { DPRINTF(HGD_D_ERROR, "stale tid file: %s" , ipc_path); goto clean; } if (hgd_file_open_and_lock(ipc_path, F_WRLCK, &ipc_file) != HGD_OK) { DPRINTF(HGD_D_ERROR, "Can't open+lock '%s'", ipc_path); goto clean; } /* try to be secure */ if (chmod(ipc_path, S_IRUSR | S_IWUSR) != 0) DPRINTF(HGD_D_WARN, "Can't secure ipc file: %s", SERROR); /* write away tid of current track to a file for hgd-netd */ if (fprintf(ipc_file, "%d", t->id) < 0) { DPRINTF(HGD_D_ERROR, "Failed to write out tid: %s", SERROR); goto clean; } /* unlock */ if (hgd_file_unlock_and_close(ipc_file) != HGD_OK) { DPRINTF(HGD_D_ERROR, "failed to unlock"); goto clean; } #ifdef HAVE_PYTHON hgd_execute_py_hook("pre_play"); #endif if (hgd_make_mplayer_input_fifo() != HGD_OK) goto clean; xasprintf(&pipe_arg, "file=%s", mplayer_fifo_path); pid = fork(); if (pid < 0) { DPRINTF(HGD_D_ERROR, "Could not fork: %s", SERROR); } else if (!pid) { /* child - your the d00d who will play this track */ execlp(MPLAYER_EXE, MPLAYER_EXE, "-really-quiet", "-slave", "-input", pipe_arg, t->filename, (char *) NULL); /* if we get here, the shit hit the fan with execlp */ DPRINTF(HGD_D_ERROR, "execlp() failed"); hgd_exit_nicely(); /* child should always exit */ } else { DPRINTF(HGD_D_INFO, "Mplayer spawned, waiting to finish: pid=%d", pid); if (waitpid(pid, &status, 0) < 0) { /* it is ok for this to fail if we are restarting */ if (errno != EINTR) DPRINTF(HGD_D_WARN, "Could not wait(): %s", SERROR); if (restarting || dying) { kill(pid, SIGINT); if (waitpid(pid, &status, 0) < 0) { DPRINTF(HGD_D_WARN, "Could not wait(): %s", SERROR); } } } /* unlink ipc file */ if (hgd_file_open_and_lock( ipc_path, F_WRLCK, &ipc_file) != HGD_OK) { DPRINTF(HGD_D_ERROR, "Can't open+lock '%s'", ipc_path); goto clean; } if (unlink(ipc_path) < 0) { DPRINTF(HGD_D_ERROR, "can't unlink ipc file %s: %s", ipc_path, SERROR); goto clean; } if (hgd_file_unlock_and_close(ipc_file) != HGD_OK) { DPRINTF(HGD_D_ERROR, "failed to unlock+close %s: %s", ipc_path, SERROR); } /* unlink input pipe */ if (unlink(mplayer_fifo_path) < 0) DPRINTF(HGD_D_WARN, "Could not unlink mplayer input fifo %s", SERROR); /* unlink media (but not if restarting, we replay the track) */ if ((!restarting) && (!dying) && (purge_fs) && (unlink(t->filename) < 0)) { DPRINTF(HGD_D_DEBUG, "Deleting finished: %s", t->filename); DPRINTF(HGD_D_WARN, "Can't unlink '%s'", ipc_path); } } #ifdef HAVE_PYTHON hgd_execute_py_hook("post_play"); #endif DPRINTF(HGD_D_DEBUG, "Finished playing (exit %d)", status); /* if we are restarting, we replay the track on restart */ if ((!restarting) && (!dying) && (hgd_mark_finished(t->id, purge_db) == HGD_FAIL)) DPRINTF(HGD_D_WARN, "Could not purge/mark finished -- trying to continue"); ret = HGD_OK; clean: if (pipe_arg) free(pipe_arg); if (ipc_path) free(ipc_path); return (ret); }
int main(int argc, char **argv) { char *config_path[4] = {NULL, NULL, NULL, NULL}; int num_config = 2, ch; FILE *hgd_pid; /* early as possible */ hgd_register_sig_handlers(); HGD_INIT_SYSLOG_DAEMON(); #ifdef HAVE_LIBCONFIG config_path[0] = NULL; xasprintf(&config_path[1], "%s", HGD_GLOBAL_CFG_DIR HGD_SERV_CFG); config_path[2] = hgd_get_XDG_userprefs_location(playd); #endif state_path = xstrdup(HGD_DFL_DIR); DPRINTF(HGD_D_DEBUG, "Parsing options:1"); while ((ch = getopt(argc, argv, "Bc:Cd:hpP:qvx:")) != -1) { switch (ch) { case 'c': if (num_config < 3) { num_config++; DPRINTF(HGD_D_DEBUG, "added config %d %s", num_config, optarg); config_path[num_config] = optarg; } else { DPRINTF(HGD_D_WARN, "Too many config files specified"); hgd_exit_nicely(); } break; case 'x': hgd_debug = atoi(optarg); if (hgd_debug > 3) hgd_debug = 3; DPRINTF(HGD_D_DEBUG, "set debug level to %d", hgd_debug); break; default: break; /* catch badness in next getopt */ }; } hgd_read_config(config_path + num_config); while(num_config > 0) { if (config_path[num_config] != NULL) { free (config_path[num_config]); config_path[num_config] = NULL; } num_config--; } RESET_GETOPT(); if (hgd_cache_exec_context(argv) != HGD_OK) hgd_exit_nicely(); DPRINTF(HGD_D_DEBUG, "Parsing options"); while ((ch = getopt(argc, argv, "Bc:Cd:hpP:qvx:")) != -1) { switch (ch) { case 'B': background = 0; DPRINTF(HGD_D_DEBUG, "Not \"backgrounding\" daemon."); break; case 'c': break; /* already handled */ case 'C': clear_playlist_on_start = 1; DPRINTF(HGD_D_DEBUG, "will clear playlist '%s'", state_path); break; case 'd': free(state_path); state_path = xstrdup(optarg); DPRINTF(HGD_D_DEBUG, "set hgd dir to '%s'", state_path); break; case 'p': DPRINTF(HGD_D_DEBUG, "No purging from fs"); purge_finished_fs = 0; break; #ifdef HAVE_PYTHON case 'P': DPRINTF(HGD_D_DEBUG, "Setting python plugin dir"); if (hgd_py_plugin_dir != NULL) free(hgd_py_plugin_dir); hgd_py_plugin_dir = xstrdup(optarg); break; #endif case 'q': DPRINTF(HGD_D_DEBUG, "No purging from db"); purge_finished_db = 0; break; case 'v': hgd_print_version(); exit_ok = 1; hgd_exit_nicely(); break; case 'x': DPRINTF(HGD_D_DEBUG, "set debug to %d", atoi(optarg)); hgd_debug = atoi(optarg); if (hgd_debug > 3) hgd_debug = 3; break; /* already set but over-rideable */ case 'h': default: hgd_usage(); exit_ok = 1; hgd_exit_nicely(); break; }; } argc -= optind; argv += optind; xasprintf(&db_path, "%s/%s", state_path, HGD_DB_NAME); xasprintf(&filestore_path, "%s/%s", state_path, HGD_FILESTORE_NAME); xasprintf(&mplayer_fifo_path, "%s/%s", state_path, HGD_MPLAYER_PIPE_NAME); umask(~S_IRWXU); hgd_mk_state_dir(); if (hgd_check_mplayer_present() != HGD_OK) hgd_exit_nicely(); db = hgd_open_db(db_path, 0); if (db == NULL) hgd_exit_nicely(); if (hgd_init_playstate() != HGD_OK) hgd_exit_nicely(); if (clear_playlist_on_start) { if (hgd_clear_playlist() != HGD_OK) hgd_exit_nicely(); } if (hgd_open_pid_file(&hgd_pid) != HGD_OK) { DPRINTF(HGD_D_ERROR, "Can't open PID file"); return (HGD_FAIL); } /* start */ if (background) hgd_daemonise(); /* do the Python dance */ #ifdef HAVE_PYTHON if (hgd_embed_py(1) != HGD_OK) { DPRINTF(HGD_D_ERROR, "Failed to initialise Python"); hgd_exit_nicely(); } #endif if (hgd_write_pid_file(&hgd_pid) != HGD_OK) { DPRINTF(HGD_D_ERROR, "Can't write PID away"); return (HGD_FAIL); } if (hgd_play_loop() == HGD_OK) exit_ok = 1; if (hgd_unlink_pid_file() != HGD_OK) DPRINTF(HGD_D_ERROR, "Could not unlink pidfile"); hgd_exit_nicely(); _exit (EXIT_SUCCESS); /* NOREACH */ }