2 * Copyright (C) 2007 by INdT
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 * @author Gustavo Sverzut Barbieri <gustavo.barbieri@openbossa.org>
26 #include <sys/types.h>
40 #include "lightmediascanner.h"
41 #include "lightmediascanner_plugin.h"
42 #include "lightmediascanner_db_private.h"
43 #include "lightmediascanner_charset_conv.h"
45 #define PATH_SIZE PATH_MAX
46 #define DEFAULT_SLAVE_TIMEOUT 1000
47 #define DEFAULT_COMMIT_INTERVAL 100
54 /* info to be carried along lms_process() */
70 struct parser *parsers;
72 lms_charset_conv_t *cs_conv;
75 unsigned int commit_interval;
76 unsigned int is_processing:1;
81 sqlite3_stmt *transaction_begin;
82 sqlite3_stmt *transaction_commit;
83 sqlite3_stmt *transaction_rollback;
84 sqlite3_stmt *get_file_info;
85 sqlite3_stmt *insert_file_info;
86 sqlite3_stmt *update_file_info;
87 sqlite3_stmt *delete_file_info;
88 sqlite3_stmt *clear_file_dtime;
91 /***********************************************************************
92 * Master-Slave communication.
93 ***********************************************************************/
96 _master_send_path(const struct fds *master, int plen, int dlen, const char *p)
103 if (write(master->w, lengths, sizeof(lengths)) < 0) {
108 if (write(master->w, p, plen) < 0) {
117 _master_send_finish(const struct fds *master)
119 const int lengths[2] = {-1, -1};
121 if (write(master->w, lengths, sizeof(lengths)) < 0) {
129 _master_recv_reply(const struct fds *master, struct pollfd *pfd, int *reply, int timeout)
133 r = poll(pfd, 1, timeout);
142 if (read(master->r, reply, sizeof(*reply)) != sizeof(*reply)) {
151 _slave_send_reply(const struct fds *slave, int reply)
153 if (write(slave->w, &reply, sizeof(reply)) == 0) {
161 _slave_recv_path(const struct fds *slave, int *plen, int *dlen, char *path)
165 r = read(slave->r, lengths, sizeof(lengths));
166 if (r != sizeof(lengths)) {
176 if (*plen > PATH_SIZE) {
177 fprintf(stderr, "ERROR: path too long (%d/%d)\n", *plen, PATH_SIZE);
181 r = read(slave->r, path, *plen);
183 fprintf(stderr, "ERROR: could not read whole path %d/%d\n", r, *plen);
192 /***********************************************************************
194 ***********************************************************************/
197 _db_create_tables_if_required(sqlite3 *db)
204 "CREATE TABLE IF NOT EXISTS lms_internal ("
205 "tab TEXT NOT NULL UNIQUE, "
206 "version INTEGER NOT NULL"
208 NULL, NULL, &errmsg);
209 if (r != SQLITE_OK) {
210 fprintf(stderr, "ERROR: could not create 'lms_internal' table: %s\n",
212 sqlite3_free(errmsg);
217 "CREATE TABLE IF NOT EXISTS files ("
218 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
219 "path BLOB NOT NULL UNIQUE, "
220 "mtime INTEGER NOT NULL, "
221 "dtime INTEGER NOT NULL, "
222 "size INTEGER NOT NULL"
224 NULL, NULL, &errmsg);
225 if (r != SQLITE_OK) {
226 fprintf(stderr, "ERROR: could not create 'files' table: %s\n", errmsg);
227 sqlite3_free(errmsg);
232 "CREATE INDEX IF NOT EXISTS files_path_idx ON files ("
235 NULL, NULL, &errmsg);
236 if (r != SQLITE_OK) {
237 fprintf(stderr, "ERROR: could not create 'files_path_idx' index: %s\n",
239 sqlite3_free(errmsg);
247 _db_compile_all_stmts(struct db *db)
249 db->transaction_begin = lms_db_compile_stmt(db->handle,
250 "BEGIN TRANSACTION");
251 if (!db->transaction_begin)
254 db->transaction_commit = lms_db_compile_stmt(db->handle,
256 if (!db->transaction_commit)
259 db->transaction_rollback = lms_db_compile_stmt(db->handle,
261 if (!db->transaction_rollback)
264 db->get_file_info = lms_db_compile_stmt(db->handle,
265 "SELECT id, mtime, dtime, size FROM files WHERE path = ?");
266 if (!db->get_file_info)
269 db->insert_file_info = lms_db_compile_stmt(db->handle,
270 "INSERT INTO files (path, mtime, dtime, size) VALUES(?, ?, ?, ?)");
271 if (!db->insert_file_info)
274 db->update_file_info = lms_db_compile_stmt(db->handle,
275 "UPDATE files SET mtime = ?, dtime = ?, size = ? WHERE id = ?");
276 if (!db->update_file_info)
279 db->delete_file_info = lms_db_compile_stmt(db->handle,
280 "DELETE FROM files WHERE id = ?");
281 if (!db->delete_file_info)
284 db->clear_file_dtime = lms_db_compile_stmt(db->handle,
285 "UPDATE files SET dtime = 0 WHERE id = ?");
286 if (!db->clear_file_dtime)
293 _db_open(const char *db_path)
297 db = calloc(1, sizeof(*db));
303 if (sqlite3_open(db_path, &db->handle) != SQLITE_OK) {
304 fprintf(stderr, "ERROR: could not open DB \"%s\": %s\n",
305 db_path, sqlite3_errmsg(db->handle));
309 if (_db_create_tables_if_required(db->handle) != 0) {
310 fprintf(stderr, "ERROR: could not setup tables and indexes.\n");
317 sqlite3_close(db->handle);
323 _db_close(struct db *db)
325 if (db->transaction_begin)
326 lms_db_finalize_stmt(db->transaction_begin, "transaction_begin");
328 if (db->transaction_commit)
329 lms_db_finalize_stmt(db->transaction_commit, "transaction_commit");
331 if (db->transaction_rollback)
332 lms_db_finalize_stmt(db->transaction_rollback, "transaction_rollback");
334 if (db->get_file_info)
335 lms_db_finalize_stmt(db->get_file_info, "get_file_info");
337 if (db->insert_file_info)
338 lms_db_finalize_stmt(db->insert_file_info, "insert_file_info");
340 if (db->update_file_info)
341 lms_db_finalize_stmt(db->update_file_info, "update_file_info");
343 if (db->delete_file_info)
344 lms_db_finalize_stmt(db->delete_file_info, "delete_file_info");
346 if (db->clear_file_dtime)
347 lms_db_finalize_stmt(db->clear_file_dtime, "clear_file_dtime");
349 if (sqlite3_close(db->handle) != SQLITE_OK) {
350 fprintf(stderr, "ERROR: clould not close DB: %s\n",
351 sqlite3_errmsg(db->handle));
360 _db_begin_transaction(struct db *db)
365 stmt = db->transaction_begin;
368 r = sqlite3_step(stmt);
369 if (r != SQLITE_DONE) {
370 fprintf(stderr, "ERROR: could not begin transaction: %s\n",
371 sqlite3_errmsg(db->handle));
375 r = sqlite3_reset(stmt);
377 fprintf(stderr, "ERROR: could not reset SQL statement: %s\n",
378 sqlite3_errmsg(db->handle));
384 _db_end_transaction(struct db *db)
389 stmt = db->transaction_commit;
392 r = sqlite3_step(stmt);
393 if (r != SQLITE_DONE) {
394 fprintf(stderr, "ERROR: could not end transaction: %s\n",
395 sqlite3_errmsg(db->handle));
399 r = sqlite3_reset(stmt);
401 fprintf(stderr, "ERROR: could not reset SQL statement: %s\n",
402 sqlite3_errmsg(db->handle));
408 _db_get_file_info(struct db *db, struct lms_file_info *finfo)
413 stmt = db->get_file_info;
415 ret = lms_db_bind_blob(stmt, 1, finfo->path, finfo->path_len);
419 r = sqlite3_step(stmt);
420 if (r == SQLITE_DONE) {
426 if (r != SQLITE_ROW) {
427 fprintf(stderr, "ERROR: could not get file info from table: %s\n",
428 sqlite3_errmsg(db->handle));
433 finfo->id = sqlite3_column_int64(stmt, 0);
434 finfo->mtime = sqlite3_column_int(stmt, 1);
435 finfo->dtime = sqlite3_column_int(stmt, 2);
436 finfo->size = sqlite3_column_int(stmt, 3);
440 lms_db_reset_stmt(stmt);
446 _db_update_file_info(struct db *db, struct lms_file_info *finfo)
451 stmt = db->update_file_info;
453 ret = lms_db_bind_int(stmt, 1, finfo->mtime);
457 ret = lms_db_bind_int(stmt, 2, finfo->dtime);
461 ret = lms_db_bind_int(stmt, 3, finfo->size);
465 ret = lms_db_bind_int(stmt, 4, finfo->id);
469 r = sqlite3_step(stmt);
470 if (r != SQLITE_DONE) {
471 fprintf(stderr, "ERROR: could not update file info: %s\n",
472 sqlite3_errmsg(db->handle));
480 lms_db_reset_stmt(stmt);
486 _db_insert_file_info(struct db *db, struct lms_file_info *finfo)
491 stmt = db->insert_file_info;
493 ret = lms_db_bind_blob(stmt, 1, finfo->path, finfo->path_len);
497 ret = lms_db_bind_int(stmt, 2, finfo->mtime);
501 ret = lms_db_bind_int(stmt, 3, finfo->dtime);
505 ret = lms_db_bind_int(stmt, 4, finfo->size);
509 r = sqlite3_step(stmt);
510 if (r != SQLITE_DONE) {
511 fprintf(stderr, "ERROR: could not insert file info: %s\n",
512 sqlite3_errmsg(db->handle));
517 finfo->id = sqlite3_last_insert_rowid(db->handle);
521 lms_db_reset_stmt(stmt);
527 _db_delete_file_info(struct db *db, struct lms_file_info *finfo)
532 stmt = db->delete_file_info;
534 ret = lms_db_bind_int64(stmt, 1, finfo->id);
538 r = sqlite3_step(stmt);
539 if (r != SQLITE_DONE) {
540 fprintf(stderr, "ERROR: could not delete file info: %s\n",
541 sqlite3_errmsg(db->handle));
548 lms_db_reset_stmt(stmt);
554 _db_clear_file_dtime(struct db *db, struct lms_file_info *finfo)
559 stmt = db->clear_file_dtime;
561 ret = lms_db_bind_int64(stmt, 1, finfo->id);
565 r = sqlite3_step(stmt);
566 if (r != SQLITE_DONE) {
567 fprintf(stderr, "ERROR: could not clear file dtime: %s\n",
568 sqlite3_errmsg(db->handle));
577 lms_db_reset_stmt(stmt);
583 _retrieve_file_status(struct db *db, struct lms_file_info *finfo)
588 if (stat(finfo->path, &st) != 0) {
593 r = _db_get_file_info(db, finfo);
595 if (st.st_mtime <= finfo->mtime && finfo->size == st.st_size)
598 finfo->mtime = st.st_mtime;
599 finfo->size = st.st_size;
603 finfo->mtime = st.st_mtime;
604 finfo->size = st.st_size;
611 _ctxt_init(struct lms_context *ctxt, const lms_t *lms, const struct db *db)
613 ctxt->cs_conv = lms->cs_conv;
614 ctxt->db = db->handle;
617 static int _parser_del_int(lms_t *lms, int i);
620 _parsers_setup(lms_t *lms, struct db *db)
622 struct lms_context ctxt;
625 _ctxt_init(&ctxt, lms, db);
627 for (i = 0; i < lms->n_parsers; i++) {
628 lms_plugin_t *plugin;
631 plugin = lms->parsers[i].plugin;
632 r = plugin->setup(plugin, &ctxt);
634 fprintf(stderr, "ERROR: parser \"%s\" failed to setup: %d.\n",
636 plugin->finish(plugin, &ctxt);
637 _parser_del_int(lms, i);
638 i--; /* cancel i++ */
646 _parsers_start(lms_t *lms, struct db *db)
648 struct lms_context ctxt;
651 _ctxt_init(&ctxt, lms, db);
653 for (i = 0; i < lms->n_parsers; i++) {
654 lms_plugin_t *plugin;
657 plugin = lms->parsers[i].plugin;
658 r = plugin->start(plugin, &ctxt);
660 fprintf(stderr, "ERROR: parser \"%s\" failed to start: %d.\n",
662 plugin->finish(plugin, &ctxt);
663 _parser_del_int(lms, i);
664 i--; /* cancel i++ */
672 _parsers_finish(lms_t *lms, struct db *db)
674 struct lms_context ctxt;
677 _ctxt_init(&ctxt, lms, db);
679 for (i = 0; i < lms->n_parsers; i++) {
680 lms_plugin_t *plugin;
683 plugin = lms->parsers[i].plugin;
684 r = plugin->finish(plugin, &ctxt);
686 fprintf(stderr, "ERROR: parser \"%s\" failed to finish: %d.\n",
694 _parsers_check_using(lms_t *lms, void **parser_match, struct lms_file_info *finfo)
699 for (i = 0; i < lms->n_parsers; i++) {
700 lms_plugin_t *plugin;
703 plugin = lms->parsers[i].plugin;
704 r = plugin->match(plugin, finfo->path, finfo->path_len, finfo->base);
714 _parsers_run(lms_t *lms, struct db *db, void **parser_match, struct lms_file_info *finfo)
716 struct lms_context ctxt;
717 int i, failed, available;
719 _ctxt_init(&ctxt, lms, db);
723 for (i = 0; i < lms->n_parsers; i++) {
724 lms_plugin_t *plugin;
726 plugin = lms->parsers[i].plugin;
727 if (parser_match[i]) {
731 r = plugin->parse(plugin, &ctxt, finfo, parser_match[i]);
739 else if (failed == available)
742 return 1; /* non critical */
746 _slave_work(lms_t *lms, struct fds *fds)
748 int r, len, base, counter;
749 char path[PATH_SIZE];
753 db = _db_open(lms->db_path);
757 if (_parsers_setup(lms, db) != 0) {
758 fprintf(stderr, "ERROR: could not setup parsers.\n");
763 if (_db_compile_all_stmts(db) != 0) {
764 fprintf(stderr, "ERROR: could not compile statements.\n");
769 if (_parsers_start(lms, db) != 0) {
770 fprintf(stderr, "ERROR: could not start parsers.\n");
774 if (lms->n_parsers < 1) {
775 fprintf(stderr, "ERROR: no parser could be started, exit.\n");
780 parser_match = malloc(lms->n_parsers * sizeof(*parser_match));
788 _db_begin_transaction(db);
790 while (((r = _slave_recv_path(fds, &len, &base, path)) == 0) && len > 0) {
791 struct lms_file_info finfo;
795 finfo.path_len = len;
798 r = _retrieve_file_status(db, &finfo);
801 _db_clear_file_dtime(db, &finfo);
804 fprintf(stderr, "ERROR: could not detect file status.\n");
808 used = _parsers_check_using(lms, parser_match, &finfo);
814 r = _db_update_file_info(db, &finfo);
816 r = _db_insert_file_info(db, &finfo);
818 fprintf(stderr, "ERROR: could not register path in DB\n");
822 r = _parsers_run(lms, db, parser_match, &finfo);
824 fprintf(stderr, "ERROR: pid=%d failed to parse \"%s\".\n",
825 getpid(), finfo.path);
826 _db_delete_file_info(db, &finfo);
830 _slave_send_reply(fds, r);
832 if (counter > lms->commit_interval) {
833 _db_end_transaction(db);
834 _db_begin_transaction(db);
840 _db_end_transaction(db);
842 _parsers_finish(lms, db);
849 /***********************************************************************
851 ***********************************************************************/
854 _consume_garbage(struct pollfd *pfd)
858 while ((r = poll(pfd, 1, 0)) > 0) {
859 if (pfd->revents & (POLLERR | POLLHUP | POLLNVAL))
861 else if (pfd->revents & POLLIN) {
864 read(pfd->fd, &c, sizeof(c));
872 _close_fds(struct fds *fds)
877 if (close(fds->r) != 0) {
882 if (close(fds->w) != 0) {
891 _close_pipes(struct pinfo *pinfo)
895 r = _close_fds(&pinfo->master);
896 r += _close_fds(&pinfo->slave);
902 _create_pipes(struct pinfo *pinfo)
906 if (pipe(fds) != 0) {
910 pinfo->master.r = fds[0];
911 pinfo->slave.w = fds[1];
913 if (pipe(fds) != 0) {
915 close(pinfo->master.r);
916 close(pinfo->slave.w);
919 pinfo->slave.r = fds[0];
920 pinfo->master.w = fds[1];
922 pinfo->poll.fd = pinfo->master.r;
923 pinfo->poll.events = POLLIN;
929 _create_slave(struct pinfo *pinfo)
933 pinfo->child = fork();
934 if (pinfo->child == -1) {
939 if (pinfo->child > 0)
942 _close_fds(&pinfo->master);
944 r = _slave_work(pinfo->lms, &pinfo->slave);
945 lms_free(pinfo->lms);
947 return r; /* shouldn't reach anyway... */
956 r = waitpid(pid, &status, 0);
966 _finish_slave(struct pinfo *pinfo)
970 if (pinfo->child <= 0)
973 r = _master_send_finish(&pinfo->master);
975 r = _waitpid(pinfo->child);
977 r = kill(pinfo->child, SIGKILL);
981 r =_waitpid(pinfo->child);
988 _restart_slave(struct pinfo *pinfo)
992 if (waitpid(pinfo->child, &status, WNOHANG) > 0) {
993 if (WIFEXITED(status)) {
996 code = WEXITSTATUS(status);
998 fprintf(stderr, "ERROR: slave returned %d, exit.\n", code);
1003 if (WIFSIGNALED(status)) {
1006 code = WTERMSIG(status);
1007 fprintf(stderr, "ERROR: slave was terminated by signal %d.\n",
1015 if (kill(pinfo->child, SIGKILL))
1018 if (waitpid(pinfo->child, &status, 0) < 0)
1021 _consume_garbage(&pinfo->poll);
1022 return _create_slave(pinfo);
1026 _strcat(int base, char *path, const char *name)
1028 int new_len, name_len;
1030 name_len = strlen(name);
1031 new_len = base + name_len;
1033 if (new_len >= PATH_SIZE) {
1036 "ERROR: path concatenation too long %d of %d "
1037 "available: \"%s\" + \"%s\"\n", new_len, PATH_SIZE,
1042 memcpy(path + base, name, name_len + 1);
1048 _process_file(struct pinfo *pinfo, int base, char *path, const char *name)
1050 int new_len, reply, r;
1052 new_len = _strcat(base, path, name);
1056 if (_master_send_path(&pinfo->master, new_len, base, path) != 0)
1059 r = _master_recv_reply(&pinfo->master, &pinfo->poll, &reply,
1060 pinfo->lms->slave_timeout);
1064 fprintf(stderr, "ERROR: slave took too long, restart %d\n",
1066 if (_restart_slave(pinfo) != 0)
1071 /* XXX callback library users to inform error. */
1072 fprintf(stderr, "ERROR: pid=%d failed to parse \"%s\".\n",
1074 return (-reply) << 8;
1081 _process_dir(struct pinfo *pinfo, int base, char *path, const char *name)
1087 new_len = _strcat(base, path, name);
1090 else if (new_len + 1 >= PATH_SIZE) {
1091 fprintf(stderr, "ERROR: path too long\n");
1095 dir = opendir(path);
1101 path[new_len] = '/';
1105 while ((de = readdir(dir)) != NULL) {
1106 if (de->d_name[0] == '.')
1108 if (de->d_type == DT_REG) {
1109 if (_process_file(pinfo, new_len, path, de->d_name) < 0) {
1110 path[new_len - 1] = '\0';
1112 "ERROR: unrecoverable error parsing file, "
1113 "exit \"%s\".\n", path);
1117 } else if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
1118 if (_process_dir(pinfo, new_len, path, de->d_name) < 0) {
1119 path[new_len - 1] = '\0';
1121 "ERROR: unrecoverable error parsing dir, "
1122 "exit \"%s\".\n", path);
1135 /***********************************************************************
1137 ***********************************************************************/
1140 _parser_load(struct parser *p, const char *so_path)
1142 lms_plugin_t *(*plugin_open)(void);
1145 memset(p, 0, sizeof(*p));
1147 p->dl_handle = dlopen(so_path, RTLD_NOW | RTLD_LOCAL);
1150 fprintf(stderr, "ERROR: could not dlopen() %s\n", errmsg);
1154 plugin_open = dlsym(p->dl_handle, "lms_plugin_open");
1157 fprintf(stderr, "ERROR: could not find plugin entry point %s\n",
1162 p->so_path = strdup(so_path);
1168 p->plugin = plugin_open();
1170 fprintf(stderr, "ERROR: plugin \"%s\" failed to init.\n", so_path);
1178 _parser_unload(struct parser *p)
1184 if (p->plugin->close(p->plugin) != 0) {
1185 fprintf(stderr, "ERROR: plugin \"%s\" failed to deinit.\n",
1194 dlclose(p->dl_handle);
1197 fprintf(stderr, "ERROR: could not dlclose() plugin \"%s\": %s\n",
1198 errmsg, p->so_path);
1210 /***********************************************************************
1212 ***********************************************************************/
1214 lms_new(const char *db_path)
1218 lms = calloc(1, sizeof(lms_t));
1224 lms->cs_conv = lms_charset_conv_new();
1225 if (!lms->cs_conv) {
1230 lms->commit_interval = DEFAULT_COMMIT_INTERVAL;
1231 lms->slave_timeout = DEFAULT_SLAVE_TIMEOUT;
1232 lms->db_path = strdup(db_path);
1233 if (!lms->db_path) {
1235 lms_charset_conv_free(lms->cs_conv);
1244 lms_free(lms_t *lms)
1251 if (lms->is_processing)
1255 for (i = 0; i < lms->n_parsers; i++)
1256 _parser_unload(lms->parsers + i);
1262 lms_charset_conv_free(lms->cs_conv);
1268 lms_parser_add(lms_t *lms, const char *so_path)
1270 struct parser *parser;
1278 if (lms->is_processing) {
1279 fprintf(stderr, "ERROR: do not add parsers while it's processing.\n");
1283 lms->parsers = realloc(lms->parsers,
1284 (lms->n_parsers + 1) * sizeof(struct parser));
1285 if (!lms->parsers) {
1290 parser = lms->parsers + lms->n_parsers;
1291 if (_parser_load(parser, so_path) != 0) {
1292 _parser_unload(parser);
1297 return parser->plugin;
1301 lms_parser_find_and_add(lms_t *lms, const char *name)
1303 char so_path[PATH_MAX];
1310 snprintf(so_path, sizeof(so_path), "%s/%s.so", PLUGINSDIR, name);
1311 return lms_parser_add(lms, so_path);
1315 _parser_del_int(lms_t *lms, int i)
1317 struct parser *parser;
1319 parser = lms->parsers + i;
1320 _parser_unload(parser);
1323 if (lms->n_parsers == 0) {
1325 lms->parsers = NULL;
1330 dif = lms->n_parsers - i;
1332 lms->parsers = memmove(parser, parser + 1,
1333 dif * sizeof(struct parser));
1335 lms->parsers = realloc(lms->parsers,
1336 lms->n_parsers * sizeof(struct parser));
1337 if (!lms->parsers) {
1347 lms_parser_del(lms_t *lms, lms_plugin_t *handle)
1357 if (lms->is_processing) {
1358 fprintf(stderr, "ERROR: do not del parsers while it's processing.\n");
1362 for (i = 0; i < lms->n_parsers; i++)
1363 if (lms->parsers[i].plugin == handle)
1364 return _parser_del_int(lms, i);
1370 lms_process(lms_t *lms, const char *top_path)
1374 char path[PATH_SIZE], *bname;
1386 if (lms->is_processing) {
1387 fprintf(stderr, "ERROR: is already processing.\n");
1392 if (!lms->parsers) {
1393 fprintf(stderr, "ERROR: no plugins registered.\n");
1400 if (_create_pipes(&pinfo) != 0) {
1405 if (_create_slave(&pinfo) != 0) {
1410 if (realpath(top_path, path) == NULL) {
1416 /* search '/' backwards, split dirname and basename, note realpath usage */
1418 for (; len >= 0 && path[len] != '/'; len--);
1420 bname = strdup(path + len);
1421 if (bname == NULL) {
1427 lms->is_processing = 1;
1428 r = _process_dir(&pinfo, len, path, bname);
1429 lms->is_processing = 0;
1433 _finish_slave(&pinfo);
1435 _close_pipes(&pinfo);
1441 lms_is_processing(const lms_t *lms)
1444 fprintf(stderr, "ERROR: lms_is_processing(NULL)\n");
1448 return lms->is_processing;
1452 lms_get_db_path(const lms_t *lms)
1455 fprintf(stderr, "ERROR: lms_get_db_path(NULL)\n");
1459 return lms->db_path;
1463 lms_get_slave_timeout(const lms_t *lms)
1466 fprintf(stderr, "ERROR: lms_get_slave_timeout(NULL)\n");
1470 return lms->slave_timeout;
1473 void lms_set_slave_timeout(lms_t *lms, int ms)
1476 fprintf(stderr, "ERROR: lms_set_slave_timeout(NULL, %d)\n", ms);
1480 lms->slave_timeout = ms;
1484 lms_get_commit_interval(const lms_t *lms)
1487 fprintf(stderr, "ERROR: lms_get_commit_interval(NULL)\n");
1488 return (unsigned int)-1;
1491 return lms->commit_interval;
1495 lms_set_commit_interval(lms_t *lms, unsigned int transactions)
1498 fprintf(stderr, "ERROR: lms_set_commit_interval(NULL, %u)\n",
1503 lms->commit_interval = transactions;
1507 lms_charset_add(lms_t *lms, const char *charset)
1510 fprintf(stderr, "ERROR: lms_charset_add(NULL)\n");
1514 return lms_charset_conv_add(lms->cs_conv, charset);
1518 lms_charset_del(lms_t *lms, const char *charset)
1521 fprintf(stderr, "ERROR: lms_charset_del(NULL)\n");
1525 return lms_charset_conv_del(lms->cs_conv, charset);