- new ls option: -lc (list chunk table)
- new executable: para_afh, the stand-alone audio file handler tool
+ - afs commands can send output more than SHMMAX (32MB on Linux). This
+ also reduces the memory usage of commands that produce large amounts
+ of output.
---------------------------------------
0.3.1 (2008-02-23) "liquid interaction"
return 1;
}
-static int com_select_callback(const struct osl_object *query,
- struct osl_object *result)
+static void com_select_callback(int fd, const struct osl_object *query)
{
- struct para_buffer pb = {.buf = NULL};
+ struct para_buffer pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ };
char *arg = query->data;
- int num_admissible, ret;
+ int num_admissible, ret, ret2;
ret = clear_score_table();
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ ret2 = para_printf(&pb, "%s\n", para_strerror(-ret));
+ goto out;
+ }
if (current_play_mode == PLAY_MODE_MOOD)
close_current_mood();
else
playlist_close();
ret = activate_mood_or_playlist(arg, &num_admissible);
if (ret < 0) {
- para_printf(&pb, "%s\n", para_strerror(-ret));
- para_printf(&pb, "switching back to %s\n", current_mop?
+ ret2 = para_printf(&pb, "%s\nswitching back to %s\n",
+ para_strerror(-ret), current_mop?
current_mop : "dummy");
ret = activate_mood_or_playlist(current_mop, &num_admissible);
if (ret < 0) {
- para_printf(&pb, "failed, switching to dummy\n");
+ if (ret2 >= 0)
+ ret2 = para_printf(&pb, "failed, switching to dummy\n");
activate_mood_or_playlist(NULL, &num_admissible);
}
- }
- para_printf(&pb, "activated %s (%d admissible files)\n", current_mop?
- current_mop : "dummy mood", num_admissible);
- result->data = pb.buf;
- result->size = pb.offset;
- return 1;
+ } else
+ ret2 = para_printf(&pb, "activated %s (%d admissible files)\n", current_mop?
+ current_mop : "dummy mood", num_admissible);
+out:
+ if (ret2 >= 0 && pb.offset)
+ pass_buffer_as_shm(pb.buf, pb.offset, &fd);
+ free(pb.buf);
}
int send_result(struct osl_object *result, void *private_result_data)
t->ret = 1;
}
-int pass_object_as_shm(int fd, struct osl_object *obj)
+int pass_buffer_as_shm(char *buf, size_t size, void *private_data)
{
- int ret, shmid;
+ int ret, shmid, fd = *(int *)private_data;
void *shm;
struct callback_result *cr;
- if (!obj->data || !obj->size)
+ if (!buf || !size)
return 0;
- ret = shm_new(obj->size + sizeof(struct callback_result));
+ ret = shm_new(size + sizeof(struct callback_result));
if (ret < 0)
return ret;
shmid = ret;
if (ret < 0)
goto err;
cr = shm;
- cr->result_size = obj->size;
- memcpy(shm + sizeof(*cr), obj->data, obj->size);
+ cr->result_size = size;
+ memcpy(shm + sizeof(*cr), buf, size);
ret = shm_detach(shm);
if (ret < 0)
goto err;
* On success: If query produced a result, the result_shmid is written to fd.
* Otherwise, zero is written.
*/
-static void call_callback(int fd, int query_shmid)
+static int call_callback(int fd, int query_shmid)
{
void *query_shm;
struct callback_query *cq;
- struct osl_object query, result = {.data = NULL};
+ struct osl_object query;
int ret;
ret = shm_attach(query_shmid, ATTACH_RW, &query_shm);
if (ret < 0)
- goto out;
+ return ret;
cq = query_shm;
query.data = (char *)query_shm + sizeof(*cq);
query.size = cq->query_size;
- ret = cq->handler(&query, &result);
- if (ret < 0)
- goto out;
- ret = pass_object_as_shm(fd, &result);
-out:
- free(result.data);
- if (ret < 0)
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+ cq->handler(fd, &query);
+ return 1;
}
static void execute_server_command(void)
char buf[sizeof(cookie) + sizeof(query_shmid)];
int ret = recv_bin_buffer(fd, buf, sizeof(buf));
- if (ret < 0) {
- PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
- return;
- }
+ if (ret < 0)
+ goto err;
if (ret != sizeof(buf)) {
PARA_NOTICE_LOG("short read (%d bytes, expected %lu)\n",
ret, (long unsigned) sizeof(buf));
query_shmid);
return;
}
- call_callback(fd, query_shmid);
+ ret = call_callback(fd, query_shmid);
+ if (ret >= 0)
+ return;
+err:
+ PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
}
/** Shutdown connection if query has not arrived until this many seconds. */
exit(EXIT_FAILURE);
}
-static int create_tables_callback(const struct osl_object *query,
- __a_unused struct osl_object *result)
+static void create_tables_callback(int fd, const struct osl_object *query)
{
uint32_t table_mask = *(uint32_t *)query->data;
int i, ret;
+ char *buf;
close_afs_tables();
for (i = 0; i < NUM_AFS_TABLES; i++) {
continue;
ret = t->create(database_dir);
if (ret < 0)
- return ret;
+ goto out;
}
ret = open_afs_tables();
- return ret < 0? ret: 0;
+out:
+ if (ret >= 0)
+ buf = make_message("successfully created afs table(s)\n");
+ else
+ buf = make_message("%s\n", para_strerror(-ret));
+ pass_buffer_as_shm(buf, strlen(buf), &fd);
+ free(buf);
}
int com_init(int fd, int argc, char * const * const argv)
}
ret = send_callback_request(create_tables_callback, &query, NULL, NULL);
if (ret < 0)
- return ret;
- return send_va_buffer(fd, "successfully created afs table(s)\n");
+ return send_va_buffer(fd, "%s\n", para_strerror(-ret));
+ return ret;
}
/**
*
* \sa send_callback_request().
*/
-typedef int callback_function(const struct osl_object *, struct osl_object *);
+typedef void callback_function(int fd, const struct osl_object *);
typedef int callback_result_handler(struct osl_object *result, void *private);
int send_result(struct osl_object *result, void *private_result_data);
+int pass_buffer_as_shm(char *buf, size_t size, void *private_data);
__noreturn void afs_init(uint32_t cookie, int socket_fd);
void afs_event(enum afs_events event, struct para_buffer *pb,
int get_audio_file_path_of_row(const struct osl_row *row, char **path);
int get_afsi_object_of_row(const struct osl_row *row, struct osl_object *obj);
int audio_file_loop(void *private_data, osl_rbtree_loop_func *func);
-int aft_check_callback(const struct osl_object *query, struct osl_object *result);
+void aft_check_callback(int fd, __a_unused const struct osl_object *query);
/* mood */
int change_current_mood(char *mood_name);
void close_current_mood(void);
int reload_current_mood(void);
-int mood_check_callback(__a_unused const struct osl_object *query,
- struct osl_object *result);
+void mood_check_callback(int fd, __a_unused const struct osl_object *query);
/* playlist */
int playlist_open(char *name);
void playlist_close(void);
-int playlist_check_callback(__a_unused const struct osl_object *query,
- struct osl_object *result);
+void playlist_check_callback(int fd, __a_unused const struct osl_object *query);
/** evaluates to 1 if x < y, to -1 if x > y and to 0 if x == y */
#define NUM_COMPARE(x, y) ((int)((x) < (y)) - (int)((x) > (y)))
#include "string.h"
#include <sys/mman.h>
#include <fnmatch.h>
+#include <sys/shm.h>
+
#include "afh.h"
#include "afs.h"
#include "net.h"
.score = score,
.hash = file_hash
};
- struct para_buffer pb = {.buf = NULL};
+ struct para_buffer pb = {.max_size = VERBOSE_LS_OUTPUT_SIZE - 1};
ret = make_status_items(&d, &pb);
if (ret < 0)
goto err;
AFTCOL_CHUNKS, &chunk_table_obj);
if (ret < 0)
return ret;
- para_printf(b, "%s\n"
+ ret = para_printf(b, "%s\n"
"chunk_time: %lu:%lu\nchunk_offsets: ",
d->path,
(long unsigned) d->afhi.chunk_tv.tv_sec,
(long unsigned) d->afhi.chunk_tv.tv_usec
);
+ if (ret < 0)
+ goto out;
buf = chunk_table_obj.data;
- for (i = 0; i <= d->afhi.chunks_total; i++)
- para_printf(b, "%u ",
- (unsigned) read_u32(buf + 4 * i));
+ for (i = 0; i <= d->afhi.chunks_total; i++) {
+ ret = para_printf(b, "%u ", (unsigned) read_u32(buf + 4 * i));
+ if (ret < 0)
+ goto out;
+ }
+ ret = para_printf(b, "\n");
+out:
osl_close_disk_object(&chunk_table_obj);
- para_printf(b, "\n");
- return 1;
+ return ret;
}
static int print_list_item(struct ls_data *d, struct ls_options *opts,
char asc_hash[2 * HASH_SIZE + 1];
char *att_lines, *lyrics_lines, *image_lines, *filename_lines;
- if (opts->mode == LS_MODE_SHORT) {
- para_printf(b, "%s\n", d->path);
- return 1;
- }
+ if (opts->mode == LS_MODE_SHORT)
+ return para_printf(b, "%s\n", d->path);
if (opts->mode == LS_MODE_CHUNKS)
return print_chunk_table(d, b);
get_attribute_bitmap(&afsi->attributes, att_buf);
}
if (opts->mode == LS_MODE_LONG) {
- para_printf(b,
+ return para_printf(b,
"%s" /* score */
"%s " /* attributes */
"%*d " /* image_id */
last_played_time,
d->path
);
- return 1;
}
hash_to_asc(d->hash, asc_hash);
att_lines = make_attribute_lines(att_buf, afsi);
filename_lines = make_filename_lines(d->path, opts->flags);
if (opts->mode == LS_MODE_MBOX) {
const char *bn = para_basename(d->path);
- para_printf(b,
+ ret = para_printf(b,
"From foo@localhost %s\n"
"Received: from\nTo: bar\nFrom: a\n"
"Subject: %s\n\n",
last_played_time,
bn? bn : "?");
+ if (ret < 0)
+ return ret;
}
- para_printf(b,
+ ret = para_printf(b,
"%s" /* filename stuff */
"%s%s%s%s" /* score */
"%s\n" /* attributes */
status_item_list[SI_CHUNK_TIME], tv2ms(&afhi->chunk_tv),
status_item_list[SI_NUM_CHUNKS], afhi->chunks_total
);
+ if (ret < 0)
+ return ret;
if (opts->mode == LS_MODE_MBOX) {
struct osl_object lyrics_def;
lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def);
if (lyrics_def.data) {
- para_printf(b, "Lyrics:\n~~~~~~~\n%s",
+ ret = para_printf(b, "Lyrics:\n~~~~~~~\n%s",
(char *)lyrics_def.data);
osl_close_disk_object(&lyrics_def);
}
free(lyrics_lines);
free(image_lines);
free(filename_lines);
- return 1;
+ return ret;
}
void make_empty_status_items(char *buf)
return 1;
}
-static int com_ls_callback(const struct osl_object *query,
- struct osl_object *ls_output)
+static void com_ls_callback(int fd, const struct osl_object *query)
{
struct ls_options *opts = query->data;
char *p, *pattern_start = (char *)query->data + sizeof(*opts);
- struct para_buffer b = {.buf = NULL, .size = 0};
+ struct para_buffer b = {.max_size = SHMMAX,
+ .max_size_handler = pass_buffer_as_shm, .private_data = &fd};
int i = 0, ret;
time_t current_time;
for (i = opts->num_matching_paths - 1; i >= 0; i--) {
ret = print_list_item(opts->data_ptr[i], opts, &b, current_time);
if (ret < 0)
- break;
+ goto out;
}
else
for (i = 0; i < opts->num_matching_paths; i++) {
ret = print_list_item(opts->data_ptr[i], opts, &b, current_time);
if (ret < 0)
- break;
+ goto out;
}
- ret = 1;
out:
- ls_output->data = b.buf;
- ls_output->size = b.offset;
+ if (b.offset)
+ pass_buffer_as_shm(b.buf, b.offset, &fd);
+ free(b.buf);
free(opts->data);
free(opts->data_ptr);
free(opts->patterns);
- return ret;
}
/*
ADD_FLAG_ALL = 8,
};
-static int com_add_callback(const struct osl_object *query,
- struct osl_object *result)
+static void com_add_callback(int fd, const struct osl_object *query)
{
char *buf = query->data, *path;
struct osl_row *pb, *aft_row;
char afsi_buf[AFSI_SIZE];
uint32_t flags = read_u32(buf + CAB_FLAGS_OFFSET);
struct afs_info default_afsi = {.last_played = 0};
- struct para_buffer msg = {.buf = NULL};
+ struct para_buffer msg = {.max_size = SHMMAX,
+ .max_size_handler = pass_buffer_as_shm, .private_data = &fd};
hash = (HASH_TYPE *)buf + CAB_HASH_OFFSET;
hash_to_asc(hash, asc);;
hs = find_hash_sister(hash);
ret = aft_get_row_of_path(path, &pb);
if (ret < 0 && ret != -E_RB_KEY_NOT_FOUND)
- return ret;
+ goto out;
if (hs && pb && hs == pb && !(flags & ADD_FLAG_FORCE)) {
if (flags & ADD_FLAG_VERBOSE)
- para_printf(&msg, "ignoring duplicate\n");
- ret = 1;
+ ret = para_printf(&msg, "ignoring duplicate\n");
+ else
+ ret = 1;
goto out;
}
if (hs && hs != pb) {
struct osl_object obj;
if (pb) { /* hs trumps pb, remove pb */
- if (flags & ADD_FLAG_VERBOSE)
- para_printf(&msg, "removing path brother\n");
+ if (flags & ADD_FLAG_VERBOSE) {
+ ret = para_printf(&msg, "removing path brother\n");
+ if (ret < 0)
+ goto out;
+ }
ret = osl_del_row(audio_file_table, pb);
if (ret < 0)
goto out;
AFTCOL_PATH, &obj);
if (ret < 0)
goto out;
- para_printf(&msg, "renamed from %s\n", (char *)obj.data);
+ ret = para_printf(&msg, "renamed from %s\n", (char *)obj.data);
+ if (ret < 0)
+ goto out;
}
ret = osl_update_object(audio_file_table, hs, AFTCOL_PATH,
&objs[AFTCOL_PATH]);
if (ret < 0)
goto out;
hash_to_asc(old_hash, old_asc);
- if (flags & ADD_FLAG_VERBOSE)
- para_printf(&msg, "file change: %s -> %s\n",
+ if (flags & ADD_FLAG_VERBOSE) {
+ ret = para_printf(&msg, "file change: %s -> %s\n",
old_asc, asc);
+ if (ret < 0)
+ goto out;
+ }
ret = osl_update_object(audio_file_table, pb, AFTCOL_HASH,
&objs[AFTCOL_HASH]);
if (ret < 0)
if (hs || pb) { /* (hs != NULL and pb != NULL) implies hs == pb */
struct osl_row *row = pb? pb : hs;
/* update afhi and chunk_table */
- if (flags & ADD_FLAG_VERBOSE)
- para_printf(&msg, "updating afhi and chunk table\n");
+ if (flags & ADD_FLAG_VERBOSE) {
+ ret = para_printf(&msg, "updating afhi and chunk table\n");
+ if (ret < 0)
+ goto out;
+ }
ret = osl_update_object(audio_file_table, row, AFTCOL_AFHI,
&objs[AFTCOL_AFHI]);
if (ret < 0)
goto out;
}
/* new entry, use default afsi */
- if (flags & ADD_FLAG_VERBOSE)
- para_printf(&msg, "new file\n");
+ if (flags & ADD_FLAG_VERBOSE) {
+ ret = para_printf(&msg, "new file\n");
+ if (ret < 0)
+ goto out;
+ }
default_afsi.last_played = time(NULL) - 365 * 24 * 60 * 60;
default_afsi.audio_format_id = read_u8(buf + CAB_AUDIO_FORMAT_OFFSET);
afs_event(AUDIO_FILE_ADD, &msg, aft_row);
out:
if (ret < 0)
- para_printf(&msg, "%s\n", para_strerror(-ret));
- if (!msg.buf)
- return 0;
- result->data = msg.buf;
- result->size = msg.offset;
- return 1;
+ ret = para_printf(&msg, "%s\n", para_strerror(-ret));
+ if (msg.offset)
+ pass_buffer_as_shm(msg.buf, msg.offset, &fd);
+ free(msg.buf);
}
/** Used by com_add(). */
uint32_t flags;
};
-static int path_brother_callback(const struct osl_object *query,
- struct osl_object *result)
+static void path_brother_callback(int fd, const struct osl_object *query)
{
char *path = query->data;
struct osl_row *path_brother;
int ret = aft_get_row_of_path(path, &path_brother);
if (ret < 0)
- return ret;
- result->data = para_malloc(sizeof(path_brother));
- result->size = sizeof(path_brother);
- *(struct osl_row **)(result->data) = path_brother;
- return 1;
+ return;
+ pass_buffer_as_shm((char *)&path_brother, sizeof(path_brother), &fd);
}
-static int hash_sister_callback(const struct osl_object *query,
- struct osl_object *result)
+static void hash_sister_callback(int fd, const struct osl_object *query)
{
HASH_TYPE *hash = query->data;
struct osl_row *hash_sister;
hash_sister = find_hash_sister(hash);
if (!hash_sister)
- return -E_RB_KEY_NOT_FOUND;
- result->data = para_malloc(sizeof(hash_sister));
- result->size = sizeof(hash_sister);
- *(struct osl_row **)(result->data) = hash_sister;
- return 1;
+ return;
+ pass_buffer_as_shm((char *)&hash_sister, sizeof(hash_sister), &fd);
}
-int get_row_pointer_from_result(struct osl_object *result, void *private)
+static int get_row_pointer_from_result(struct osl_object *result, void *private)
{
struct osl_row **row = private;
*row = result->data;
query.size = HASH_SIZE;
ret = send_callback_request(hash_sister_callback, &query,
get_row_pointer_from_result, &hs);
- if (ret < 0 && ret != -E_RB_KEY_NOT_FOUND)
+ if (ret < 0)
goto out_unmap;
/* Return success if we already know this file. */
ret = 1;
struct afsi_change_event_data aced;
ret = get_afsi_object_of_row(row, &obj);
- if (ret < 0) {
- para_printf(&tad->pb, "%s: %s\n", name, para_strerror(-ret));
- return 1;
- }
+ if (ret < 0)
+ return para_printf(&tad->pb, "%s: %s\n", name, para_strerror(-ret));
ret = load_afsi(&old_afsi, &obj);
- if (ret < 0) {
- para_printf(&tad->pb, "%s: %s\n", name, para_strerror(-ret));
- return 1;
- }
+ if (ret < 0)
+ return para_printf(&tad->pb, "%s: %s\n", name, para_strerror(-ret));
new_afsi = old_afsi;
if (no_options) {
new_afsi.num_played++;
new_afsi.last_played = time(NULL);
- if (tad->cto->flags & TOUCH_FLAG_VERBOSE)
- para_printf(&tad->pb, "%s: num_played = %u, "
+ if (tad->cto->flags & TOUCH_FLAG_VERBOSE) {
+ ret = para_printf(&tad->pb, "%s: num_played = %u, "
"last_played = now()\n", name,
new_afsi.num_played);
+ if (ret < 0)
+ return ret;
+ }
} else {
- if (tad->cto->flags & TOUCH_FLAG_VERBOSE)
- para_printf(&tad->pb, "touching %s\n", name);
+ if (tad->cto->flags & TOUCH_FLAG_VERBOSE) {
+ ret = para_printf(&tad->pb, "touching %s\n", name);
+ if (ret < 0)
+ return ret;
+ }
if (tad->cto->lyrics_id >= 0)
new_afsi.lyrics_id = tad->cto->lyrics_id;
if (tad->cto->image_id >= 0)
return 1;
}
-static int com_touch_callback(const struct osl_object *query,
- struct osl_object *result)
+static void com_touch_callback(int fd, const struct osl_object *query)
{
- struct touch_action_data tad = {.cto = query->data};
- int ret;
+ struct touch_action_data tad = {.cto = query->data,
+ .pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ }
+ };
+ int ret, ret2 = 0;
struct pattern_match_data pmd = {
.table = audio_file_table,
.loop_col_num = AFTCOL_HASH,
pmd.fnmatch_flags |= FNM_PATHNAME;
ret = for_each_matching_row(&pmd);
if (ret < 0)
- para_printf(&tad.pb, "%s\n", para_strerror(-ret));
+ ret2 = para_printf(&tad.pb, "%s\n", para_strerror(-ret));
else
if (!tad.num_matches)
- para_printf(&tad.pb, "no matches\n");
- if (tad.pb.buf) {
- result->data = tad.pb.buf;
- result->size = tad.pb.offset;
- return 1;
- }
- return ret < 0? ret : 0;
+ ret2 = para_printf(&tad.pb, "no matches\n");
+ if (ret2 >= 0 && tad.pb.offset)
+ pass_buffer_as_shm(tad.pb.buf, tad.pb.offset, &fd);
+ free(tad.pb.buf);
}
int com_touch(int fd, int argc, char * const * const argv)
struct osl_row *row, const char *name, void *data)
{
struct com_rm_action_data *crd = data;
- int ret;
+ int ret, ret2;
- if (crd->flags & RM_FLAG_VERBOSE)
- para_printf(&crd->pb, "removing %s\n", name);
+ if (crd->flags & RM_FLAG_VERBOSE) {
+ ret = para_printf(&crd->pb, "removing %s\n", name);
+ if (ret < 0)
+ return ret;
+ }
afs_event(AUDIO_FILE_REMOVE, &crd->pb, row);
ret = osl_del_row(audio_file_table, row);
if (ret < 0)
- para_printf(&crd->pb, "%s: %s\n", name, para_strerror(-ret));
+ ret2 = para_printf(&crd->pb, "%s: %s\n", name,
+ para_strerror(-ret));
else
crd->num_removed++;
- return 1;
+ return ret;
}
-static int com_rm_callback(const struct osl_object *query,
- struct osl_object *result)
+static void com_rm_callback(int fd, const struct osl_object *query)
{
- struct com_rm_action_data crd = {.flags = *(uint32_t *)query->data};
+ struct com_rm_action_data crd = {.flags = *(uint32_t *)query->data,
+ .pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ }
+ };
int ret;
struct pattern_match_data pmd = {
.table = audio_file_table,
if (crd.flags & RM_FLAG_FNM_PATHNAME)
pmd.fnmatch_flags |= FNM_PATHNAME;
ret = for_each_matching_row(&pmd);
- if (ret < 0)
- para_printf(&crd.pb, "%s\n", para_strerror(-ret));
+ if (ret < 0) {
+ ret = para_printf(&crd.pb, "%s\n", para_strerror(-ret));
+ return;
+ }
if (!crd.num_removed && !(crd.flags & RM_FLAG_FORCE))
- para_printf(&crd.pb, "no matches -- nothing removed\n");
+ ret = para_printf(&crd.pb, "no matches -- nothing removed\n");
else {
if (crd.flags & RM_FLAG_VERBOSE)
- para_printf(&crd.pb, "removed %u files\n", crd.num_removed);
- }
- if (crd.pb.buf) {
- result->data = crd.pb.buf;
- result->size = crd.pb.offset;
- return 1;
+ ret = para_printf(&crd.pb, "removed %u files\n", crd.num_removed);
}
- return ret < 0? ret : 0;
+ if (ret >= 0 && crd.pb.offset)
+ pass_buffer_as_shm(crd.pb.buf, crd.pb.offset, &fd);
+ free(crd.pb.buf);
}
/* TODO options: -r (recursive) */
target_afsi.attributes = cad->source_afsi.attributes;
save_afsi(&target_afsi, &target_afsi_obj); /* in-place update */
cad->num_copied++;
- if (cad->flags & CPSI_FLAG_VERBOSE)
- para_printf(&cad->pb, "copied afsi to %s\n", name);
+ if (cad->flags & CPSI_FLAG_VERBOSE) {
+ ret = para_printf(&cad->pb, "copied afsi to %s\n", name);
+ if (ret < 0)
+ return ret;
+ }
aced.aft_row = row;
aced.old_afsi = &old_afsi;
afs_event(AFSI_CHANGE, &cad->pb, &aced);
return 1;
}
-static int com_cpsi_callback(const struct osl_object *query,
- struct osl_object *result)
+static void com_cpsi_callback(int fd, const struct osl_object *query)
{
- struct cpsi_action_data cad = {.flags = *(unsigned *)query->data};
+ struct cpsi_action_data cad = {
+ .flags = *(unsigned *)query->data,
+ .pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ }
+ };
int ret;
char *source_path = (char *)query->data + sizeof(cad.flags);
ret = for_each_matching_row(&pmd);
out:
if (ret < 0)
- para_printf(&cad.pb, "%s\n", para_strerror(-ret));
- if (cad.flags & CPSI_FLAG_VERBOSE) {
+ ret = para_printf(&cad.pb, "%s\n", para_strerror(-ret));
+ else if (cad.flags & CPSI_FLAG_VERBOSE) {
if (cad.num_copied)
- para_printf(&cad.pb, "copied requested afsi from %s "
+ ret = para_printf(&cad.pb, "copied requested afsi from %s "
"to %u files\n",
source_path, cad.num_copied);
else
- para_printf(&cad.pb, "nothing copied\n");
- }
- if (cad.pb.buf) {
- result->data = cad.pb.buf;
- result->size = cad.pb.offset;
- return 1;
+ ret = para_printf(&cad.pb, "nothing copied\n");
}
- return ret < 0? ret : 0;
+ if (cad.pb.offset)
+ pass_buffer_as_shm(cad.pb.buf, cad.pb.offset, &fd);
+ free(cad.pb.buf);
}
int com_cpsi(int fd, int argc, char * const * const argv)
struct afs_info afsi;
char *blob_name;
- if (ret < 0) {
- para_printf(pb, "%s\n", para_strerror(-ret));
- return 1;
- }
- if (stat(path, &statbuf) < 0)
- para_printf(pb, "%s: stat error (%s)\n", path, strerror(errno));
- else {
- if (!S_ISREG(statbuf.st_mode))
- para_printf(pb, "%s: not a regular file\n", path);
+ if (ret < 0)
+ return para_printf(pb, "%s\n", para_strerror(-ret));
+ if (stat(path, &statbuf) < 0) {
+ ret = para_printf(pb, "%s: stat error (%s)\n", path, strerror(errno));
+ if (ret < 0)
+ return ret;
+ } else {
+ if (!S_ISREG(statbuf.st_mode)) {
+ ret = para_printf(pb, "%s: not a regular file\n", path);
+ if (ret < 0)
+ return ret;
+ }
}
ret = get_afsi_of_row(row, &afsi);
- if (ret < 0) {
- para_printf(pb, "%s: %s\n", path, para_strerror(-ret));
- return 1;
- }
- ret = lyr_get_name_by_id(afsi.lyrics_id, &blob_name);
if (ret < 0)
- para_printf(pb, "%s lyrics id %u: %s\n", path, afsi.lyrics_id,
+ return para_printf(pb, "%s: %s\n", path, para_strerror(-ret));
+ ret = lyr_get_name_by_id(afsi.lyrics_id, &blob_name);
+ if (ret < 0) {
+ ret = para_printf(pb, "%s lyrics id %u: %s\n", path, afsi.lyrics_id,
para_strerror(-ret));
+ if (ret < 0)
+ return ret;
+ }
ret = img_get_name_by_id(afsi.image_id, &blob_name);
if (ret < 0)
- para_printf(pb, "%s image id %u: %s\n", path, afsi.image_id,
+ ret = para_printf(pb, "%s image id %u: %s\n", path, afsi.image_id,
para_strerror(-ret));
- return 1;
+ return ret;
}
/**
*
* \sa com_check().
*/
-int aft_check_callback(__a_unused const struct osl_object *query, struct osl_object *result)
+void aft_check_callback(int fd, __a_unused const struct osl_object *query)
{
- struct para_buffer pb = {.buf = NULL};
+ struct para_buffer pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ };
+ int ret = para_printf(&pb, "checking audio file table...\n");
- para_printf(&pb, "checking audio file table...\n");
+ if (ret < 0)
+ return;
audio_file_loop(&pb, check_audio_file);
- result->data = pb.buf;
- result->size = pb.offset;
- return 1;
-
+ if (pb.offset)
+ pass_buffer_as_shm(pb.buf, pb.offset, &fd);
+ free(pb.buf);
}
/**
static int aft_event_handler(enum afs_events event, struct para_buffer *pb,
void *data)
{
+ int ret;
+
switch(event) {
case ATTRIBUTE_REMOVE: {
const struct rmatt_event_data *red = data;
- para_printf(pb, "clearing attribute %s (bit %u) from all "
+ ret = para_printf(pb, "clearing attribute %s (bit %u) from all "
"entries in the audio file table\n", red->name,
red->bitnum);
+ if (ret < 0)
+ return ret;
return audio_file_loop(data, clear_attribute);
}
default:
#include "afh.h"
#include "afs.h"
#include "net.h"
+#include "ipc.h"
static struct osl_table *attribute_table;
static int greatest_att_bitnum;
{
struct lsatt_action_data *laad = data;
struct osl_object bitnum_obj;
- int ret;
+ int ret, ret2;
- if (!(laad->flags & LSATT_FLAG_LONG)) {
- para_printf(&laad->pb, "%s\n", name);
- return 1;
- }
+ if (!(laad->flags & LSATT_FLAG_LONG))
+ return para_printf(&laad->pb, "%s\n", name);
ret = osl_get_object(table, row, ATTCOL_BITNUM, &bitnum_obj);
if (ret < 0) {
- para_printf(&laad->pb, "%s: %s\n", name, para_strerror(-ret));
+ ret2 = para_printf(&laad->pb, "%s: %s\n", name, para_strerror(-ret));
return ret;
}
- para_printf(&laad->pb, "%u\t%s\n", *(unsigned char*)bitnum_obj.data,
+ return para_printf(&laad->pb, "%u\t%s\n", *(unsigned char*)bitnum_obj.data,
name);
- return 1;
}
-static int com_lsatt_callback(const struct osl_object *query,
- struct osl_object *result)
+static void com_lsatt_callback(int fd, const struct osl_object *query)
{
- struct lsatt_action_data laad = {.flags = *(unsigned *) query->data};
+ struct lsatt_action_data laad = {
+ .flags = *(unsigned *) query->data,
+ .pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ }
+
+ };
struct pattern_match_data pmd = {
.table = attribute_table,
.loop_col_num = ATTCOL_BITNUM,
.data = &laad,
.action = print_attribute
};
- int ret;
-
if (laad.flags & LSATT_FLAG_SORT_BY_ID)
pmd.loop_col_num = ATTCOL_NAME;
if (laad.flags & LSATT_FLAG_REVERSE)
pmd.pm_flags |= PM_REVERSE_LOOP;
- ret = for_each_matching_row(&pmd);
- if (ret < 0)
- para_printf(&laad.pb, "%s\n", para_strerror(-ret));
- if (!laad.pb.buf)
- return 0;
- result->data = laad.pb.buf;
- result->size = laad.pb.offset;
- return 1;
+ for_each_matching_row(&pmd);
+ if (!laad.pb.offset)
+ pass_buffer_as_shm(laad.pb.buf, laad.pb.offset, &fd);
+ free(laad.pb.buf);
}
int com_lsatt(int fd, int argc, char * const * const argv)
return ret;
}
-static int com_setatt_callback(const struct osl_object *query,
- __a_unused struct osl_object *result)
+static void com_setatt_callback(__a_unused int fd, const struct osl_object *query)
{
char *p;
uint64_t add_mask = 0, del_mask = 0;
char c;
len = strlen(p);
+ ret = -E_ATTR_SYNTAX;
if (!*p)
- return -E_ATTR_SYNTAX;
+ goto out;
c = p[len - 1];
if (c != '+' && c != '-')
break;
obj.size = len + 1;
ret = osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row);
if (ret < 0)
- return ret;
+ goto out;
ret = osl_get_object(attribute_table, row, ATTCOL_BITNUM,
&obj);
if (ret < 0)
- return ret;
+ goto out;
if (c == '+')
add_mask |= (1UL << *(unsigned char *)obj.data);
else
del_mask |= (1UL << *(unsigned char *)obj.data);
}
+ ret = -E_ATTR_SYNTAX;
if (!add_mask && !del_mask)
- return -E_ATTR_SYNTAX;
+ goto out;
PARA_DEBUG_LOG("masks: %llx:%llx\n",(long long unsigned)add_mask,
(long long unsigned)del_mask);
for (; p < (char *)query->data + query->size; p += len + 1) { /* TODO: fnmatch */
len = strlen(p);
ret = aft_get_row_of_path(p, &aced.aft_row);
if (ret < 0)
- return ret;
+ goto out;
ret = get_afsi_object_of_row(aced.aft_row, &obj);
if (ret < 0)
- return ret;
+ goto out;
ret = load_afsi(&old_afsi, &obj);
if (ret < 0)
- return ret;
+ goto out;
new_afsi = old_afsi;
new_afsi.attributes |= add_mask;
new_afsi.attributes &= ~del_mask;
save_afsi(&new_afsi, &obj); /* in-place update */
afs_event(AFSI_CHANGE, NULL, &aced);
}
- return 1;
+out:
+ if (ret < 0)
+ PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
}
int com_setatt(__a_unused int fd, int argc, char * const * const argv)
};
-static int com_addatt_callback(const struct osl_object *query,
- struct osl_object *result)
+static void com_addatt_callback(int fd, const struct osl_object *query)
{
char *p = query->data;
- int ret = 1;
- struct para_buffer pb = {.size = 0};
+ int ret = 1, ret2 = 0;
+ struct para_buffer pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ };
size_t len;
for (p = query->data; p < (char *)query->data + query->size; p += len + 1) {
struct addatt_event_data aed;
if (!len || p[len - 1] == '-' || p[len - 1] == '+') {
- para_printf(&pb, "invalid attribute name: %s\n", p);
+ ret2 = para_printf(&pb, "invalid attribute name: %s\n", p);
+ if (ret2 < 0)
+ goto out;
continue;
}
ret = get_attribute_bitnum_by_name(p, &bitnum);
if (ret >= 0) {
- para_printf(&pb, "attribute \"%s\" already exists\n", p);
+ ret2 = para_printf(&pb, "attribute \"%s\" already exists\n", p);
+ if (ret2 < 0)
+ goto out;
continue;
}
if (ret != -E_RB_KEY_NOT_FOUND) /* error */
greatest_att_bitnum = PARA_MAX(greatest_att_bitnum, bitnum);
}
out:
- if (ret < 0)
- para_printf(&pb, "%s: %s\n", p, para_strerror(-ret));
- result->data = pb.buf;
- result->size = pb.offset;
- return result->data? 0 : 1;
+ if (ret < 0 && ret2 >= 0)
+ ret = para_printf(&pb, "%s: %s\n", p, para_strerror(-ret));
+ if (pb.offset)
+ pass_buffer_as_shm(pb.buf, pb.offset, &fd);
+ free(pb.buf);
}
int com_addatt(int fd, int argc, char * const * const argv)
return ret;
}
-static int com_mvatt_callback(const struct osl_object *query,
- struct osl_object *result)
+static void com_mvatt_callback(int fd, const struct osl_object *query)
{
char *old = query->data;
size_t size = strlen(old) + 1;
char *new = old + size;
struct osl_object obj = {.data = old, .size = size};
struct osl_row *row;
- struct para_buffer pb = {.size = 0};
+ struct para_buffer pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ };
int ret;
ret = osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row);
ret = osl_update_object(attribute_table, row, ATTCOL_NAME, &obj);
out:
if (ret < 0)
- para_printf(&pb, "%s\n", para_strerror(-ret));
+ ret = para_printf(&pb, "%s\n", para_strerror(-ret));
else
afs_event(ATTRIBUTE_RENAME, &pb, NULL);
- if (!pb.buf)
- return 0;
- result->data = pb.buf;
- result->size = pb.offset;
- return 1;
+ if (pb.offset)
+ pass_buffer_as_shm(pb.buf, pb.offset, &fd);
+ free(pb.buf);
}
int com_mvatt(int fd, int argc, char * const * const argv)
struct rmatt_event_data red = {.name = name};
ret = get_attribute_bitnum_by_name(name, &red.bitnum);
- if (ret < 0) {
- para_printf(&raad->pb, "%s: %s\n", name, para_strerror(-ret));
- return 1;
- }
+ if (ret < 0)
+ return para_printf(&raad->pb, "%s: %s\n", name, para_strerror(-ret));
ret = osl_del_row(table, row);
- if (ret < 0) {
- para_printf(&raad->pb, "%s: %s\n", name, para_strerror(-ret));
- return 1;
- }
- para_printf(&raad->pb, "removed attribute %s\n", name);
+ if (ret < 0)
+ return para_printf(&raad->pb, "%s: %s\n", name, para_strerror(-ret));
+ ret = para_printf(&raad->pb, "removed attribute %s\n", name);
raad->num_removed++;
raad->mask_of_removed_atts |= (1 << red.bitnum);
afs_event(ATTRIBUTE_REMOVE, &raad->pb, &red);
- return 1;
+ return ret;
}
-static int com_rmatt_callback(const struct osl_object *query,
- struct osl_object *result)
+static void com_rmatt_callback(int fd, const struct osl_object *query)
{
- struct remove_attribute_action_data raad = {.num_removed = 0};
- int ret;
+ struct remove_attribute_action_data raad = {
+ .num_removed = 0,
+ .pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ }
+ };
+ int ret, ret2 = 0;
struct pattern_match_data pmd = {
.table = attribute_table,
.patterns = *query,
};
ret = for_each_matching_row(&pmd);
if (ret < 0)
- para_printf(&raad.pb, "%s\n", para_strerror(-ret));
- if (!raad.num_removed)
- para_printf(&raad.pb, "no match -- nothing removed\n");
- result->data = raad.pb.buf;
- result->size = raad.pb.offset;
- return 1;
+ ret2 = para_printf(&raad.pb, "%s\n", para_strerror(-ret));
+ else if (!raad.num_removed)
+ ret2 = para_printf(&raad.pb, "no match -- nothing removed\n");
+ if (ret2 >= 0 && raad.pb.offset)
+ pass_buffer_as_shm(raad.pb.buf, raad.pb.offset, &fd);
+ free(raad.pb.buf);
}
int com_rmatt(int fd, int argc, char * const * const argv)
#include "afh.h"
#include "afs.h"
#include "net.h"
+#include "ipc.h"
static struct osl_column_description blob_cols[] = {
[BLOBCOL_ID] = {
struct lsblob_action_data *lbad = data;
struct osl_object obj;
uint32_t id;
- int ret;
+ int ret, ret2;
- if (!(lbad->flags & BLOB_LS_FLAG_LONG)) {
- para_printf(&lbad->pb, "%s\n", name);
- return 1;
- }
+ if (!(lbad->flags & BLOB_LS_FLAG_LONG))
+ return para_printf(&lbad->pb, "%s\n", name);
ret = osl_get_object(table, row, BLOBCOL_ID, &obj);
if (ret < 0) {
- para_printf(&lbad->pb, "%s: %s\n", name, para_strerror(-ret));
+ ret2 = para_printf(&lbad->pb, "%s: %s\n", name, para_strerror(-ret));
return ret;
}
id = *(uint32_t *)obj.data;
- para_printf(&lbad->pb, "%u\t%s\n", id, name);
- return 1;
+ return para_printf(&lbad->pb, "%u\t%s\n", id, name);
}
-static int com_lsblob_callback(struct osl_table *table,
- const struct osl_object *query, struct osl_object *result)
+static void com_lsblob_callback(struct osl_table *table,
+ int fd, const struct osl_object *query)
{
- struct lsblob_action_data lbad = {.flags = *(uint32_t *)query->data};
+ struct lsblob_action_data lbad = {
+ .flags = *(uint32_t *)query->data,
+ .pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ }
+ };
struct pattern_match_data pmd = {
.table = table,
.patterns = {.data = (char *)query->data + sizeof(uint32_t),
pmd.loop_col_num = BLOBCOL_ID;
ret = for_each_matching_row(&pmd);
if (ret < 0)
- para_printf(&lbad.pb, "%s\n", para_strerror(-ret));
- if (!lbad.pb.buf)
- return 0;
- result->data = lbad.pb.buf;
- result->size = lbad.pb.offset;
- return 1;
+ ret = para_printf(&lbad.pb, "%s\n", para_strerror(-ret));
+ if (lbad.pb.offset)
+ pass_buffer_as_shm(lbad.pb.buf, lbad.pb.offset, &fd);
+ free(lbad.pb.buf);
}
static int com_lsblob(callback_function *f, int fd, int argc, char * const * const argv)
static int cat_blob(struct osl_table *table, struct osl_row *row,
__a_unused const char *name, void *data)
{
- int ret;
- struct osl_object *blobs = data;
+ int ret = 0, ret2;
struct osl_object obj;
ret = osl_open_disk_object(table, row, BLOBCOL_DEF, &obj);
if (ret < 0)
return ret;
- if (obj.size) {
- blobs->data = para_realloc(blobs->data, blobs->size + obj.size);
- memcpy(blobs->data + blobs->size, obj.data, obj.size);
- blobs->size += obj.size;
- }
- return osl_close_disk_object(&obj);
+ if (obj.size)
+ ret = pass_buffer_as_shm(obj.data, obj.size, data);
+ ret2 = osl_close_disk_object(&obj);
+ return (ret < 0)? ret : ret2;
}
-static int com_catblob_callback(struct osl_table *table,
- const struct osl_object *query, struct osl_object *result)
+static void com_catblob_callback(struct osl_table *table, int fd,
+ const struct osl_object *query)
{
- int ret;
struct pattern_match_data pmd = {
.table = table,
.patterns = *query,
.loop_col_num = BLOBCOL_NAME,
.match_col_num = BLOBCOL_NAME,
.pm_flags = PM_SKIP_EMPTY_NAME,
- .data = result,
+ .data = &fd,
.action = cat_blob
};
- result->data = NULL;
- ret = for_each_matching_row(&pmd);
- if (result->data)
- return 1;
- return (ret > 0)? 0 : ret;
+ for_each_matching_row(&pmd);
}
static int com_catblob(callback_function *f, int fd, int argc,
const char *name, void *data)
{
struct rmblob_data *rmbd = data;
- int ret = osl_del_row(table, row);
+ int ret = osl_del_row(table, row), ret2;
if (ret < 0) {
- para_printf(&rmbd->pb, "%s: %s\n", name, para_strerror(-ret));
+ ret2 = para_printf(&rmbd->pb, "%s: %s\n", name, para_strerror(-ret));
return ret;
}
rmbd->num_removed++;
- return 1; /* return success to remove other matching blobs. */
+ return 1;
}
-static int com_rmblob_callback(struct osl_table *table,
- const struct osl_object *query,
- struct osl_object *result)
+static void com_rmblob_callback(struct osl_table *table, int fd,
+ const struct osl_object *query)
{
- int ret;
- struct rmblob_data rmbd = {.num_removed = 0};
+ int ret, ret2 = 0;
+ struct rmblob_data rmbd = {
+ .num_removed = 0,
+ .pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ }
+ };
struct pattern_match_data pmd = {
.table = table,
.patterns = *query,
.data = &rmbd,
.action = remove_blob
};
- result->data = NULL;
ret = for_each_matching_row(&pmd);
- if (ret < 0)
- para_printf(&rmbd.pb, "%s\n", para_strerror(-ret));
+ if (ret < 0) {
+ ret2 = para_printf(&rmbd.pb, "%s\n", para_strerror(-ret));
+ if (ret2 < 0)
+ goto out;
+ }
if (!rmbd.num_removed)
- para_printf(&rmbd.pb, "no matches, nothing removed\n");
+ ret2 = para_printf(&rmbd.pb, "no matches, nothing removed\n");
else {
- para_printf(&rmbd.pb, "removed %d blobs\n", rmbd.num_removed);
+ ret2 = para_printf(&rmbd.pb, "removed %d blobs\n", rmbd.num_removed);
afs_event(BLOB_RENAME, NULL, table);
}
- result->data = rmbd.pb.buf;
- result->size = rmbd.pb.offset;
- return 1;
+out:
+ if (ret2 >= 0 && rmbd.pb.offset)
+ pass_buffer_as_shm(rmbd.pb.buf, rmbd.pb.offset, &fd);
+ free(rmbd.pb.buf);
}
static int com_rmblob(callback_function *f, int fd, int argc,
send_result, &fd);
}
-static int com_addblob_callback(struct osl_table *table,
- const struct osl_object *query,
- __a_unused struct osl_object *result)
+static void com_addblob_callback(struct osl_table *table, __a_unused int fd,
+ const struct osl_object *query)
{
struct osl_object objs[NUM_BLOB_COLUMNS];
char *name = query->data;
ret = osl_get_num_rows(table, &num_rows);
if (ret < 0)
- return ret;
+ goto out;
if (!num_rows) { /* this is the first entry ever added */
/* insert dummy row containing the id */
id = 2; /* this entry will be entry #1, so 2 is the next */
objs[BLOBCOL_DEF].size = 1;
ret = osl_add_row(table, objs);
if (ret < 0)
- return ret;
+ goto out;
} else {
/* check if name already exists */
struct osl_row *row;
struct osl_object obj = {.data = name, .size = name_len};
ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row);
if (ret < 0 && ret != -E_RB_KEY_NOT_FOUND)
- return ret;
+ goto out;
if (ret >= 0) { /* we already have a blob with this name */
obj.data = name + name_len;
obj.size = query->size - name_len;
- return osl_update_object(table, row, BLOBCOL_DEF, &obj);
+ ret = osl_update_object(table, row, BLOBCOL_DEF, &obj);
+ goto out;
}
/* new blob, get id of the dummy row and increment it */
obj.data = "";
obj.size = 1;
ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row);
if (ret < 0)
- return ret;
+ goto out;
ret = osl_get_object(table, row, BLOBCOL_ID, &obj);
if (ret < 0)
- return ret;
+ goto out;
id = *(uint32_t *)obj.data + 1;
obj.data = &id;
ret = osl_update_object(table, row, BLOBCOL_ID, &obj);
if (ret < 0)
- return ret;
+ goto out;
}
id--;
objs[BLOBCOL_ID].data = &id;
objs[BLOBCOL_DEF].size = query->size - name_len;
ret = osl_add_row(table, objs);
if (ret < 0)
- return ret;
+ goto out;
afs_event(BLOB_ADD, NULL, table);
- return 1;
+out:
+ if (ret < 0)
+ PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
}
static int com_addblob(callback_function *f, int fd, int argc,
return -E_BLOB_SYNTAX;
if (!*argv[1]) /* empty name is reserved for the dummy row */
return -E_BLOB_SYNTAX;
- PARA_NOTICE_LOG("argv[1]: %s\n", argv[1]);
arg_obj.size = strlen(argv[1]) + 1;
arg_obj.data = (char *)argv[1];
return stdin_command(fd, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL);
}
-static int com_mvblob_callback(struct osl_table *table,
- const struct osl_object *query,
- __a_unused struct osl_object *result)
+/* FIXME: Print output to client, not to log file */
+static void com_mvblob_callback(struct osl_table *table, __a_unused int fd,
+ const struct osl_object *query)
{
char *src = (char *) query->data;
struct osl_object obj = {.data = src, .size = strlen(src) + 1};
int ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row);
if (ret < 0)
- return ret;
+ goto out;
obj.data = dest;
obj.size = strlen(dest) + 1;
ret = osl_update_object(table, row, BLOBCOL_NAME, &obj);
if (ret < 0)
- return ret;
+ goto out;
afs_event(BLOB_RENAME, NULL, table);
- return 1;
+out:
+ if (ret < 0)
+ PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
}
static int com_mvblob(callback_function *f, __a_unused int fd,
}
#define DEFINE_BLOB_COMMAND(cmd_name, table_name, cmd_prefix) \
- static int com_ ## cmd_name ## cmd_prefix ## _callback(const struct osl_object *query, \
- struct osl_object *output) \
+ static void com_ ## cmd_name ## cmd_prefix ## _callback(int fd, const struct osl_object *query) \
{ \
- return com_ ## cmd_name ## blob_callback(table_name ## _table, query, output); \
+ return com_ ## cmd_name ## blob_callback(table_name ## _table, fd, query); \
} \
int com_ ## cmd_name ## cmd_prefix(int fd, int argc, char * const * const argv) \
{ \
int shm_attach(int id, enum shm_attach_mode mode, void **result);
int shm_detach(void *addr);
int shm_destroy(int id);
+
+#ifndef SHMMAX
+#define SHMMAX 65535
+#endif
#include "afh.h"
#include "afs.h"
#include "list.h"
+#include "ipc.h"
/**
* Contains statistical data of the currently admissible audio files.
struct osl_object mood_def;
struct mood_line_parser_data mlpd = {.line_num = 0};
- int ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def);
+ int ret2, ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def);
if (ret < 0) {
- para_printf(pb, "failed to get mood definition\n");
+ ret2 = para_printf(pb, "failed to get mood definition: %s\n",
+ para_strerror(-ret));
return ret;
}
if (!*mood_name) /* ignore dummy row */
goto out;
- para_printf(pb, "checking mood %s...\n", mood_name);
+ ret = para_printf(pb, "checking mood %s...\n", mood_name);
+ if (ret < 0)
+ goto out;
ret = for_each_line_ro(mood_def.data, mood_def.size,
parse_mood_line, &mlpd);
if (ret < 0)
- para_printf(pb, "%s line %u: %s\n", mood_name, mlpd.line_num,
+ ret2 = para_printf(pb, "%s line %u: %s\n", mood_name, mlpd.line_num,
para_strerror(-ret));
out:
osl_close_disk_object(&mood_def);
- return 1;
+ return ret;
}
/**
* \param query Unused.
* \param result: Contains check messages.
*/
-int mood_check_callback(__a_unused const struct osl_object *query,
- struct osl_object *result)
+void mood_check_callback(int fd, __a_unused const struct osl_object *query)
{
- struct para_buffer pb = {.buf = NULL};
+ struct para_buffer pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ };
- para_printf(&pb, "checking moods...\n");
+ int ret = para_printf(&pb, "checking moods...\n");
+ if (ret < 0)
+ return;
osl_rbtree_loop(moods_table, BLOBCOL_ID, &pb,
check_mood);
- result->data = pb.buf;
- result->size = pb.offset;
- return 1;
+ if (pb.offset)
+ pass_buffer_as_shm(pb.buf, pb.offset, &fd);
+ free(pb.buf);
}
#if 0
#include "string.h"
#include "afh.h"
#include "afs.h"
+#include "ipc.h"
/** \file playlist.c Functions for loading and saving playlists. */
struct osl_row *aft_row;
int ret = aft_get_row_of_path(path, &aft_row);
- if (ret < 0)
- para_printf(pb, "%s: %s\n", path, para_strerror(-ret));
- return 1;
+ if (ret >= 0)
+ return 1;
+ return para_printf(pb, "%s: %s\n", path, para_strerror(-ret));
}
static int check_playlist(struct osl_row *row, void *data)
char *playlist_name;
int ret = pl_get_name_and_def_by_row(row, &playlist_name, &playlist_def);
- if (ret < 0) {
- para_printf(pb, "failed to get playlist data: %s\n",
+ if (ret < 0)
+ return para_printf(pb, "failed to get playlist data: %s\n",
para_strerror(-ret));
- return 1;
- }
if (*playlist_name) { /* skip dummy row */
- para_printf(pb, "checking playlist %s...\n", playlist_name);
- for_each_line_ro(playlist_def.data, playlist_def.size,
+ ret = para_printf(pb, "checking playlist %s...\n", playlist_name);
+ if (ret < 0)
+ return ret;
+ ret = for_each_line_ro(playlist_def.data, playlist_def.size,
check_playlist_path, pb);
}
osl_close_disk_object(&playlist_def);
- return 1;
+ return ret;
}
/**
*
* \return The return value of the underlying call to osl_rbtree_loop().
*/
-int playlist_check_callback(__a_unused const struct osl_object *query,
- struct osl_object *result)
+void playlist_check_callback(int fd, __a_unused const struct osl_object *query)
{
- struct para_buffer pb = {.buf = NULL};
+ struct para_buffer pb = {
+ .max_size = SHMMAX,
+ .private_data = &fd,
+ .max_size_handler = pass_buffer_as_shm
+ };
+ int ret = para_printf(&pb, "checking playlists...\n");
- para_printf(&pb, "checking playlists...\n");
+ if (ret < 0)
+ return;
osl_rbtree_loop(playlists_table, BLOBCOL_ID, &pb,
check_playlist);
- result->data = pb.buf;
- result->size = pb.offset;
- return 1;
+ if (pb.offset)
+ pass_buffer_as_shm(pb.buf, pb.offset, &fd);
+ free(pb.buf);
}
/**
*
* This function prints into the buffer given by \a b at the offset which is
* also given by \a b. If there is not enough space to hold the result, the
- * buffer size is doubled until the underlying call to vsnprintf() succeeds.
+ * buffer size is doubled until the underlying call to vsnprintf() succeeds
+ * or the size of the buffer exceeds the maximal size specified in \a pb.
+ *
+ * In the latter case the unmodified \a buf and \a offset values as well as the
+ * private_data pointer of \a b are passed to the \a max_size_handler of \a b.
+ * If this function succeeds, i.e. returns a non-negative value, the offset of
+ * \a b is reset to zero and the given data is written to the beginning of the
+ * buffer.
+ *
* Upon return, the offset of \a b is adjusted accordingly so that subsequent
* calls to this function append data to what is already contained in the
* buffer.
b->buf = para_malloc(128);
b->size = 128;
b->offset = 0;
- } else if (b->size <= b->offset + 1) {
- b->size *= 2;
- b->buf = para_realloc(b->buf, b->size);
}
while (1) {
char *p = b->buf + b->offset;
size_t size = b->size - b->offset;
va_list ap;
- va_start(ap, fmt);
- ret = vsnprintf(p, size, fmt, ap);
- va_end(ap);
- if (ret > -1 && ret < size) { /* success */
- b->offset += ret;
- break;
+ if (size) {
+ va_start(ap, fmt);
+ ret = vsnprintf(p, size, fmt, ap);
+ va_end(ap);
+ if (ret > -1 && ret < size) { /* success */
+ b->offset += ret;
+ return ret;
+ }
+ }
+ /* check if we may grow the buffer */
+ if (!b->max_size || 2 * b->size < b->max_size) { /* yes */
+ /* try again with more space */
+ b->size *= 2;
+ b->buf = para_realloc(b->buf, b->size);
+ continue;
}
- /* try again with more space */
- b->size *= 2;
- b->buf = para_realloc(b->buf, b->size);
+ /* can't grow buffer */
+ if (!b->offset || !b->max_size_handler) /* message too large */
+ return -ERRNO_TO_PARA_ERROR(ENOSPC);
+ ret = b->max_size_handler(b->buf, b->offset, b->private_data);
+ if (ret < 0)
+ return ret;
+ b->offset = 0;
}
- return ret;
}
/** \cond LLONG_MAX and LLONG_LIN might not be defined. */
char *buf;
/** The size of \a buf. */
size_t size;
+ /** The maximal size this buffer may grow. Zero means unlimited. */
+ size_t max_size;
/** The next para_printf() will write at this offset. */
size_t offset;
+ /**
+ * If an attempt to print into this buffer is made that would need to
+ * grow \buf to a size larger than \a max_size, then this function is
+ * called.
+ */
+ int (*max_size_handler)(char *buf, size_t size, void *private_data);
+ /** Passed to max_size_handler(). */
+ void *private_data;
};
__must_check __malloc void *para_realloc(void *p, size_t size);