X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=mysql_selector.c;h=bbc05bdf39ddcf9a4f8e9c503d3d21efff72ae67;hp=d4ccc86845821d02f53edd5868a265ca6bd777f9;hb=61b0a431ca3c5dabfa5445355664f00e312c5299;hpb=c0b370bfc250a599e88b482978c6c50206f7e4a5 diff --git a/mysql_selector.c b/mysql_selector.c index d4ccc868..bbc05bdf 100644 --- a/mysql_selector.c +++ b/mysql_selector.c @@ -1,19 +1,7 @@ /* * Copyright (C) 1999-2007 Andre Noll * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Licensed under the GPL v2. For licencing details see COPYING. */ /** \file mysql_selector.c para_server's mysql-based audio file selector */ @@ -25,7 +13,7 @@ #include "server.cmdline.h" #include "server.h" #include "vss.h" -#include "db.h" +#include "afs.h" #include #include #include @@ -34,11 +22,13 @@ #include "string.h" #include "user_list.h" #include "mysql_selector_command_list.h" +#include "ipc.h" /** pointer to the shared memory area */ extern struct misc_meta_data *mmd; static void *mysql_ptr = NULL; +static int mysql_lock; /** * contains name/replacement pairs used by s_a_r_list() @@ -52,7 +42,7 @@ struct para_macro { const char *replacement; }; -static struct para_macro macro_list[] = { +static const struct para_macro mysql_macro_list[] = { { .name = "IS_N_SET", .replacement = "(data.%s != '1')" }, { @@ -77,11 +67,11 @@ static struct para_macro macro_list[] = { }; /** - * simple search and replace routine + * Simple search and replace routine. * - * \param src source string - * \param macro_name the name of the macro - * \param replacement the replacement format string + * \param src Source String. + * \param macro_name The name of the macro. + * \param replacement The replacement format string. * * In \p src, replace each occurence of \p macro_name(arg) by the string * determined by the \p replacement format string. \p replacement may (but @@ -89,7 +79,7 @@ static struct para_macro macro_list[] = { * replaced by \p arg. * * \return A string in which all matches in \p src are replaced, or \p NULL if - * an syntax error was encountered. Caller must free the result. + * an error was encountered. Caller must free the result. * * \sa regcomp(3) */ @@ -105,7 +95,8 @@ __must_check __malloc static char *s_a_r(const char *src, const char* macro_name if (!macro_name || !replacement || !src) return para_strdup(src); - regcomp(&preg, macro_name, 0); + if (regcomp(&preg, macro_name, 0) != 0) + return NULL; while (regexec(&preg, bufptr, nmatch, pmatch, eflags) != REG_NOMATCH) { char *tmp, *arg, *o_bracket, *c_bracket; @@ -146,9 +137,10 @@ out: * \return \p NULL if one of the underlying calls to \p s_a_r returned \p NULL. * Otherwise the completely expanded version of \p src is returned. */ -__must_check __malloc static char *s_a_r_list(struct para_macro *macro_list, char *src) +__must_check __malloc static char *s_a_r_list(const struct para_macro *macro_list, + char *src) { - struct para_macro *mp = macro_list; + const struct para_macro *mp = macro_list; char *ret = NULL, *tmp = para_strdup(src); while (mp->name) { @@ -163,7 +155,7 @@ __must_check __malloc static char *s_a_r_list(struct para_macro *macro_list, cha return ret; } -static int real_query(const char *query) +static int lockless_real_query(const char *query) { if (!mysql_ptr) return -E_NOTCONN; @@ -176,19 +168,32 @@ static int real_query(const char *query) return 1; } +static int real_query(const char *query) +{ + int ret; + + mutex_lock(mysql_lock); + ret = lockless_real_query(query); + mutex_unlock(mysql_lock); + return ret; +} + /* * Use open connection given by mysql_ptr to query server. Returns a * result pointer on succes and NULL on errors */ static struct MYSQL_RES *get_result(const char *query) { - void *result; + void *result = NULL; - if (real_query(query) < 0) - return NULL; + mutex_lock(mysql_lock); + if (lockless_real_query(query) < 0) + goto out; result = mysql_store_result(mysql_ptr); if (!result) PARA_ERROR_LOG("%s", "store_result error\n"); +out: + mutex_unlock(mysql_lock); return result; } /* @@ -227,11 +232,11 @@ out: return ret; } -static char *escape_blob(const char* old, int size) +static char *escape_blob(const char* old, size_t size) { char *new; - if (!mysql_ptr || size < 0) + if (!mysql_ptr) return NULL; new = para_malloc(2 * size * sizeof(char) + 1); mysql_real_escape_string(mysql_ptr, new, old, size); @@ -367,8 +372,8 @@ int com_picadd(int fd, int argc, char *argv[]) * print results to fd */ static int print_results(int fd, void *result, - unsigned int top, unsigned int left, - unsigned int bottom, unsigned int right) + my_ulonglong top, my_ulonglong left, + my_ulonglong bottom, my_ulonglong right) { unsigned int i,j; int ret; @@ -398,7 +403,7 @@ int com_verb(int fd, int argc, char *argv[]) { void *result = NULL; int ret; - unsigned int num_rows, num_fields; + my_ulonglong num_rows, num_fields, top = 0, left = 0; char *tmp; if (argc < 2) @@ -415,7 +420,7 @@ int com_verb(int fd, int argc, char *argv[]) num_rows = mysql_num_rows(result); ret = 1; if (num_fields && num_rows) - ret = print_results(fd, result, 0, 0, num_rows - 1, + ret = print_results(fd, result, top, left, num_rows - 1, num_fields - 1); mysql_free_result(result); return ret; @@ -434,7 +439,7 @@ static void *get_all_attributes(void) mysql_free_result(result); return NULL; } - mysql_data_seek(result, 4); /* skip Lastplayed, Numplayed... */ + mysql_data_seek(result, (my_ulonglong)4); /* skip Lastplayed, Numplayed... */ return result; } @@ -445,13 +450,18 @@ int com_laa(int fd, int argc, __a_unused char *argv[]) { void *result; int ret; + my_ulonglong top = 0, left = 0, bottom, right = 0; if (argc != 1) return -E_MYSQL_SYNTAX; result = get_all_attributes(); if (!result) return -E_NOATTS; - ret = print_results(fd, result, 0, 0, mysql_num_rows(result) - 5, 0); + bottom = mysql_num_rows(result); + if (bottom < 5) + return -E_MYSQL_SYNTAX; + bottom -= 5; + ret = print_results(fd, result, top, left, bottom, right); mysql_free_result(result); return ret; } @@ -464,7 +474,7 @@ int com_hist(int fd, int argc, char *argv[]) int ret; void *result = NULL; char *q, *atts; - unsigned int num_rows; + my_ulonglong num_rows, top = 0, left = 0, right = 1; if (argc > 3) return -E_MYSQL_SYNTAX; @@ -487,7 +497,7 @@ int com_hist(int fd, int argc, char *argv[]) num_rows = mysql_num_rows(result); ret = 1; if (num_rows) - ret = print_results(fd, result, 0, 0, num_rows - 1, 1); + ret = print_results(fd, result, top, left, num_rows - 1, right); mysql_free_result(result); return ret; } @@ -500,6 +510,7 @@ int com_last(int fd, int argc, char *argv[]) void *result = NULL; char *q; int num, ret; + my_ulonglong top = 0, left = 0, right = 0; if (argc < 2) num = 10; @@ -513,7 +524,8 @@ int com_last(int fd, int argc, char *argv[]) free(q); if (!result) return -E_NORESULT; - ret = print_results(fd, result, 0, 0, mysql_num_rows(result) - 1, 0); + ret = print_results(fd, result, top, left, mysql_num_rows(result) - 1, + right); mysql_free_result(result); return ret; } @@ -523,7 +535,7 @@ int com_mbox(int fd, int argc, char *argv[]) void *result; MYSQL_ROW row; int ret; - unsigned int num_rows, num_fields; + my_ulonglong num_rows, num_fields, top = 0, left = 0; char *query = para_strdup("select concat('From foo@localhost ', " "date_format(Lastplayed, '%a %b %e %T %Y'), " "'\nReceived: from\nTo: bar\n"); @@ -570,7 +582,8 @@ int com_mbox(int fd, int argc, char *argv[]) num_rows = mysql_num_rows(result); if (!num_fields || !num_rows) goto out; - ret = print_results(fd, result, 0, 0, num_rows - 1, num_fields - 1); + ret = print_results(fd, result, top, left, num_rows - 1, + num_fields - 1); out: free(query); if (result) @@ -591,7 +604,8 @@ static char *get_atts(char *name, int verbose) void *result = NULL, *result2 = NULL; MYSQL_ROW row, row2; int i; - unsigned num_fields; + my_ulonglong num_fields, offset = 4; /* skip Lastplayed, Numplayed... */ + result2 = get_all_attributes(); if (!result2) @@ -608,7 +622,7 @@ static char *get_atts(char *name, int verbose) num_fields = mysql_num_fields(result); if (num_fields < 5) goto out; - mysql_data_seek(result2, 4); /* skip Lastplayed, Numplayed... */ + mysql_data_seek(result2, offset); row = mysql_fetch_row(result); if (!row) goto out; @@ -785,7 +799,7 @@ static char *get_query(char *streamname, char *filename, int with_path) continue; arg = line + n; if (!strcmp(command, "accept:")) { - char *tmp2 = s_a_r_list(macro_list, arg); + char *tmp2 = s_a_r_list(mysql_macro_list, arg); if (accept_opts) accept_opts = para_strcat( accept_opts, " or "); @@ -794,7 +808,7 @@ static char *get_query(char *streamname, char *filename, int with_path) continue; } if (!strcmp(command, "deny:")) { - char *tmp2 = s_a_r_list(macro_list, arg); + char *tmp2 = s_a_r_list(mysql_macro_list, arg); if (deny_opts) deny_opts = para_strcat(deny_opts, " or "); deny_opts = para_strcat(deny_opts, tmp2); @@ -802,10 +816,10 @@ static char *get_query(char *streamname, char *filename, int with_path) continue; } if (!score && !strcmp(command, "score:")) - score = s_a_r_list(macro_list, arg); + score = s_a_r_list(mysql_macro_list, arg); } if (!score) { - score = s_a_r_list(macro_list, conf.mysql_default_score_arg); + score = s_a_r_list(mysql_macro_list, conf.mysql_default_score_arg); if (!score) goto out; } @@ -899,7 +913,6 @@ write: return info; } - /* might return NULL */ static char *get_current_audio_file(void) { @@ -910,11 +923,34 @@ static char *get_current_audio_file(void) return name; } +/* If called as child, mmd_lock must be held */ +static void update_mmd(char *info) +{ + PARA_DEBUG_LOG("%s", "updating shared memory area\n"); + strncpy(mmd->selector_info, info, MMD_INFO_SIZE - 1); + mmd->selector_info[MMD_INFO_SIZE - 1] = '\0'; +} + +static void refresh_selector_info(void) +{ + char *name = get_current_audio_file(); + char *info; + + if (!name) + return; + info = get_selector_info(name); + free(name); + mmd_lock(); + update_mmd(info); + mmd_unlock(); + free(info); +} + /* list attributes / print database info */ static int com_la_info(int fd, int argc, char *argv[]) { char *name = NULL, *meta = NULL, *atts = NULL, *dir = NULL; - int ret, com_la = strcmp(argv[0], "info"); + int ret, la = strcmp(argv[0], "info"); if (argc < 2) { ret = -E_GET_AUDIO_FILE; @@ -931,7 +967,7 @@ static int com_la_info(int fd, int argc, char *argv[]) meta = get_meta(name, 1); atts = get_atts(name, 0); dir = get_dir(name); - if (com_la) + if (la) ret = send_va_buffer(fd, "%s\n", atts); else ret = send_va_buffer(fd, "dir: %s\n" "%s\n" "attributes: %s\n", @@ -971,7 +1007,7 @@ static int get_pic_id_by_name(char *name) { char *q, *ebn; void *result = NULL; - long unsigned ret; + int ret; MYSQL_ROW row; if (!(ebn = escaped_basename(name))) @@ -985,7 +1021,7 @@ static int get_pic_id_by_name(char *name) row = mysql_fetch_row(result); ret = -E_NOROW; if (row && row[0]) - ret = atol(row[0]); + ret = atoi(row[0]); mysql_free_result(result); return ret; } @@ -1185,7 +1221,10 @@ int com_picass(int fd, int argc, char *argv[]) */ int com_snp(int fd, int argc, char *argv[]) { - return com_set(fd, argc, argv); + int ret = com_set(fd, argc, argv); + if (ret >= 0) + refresh_selector_info(); + return ret; } /* @@ -1341,7 +1380,7 @@ int com_ls(int fd, int argc, char *argv[]) char *q; void *result; int ret; - unsigned int num_rows; + my_ulonglong num_rows, top = 0, left = 0, right = 0; if (argc > 2) return -E_MYSQL_SYNTAX; @@ -1361,7 +1400,7 @@ int com_ls(int fd, int argc, char *argv[]) num_rows = mysql_num_rows(result); ret = 1; if (num_rows) - ret = print_results(fd, result, 0, 0, num_rows - 1, 0); + ret = print_results(fd, result, top, left, num_rows - 1, right); mysql_free_result(result); return ret; } @@ -1462,14 +1501,6 @@ out: return ret; } -/* If called as child, mmd_lock must be held */ -static void update_mmd(char *info) -{ - PARA_DEBUG_LOG("%s", "updating shared memory area\n"); - strncpy(mmd->selector_info, info, MMD_INFO_SIZE - 1); - mmd->selector_info[MMD_INFO_SIZE - 1] = '\0'; -} - static void update_audio_file_server_handler(char *name) { char *info; @@ -1491,35 +1522,23 @@ int com_us(__a_unused int fd, int argc, char *argv[]) return -E_ESCAPE; ret = update_audio_file(argv[1]); free(tmp); + if (ret >= 0) + refresh_selector_info(); return ret; } -static void refresh_selector_info(void) -{ - char *name = get_current_audio_file(); - char *info; - - if (!name) - return; - info = get_selector_info(name); - free(name); - mmd_lock(); - update_mmd(info); - mmd_unlock(); - free(info); -} - /* select previous / next stream */ static int com_ps_ns(__a_unused int fd, int argc, char *argv[]) { char *query, *stream = get_current_stream(); void *result = get_result("select name from streams"); MYSQL_ROW row; - int match = -1, ret, i; - unsigned int num_rows; + int ret; + my_ulonglong num_rows, match, i; + ret = -E_MYSQL_SYNTAX; if (argc != 1) - return -E_MYSQL_SYNTAX; + goto out; ret = -E_NORESULT; if (!result) goto out; @@ -1534,14 +1553,13 @@ static int com_ps_ns(__a_unused int fd, int argc, char *argv[]) goto out; if (!strcmp(row[0], "current_stream")) continue; - if (!strcmp(row[0], stream)) { - match = i; + if (!strcmp(row[0], stream)) break; - } } ret = -E_NO_STREAM; - if (match < 0) + if (i == num_rows) goto out; + match = i; if (!strcmp(argv[0], "ps")) i = match > 0? match - 1 : num_rows - 1; else @@ -1553,8 +1571,7 @@ static int com_ps_ns(__a_unused int fd, int argc, char *argv[]) goto out; if (!strcmp(row[0], "current_stream")) { if (!strcmp(argv[0], "ps")) { - i = match - 2; - i = i < 0? i + num_rows : i; + i = match < 2? match + num_rows - 2 : match - 2; } else { i = match + 2; i = i > num_rows - 1? i - num_rows : i; @@ -1929,9 +1946,9 @@ static int com_vrfy_clean(int fd, int argc, __a_unused char *argv[]) char *query; int ret, vrfy_mode = strcmp(argv[0], "clean"); void *result = NULL; - unsigned int num_rows; MYSQL_ROW row; char *escaped_name; + my_ulonglong num_rows, top = 0, left = 0, right = 0; if (argc != 1) return -E_MYSQL_SYNTAX; @@ -1946,9 +1963,9 @@ static int com_vrfy_clean(int fd, int argc, __a_unused char *argv[]) goto out; } if (vrfy_mode) { - send_va_buffer(fd, "found %i invalid entr%s\n", num_rows, + send_va_buffer(fd, "found %lli invalid entr%s\n", num_rows, num_rows == 1? "y" : "ies"); - ret = print_results(fd, result, 0, 0, num_rows - 1, 0); + ret = print_results(fd, result, top, left, num_rows - 1, right); goto out; } while ((row = mysql_fetch_row(result))) { @@ -2136,14 +2153,17 @@ success: static int init_mysql_server(void) { char *u = conf.mysql_user_arg? conf.mysql_user_arg : para_logname(); + unsigned int port; mysql_ptr = mysql_init(NULL); if (!mysql_ptr) { PARA_CRIT_LOG("%s", "mysql init error\n"); return -E_NOTCONN; } - PARA_DEBUG_LOG("connecting: %s@%s:%d\n", u, conf.mysql_host_arg, - conf.mysql_port_arg); + if (conf.mysql_port_arg < 0) + return -E_MYSQL_SYNTAX; + port = conf.mysql_port_arg; + PARA_DEBUG_LOG("connecting: %s@%s:%d\n", u, conf.mysql_host_arg, port); if (!conf.mysql_user_arg) free(u); /* @@ -2155,7 +2175,7 @@ static int init_mysql_server(void) conf.mysql_user_arg, conf.mysql_passwd_arg, conf.mysql_database_arg, - conf.mysql_port_arg, NULL, 0))) { + port, NULL, 0))) { PARA_CRIT_LOG("%s", "connect error\n"); return -E_NOTCONN; } @@ -2240,11 +2260,19 @@ out: static void shutdown_connection(void) { + int ret; + if (mysql_ptr) { PARA_NOTICE_LOG("%s", "shutting down mysql connection\n"); mysql_close(mysql_ptr); mysql_ptr = NULL; } + if (mysql_lock) { + ret = mutex_destroy(mysql_lock); + if (ret < 0) + PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret)); + mysql_lock = 0; + } } /** @@ -2276,6 +2304,10 @@ int mysql_selector_init(struct audio_file_selector *db) db->get_audio_file_list = server_get_audio_file_list; db->update_audio_file = update_audio_file_server_handler; db->shutdown = shutdown_connection; + ret = mutex_new(); + if (ret < 0) + return ret; + mysql_lock = ret; ret = init_mysql_server(); if (ret < 0) PARA_WARNING_LOG("%s\n", PARA_STRERROR(-ret));