2 * Copyright (C) 2006 Andre Noll <maan@systemlinux.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (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 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, USA.
19 /** \file plm_dbtool.c Playlist manager for paraslash */
28 struct plm_client_data {
30 /** allocated and set by com_lpl() (child) */
32 /** initially locked, gets unlocked by parent when it is done */
34 /** return value, set by parent */
38 /** data specific to the plm database tool */
39 struct private_plm_data {
40 /** guards against concurrent client access */
42 /** guards against concurrent parent-child access */
44 /** pointer to the client data */
45 struct plm_client_data *client_data;
46 /** id of the shm corresponding to \a client_data */
47 int client_data_shm_id;
50 /** we refuse to load playlists bigger than that */
51 #define MAX_PLAYLIST_BYTES (1024 * 1024)
53 static unsigned playlist_len, playlist_size, current_playlist_entry;
54 static char **playlist;
55 static struct dbtool *self;
57 static int com_ppl(int, int, char **);
58 static int com_lpl(int, int, char **);
59 extern struct misc_meta_data *mmd;
61 /* array of commands that are supported by this database tool */
62 static struct server_command cmds[] = {
67 .description = "print playlist",
70 "Print out the current playlist"
75 .description = "load playlist",
78 "Read a new playlist from stdin. Example:\n"
79 "\tfind /audio -name '*.mp3' | para_client lpl"
85 static void playlist_add(char *path)
87 if (playlist_len >= playlist_size) {
88 playlist_size = 2 * playlist_size + 1;
89 playlist = para_realloc(playlist, playlist_size * sizeof(char *));
91 PARA_DEBUG_LOG("adding #%d/%d: %s\n", playlist_len, playlist_size, path);
92 playlist[playlist_len++] = para_strdup(path);
95 static int send_playlist_to_server(const char *buf, size_t size)
97 struct private_plm_data *ppd = self->private_data;
98 int ret, shm_mutex = -1, shm_id = -1;
101 PARA_DEBUG_LOG("new playlist (%d bytes)\n", size);
113 ret = shm_attach(shm_id, ATTACH_RW, &shm);
116 mutex_lock(shm_mutex);
117 memcpy(shm, buf, size);
118 mutex_lock(ppd->client_mutex);
119 mutex_lock(ppd->server_mutex);
120 ppd->client_data->size = size;
121 ppd->client_data->shm_id = shm_id;
122 ppd->client_data->mutex = shm_mutex;
123 kill(getppid(), SIGUSR1); /* wake up the server */
124 mutex_unlock(ppd->server_mutex);
125 mutex_lock(shm_mutex); /* wait until server is done */
126 mutex_unlock(shm_mutex);
127 ret = ppd->client_data->retval;
128 mutex_unlock(ppd->client_mutex);
133 mutex_destroy(shm_mutex);
134 PARA_DEBUG_LOG("returning %d\n", ret);
138 static int com_lpl(int fd, __unused int argc, __unused char *argv[])
141 size_t bufsize = 4096; /* guess that's enough */
142 char *buf = para_malloc(bufsize);
144 ret = send_buffer(fd, AWAITING_DATA_MSG);
148 ret = recv_bin_buffer(fd, buf + loaded, bufsize - loaded);
152 ret = send_playlist_to_server(buf, loaded);
156 ret = -E_LOAD_PLAYLIST;
157 if (loaded >= MAX_PLAYLIST_BYTES)
159 if (loaded >= bufsize) {
161 buf = para_realloc(buf, bufsize);
169 static int com_ppl(int fd, __unused int argc, __unused char *argv[])
173 PARA_DEBUG_LOG("sending playlist to client (%d entries)\n", playlist_len);
174 for (i = 0; i < playlist_len; i++) {
175 int ret = send_va_buffer(fd, "%s\n", playlist[
176 (i + current_playlist_entry) % playlist_len]);
183 static char **plm_get_audio_file_list(unsigned int num)
188 num = MIN(num, playlist_len);
191 file_list = para_malloc((num + 1) * sizeof(char *));
192 for (i = 0; i < num; i++) {
193 unsigned j = (current_playlist_entry + i) % playlist_len;
194 file_list[i] = para_strdup(playlist[j]);
200 static void free_playlist_contents(void)
204 PARA_DEBUG_LOG("freeing playlist (%d entries)\n", playlist_len);
205 for (i = 0; i < playlist_len; i++)
207 current_playlist_entry = 0;
211 static void plm_shutdown(void)
213 struct private_plm_data *ppd = self->private_data;
215 shm_detach(ppd->client_data);
216 shm_destroy(ppd->client_data_shm_id);
217 mutex_destroy(ppd->server_mutex);
218 mutex_destroy(ppd->client_mutex);
220 free_playlist_contents();
227 static void plm_post_select(__unused fd_set *rfds, __unused fd_set *wfds)
229 struct private_plm_data *ppd = self->private_data;
230 struct plm_client_data *pcd = ppd->client_data;
234 mutex_lock(ppd->server_mutex);
237 free_playlist_contents();
238 ret = shm_attach(pcd->shm_id, ATTACH_RW, &shm);
240 PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
243 PARA_DEBUG_LOG("loading new playlist (%d bytes)\n", pcd->size);
244 ret = for_each_line((char *)shm, pcd->size, &playlist_add, 0);
246 PARA_NOTICE_LOG("new playlist (%d entries)\n", playlist_len);
249 mutex_unlock(pcd->mutex);
251 mutex_unlock(ppd->server_mutex);
254 void plm_update_audio_file(char *audio_file)
258 for (i = 0; i < playlist_len; i++) {
259 unsigned j = (current_playlist_entry + i) % playlist_len;
260 if (strcmp(playlist[j], audio_file))
262 current_playlist_entry = (j + 1) % playlist_len;
267 * the init function for the plm database tool
269 * Init all function pointers of \a db
271 * \sa struct dbtool, misc_meta_data::dbinfo, mysql.c random_dbtool.c
273 int plm_dbtool_init(struct dbtool *db)
276 struct private_plm_data *ppd = NULL;
281 db->get_audio_file_list = plm_get_audio_file_list;
282 db->shutdown = plm_shutdown;
283 db->post_select = plm_post_select;
284 db->update_audio_file = plm_update_audio_file;
285 ppd = para_calloc(sizeof(struct private_plm_data));
286 db->private_data = ppd;
288 ppd->client_mutex = -1;
289 ppd->server_mutex = -1;
290 ppd->client_data_shm_id = -1;
291 ppd->client_data = NULL;
296 ppd->client_mutex = ret;
301 ppd->server_mutex = ret;
303 ret = shm_new(sizeof(struct plm_client_data));
306 ppd->client_data_shm_id = ret;
308 ret = shm_attach(ppd->client_data_shm_id, ATTACH_RW, &shm);
311 ppd->client_data = shm;
312 ppd->client_data->size = 0;
313 sprintf(mmd->dbinfo, "plm initialized");
316 if (ppd->client_data_shm_id >= 0)
317 shm_destroy(ppd->client_data_shm_id);
318 if (ppd->client_mutex >= 0)
319 mutex_destroy(ppd->client_mutex);
320 if (ppd->server_mutex >= 0)
321 mutex_destroy(ppd->server_mutex);