From: Andre Noll Date: Sat, 4 Jul 2009 15:15:50 +0000 (+0200) Subject: Merge branch 'afh_cleanup' into next. X-Git-Tag: v0.4.0~75 X-Git-Url: http://git.tuebingen.mpg.de/?a=commitdiff_plain;h=299df142bb50bacebc0b3050768f941bc95b5b6f;hp=-c;p=paraslash.git Merge branch 'afh_cleanup' into next. Quite a few conflicts, but no real problem. git rerere rulez! Conflicts: afs.c afs.cmd aft.c attribute.c audiod_command.c blob.c command.c para.h server.c server.cmd stat.c --- 299df142bb50bacebc0b3050768f941bc95b5b6f diff --combined Makefile.in index b4392a3c,6ea868b0..b6505f2a --- a/Makefile.in +++ b/Makefile.in @@@ -50,21 -50,21 +50,22 @@@ CPPFLAGS += -Wmissing-format-attribut CPPFLAGS += -Wmissing-noreturn CPPFLAGS += -Wunused-macros CPPFLAGS += -Wbad-function-cast +CPPFLAGS += -fno-strict-aliasing CPPFLAGS += -DMAIN_INPUT_FILE_IS_$(*F) CPPFLAGS += @SSL_CPPFLAGS@ CPPFLAGS += @ncurses_cppflags@ CPPFLAGS += @arch_cppflags@ + CPPFLAGS += -I/usr/local/include BINARIES = para_server para_client para_audioc para_recv \ - para_filter para_write para_fsck para_afh @extra_binaries@ + para_filter para_write para_afh @extra_binaries@ man_binaries := $(BINARIES) man_pages := $(patsubst %, man/man1/%.1, $(man_binaries)) man_pages_in := $(patsubst %, web/%.man.in.html, $(man_binaries)) ggo_dir := ggo - m4_ggos := afh audioc audiod client filter fsck gui recv server write + m4_ggos := afh audioc audiod client filter gui recv server write all_ggos := $(m4_ggos) dccp_recv oggdec_filter alsa_write oss_write fade http_recv \ osx_write udp_recv amp_filter compress_filter file_write \ grab_client mp3dec_filter @@@ -164,9 -164,6 +165,6 @@@ para_fade: @fade_objs para_server: @server_objs@ $(CC) $(LDFLAGS) -o $@ @server_objs@ @server_ldflags@ - para_fsck: @fsck_objs@ - $(CC) $(LDFLAGS) -o $@ @fsck_objs@ @fsck_ldflags@ - para_write: @write_objs@ $(CC) $(LDFLAGS) -o $@ @write_objs@ @write_ldflags@ diff --combined aac_afh.c index 80b50a4d,68f17c27..04461178 --- a/aac_afh.c +++ b/aac_afh.c @@@ -10,12 -10,13 +10,12 @@@ /** \file aac_afh.c para_server's aac audio format handler */ + #include ++ #include "para.h" #include "error.h" --#include "string.h" #include "afh.h" --#include "afs.h" --#include "server.h" ++#include "string.h" #include "aac.h" static int aac_find_stsz(unsigned char *buf, size_t buflen, off_t *skip) @@@ -91,11 -92,9 +91,9 @@@ static char *get_tag(unsigned char *p, return buf; } - static char *read_tags(unsigned char *buf, size_t buflen) + static void read_tags(unsigned char *buf, size_t buflen, struct afh_info *afhi) { unsigned char *p = buf; - char *title = NULL, *artist = NULL, *album = NULL, *year = NULL, - *comment = NULL, *result; while (p + 32 < buf + buflen) { unsigned char *q, type1[5], type2[5]; @@@ -114,27 -113,20 +112,20 @@@ if (q + size2 > buf + buflen) break; if (!atom_cmp(type1, "©ART")) - artist = get_tag(q, size2); + afhi->tags.artist = get_tag(q, size2); else if (!atom_cmp(type1, "©alb")) - album = get_tag(q, size2); + afhi->tags.album = get_tag(q, size2); else if (!atom_cmp(type1, "©nam")) - title = get_tag(q, size2); + afhi->tags.title = get_tag(q, size2); else if (!atom_cmp(type1, "©cmt")) - comment = get_tag(q, size2); + afhi->tags.comment = get_tag(q, size2); else if (!atom_cmp(type1, "©day")) - year = get_tag(q, size2); + afhi->tags.year = get_tag(q, size2); p += size1; } - result = make_taginfo(title, artist, album, year, comment); - free(title); - free(artist); - free(album); - free(year); - free(comment); - return result; } - static char *read_meta(unsigned char *buf, size_t buflen) + static void read_meta(unsigned char *buf, size_t buflen, struct afh_info *afhi) { unsigned char *p = buf; @@@ -145,12 -137,12 +136,12 @@@ continue; } p += 4; - return read_tags(p, buflen - (p - buf)); + return read_tags(p, buflen - (p - buf), afhi); } - return make_taginfo(NULL, NULL, NULL, NULL, NULL); } - static char *aac_get_taginfo(unsigned char *buf, size_t buflen) + static void aac_get_taginfo(unsigned char *buf, size_t buflen, + struct afh_info *afhi) { int i; uint64_t subsize; @@@ -165,10 -157,9 +156,9 @@@ p = buf + i; i += read_atom_header(p, &subsize, type); p = buf + i; - return read_meta(p, buflen - i); + return read_meta(p, buflen - i, afhi); } PARA_INFO_LOG("no meta data\n"); - return make_taginfo(NULL, NULL, NULL, NULL, NULL); } static ssize_t aac_compute_chunk_table(struct afh_info *afhi, @@@ -232,12 -223,11 +222,11 @@@ static int aac_get_file_info(char *map mp4AudioSpecificConfig mp4ASC; NeAACDecHandle handle = NULL; unsigned char *umap = (unsigned char *) map; - char *taginfo; ret = aac_find_esds(umap, numbytes, &skip, &decoder_len); if (ret < 0) goto out; - taginfo = aac_get_taginfo(umap, numbytes); + aac_get_taginfo(umap, numbytes, afhi); handle = aac_open(); ret = -E_AAC_AFH_INIT; if (NeAACDecInit(handle, umap + skip, decoder_len, &rate, &channels)) @@@ -268,11 -258,6 +257,6 @@@ ret = (afhi->chunk_table[afhi->chunks_total] - afhi->chunk_table[0]) * 8; /* bits */ ret += (channels * afhi->seconds_total * 500); /* avoid rounding error */ afhi->bitrate = ret / (channels * afhi->seconds_total * 1000); - afhi->info_string = make_message("%s:\n%s", - status_item_list[SI_AUDIO_FILE_INFO], - taginfo); - free(taginfo); - tv_scale(20, &afhi->chunk_tv, &afhi->eof_tv); ret = 1; out: if (handle) diff --combined afs.c index c89e3cec,6cbc744d..b40fe8e0 --- a/afs.c +++ b/afs.c @@@ -8,12 -8,10 +8,13 @@@ #include #include +#include + #include + #include "server.cmdline.h" #include "para.h" #include "error.h" +#include "crypt.h" #include "string.h" #include "afh.h" #include "afs.h" @@@ -88,7 -86,6 +89,6 @@@ static struct signal_task signal_task_s static enum play_mode current_play_mode; static char *current_mop; /* mode or playlist specifier. NULL means dummy mooe */ - /** * A random number used to "authenticate" the connection. * @@@ -345,7 -342,7 +345,7 @@@ static int action_if_pattern_matches(st struct pattern_match_data *pmd = data; struct osl_object name_obj; const char *p, *name; - int ret = osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj); + int ret = osl(osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj)); const char *pattern_txt = (const char *)pmd->patterns.data; if (ret < 0) @@@ -372,16 -369,15 +372,15 @@@ * * \param pmd Describes what to match and how. * - * \return The return value of the underlying call to osl_rbtree_loop() - * or osl_rbtree_loop_reverse(). + * \return Standard. */ int for_each_matching_row(struct pattern_match_data *pmd) { if (pmd->pm_flags & PM_REVERSE_LOOP) - return osl_rbtree_loop_reverse(pmd->table, pmd->loop_col_num, pmd, - action_if_pattern_matches); - return osl_rbtree_loop(pmd->table, pmd->loop_col_num, pmd, - action_if_pattern_matches); + return osl(osl_rbtree_loop_reverse(pmd->table, pmd->loop_col_num, pmd, + action_if_pattern_matches)); + return osl(osl_rbtree_loop(pmd->table, pmd->loop_col_num, pmd, + action_if_pattern_matches)); } /** @@@ -406,6 -402,80 +405,6 @@@ int string_compare(const struct osl_obj return strncmp(str1, str2, PARA_MIN(obj1->size, obj2->size)); } -/* - * write input from fd to dynamically allocated buffer, - * but maximal max_size byte. - */ -static int fd2buf(int fd, unsigned max_size, struct osl_object *obj) -{ - const size_t chunk_size = 1024; - size_t size = 2048, received = 0; - int ret; - char *buf = para_malloc(size); - - for (;;) { - ret = recv_bin_buffer(fd, buf + received, chunk_size); - if (ret <= 0) - break; - received += ret; - if (received + chunk_size >= size) { - size *= 2; - ret = -E_INPUT_TOO_LARGE; - if (size > max_size) - break; - buf = para_realloc(buf, size); - } - } - obj->data = buf; - obj->size = received; - if (ret < 0) - free(buf); - return ret; -} - -/** - * Read data from a file descriptor, and send it to the afs process. - * - * \param fd File descriptor to read data from. - * \param arg_obj Pointer to the arguments to \a f. - * \param f The callback function. - * \param max_len Don't read more than that many bytes from stdin. - * \param result_handler See \ref send_callback_request. - * \param private_result_data See \ref send_callback_request. - * - * This function is used by commands that wish to let para_server store - * arbitrary data specified by the user (for instance the add_blob family of - * commands). First, at most \a max_len bytes are read from \a fd, the result - * is concatenated with the buffer given by \a arg_obj, and the combined buffer - * is made available to the afs process via the callback method. See \ref - * send_callback_request for details. - * - * \return Negative on errors, the return value of the underlying call to - * send_callback_request() otherwise. - */ -int stdin_command(int fd, struct osl_object *arg_obj, callback_function *f, - unsigned max_len, callback_result_handler *result_handler, - void *private_result_data) -{ - struct osl_object query, stdin_obj; - int ret; - - ret = send_buffer(fd, AWAITING_DATA_MSG); - if (ret < 0) - return ret; - ret = fd2buf(fd, max_len, &stdin_obj); - if (ret < 0) - return ret; - query.size = arg_obj->size + stdin_obj.size; - query.data = para_malloc(query.size); - memcpy(query.data, arg_obj->data, arg_obj->size); - memcpy((char *)query.data + arg_obj->size, stdin_obj.data, stdin_obj.size); - free(stdin_obj.data); - ret = send_callback_request(f, &query, result_handler, private_result_data); - free(query.data); - return ret; -} - static int pass_afd(int fd, char *buf, size_t size) { struct msghdr msg = {.msg_iov = NULL}; @@@ -581,22 -651,21 +580,22 @@@ out * Result handler for sending data to the para_client process. * * \param result The data to be sent. - * \param fd_ptr Pointer to the file descriptor. + * \param private Pointer to rc4 context. * - * \return The return value of the underlying call to send_bin_buffer(). + * \return The return value of the underlying call to rc4_send_bin_buffer(). * - * \sa \ref callback_result_handler. + * \sa \ref callback_result_handler, \ref rc4_send_bin_buffer(). */ -int send_result(struct osl_object *result, void *fd_ptr) +int rc4_send_result(struct osl_object *result, void *private) { - int fd = *(int *)fd_ptr; + struct rc4_context *rc4c = private; + if (!result->size) return 1; - return send_bin_buffer(fd, result->data, result->size); + return rc4_send_bin_buffer(rc4c, result->data, result->size); } -int com_select(int fd, int argc, char * const * const argv) +int com_select(struct rc4_context *rc4c, int argc, char * const * const argv) { struct osl_object query; @@@ -605,7 -674,7 +604,7 @@@ query.data = argv[1]; query.size = strlen(argv[1]) + 1; return send_callback_request(com_select_callback, &query, - &send_result, &fd); + &rc4_send_result, rc4c); } static void init_admissible_files(char *arg) @@@ -660,7 -729,7 +659,7 @@@ static void get_database_dir(void else { char *home = para_homedir(); database_dir = make_message( - "%s/.paraslash/afs_database", home); + "%s/.paraslash/afs_database-0.4", home); free(home); } } @@@ -1026,7 -1095,7 +1025,7 @@@ out free(buf); } -int com_init(int fd, int argc, char * const * const argv) +int com_init(struct rc4_context *rc4c, int argc, char * const * const argv) { int i, j, ret; uint32_t table_mask = (1 << (NUM_AFS_TABLES + 1)) - 1; @@@ -1051,10 -1120,9 +1050,10 @@@ return -E_BAD_TABLE_NAME; } } - ret = send_callback_request(create_tables_callback, &query, &send_result, &fd); + ret = send_callback_request(create_tables_callback, &query, + rc4_send_result, rc4c); if (ret < 0) - return send_va_buffer(fd, "%s\n", para_strerror(-ret)); + return rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@@ -1072,7 -1140,7 +1071,7 @@@ enum com_check_flags CHECK_PLAYLISTS = 4 }; -int com_check(int fd, int argc, char * const * const argv) +int com_check(struct rc4_context *rc4c, int argc, char * const * const argv) { unsigned flags = 0; int i, ret; @@@ -1104,20 -1172,17 +1103,20 @@@ if (!flags) flags = ~0U; if (flags & CHECK_AFT) { - ret = send_callback_request(aft_check_callback, NULL, send_result, &fd); + ret = send_callback_request(aft_check_callback, NULL, + rc4_send_result, rc4c); if (ret < 0) return ret; } if (flags & CHECK_PLAYLISTS) { - ret = send_callback_request(playlist_check_callback, NULL, send_result, &fd); + ret = send_callback_request(playlist_check_callback, + NULL, rc4_send_result, rc4c); if (ret < 0) return ret; } if (flags & CHECK_MOODS) { - ret = send_callback_request(mood_check_callback, NULL, send_result, &fd); + ret = send_callback_request(mood_check_callback, NULL, + rc4_send_result, rc4c); if (ret < 0) return ret; } diff --combined afs.cmd index 31734046,293b5b7e..c55dfe71 --- a/afs.cmd +++ b/afs.cmd @@@ -3,8 -3,8 +3,8 @@@ SF: afs.c aft.c attribute. HC: Prototypes for the commands of the audio file selector. CC: Array of commands for the audio file selector. AT: server_command - SI: openssl/rc4 -SI: osl -IN: para error string afh afs server list user_list ++SI: openssl/rc4 osl +IN: para error crypt command string afh afs server list user_list SN: list of afs commands TM: mood lyr img pl --- @@@ -42,7 -42,7 +42,7 @@@ H: only the tables given by table_name. N: ls P: AFS_READ D: List audio files. -U: ls [-l[s|l|v|m]] -p -a -r -s{p|s|l|n|f|c|i|y|b|d|a} [pattern...] +U: ls [-l[s|l|v|m]] [-p] [-a] [-r] [-d] [-s{p|s|l|n|f|c|i|y|b|d|a}] [pattern...] H: Print a list of all audio files matching pattern. H: H: Options: @@@ -55,6 -55,8 +55,8 @@@ H: -ll: long listing mode (equivale H: H: -lv: verbose listing mode H: + H: -lp: parser-friendly mode + H: H: -lm: mbox listing mode H: H: -lc: chunk-table listing mode @@@ -67,8 -69,6 +69,8 @@@ H: playlist H: H: -r Reverse sort order. H: +H: -d Print dates as seconds after the epoch. +H: H: -s Change sort order. Defaults to alphabetical path sort if not given. H: H: -sp: sort by path. @@@ -95,7 -95,7 +97,7 @@@ H: -sa: sort by audio format --- N: lsatt P: AFS_READ -D: List attributes +D: List attributes. U: lsatt [-i] [-l] [-r] [pattern] H: Print the list of all defined attributes which match the H: given pattern. If no pattern is given, the full list is @@@ -258,7 -258,7 +260,7 @@@ H: loads the mood named 'foo' --- T: add N: add@member@ -O: int com_add@member@(int fd, int argc, char * const * const argv); +O: int com_add@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ | AFS_WRITE D: Read data from stdin and add it as a blob to the @member@ table. U: add@member@ @member@_name @@@ -271,7 -271,7 +273,7 @@@ H: given name already exists, its conte --- T: cat N: cat@member@ -O: int com_cat@member@(int fd, int argc, char * const * const argv); +O: int com_cat@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ D: Dump the contents of a blob of type @member@ to stdout. U: cat@member@ @member@_name @@@ -281,7 -281,7 +283,7 @@@ H: they were previously added --- T: ls N: ls@member@ -O: int com_ls@member@(int fd, int argc, char * const * const argv); +O: int com_ls@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ D: List blobs of type @member@ matching a pattern. U: ls@member@ [-i] [-l] [-r] [pattern] @@@ -301,7 -301,7 +303,7 @@@ H: -r Reverse sort order --- T: rm N: rm@member@ -O: int com_rm@member@(int fd, int argc, char * const * const argv); +O: int com_rm@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ | AFS_WRITE D: Remove blob(s) of type @member@ from the @member@ table. U: rm@member@ pattern... @@@ -310,7 -310,7 +312,7 @@@ H: any given pattern --- T: mv N: mv@member@ -O: int com_mv@member@(int fd, int argc, char * const * const argv); +O: int com_mv@member@(struct rc4_context *rc4c, int argc, char * const * const argv); P: AFS_READ | AFS_WRITE D: Rename a blob of type @member@. U: mv@member@ old_@member@_name new_@member@_name diff --combined afs.h index edeb348e,d25b7043..bfafd949 --- a/afs.h +++ b/afs.h @@@ -7,7 -7,6 +7,6 @@@ /** \file afs.h Exported symbols of the audio file selector. */ #include - #include "osl.h" #include "hash.h" /** Audio file selector data stored in the audio file table. */ @@@ -118,15 -117,10 +117,10 @@@ struct ls_data HASH_TYPE *hash; }; - void make_empty_status_items(char *buf); - - /** At most that many bytes will be passed from afs to para_server. */ - #define VERBOSE_LS_OUTPUT_SIZE 4096 -int send_afs_status(int fd, int parser_friendly); ++int send_afs_status(struct rc4_context *rc4c, int parser_friendly); /** Data about the current audio file, passed from afs to server. */ struct audio_file_data { - /** Same info as ls -lv -p current audio_file. */ - char verbose_ls_output[VERBOSE_LS_OUTPUT_SIZE]; /** The open file descriptor to the current audio file. */ int fd; /** Vss needs this for streaming. */ @@@ -188,7 -182,7 +182,7 @@@ typedef void callback_function(int fd, * \sa \ref send_callback_request(). */ typedef int callback_result_handler(struct osl_object *result, void *private); -int send_result(struct osl_object *result, void *fd_ptr); +int rc4_send_result(struct osl_object *result, void *private); int pass_buffer_as_shm(char *buf, size_t size, void *fd_ptr); __noreturn void afs_init(uint32_t cookie, int socket_fd); @@@ -204,6 -198,9 +198,6 @@@ int send_option_arg_callback_request(st int send_standard_callback_request(int argc, char * const * const argv, callback_function *f, callback_result_handler *result_handler, void *private_result_data); -int stdin_command(int fd, struct osl_object *arg_obj, callback_function *f, - unsigned max_len, callback_result_handler *result_handler, - void *private_result_data); int string_compare(const struct osl_object *obj1, const struct osl_object *obj2); int for_each_matching_row(struct pattern_match_data *pmd); diff --combined aft.c index e5409244,5ad5d8f0..daa9a500 --- a/aft.c +++ b/aft.c @@@ -7,11 -7,9 +7,12 @@@ /** \file aft.c Audio file table functions. */ #include /* readdir() */ +#include + + #include #include "para.h" #include "error.h" +#include "crypt.h" #include "string.h" #include #include @@@ -26,6 -24,8 +27,8 @@@ #include "portable_io.h" static struct osl_table *audio_file_table; + static char *status_items; + static char *parser_friendly_status_items; /** The different sorting methods of the ls command. */ enum ls_sorting_method { @@@ -66,7 -66,9 +69,9 @@@ enum ls_listing_mode /** -lm */ LS_MODE_MBOX, /** -lc */ - LS_MODE_CHUNKS + LS_MODE_CHUNKS, + /** -lp */ + LS_MODE_PARSER, }; /** The flags accepted by the ls command. */ @@@ -77,8 -79,6 +82,8 @@@ enum ls_flags LS_FLAG_ADMISSIBLE_ONLY = 2, /** -r */ LS_FLAG_REVERSE = 4, + /** -d */ + LS_FLAG_UNIXDATE = 8, }; /** @@@ -223,12 -223,27 +228,27 @@@ enum audio_file_table_columns NUM_AFT_COLUMNS }; + /** + * Compare two osl objects pointing to hash values. + * + * \param obj1 Pointer to the first hash object. + * \param obj2 Pointer to the second hash object. + * + * \return The values required for an osl compare function. + * + * \sa osl_compare_func, uint32_compare(). + */ + int aft_hash_compare(const struct osl_object *obj1, const struct osl_object *obj2) + { + return hash_compare((HASH_TYPE *)obj1->data, (HASH_TYPE *)obj2->data); + } + static struct osl_column_description aft_cols[] = { [AFTCOL_HASH] = { .storage_type = OSL_MAPPED_STORAGE, .storage_flags = OSL_RBTREE | OSL_FIXED_SIZE | OSL_UNIQUE, .name = "hash", - .compare_function = osl_hash_compare, + .compare_function = aft_hash_compare, .data_size = HASH_SIZE }, [AFTCOL_PATH] = { @@@ -341,23 -356,29 +361,29 @@@ enum afhi_offsets CHUNK_TV_TV_USEC_OFFSET = 36, /** Number of channels is stored here. (1 byte) */ AFHI_CHANNELS_OFFSET = 40, - /** EOF timeout in ms. (2 byte) */ - AFHI_EOF_OFFSET = 41, /** The tag info position. */ - AFHI_INFO_STRING_OFFSET = 43, + AFHI_INFO_STRING_OFFSET = 41, /** Minimal on-disk size of a valid afhi struct. */ - MIN_AFHI_SIZE = 44 + MIN_AFHI_SIZE = 47, /* at least 6 null bytes for techinfo/tags */ }; static unsigned sizeof_afhi_buf(const struct afh_info *afhi) { if (!afhi) return 0; - return strlen(afhi->info_string) + MIN_AFHI_SIZE; + return MIN_AFHI_SIZE + + strlen(afhi->techinfo) + + strlen(afhi->tags.artist) + + strlen(afhi->tags.title) + + strlen(afhi->tags.year) + + strlen(afhi->tags.album) + + strlen(afhi->tags.comment); } static void save_afhi(struct afh_info *afhi, char *buf) { + char *p; + if (!afhi) return; write_u32(buf + AFHI_SECONDS_TOTAL_OFFSET, afhi->seconds_total); @@@ -371,8 -392,14 +397,14 @@@ write_u32(buf + HEADER_OFFSET_OFFSET, afhi->header_offset); write_u32(buf + CHUNK_TV_TV_SEC_OFFSET, afhi->chunk_tv.tv_sec); write_u32(buf + CHUNK_TV_TV_USEC_OFFSET, afhi->chunk_tv.tv_usec); - write_u16(buf + AFHI_EOF_OFFSET, tv2ms(&afhi->eof_tv)); - strcpy(buf + AFHI_INFO_STRING_OFFSET, afhi->info_string); /* OK */ + p = buf + AFHI_INFO_STRING_OFFSET; + /* The sprintf's below are OK as our caller made sure that buf is large enough */ + p += sprintf(p, "%s", afhi->techinfo) + 1; + p += sprintf(p, "%s", afhi->tags.artist) + 1; + p += sprintf(p, "%s", afhi->tags.title) + 1; + p += sprintf(p, "%s", afhi->tags.year) + 1; + p += sprintf(p, "%s", afhi->tags.album) + 1; + sprintf(p, "%s", afhi->tags.comment); } static void load_afhi(const char *buf, struct afh_info *afhi) @@@ -388,8 -415,12 +420,12 @@@ afhi->header_offset = read_u32(buf + HEADER_OFFSET_OFFSET); afhi->chunk_tv.tv_sec = read_u32(buf + CHUNK_TV_TV_SEC_OFFSET); afhi->chunk_tv.tv_usec = read_u32(buf + CHUNK_TV_TV_USEC_OFFSET); - ms2tv(read_u16(buf + AFHI_EOF_OFFSET), &afhi->eof_tv); - afhi->info_string = para_strdup(buf + AFHI_INFO_STRING_OFFSET); + afhi->techinfo = (char *)buf + AFHI_INFO_STRING_OFFSET; + afhi->tags.artist = afhi->techinfo + strlen(afhi->techinfo) + 1; + afhi->tags.title = afhi->tags.artist + strlen(afhi->tags.artist) + 1; + afhi->tags.year = afhi->tags.title + strlen(afhi->tags.title) + 1; + afhi->tags.album = afhi->tags.year + strlen(afhi->tags.year) + 1; + afhi->tags.comment = afhi->tags.album + strlen(afhi->tags.album) + 1; } static unsigned sizeof_chunk_table(struct afh_info *afhi) @@@ -422,27 -453,27 +458,27 @@@ static void load_chunk_table(struct afh * \param path The full path of the audio file. * \param row Result pointer. * - * \return The return value of the underlying call to osl_get_row(). + * \return Standard. */ int aft_get_row_of_path(const char *path, struct osl_row **row) { struct osl_object obj = {.data = (char *)path, .size = strlen(path) + 1}; - return osl_get_row(audio_file_table, AFTCOL_PATH, &obj, row); + return osl(osl_get_row(audio_file_table, AFTCOL_PATH, &obj, row)); } /** * Get the row of the audio file table corresponding to the given hash value. * * \param hash The hash value of the desired audio file. - * \param row resul pointer. + * \param row Result pointer. * - * \return The return value of the underlying call to osl_get_row(). + * \return Standard. */ int aft_get_row_of_hash(HASH_TYPE *hash, struct osl_row **row) { const struct osl_object obj = {.data = hash, .size = HASH_SIZE}; - return osl_get_row(audio_file_table, AFTCOL_HASH, &obj, row); + return osl(osl_get_row(audio_file_table, AFTCOL_HASH, &obj, row)); } /** @@@ -451,11 -482,11 +487,11 @@@ * \param row Pointer to a row in the audio file table. * \param obj Result pointer. * - * \return The return value of the underlying call to osl_get_object(). + * \return Standard. */ int get_afsi_object_of_row(const struct osl_row *row, struct osl_object *obj) { - return osl_get_object(audio_file_table, row, AFTCOL_AFSI, obj); + return osl(osl_get_object(audio_file_table, row, AFTCOL_AFSI, obj)); } /** @@@ -524,8 -555,8 +560,8 @@@ int get_afsi_of_path(const char *path, int get_audio_file_path_of_row(const struct osl_row *row, char **path) { struct osl_object path_obj; - int ret = osl_get_object(audio_file_table, row, AFTCOL_PATH, - &path_obj); + int ret = osl(osl_get_object(audio_file_table, row, AFTCOL_PATH, + &path_obj)); if (ret < 0) return ret; *path = path_obj.data; @@@ -542,9 -573,10 +578,10 @@@ * * \sa get_hash_of_row(). */ - static int get_hash_object_of_aft_row(const struct osl_row *row, struct osl_object *obj) + static int get_hash_object_of_aft_row(const struct osl_row *row, + struct osl_object *obj) { - return osl_get_object(audio_file_table, row, AFTCOL_HASH, obj); + return osl(osl_get_object(audio_file_table, row, AFTCOL_HASH, obj)); } /** @@@ -582,8 -614,8 +619,8 @@@ static int get_hash_of_row(const struc int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi) { struct osl_object obj; - int ret = osl_get_object(audio_file_table, row, AFTCOL_AFHI, - &obj); + int ret = osl(osl_get_object(audio_file_table, row, AFTCOL_AFHI, + &obj)); if (ret < 0) return ret; load_afhi(obj.data, afhi); @@@ -694,56 -726,68 +731,68 @@@ static void get_duration_buf(int second } } - static char *make_attribute_lines(const char *att_bitmap, struct afs_info *afsi) + + static int write_attribute_items(struct para_buffer *b, + const char *att_bitmap, struct afs_info *afsi) { - char *att_text, *att_lines; + char *att_text; + int ret; - get_attribute_text(&afsi->attributes, " ", &att_text); - if (!att_text) - return para_strdup(att_bitmap); - att_lines = make_message("%s: %s\n%s: %s", - status_item_list[SI_ATTRIBUTES_BITMAP], att_bitmap, - status_item_list[SI_ATTRIBUTES_TXT], att_text); + ret = WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_BITMAP, "%s\n", att_bitmap); + if (ret < 0) + return ret; + ret = get_attribute_text(&afsi->attributes, " ", &att_text); + if (ret < 0) + return ret; + ret = WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_TXT, "%s\n", att_text); free(att_text); - return att_lines; + return ret; } - static char *make_lyrics_lines(struct afs_info *afsi) + static int write_lyrics_items(struct para_buffer *b, struct afs_info *afsi) { char *lyrics_name; + int ret; + ret = WRITE_STATUS_ITEM(b, SI_LYRICS_ID, "%u\n", afsi->lyrics_id); + if (ret < 0) + return ret; lyr_get_name_by_id(afsi->lyrics_id, &lyrics_name); - return make_message("%s: %u\n%s: %s\n", - status_item_list[SI_LYRICS_ID], afsi->lyrics_id, - status_item_list[SI_LYRICS_NAME], lyrics_name? - lyrics_name : "(none)"); + return WRITE_STATUS_ITEM(b, SI_LYRICS_NAME, "%s\n", lyrics_name? + lyrics_name : "(none)"); } - static char *make_image_lines(struct afs_info *afsi) + static int write_image_items(struct para_buffer *b, struct afs_info *afsi) { char *image_name; + int ret; + + ret = WRITE_STATUS_ITEM(b, SI_IMAGE_ID, "%u\n", afsi->image_id); + if (ret < 0) + return ret; img_get_name_by_id(afsi->image_id, &image_name); - return make_message("%s: %u\n%s: %s\n", - status_item_list[SI_IMAGE_ID], afsi->image_id, - status_item_list[SI_IMAGE_NAME], image_name? - image_name : "(none)"); + return WRITE_STATUS_ITEM(b, SI_IMAGE_NAME, "%s\n", image_name? + image_name : "(none)"); } - static char *make_filename_lines(const char *path, unsigned flags) + static int write_filename_items(struct para_buffer *b, const char *path, + unsigned flags) { - char *dirname, *ret; - const char *basename; + char *val; + int ret; if (!(flags & LS_FLAG_FULL_PATH)) - return make_message("%s: %s\n", - status_item_list[SI_BASENAME], path); - basename = para_basename(path), - dirname = para_dirname(path); - ret = make_message("%s: %s\n%s: %s\n%s: %s\n", - status_item_list[SI_PATH], path, - status_item_list[SI_DIRECTORY], dirname? dirname : "?", - status_item_list[SI_BASENAME], basename? basename : "?"); - free(dirname); + return WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", path); + ret = WRITE_STATUS_ITEM(b, SI_PATH, "%s\n", path); + if (ret < 0) + return ret; + val = para_basename(path); + ret = WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", val? val : ""); + if (ret < 0) + return ret; + val = para_dirname(path); + ret = WRITE_STATUS_ITEM(b, SI_DIRECTORY, "%s\n", val? val : ""); + free(val); return ret; } @@@ -781,6 -825,14 +830,14 @@@ out return ret; } + static int write_score(struct para_buffer *b, struct ls_data *d, + struct ls_options *opts) + { + if (!(opts->flags & LS_FLAG_ADMISSIBLE_ONLY)) /* no score*/ + return 0; + return WRITE_STATUS_ITEM(b, SI_SCORE, "%li\n", d->score); + } + static int print_list_item(struct ls_data *d, struct ls_options *opts, struct para_buffer *b, time_t current_time) { @@@ -788,13 -840,9 +845,9 @@@ char att_buf[65]; char last_played_time[30]; char duration_buf[30]; /* nobody has an audio file long enough to overflow this */ - char score_buf[30] = ""; struct afs_info *afsi = &d->afsi; struct afh_info *afhi = &d->afhi; - struct ls_widths *w = &opts->widths; - int have_score = opts->flags & LS_FLAG_ADMISSIBLE_ONLY; char asc_hash[2 * HASH_SIZE + 1]; - char *att_lines, *lyrics_lines, *image_lines, *filename_lines; if (opts->mode == LS_MODE_SHORT) { ret = para_printf(b, "%s\n", d->path); @@@ -805,26 -853,20 +858,25 @@@ goto out; } get_attribute_bitmap(&afsi->attributes, att_buf); - ret = get_local_time(&afsi->last_played, last_played_time, - sizeof(last_played_time), current_time, opts->mode); - if (ret < 0) - goto out; + if (opts->flags & LS_FLAG_UNIXDATE) + sprintf(last_played_time, "%llu", + (long long unsigned)afsi->last_played); + else { + ret = get_local_time(&afsi->last_played, last_played_time, + sizeof(last_played_time), current_time, opts->mode); + if (ret < 0) + goto out; + } get_duration_buf(afhi->seconds_total, duration_buf, opts); - if (have_score) { - if (opts->mode == LS_MODE_LONG) - sprintf(score_buf, "%*li ", w->score_width, d->score); - else - sprintf(score_buf, "%li ", d->score); - } - if (opts->mode == LS_MODE_LONG) { + struct ls_widths *w = &opts->widths; + if (opts->flags & LS_FLAG_ADMISSIBLE_ONLY) { + ret = para_printf(b, "%*li ", + opts->widths.score_width, d->score); + if (ret < 0) + goto out; + } ret = para_printf(b, - "%s" /* score */ "%s " /* attributes */ "%*u " /* amp */ "%*d " /* image_id */ @@@ -837,7 -879,6 +889,6 @@@ "%*d " /* num_played */ "%s " /* last_played */ "%s\n", /* path */ - score_buf, att_buf, w->amp_width, afsi->amp, w->image_id_width, afsi->image_id, @@@ -853,11 -894,6 +904,6 @@@ ); goto out; } - hash_to_asc(d->hash, asc_hash); - att_lines = make_attribute_lines(att_buf, afsi); - lyrics_lines = make_lyrics_lines(afsi); - image_lines = make_image_lines(afsi); - filename_lines = make_filename_lines(d->path, opts->flags); if (opts->mode == LS_MODE_MBOX) { const char *bn = para_basename(d->path); ret = para_printf(b, @@@ -869,47 -905,78 +915,78 @@@ if (ret < 0) goto out; } - ret = para_printf(b, - "%s" /* filename stuff */ - "%s%s%s%s" /* score */ - "%s\n" /* attributes */ - "%s: %s\n" /* hash */ - "%s" /* image id, image name */ - "%s" /* lyrics */ - "%s: %dkbit/s\n" /* bitrate */ - "%s: %s\n" /* format */ - "%s: %dHz\n" /* frequency */ - "%s: %d\n" /* channels */ - "%s: %s\n" /* duration */ - "%s: %lu\n" /* seconds total */ - "%s: %s\n" /* last played time */ - "%s: %d\n" /* num_played */ - "%s: %u\n" /* ampplification */ - "%s" /* tag info */ - "%s: %lu\n" /* chunk time */ - "%s: %lu\n", /* num chunks */ - filename_lines, - have_score? status_item_list[SI_SCORE] : "", - have_score? ": " : "", - score_buf, - have_score? "\n" : "", - att_lines, - status_item_list[SI_HASH], asc_hash, - image_lines, - lyrics_lines, - status_item_list[SI_BITRATE], afhi->bitrate, - status_item_list[SI_FORMAT], audio_format_name(afsi->audio_format_id), - status_item_list[SI_FREQUENCY], afhi->frequency, - status_item_list[SI_CHANNELS], afhi->channels, - status_item_list[SI_DURATION], duration_buf, - status_item_list[SI_SECONDS_TOTAL], afhi->seconds_total, - status_item_list[SI_LAST_PLAYED], last_played_time, - status_item_list[SI_NUM_PLAYED], afsi->num_played, - status_item_list[SI_AMPLIFICATION], afsi->amp, - afhi->info_string, - status_item_list[SI_CHUNK_TIME], tv2ms(&afhi->chunk_tv), - status_item_list[SI_NUM_CHUNKS], afhi->chunks_total - ); + ret = write_filename_items(b, d->path, opts->flags); + if (ret < 0) + goto out; + ret = write_score(b, d, opts); + if (ret < 0) + goto out; + ret = write_attribute_items(b, att_buf, afsi); + if (ret < 0) + goto out; + ret = write_image_items(b, afsi); + if (ret < 0) + goto out; + ret = write_lyrics_items(b, afsi); + if (ret < 0) + goto out; + hash_to_asc(d->hash, asc_hash); + ret = WRITE_STATUS_ITEM(b, SI_HASH, "%s\n", asc_hash); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_BITRATE, "%dkbit/s\n", afhi->bitrate); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_FORMAT, "%s\n", + audio_format_name(afsi->audio_format_id)); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_FREQUENCY, "%dHz\n", afhi->frequency); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_CHANNELS, "%d\n", afhi->channels); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_DURATION, "%s\n", duration_buf); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%lu\n", + afhi->seconds_total); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%d\n", afsi->num_played); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", + tv2ms(&afhi->chunk_tv)); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%lu\n", + afhi->chunks_total); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_YEAR, "%s\n", afhi->tags.year); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_ALBUM, "%s\n", afhi->tags.album); + if (ret < 0) + goto out; + ret = WRITE_STATUS_ITEM(b, SI_COMMENT, "%s\n", afhi->tags.comment); if (ret < 0) goto out; if (opts->mode == LS_MODE_MBOX) { @@@ -921,129 -988,10 +998,10 @@@ osl_close_disk_object(&lyrics_def); } } - free(att_lines); - free(lyrics_lines); - free(image_lines); - free(filename_lines); out: - free(afhi->info_string); return ret; } - /** - * Write a list of audio-file related status items with empty values. - * - * \param buf Result pointer. - * - * This is used by vss when currently no audio file is open. - */ - void make_empty_status_items(char *buf) - { - sprintf(buf, - "%s: \n" /* path */ - "%s: \n" /* dirname */ - "%s: \n" /* basename */ - "%s: \n" /* score */ - "%s: \n" /* attributes bitmap */ - "%s: \n" /* attributes txt */ - "%s: \n" /* hash */ - "%s: \n" /* image id */ - "%s: \n" /* image name */ - "%s: \n" /* lyrics id */ - "%s: \n" /* lyrics name */ - "%s: \n" /* bitrate */ - "%s: \n" /* format */ - "%s: \n" /* frequency */ - "%s: \n" /* channels */ - "%s: \n" /* duration */ - "%s: \n" /* seconds total */ - "%s: \n" /* num played */ - "%s: \n" /* last played */ - "%s: \n" /* audio file info */ - "%s: \n" /* taginfo1 */ - "%s: \n" /* taginfo2 */ - "%s: \n" /* amplification */ - , - status_item_list[SI_PATH], - status_item_list[SI_DIRECTORY], - status_item_list[SI_BASENAME], - status_item_list[SI_SCORE], - status_item_list[SI_ATTRIBUTES_BITMAP], - status_item_list[SI_ATTRIBUTES_TXT], - status_item_list[SI_HASH], - status_item_list[SI_IMAGE_ID], - status_item_list[SI_IMAGE_NAME], - status_item_list[SI_LYRICS_ID], - status_item_list[SI_LYRICS_NAME], - status_item_list[SI_BITRATE], - status_item_list[SI_FORMAT], - status_item_list[SI_FREQUENCY], - status_item_list[SI_CHANNELS], - status_item_list[SI_DURATION], - status_item_list[SI_SECONDS_TOTAL], - status_item_list[SI_NUM_PLAYED], - status_item_list[SI_LAST_PLAYED], - status_item_list[SI_AUDIO_FILE_INFO], - status_item_list[SI_TAGINFO1], - status_item_list[SI_TAGINFO2], - status_item_list[SI_AMPLIFICATION] - ); - } - - static void fixup_taginfo(char *begin, char *end) - { - char *p = begin; - - for (;;) { - p = strchr(p, '\n'); - if (!p) - break; - if (p >= end - 1) - break; - *p = ' '; - p++; - } - } - - /* crap, remove this ASAP. */ - static int fixup_info_string(char *info_string) - { - char *t1, *t2, *end; - - if (strncmp(info_string, "audio_file_info:", 16)) - return -ERRNO_TO_PARA_ERROR(EINVAL); - t1 = strstr(info_string, "\ntaginfo1:"); - if (!t1) - return -ERRNO_TO_PARA_ERROR(EINVAL); - t2 = strstr(info_string, "\ntaginfo2: "); - if (!t2) - return -ERRNO_TO_PARA_ERROR(EINVAL); - - end = t2 + strlen(t2) + 1; - fixup_taginfo(info_string + 16, t1); - fixup_taginfo(t1 + 10, t2); - fixup_taginfo(t2 + 10, end); - - if (t1 - info_string < 80 && t2 - t1 < 80 && end - t2 < 80) - return 0; - if (t1 - info_string >= 80) { - memmove(info_string + 80, t1, end - t1); - t1 = info_string + 80; - t2 -= t1 - info_string - 80; - end -= t1 - info_string - 80; - } - if (t2 - t1 >= 80) { - memmove(t1 + 80, t2, end - t2); - end -= t2 - t1 - 80; - t2 = t1 + 80; - } - if (end - t2 >= 80) { - t2[78] = '\n'; - t2[79] = '\0'; - } - return 1; - } - static int make_status_items(struct audio_file_data *afd, struct afs_info *afsi, char *path, long score, HASH_TYPE *hash) @@@ -1059,26 -1007,28 +1017,28 @@@ .flags = LS_FLAG_FULL_PATH | LS_FLAG_ADMISSIBLE_ONLY, .mode = LS_MODE_VERBOSE, }; - struct para_buffer pb = {.max_size = VERBOSE_LS_OUTPUT_SIZE - 1}; + struct para_buffer pb = {.max_size = SHMMAX - 1}; time_t current_time; int ret; - ret = fixup_info_string(afd->afhi.info_string); - if (ret < 0) { - PARA_WARNING_LOG("ignoring invalid tag info\n"); - afd->afhi.info_string[0] = '\0'; - } else if (ret) - PARA_NOTICE_LOG("truncated overlong tag info\n"); time(¤t_time); - ret = print_list_item(&d, &opts, &pb, current_time); /* frees info string */ - afd->afhi.info_string = NULL; + ret = print_list_item(&d, &opts, &pb, current_time); if (ret < 0) - goto out; - strncpy(afd->verbose_ls_output, pb.buf, VERBOSE_LS_OUTPUT_SIZE); - afd->verbose_ls_output[VERBOSE_LS_OUTPUT_SIZE - 1] = '\0'; - out: - free(pb.buf); - return ret; + return ret; + free(status_items); + status_items = pb.buf; + memset(&pb, 0, sizeof(pb)); + pb.max_size = SHMMAX - 1; + pb.flags = PBF_SIZE_PREFIX; + ret = print_list_item(&d, &opts, &pb, current_time); + if (ret < 0) { + free(status_items); + status_items = NULL; + return ret; + } + free(parser_friendly_status_items); + parser_friendly_status_items = pb.buf; + return 1; } /** @@@ -1150,7 -1100,6 +1110,6 @@@ int open_and_update_audio_file(struct o ret = save_afd(afd); err: free(afd->afhi.chunk_table); - free(afd->afhi.info_string); osl_close_disk_object(&chunk_table_obj); return ret; } @@@ -1353,7 -1302,6 +1312,6 @@@ static int prepare_ls_row(struct osl_ro } return 1; err: - free(d->afhi.info_string); return ret; } @@@ -1362,11 -1310,11 +1320,11 @@@ static void com_ls_callback(int fd, con struct ls_options *opts = query->data; char *p, *pattern_start = (char *)query->data + sizeof(*opts); struct para_buffer b = {.max_size = SHMMAX, + .flags = (opts->mode == LS_MODE_PARSER)? PBF_SIZE_PREFIX : 0, .max_size_handler = pass_buffer_as_shm, .private_data = &fd}; int i = 0, ret; time_t current_time; - if (opts->num_patterns) { opts->patterns = para_malloc(opts->num_patterns * sizeof(char *)); for (i = 0, p = pattern_start; i < opts->num_patterns; i++) { @@@ -1378,8 -1326,8 +1336,8 @@@ if (opts->flags & LS_FLAG_ADMISSIBLE_ONLY) ret = admissible_file_loop(opts, prepare_ls_row); else - ret = osl_rbtree_loop(audio_file_table, AFTCOL_PATH, opts, - prepare_ls_row); + ret = osl(osl_rbtree_loop(audio_file_table, AFTCOL_PATH, opts, + prepare_ls_row)); if (ret < 0) goto out; if (!opts->num_matching_paths) @@@ -1412,7 -1360,7 +1370,7 @@@ out /* * TODO: flags -h (sort by hash) */ -int com_ls(int fd, int argc, char * const * const argv) +int com_ls(struct rc4_context *rc4c, int argc, char * const * const argv) { int i, ret; unsigned flags = 0; @@@ -1452,6 -1400,9 +1410,9 @@@ case 'c': mode = LS_MODE_CHUNKS; continue; + case 'p': + mode = LS_MODE_PARSER; + continue; default: return -E_AFT_SYNTAX; } @@@ -1468,10 -1419,6 +1429,10 @@@ flags |= LS_FLAG_REVERSE; continue; } + if (!strcmp(arg, "-d")) { + flags |= LS_FLAG_UNIXDATE; + continue; + } if (!strncmp(arg, "-s", 2)) { if (!*(arg + 2) || *(arg + 3)) return -E_AFT_SYNTAX; @@@ -1521,7 -1468,7 +1482,7 @@@ opts.mode = mode; opts.num_patterns = argc - i; ret = send_option_arg_callback_request(&query, opts.num_patterns, - argv + i, com_ls_callback, send_result, &fd); + argv + i, com_ls_callback, rc4_send_result, rc4c); return ret; } @@@ -1531,12 -1478,12 +1492,12 @@@ * \param private_data An arbitrary data pointer, passed to \a func. * \param func The custom function to be called. * - * \return The return value of the underlying call to osl_rbtree_loop(). + * \return Standard. */ int audio_file_loop(void *private_data, osl_rbtree_loop_func *func) { - return osl_rbtree_loop(audio_file_table, AFTCOL_HASH, private_data, - func); + return osl(osl_rbtree_loop(audio_file_table, AFTCOL_HASH, private_data, + func)); } static struct osl_row *find_hash_sister(HASH_TYPE *hash) @@@ -1696,7 -1643,7 +1657,7 @@@ static void com_add_callback(int fd, co PARA_INFO_LOG("request to add %s\n", path); hs = find_hash_sister(hash); ret = aft_get_row_of_path(path, &pb); - if (ret < 0 && ret != -E_RB_KEY_NOT_FOUND) + if (ret < 0 && ret != -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND)) goto out; if (hs && pb && hs == pb && !(flags & ADD_FLAG_FORCE)) { if (flags & ADD_FLAG_VERBOSE) @@@ -1713,23 -1660,23 +1674,23 @@@ if (ret < 0) goto out; } - ret = osl_del_row(audio_file_table, pb); + ret = osl(osl_del_row(audio_file_table, pb)); if (ret < 0) goto out; pb = NULL; } /* file rename, update hs' path */ if (flags & ADD_FLAG_VERBOSE) { - ret = osl_get_object(audio_file_table, hs, - AFTCOL_PATH, &obj); + ret = osl(osl_get_object(audio_file_table, hs, + AFTCOL_PATH, &obj)); if (ret < 0) goto out; 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]); + ret = osl(osl_update_object(audio_file_table, hs, AFTCOL_PATH, + &objs[AFTCOL_PATH])); if (ret < 0) goto out; afs_event(AUDIO_FILE_RENAME, &msg, hs); @@@ -1773,12 -1720,12 +1734,12 @@@ if (ret < 0) goto out; } - ret = osl_update_object(audio_file_table, row, AFTCOL_AFHI, - &objs[AFTCOL_AFHI]); + ret = osl(osl_update_object(audio_file_table, row, AFTCOL_AFHI, + &objs[AFTCOL_AFHI])); if (ret < 0) goto out; - ret = osl_update_object(audio_file_table, row, AFTCOL_CHUNKS, - &objs[AFTCOL_CHUNKS]); + ret = osl(osl_update_object(audio_file_table, row, AFTCOL_CHUNKS, + &objs[AFTCOL_CHUNKS])); if (ret < 0) goto out; afs_event(AFHI_CHANGE, &msg, row); @@@ -1796,7 -1743,7 +1757,7 @@@ objs[AFTCOL_AFSI].data = &afsi_buf; objs[AFTCOL_AFSI].size = AFSI_SIZE; save_afsi(&default_afsi, &objs[AFTCOL_AFSI]); - ret = osl_add_and_get_row(audio_file_table, objs, &aft_row); + ret = osl(osl_add_and_get_row(audio_file_table, objs, &aft_row)); afs_event(AUDIO_FILE_ADD, &msg, aft_row); out: if (ret < 0) @@@ -1808,8 -1755,8 +1769,8 @@@ /** Used by com_add(). */ struct private_add_data { - /** The socket file descriptor. */ - int fd; + /** The socket file descriptor, including rc4 keys. */ + struct rc4_context *rc4c; /** The given add flags. */ uint32_t flags; }; @@@ -1859,13 -1806,12 +1820,13 @@@ static int add_one_audio_file(const cha query.size = strlen(path) + 1; ret = send_callback_request(path_brother_callback, &query, get_row_pointer_from_result, &pb); - if (ret < 0 && ret != -E_RB_KEY_NOT_FOUND) + if (ret < 0 && ret != -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND)) goto out_free; ret = 1; if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */ if (pad->flags & ADD_FLAG_VERBOSE) - send_ret = send_va_buffer(pad->fd, "lazy-ignore: %s\n", path); + send_ret = rc4_send_va_buffer(pad->rc4c, + "lazy-ignore: %s\n", path); goto out_free; } /* We still want to add this file. Compute its hash. */ @@@ -1885,7 -1831,7 +1846,7 @@@ ret = 1; if (pb && hs && hs == pb && !(pad->flags & ADD_FLAG_FORCE)) { if (pad->flags & ADD_FLAG_VERBOSE) - send_ret = send_va_buffer(pad->fd, + send_ret = rc4_send_va_buffer(pad->rc4c, "%s exists, not forcing update\n", path); goto out_unmap; } @@@ -1903,13 -1849,13 +1864,13 @@@ munmap(map.data, map.size); close(fd); if (pad->flags & ADD_FLAG_VERBOSE) { - send_ret = send_va_buffer(pad->fd, "adding %s\n", path); + send_ret = rc4_send_va_buffer(pad->rc4c, "adding %s\n", path); if (send_ret < 0) goto out_free; } save_add_callback_buffer(hash, path, afhi_ptr, pad->flags, format_num, &obj); /* Ask afs to consider this entry for adding. */ - ret = send_callback_request(com_add_callback, &obj, send_result, &pad->fd); + ret = send_callback_request(com_add_callback, &obj, rc4_send_result, pad->rc4c); goto out_free; out_unmap: @@@ -1917,21 -1863,26 +1878,26 @@@ munmap(map.data, map.size); out_free: if (ret < 0 && send_ret >= 0) - send_ret = send_va_buffer(pad->fd, "failed to add %s (%s)\n", path, - para_strerror(-ret)); + send_ret = rc4_send_va_buffer(pad->rc4c, + "failed to add %s (%s)\n", path, para_strerror(-ret)); free(obj.data); if (afhi_ptr) { free(afhi_ptr->chunk_table); - free(afhi_ptr->info_string); + free(afhi_ptr->techinfo); + free(afhi_ptr->tags.artist); + free(afhi_ptr->tags.title); + free(afhi_ptr->tags.year); + free(afhi_ptr->tags.album); + free(afhi_ptr->tags.comment); } /* Stop adding files only on send errors. */ return send_ret; } -int com_add(int fd, int argc, char * const * const argv) +int com_add(struct rc4_context *rc4c, int argc, char * const * const argv) { int i, ret; - struct private_add_data pad = {.fd = fd, .flags = 0}; + struct private_add_data pad = {.rc4c = rc4c, .flags = 0}; struct stat statbuf; for (i = 1; i < argc; i++) { @@@ -1965,7 -1916,7 +1931,7 @@@ char *path; ret = verify_path(argv[i], &path); if (ret < 0) { - ret = send_va_buffer(fd, "%s: %s\n", argv[i], + ret = rc4_send_va_buffer(rc4c, "%s: %s\n", argv[i], para_strerror(-ret)); if (ret < 0) return ret; @@@ -1973,7 -1924,7 +1939,7 @@@ } ret = stat(path, &statbuf); if (ret < 0) { - ret = send_va_buffer(fd, "failed to stat %s (%s)\n", path, + ret = rc4_send_va_buffer(rc4c, "failed to stat %s (%s)\n", path, strerror(errno)); free(path); if (ret < 0) @@@ -1986,7 -1937,7 +1952,7 @@@ else ret = add_one_audio_file(path, &pad); if (ret < 0) { - send_va_buffer(fd, "%s: %s\n", path, para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s: %s\n", path, para_strerror(-ret)); free(path); return ret; } @@@ -2118,7 -2069,7 +2084,7 @@@ static void com_touch_callback(int fd, free(tad.pb.buf); } -int com_touch(int fd, int argc, char * const * const argv) +int com_touch(struct rc4_context *rc4c, int argc, char * const * const argv) { struct com_touch_options cto = { .num_played = -1, @@@ -2186,9 -2137,9 +2152,9 @@@ if (i >= argc) return -E_AFT_SYNTAX; ret = send_option_arg_callback_request(&query, argc - i, - argv + i, com_touch_callback, send_result, &fd); + argv + i, com_touch_callback, rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@@ -2224,7 -2175,7 +2190,7 @@@ static int remove_audio_file(__a_unuse return ret; } afs_event(AUDIO_FILE_REMOVE, &crd->pb, row); - ret = osl_del_row(audio_file_table, row); + ret = osl(osl_del_row(audio_file_table, row)); if (ret < 0) para_printf(&crd->pb, "%s: %s\n", name, para_strerror(-ret)); else @@@ -2270,7 -2221,7 +2236,7 @@@ static void com_rm_callback(int fd, con } /* TODO options: -r (recursive) */ -int com_rm(int fd, int argc, char * const * const argv) +int com_rm(struct rc4_context *rc4c, int argc, char * const * const argv) { uint32_t flags = 0; struct osl_object query = {.data = &flags, .size = sizeof(flags)}; @@@ -2301,9 -2252,9 +2267,9 @@@ if (i >= argc) return -E_AFT_SYNTAX; ret = send_option_arg_callback_request(&query, argc - i, argv + i, - com_rm_callback, send_result, &fd); + com_rm_callback, rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@@ -2418,7 -2369,7 +2384,7 @@@ out free(cad.pb.buf); } -int com_cpsi(int fd, int argc, char * const * const argv) +int com_cpsi(struct rc4_context *rc4c, int argc, char * const * const argv) { unsigned flags = 0; int i, ret; @@@ -2458,17 -2409,36 +2424,36 @@@ } break; } - if (i + 1 >= argc) /* need at least souce file and pattern */ + if (i + 1 >= argc) /* need at least source file and pattern */ return -E_AFT_SYNTAX; if (!(flags & ~CPSI_FLAG_VERBOSE)) /* no copy flags given */ flags = ~(unsigned)CPSI_FLAG_VERBOSE | flags; ret = send_option_arg_callback_request(&options, argc - i, argv + i, - com_cpsi_callback, send_result, &fd); + com_cpsi_callback, rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } + void afs_stat_callback(int fd, const struct osl_object *query) + { + int *parser_friendly = query->data; + char *buf = *parser_friendly? + parser_friendly_status_items : status_items; + + if (!buf) + return; + pass_buffer_as_shm(buf, strlen(buf), &fd); + } + -int send_afs_status(int fd, int parser_friendly) ++int send_afs_status(struct rc4_context *rc4c, int parser_friendly) + { + struct osl_object query = {.data = &parser_friendly, + .size = sizeof(parser_friendly)}; + - return send_callback_request(afs_stat_callback, &query, send_result, &fd); ++ return send_callback_request(afs_stat_callback, &query, rc4_send_result, rc4c); + } + /* TODO: optionally fix problems by removing offending rows */ static int check_audio_file(struct osl_row *row, void *data) { @@@ -2547,6 -2517,10 +2532,10 @@@ static void aft_close(void { osl_close_table(audio_file_table, OSL_MARK_CLEAN); audio_file_table = NULL; + free(status_items); + status_items = NULL; + free(parser_friendly_status_items); + parser_friendly_status_items = NULL; } /** @@@ -2563,7 -2537,7 +2552,7 @@@ static int aft_open(const char *dir int ret; audio_file_table_desc.dir = dir; - ret = osl_open_table(&audio_file_table_desc, &audio_file_table); + ret = osl(osl_open_table(&audio_file_table_desc, &audio_file_table)); if (ret >= 0) { unsigned num; osl_get_num_rows(audio_file_table, &num); @@@ -2572,7 -2546,7 +2561,7 @@@ } PARA_INFO_LOG("failed to open audio file table\n"); audio_file_table = NULL; - if (ret >= 0 || is_errno(-ret, ENOENT)) + if (ret >= 0 || ret == -OSL_ERRNO_TO_PARA_ERROR(E_OSL_NOENT)) return 1; return ret; } @@@ -2580,7 -2554,7 +2569,7 @@@ static int aft_create(const char *dir) { audio_file_table_desc.dir = dir; - return osl_create_table(&audio_file_table_desc); + return osl(osl_create_table(&audio_file_table_desc)); } static int clear_attribute(struct osl_row *row, void *data) diff --combined attribute.c index ff284c3a,dc375c1d..41a10058 --- a/attribute.c +++ b/attribute.c @@@ -5,12 -5,9 +5,13 @@@ */ /** \file attribute.c Attribute handling functions. */ + +#include + #include + #include "para.h" #include "error.h" +#include "crypt.h" #include "string.h" #include "afh.h" #include "afs.h" @@@ -93,11 -90,11 +94,11 @@@ int get_attribute_bitnum_by_name(const struct osl_object obj = {.data = (char *)att_name, .size = strlen(att_name) + 1}; struct osl_row *row; - int ret = osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row); + int ret = osl(osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row)); if (ret < 0) return ret; - ret = osl_get_object(attribute_table, row, ATTCOL_BITNUM, &obj); + ret = osl(osl_get_object(attribute_table, row, ATTCOL_BITNUM, &obj)); if (ret < 0) return ret; *bitnum = *(unsigned char *)obj.data; @@@ -135,7 -132,7 +136,7 @@@ static int print_attribute(struct osl_t if (!(laad->flags & LSATT_FLAG_LONG)) return para_printf(&laad->pb, "%s\n", name); - ret = osl_get_object(table, row, ATTCOL_BITNUM, &bitnum_obj); + ret = osl(osl_get_object(table, row, ATTCOL_BITNUM, &bitnum_obj)); if (ret < 0) { para_printf(&laad->pb, "%s: %s\n", name, para_strerror(-ret)); return ret; @@@ -175,7 -172,7 +176,7 @@@ static void com_lsatt_callback(int fd, free(laad.pb.buf); } -int com_lsatt(int fd, int argc, char * const * const argv) +int com_lsatt(struct rc4_context *rc4c, int argc, char * const * const argv) { unsigned flags = 0; struct osl_object options = {.data = &flags, .size = sizeof(flags)}; @@@ -203,12 -200,12 +204,12 @@@ } } ret = send_option_arg_callback_request(&options, argc - i, argv + i, - com_lsatt_callback, send_result, &fd); + com_lsatt_callback, rc4_send_result, rc4c); if (!ret) { if (argc > 1) - ret = send_va_buffer(fd, "no matches\n"); + ret = rc4_send_va_buffer(rc4c, "no matches\n"); } else if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@@ -234,11 -231,11 +235,11 @@@ static void com_setatt_callback(__a_unu p[len - 1] = '\0'; obj.data = p; obj.size = len + 1; - ret = osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row); + ret = osl(osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row)); if (ret < 0) goto out; - ret = osl_get_object(attribute_table, row, ATTCOL_BITNUM, - &obj); + ret = osl(osl_get_object(attribute_table, row, ATTCOL_BITNUM, + &obj)); if (ret < 0) goto out; if (c == '+') @@@ -276,7 -273,7 +277,7 @@@ out PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); } -int com_setatt(__a_unused int fd, int argc, char * const * const argv) +int com_setatt(__a_unused struct rc4_context *rc4c, int argc, char * const * const argv) { if (argc < 3) return -E_ATTR_SYNTAX; @@@ -321,15 -318,15 +322,15 @@@ static void com_addatt_callback(int fd goto out; continue; } - if (ret != -E_RB_KEY_NOT_FOUND) /* error */ + if (ret != -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND)) /* error */ goto out; objs[ATTCOL_BITNUM].size = 1; /* find smallest unused attribute */ for (bitnum = 0; bitnum < 64; bitnum++) { objs[ATTCOL_BITNUM].data = &bitnum; - ret = osl_get_row(attribute_table, ATTCOL_BITNUM, - &objs[ATTCOL_BITNUM], &row); - if (ret == -E_RB_KEY_NOT_FOUND) + ret = osl(osl_get_row(attribute_table, ATTCOL_BITNUM, + &objs[ATTCOL_BITNUM], &row)); + if (ret == -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND)) break; /* this bitnum is unused, use it */ if (ret < 0) /* error */ goto out; @@@ -341,7 -338,7 +342,7 @@@ } objs[ATTCOL_NAME].data = p; objs[ATTCOL_NAME].size = len + 1; - ret = osl_add_row(attribute_table, objs); + ret = osl(osl_add_row(attribute_table, objs)); if (ret < 0) goto out; aed.name = p; @@@ -357,16 -354,16 +358,16 @@@ out free(pb.buf); } -int com_addatt(int fd, int argc, char * const * const argv) +int com_addatt(struct rc4_context *rc4c, int argc, char * const * const argv) { int ret; if (argc < 2) return -E_ATTR_SYNTAX; ret = send_standard_callback_request(argc - 1, argv + 1, com_addatt_callback, - send_result, &fd); + rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@@ -384,12 -381,12 +385,12 @@@ static void com_mvatt_callback(int fd, }; int ret; - ret = osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row); + ret = osl(osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row)); if (ret < 0) goto out; obj.data = new; obj.size = strlen(new) + 1; - ret = osl_update_object(attribute_table, row, ATTCOL_NAME, &obj); + ret = osl(osl_update_object(attribute_table, row, ATTCOL_NAME, &obj)); out: if (ret < 0) para_printf(&pb, "%s\n", para_strerror(-ret)); @@@ -400,16 -397,16 +401,16 @@@ free(pb.buf); } -int com_mvatt(int fd, int argc, char * const * const argv) +int com_mvatt(struct rc4_context *rc4c, int argc, char * const * const argv) { int ret; if (argc != 3) return -E_ATTR_SYNTAX; ret = send_standard_callback_request(argc - 1, argv + 1, com_mvatt_callback, - send_result, &fd); + rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@@ -433,7 -430,7 +434,7 @@@ static int remove_attribute(struct osl_ ret = get_attribute_bitnum_by_name(name, &red.bitnum); if (ret < 0) return para_printf(&raad->pb, "%s: %s\n", name, para_strerror(-ret)); - ret = osl_del_row(table, row); + ret = osl(osl_del_row(table, row)); 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); @@@ -472,16 -469,16 +473,16 @@@ static void com_rmatt_callback(int fd, free(raad.pb.buf); } -int com_rmatt(int fd, int argc, char * const * const argv) +int com_rmatt(struct rc4_context *rc4c, int argc, char * const * const argv) { int ret; if (argc < 2) return -E_ATTR_SYNTAX; ret = send_standard_callback_request(argc - 1, argv + 1, com_rmatt_callback, - send_result, &fd); + rc4_send_result, rc4c); if (ret < 0) - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@@ -537,10 -534,10 +538,10 @@@ int get_attribute_text(uint64_t *atts, if (!(*atts & (one << i))) continue; - ret = osl_get_row(attribute_table, ATTCOL_BITNUM, &obj, &row); + ret = osl(osl_get_row(attribute_table, ATTCOL_BITNUM, &obj, &row)); if (ret < 0) goto err; - ret = osl_get_object(attribute_table, row, ATTCOL_NAME, &obj); + ret = osl(osl_get_object(attribute_table, row, ATTCOL_NAME, &obj)); if (ret < 0) goto err; if (*text) { @@@ -583,14 -580,14 +584,14 @@@ static int attribute_open(const char *d int ret; attribute_table_desc.dir = dir; - ret = osl_open_table(&attribute_table_desc, &attribute_table); + ret = osl(osl_open_table(&attribute_table_desc, &attribute_table)); greatest_att_bitnum = -1; /* no atts available */ if (ret >= 0) { find_greatest_att_bitnum(); return ret; } attribute_table = NULL; - if (ret >= 0 || is_errno(-ret, ENOENT)) + if (ret >= 0 || ret == -OSL_ERRNO_TO_PARA_ERROR(E_OSL_NOENT)) return 1; return ret; } @@@ -598,7 -595,7 +599,7 @@@ static int attribute_create(const char *dir) { attribute_table_desc.dir = dir; - return osl_create_table(&attribute_table_desc); + return osl(osl_create_table(&attribute_table_desc)); } /** diff --combined audiod.c index 4a88cc88,767afa8d..2b6f1e69 --- a/audiod.c +++ b/audiod.c @@@ -8,11 -8,9 +8,11 @@@ #include #include #include +#include #include "para.h" #include "error.h" +#include "crypt.h" #include "audiod.cmdline.h" #include "list.h" #include "sched.h" @@@ -221,8 -219,7 +221,7 @@@ out seconds = PARA_MIN(seconds, length); seconds = PARA_MAX(seconds, 0); return make_message( - "%s: %s%d:%02d [%d:%02d] (%d%%/%d:%02d)\n", - status_item_list[SI_PLAY_TIME], + "%s%d:%02d [%d:%02d] (%d%%/%d:%02d)", s? "" : "~", seconds / 60, seconds % 60, @@@ -233,7 -230,7 +232,7 @@@ length % 60 ); empty: - return make_message("%s:\n", status_item_list[SI_PLAY_TIME]); + return para_strdup(NULL); } static int want_colors(void) @@@ -580,45 -577,31 +579,31 @@@ out return count; } - static int check_stat_line(char *line, __a_unused void *data) + static int update_item(int itemnum, char *buf) { - int itemnum; - size_t ilen = 0; long unsigned sec, usec; - char *tmp; - //PARA_INFO_LOG("line: %s\n", line); - if (!line) - return 1; - itemnum = stat_line_valid(line); - if (itemnum < 0) { - PARA_WARNING_LOG("invalid status line: %s\n", line); - return 1; - } if (stat_task->clock_diff_count && itemnum != SI_CURRENT_TIME) return 1; - tmp = make_message("%s\n", line); - stat_client_write(tmp, itemnum); - free(tmp); free(stat_item_values[itemnum]); - stat_item_values[itemnum] = para_strdup(line); - ilen = strlen(status_item_list[itemnum]); + stat_item_values[itemnum] = para_strdup(buf); + stat_client_write_item(itemnum); switch (itemnum) { case SI_STATUS_FLAGS: stat_task->vss_status = 0; - if (strchr(line, 'N')) + if (strchr(buf, 'N')) stat_task->vss_status |= VSS_STATUS_FLAG_NEXT; - if (strchr(line, 'P')) + if (strchr(buf, 'P')) stat_task->vss_status |= VSS_STATUS_FLAG_PLAYING; break; case SI_OFFSET: - stat_task->offset_seconds = atoi(line + ilen + 1); + stat_task->offset_seconds = atoi(buf); break; case SI_SECONDS_TOTAL: - stat_task->length_seconds = atoi(line + ilen + 1); + stat_task->length_seconds = atoi(buf); break; case SI_STREAM_START: - if (sscanf(line + ilen + 1, "%lu.%lu", &sec, &usec) == 2) { + if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) { struct timeval a_start, delay; delay.tv_sec = conf.stream_delay_arg / 1000; delay.tv_usec = (conf.stream_delay_arg % 1000) * 1000; @@@ -636,14 -619,14 +621,14 @@@ } break; case SI_CURRENT_TIME: - if (sscanf(line + ilen + 1, "%lu.%lu", &sec, &usec) == 2) { + if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) { struct timeval tv = {sec, usec}; compute_time_diff(&tv); } break; case SI_FORMAT: - stat_task->current_audio_format_num = get_audio_format_num( - line + ilen + 1); + stat_task->current_audio_format_num + = get_audio_format_num(buf); } return 1; } @@@ -937,17 -920,11 +922,11 @@@ static void init_command_task(struct co static void close_stat_pipe(void) { - int i; - if (!stat_task->ct) return; client_close(stat_task->ct); stat_task->ct = NULL; - FOR_EACH_STATUS_ITEM(i) { - free(stat_item_values[i]); - stat_item_values[i] = NULL; - } - dump_empty_status(); + clear_and_dump_items(); stat_task->length_seconds = 0; stat_task->offset_seconds = 0; stat_task->vss_status = 0; @@@ -1071,7 -1048,7 +1050,7 @@@ static void status_pre_select(struct sc goto out; } if (st->ct) { - unsigned bytes_left; + int ret; if (st->ct->task.error < 0) { if (st->ct->task.error != -E_TASK_UNREGISTERED) goto out; @@@ -1080,11 -1057,15 +1059,15 @@@ } if (st->ct->status != CL_RECEIVING) goto out; - bytes_left = for_each_line(st->ct->buf, st->ct->loaded, - &check_stat_line, NULL); - if (st->ct->loaded != bytes_left) { + ret = for_each_stat_item(st->ct->buf, st->ct->loaded, + update_item); + if (ret < 0) { + st->ct->task.error = ret; + goto out; + } + if (st->ct->loaded != ret) { st->last_status_read = *now; - st->ct->loaded = bytes_left; + st->ct->loaded = ret; } else { struct timeval diff; tv_diff(now, &st->last_status_read, &diff); @@@ -1096,25 -1077,23 +1079,23 @@@ if (tv_diff(now, &st->restart_barrier, NULL) < 0) goto out; if (st->clock_diff_count) { /* get status only one time */ - char *argv[] = {"audiod", "stat", "1", NULL}; - int argc = 3; + char *argv[] = {"audiod", "--", "stat", "-p", "1", NULL}; + int argc = 5; PARA_INFO_LOG("clock diff count: %d\n", st->clock_diff_count); st->clock_diff_count--; client_open(argc, argv, &st->ct, NULL); set_stat_task_restart_barrier(2); } else { - char *argv[] = {"audiod", "stat", NULL}; - int argc = 2; + char *argv[] = {"audiod", "--", "stat", "-p", NULL}; + int argc = 4; client_open(argc, argv, &st->ct, NULL); set_stat_task_restart_barrier(5); } free(stat_item_values[SI_BASENAME]); - stat_item_values[SI_BASENAME] = make_message( - "%s: no connection to para_server\n", - status_item_list[SI_BASENAME]); - stat_client_write(stat_item_values[SI_BASENAME], - SI_BASENAME); + stat_item_values[SI_BASENAME] = para_strdup( + "no connection to para_server"); + stat_client_write_item(SI_BASENAME); st->last_status_read = *now; out: start_stop_decoders(s); diff --combined blob.c index 5905c9ad,b4ac2fa4..38e5cb54 --- a/blob.c +++ b/blob.c @@@ -7,16 -7,37 +7,40 @@@ /** \file blob.c Macros and functions for blob handling. */ #include +#include + #include + #include "para.h" #include "error.h" +#include "crypt.h" #include "string.h" #include "afh.h" #include "afs.h" #include "net.h" #include "ipc.h" + #include "portable_io.h" + + /** + * Compare two osl objects pointing to unsigned integers of 32 bit size. + * + * \param obj1 Pointer to the first integer. + * \param obj2 Pointer to the second integer. + * + * \return The values required for an osl compare function. + * + * \sa osl_compare_func, osl_hash_compare(). + */ + static int uint32_compare(const struct osl_object *obj1, const struct osl_object *obj2) + { + uint32_t d1 = read_u32((const char *)obj1->data); + uint32_t d2 = read_u32((const char *)obj2->data); + + if (d1 < d2) + return 1; + if (d1 > d2) + return -1; + return 0; + } static struct osl_column_description blob_cols[] = { [BLOBCOL_ID] = { @@@ -74,7 -95,7 +98,7 @@@ static int print_blob(struct osl_table if (!(lbad->flags & BLOB_LS_FLAG_LONG)) return para_printf(&lbad->pb, "%s\n", name); - ret = osl_get_object(table, row, BLOBCOL_ID, &obj); + ret = osl(osl_get_object(table, row, BLOBCOL_ID, &obj)); if (ret < 0) { para_printf(&lbad->pb, "%s: %s\n", name, para_strerror(-ret)); return ret; @@@ -119,7 -140,7 +143,7 @@@ static void com_lsblob_callback(struct free(lbad.pb.buf); } -static int com_lsblob(callback_function *f, int fd, int argc, char * const * const argv) +static int com_lsblob(callback_function *f, struct rc4_context *rc4c, int argc, char * const * const argv) { uint32_t flags = 0; struct osl_object options = {.data = &flags, .size = sizeof(flags)}; @@@ -150,7 -171,7 +174,7 @@@ // if (argc > i) // return -E_BLOB_SYNTAX; return send_option_arg_callback_request(&options, argc - i, - argv + i, f, send_result, &fd); + argv + i, f, rc4_send_result, rc4c); } static int cat_blob(struct osl_table *table, struct osl_row *row, @@@ -159,12 -180,12 +183,12 @@@ int ret = 0, ret2; struct osl_object obj; - ret = osl_open_disk_object(table, row, BLOBCOL_DEF, &obj); + ret = osl(osl_open_disk_object(table, row, BLOBCOL_DEF, &obj)); if (ret < 0) return ret; if (obj.size) ret = pass_buffer_as_shm(obj.data, obj.size, data); - ret2 = osl_close_disk_object(&obj); + ret2 = osl(osl_close_disk_object(&obj)); return (ret < 0)? ret : ret2; } @@@ -183,13 -204,12 +207,13 @@@ static void com_catblob_callback(struc for_each_matching_row(&pmd); } -static int com_catblob(callback_function *f, int fd, int argc, +static int com_catblob(callback_function *f, struct rc4_context *rc4c, int argc, char * const * const argv) { if (argc < 2) return -E_BLOB_SYNTAX; - return send_standard_callback_request(argc - 1, argv + 1, f, send_result, &fd); + return send_standard_callback_request(argc - 1, argv + 1, f, + rc4_send_result, rc4c); } /** Used for removing rows from a blob table. */ @@@ -204,7 -224,7 +228,7 @@@ static int remove_blob(struct osl_tabl const char *name, void *data) { struct rmblob_data *rmbd = data; - int ret = osl_del_row(table, row); + int ret = osl(osl_del_row(table, row)); if (ret < 0) { para_printf(&rmbd->pb, "%s: %s\n", name, para_strerror(-ret)); return ret; @@@ -252,13 -272,13 +276,13 @@@ out free(rmbd.pb.buf); } -static int com_rmblob(callback_function *f, int fd, int argc, +static int com_rmblob(callback_function *f, struct rc4_context *rc4c, int argc, char * const * const argv) { if (argc < 2) return -E_MOOD_SYNTAX; return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f, - send_result, &fd); + rc4_send_result, rc4c); } static void com_addblob_callback(struct osl_table *table, __a_unused int fd, @@@ -271,7 -291,7 +295,7 @@@ unsigned num_rows; int ret; - ret = osl_get_num_rows(table, &num_rows); + ret = osl(osl_get_num_rows(table, &num_rows)); if (ret < 0) goto out; if (!num_rows) { /* this is the first entry ever added */ @@@ -283,34 -303,34 +307,34 @@@ objs[BLOBCOL_NAME].size = 1; objs[BLOBCOL_DEF].data = ""; objs[BLOBCOL_DEF].size = 1; - ret = osl_add_row(table, objs); + ret = osl(osl_add_row(table, objs)); if (ret < 0) 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) + ret = osl(osl_get_row(table, BLOBCOL_NAME, &obj, &row)); + if (ret < 0 && ret != -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND)) goto out; if (ret >= 0) { /* we already have a blob with this name */ obj.data = name + name_len; obj.size = query->size - name_len; - ret = osl_update_object(table, row, BLOBCOL_DEF, &obj); + ret = osl(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); + ret = osl(osl_get_row(table, BLOBCOL_NAME, &obj, &row)); if (ret < 0) goto out; - ret = osl_get_object(table, row, BLOBCOL_ID, &obj); + ret = osl(osl_get_object(table, row, BLOBCOL_ID, &obj)); if (ret < 0) goto out; id = *(uint32_t *)obj.data + 1; obj.data = &id; - ret = osl_update_object(table, row, BLOBCOL_ID, &obj); + ret = osl(osl_update_object(table, row, BLOBCOL_ID, &obj)); if (ret < 0) goto out; } @@@ -321,7 -341,7 +345,7 @@@ objs[BLOBCOL_NAME].size = name_len; objs[BLOBCOL_DEF].data = name + name_len; objs[BLOBCOL_DEF].size = query->size - name_len; - ret = osl_add_row(table, objs); + ret = osl(osl_add_row(table, objs)); if (ret < 0) goto out; afs_event(BLOB_ADD, NULL, table); @@@ -330,82 -350,7 +354,82 @@@ out PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); } -static int com_addblob(callback_function *f, int fd, int argc, +/* + * write input from fd to dynamically allocated buffer, + * but maximal max_size byte. + */ +static int fd2buf(struct rc4_context *rc4c, unsigned max_size, struct osl_object *obj) +{ + const size_t chunk_size = 1024; + size_t size = 2048, received = 0; + int ret; + char *buf = para_malloc(size); + + for (;;) { + ret = rc4_recv_bin_buffer(rc4c, buf + received, chunk_size); + if (ret <= 0) + break; + received += ret; + if (received + chunk_size >= size) { + size *= 2; + ret = -E_INPUT_TOO_LARGE; + if (size > max_size) + break; + buf = para_realloc(buf, size); + } + } + obj->data = buf; + obj->size = received; + if (ret < 0) + free(buf); + return ret; +} + +/* + * Read data from a file descriptor, and send it to the afs process. + * + * \param rc4c crypt context containing the file descriptor to read data from. + * \param arg_obj Pointer to the arguments to \a f. + * \param f The callback function. + * \param max_len Don't read more than that many bytes from stdin. + * \param result_handler See \ref send_callback_request. + * \param private_result_data See \ref send_callback_request. + * + * This function is used by commands that wish to let para_server store + * arbitrary data specified by the user (for instance the add_blob family of + * commands). First, at most \a max_len bytes are read and decrypted from the + * file descriptor given by \a rc4c. The result is concatenated with the buffer + * given by \a arg_obj, and the combined buffer is made available to the afs + * process via the callback method. See \ref send_callback_request for details. + * + * \return Negative on errors, the return value of the underlying call to + * send_callback_request() otherwise. + */ +static int stdin_command(struct rc4_context *rc4c, struct osl_object *arg_obj, + callback_function *f, unsigned max_len, + callback_result_handler *result_handler, + void *private_result_data) +{ + struct osl_object query, stdin_obj; + int ret; + + ret = rc4_send_buffer(rc4c, AWAITING_DATA_MSG); + if (ret < 0) + return ret; + ret = fd2buf(rc4c, max_len, &stdin_obj); + if (ret < 0) + return ret; + query.size = arg_obj->size + stdin_obj.size; + query.data = para_malloc(query.size); + memcpy(query.data, arg_obj->data, arg_obj->size); + memcpy((char *)query.data + arg_obj->size, stdin_obj.data, stdin_obj.size); + free(stdin_obj.data); + ret = send_callback_request(f, &query, result_handler, private_result_data); + free(query.data); + return ret; +} + +static int com_addblob(callback_function *f, struct rc4_context *rc4c, int argc, char * const * const argv) { struct osl_object arg_obj; @@@ -416,7 -361,7 +440,7 @@@ return -E_BLOB_SYNTAX; 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); + return stdin_command(rc4c, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL); } /* FIXME: Print output to client, not to log file */ @@@ -427,13 -372,13 +451,13 @@@ static void com_mvblob_callback(struct struct osl_object obj = {.data = src, .size = strlen(src) + 1}; char *dest = src + obj.size; struct osl_row *row; - int ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row); + int ret = osl(osl_get_row(table, BLOBCOL_NAME, &obj, &row)); if (ret < 0) goto out; obj.data = dest; obj.size = strlen(dest) + 1; - ret = osl_update_object(table, row, BLOBCOL_NAME, &obj); + ret = osl(osl_update_object(table, row, BLOBCOL_NAME, &obj)); if (ret < 0) goto out; afs_event(BLOB_RENAME, NULL, table); @@@ -442,7 -387,7 +466,7 @@@ out PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); } -static int com_mvblob(callback_function *f, __a_unused int fd, +static int com_mvblob(callback_function *f, __a_unused struct rc4_context *rc4c, int argc, char * const * const argv) { if (argc != 3) @@@ -456,9 -401,9 +480,9 @@@ { \ 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 com_ ## cmd_name ## cmd_prefix(struct rc4_context *rc4c, int argc, char * const * const argv) \ { \ - return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, fd, argc, argv); \ + return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, rc4c, argc, argv); \ } static int blob_get_name_by_id(struct osl_table *table, uint32_t id, @@@ -471,10 -416,10 +495,10 @@@ *name = NULL; if (!id) return 1; - ret = osl_get_row(table, BLOBCOL_ID, &obj, &row); + ret = osl(osl_get_row(table, BLOBCOL_ID, &obj, &row)); if (ret < 0) return ret; - ret = osl_get_object(table, row, BLOBCOL_NAME, &obj); + ret = osl(osl_get_object(table, row, BLOBCOL_NAME, &obj)); if (ret < 0) return ret; *name = (char *)obj.data; @@@ -499,10 -444,10 +523,10 @@@ static int blob_get_def_by_name(struct def->data = NULL; if (!*name) return 1; - ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row); + ret = osl(osl_get_row(table, BLOBCOL_NAME, &obj, &row)); if (ret < 0) return ret; - return osl_open_disk_object(table, row, BLOBCOL_DEF, def); + return osl(osl_open_disk_object(table, row, BLOBCOL_DEF, def)); } /** Define the \p get_def_by_id function for this blob type. */ @@@ -522,10 -467,10 +546,10 @@@ static int blob_get_def_by_id(struct os def->data = NULL; if (!id) return 1; - ret = osl_get_row(table, BLOBCOL_ID, &obj, &row); + ret = osl(osl_get_row(table, BLOBCOL_ID, &obj, &row)); if (ret < 0) return ret; - return osl_open_disk_object(table, row, BLOBCOL_DEF, def); + return osl(osl_open_disk_object(table, row, BLOBCOL_DEF, def)); } /** Define the \p get_def_by_id function for this blob type. */ @@@ -539,11 -484,11 +563,11 @@@ static int blob_get_name_and_def_by_row const struct osl_row *row, char **name, struct osl_object *def) { struct osl_object obj; - int ret = osl_get_object(table, row, BLOBCOL_NAME, &obj); + int ret = osl(osl_get_object(table, row, BLOBCOL_NAME, &obj)); if (ret < 0) return ret; *name = obj.data; - return osl_open_disk_object(table, row, BLOBCOL_DEF, def); + return osl(osl_open_disk_object(table, row, BLOBCOL_DEF, def)); } /** Define the \p get_name_and_def_by_row function for this blob type. */ #define DEFINE_GET_NAME_AND_DEF_BY_ROW(table_name, cmd_prefix) \ @@@ -576,11 -521,11 +600,11 @@@ static int blob_open(struct osl_table * { int ret; desc->dir = dir; - ret = osl_open_table(desc, table); + ret = osl(osl_open_table(desc, table)); if (ret >= 0) return ret; *table = NULL; - if (ret >= 0 || is_errno(-ret, ENOENT)) + if (ret >= 0 || ret == -OSL_ERRNO_TO_PARA_ERROR(E_OSL_NOENT)) return 1; return ret; } diff --combined command.c index fc5b5cac,17132e87..fa844b5e --- a/command.c +++ b/command.c @@@ -11,11 -11,10 +11,12 @@@ #include #include #include + #include #include "para.h" #include "error.h" +#include "crypt.h" +#include "command.h" #include "server.cmdline.h" #include "string.h" #include "afh.h" @@@ -38,6 -37,10 +39,6 @@@ /** Commands including options must be shorter than this. */ #define MAX_COMMAND_LEN 32768 -static RC4_KEY rc4_recv_key; -static RC4_KEY rc4_send_key; -static unsigned char rc4_buf[2 * RC4_KEY_LEN]; - extern int mmd_mutex; extern struct misc_meta_data *mmd; extern struct sender senders[]; @@@ -100,14 -103,15 +101,15 @@@ static char *vss_get_status_flags(unsig return msg; } - static char *get_status(struct misc_meta_data *nmmd) + static char *get_status(struct misc_meta_data *nmmd, int parser_friendly) { - char *ret, mtime[30] = ""; + char mtime[30] = ""; char *status, *flags; /* vss status info */ char *ut = uptime_str(); long offset = (nmmd->offset + 500) / 1000; struct timeval current_time; struct tm mtime_tm; + struct para_buffer b = {.flags = parser_friendly? PBF_SIZE_PREFIX : 0}; /* report real status */ status = vss_status_tohuman(nmmd->vss_status_flags); @@@ -117,38 -121,22 +119,22 @@@ strftime(mtime, 29, "%b %d %Y", &mtime_tm); } gettimeofday(¤t_time, NULL); - ret = make_message( - "%s: %zu\n" /* file size */ - "%s: %s\n" /* mtime */ - "%s: %s\n" /* status */ - "%s: %s\n" /* status flags */ - "%s: %li\n" /* offset */ - "%s: %s\n" /* afs mode */ - "%s: %lu.%lu\n" /* stream start */ - "%s: %lu.%lu\n" /* current server time */ - "%s", /* afs status info */ - status_item_list[SI_FILE_SIZE], nmmd->size / 1024, - status_item_list[SI_MTIME], mtime, - status_item_list[SI_STATUS], status, - status_item_list[SI_STATUS_FLAGS], flags, - - status_item_list[SI_OFFSET], offset, - status_item_list[SI_AFS_MODE], mmd->afs_mode_string, - - status_item_list[SI_STREAM_START], - (long unsigned)nmmd->stream_start.tv_sec, - (long unsigned)nmmd->stream_start.tv_usec, - status_item_list[SI_CURRENT_TIME], - (long unsigned)current_time.tv_sec, - (long unsigned)current_time.tv_usec, - - nmmd->afd.verbose_ls_output - - ); + WRITE_STATUS_ITEM(&b, SI_FILE_SIZE, "%zu\n", nmmd->size / 1024); + WRITE_STATUS_ITEM(&b, SI_MTIME, "%s\n", mtime); + WRITE_STATUS_ITEM(&b, SI_STATUS, "%s\n", status); + WRITE_STATUS_ITEM(&b, SI_STATUS_FLAGS, "%s\n", flags); + WRITE_STATUS_ITEM(&b, SI_OFFSET, "%li\n", offset); + WRITE_STATUS_ITEM(&b, SI_AFS_MODE, "%s\n", mmd->afs_mode_string); + WRITE_STATUS_ITEM(&b, SI_STREAM_START, "%lu.%lu\n", + (long unsigned)nmmd->stream_start.tv_sec, + (long unsigned)nmmd->stream_start.tv_usec); + WRITE_STATUS_ITEM(&b, SI_CURRENT_TIME, "%lu.%lu\n", + (long unsigned)current_time.tv_sec, + (long unsigned)current_time.tv_usec); free(flags); free(status); free(ut); - return ret; + return b.buf; } static int check_sender_args(int argc, char * const * argv, struct sender_command_data *scd) @@@ -183,9 -171,17 +169,9 @@@ break; case SENDER_DENY: case SENDER_ALLOW: - if (argc != 4 && argc != 5) - return -E_COMMAND_SYNTAX; - if (!is_valid_ipv4_address(argv[3])) + if (argc != 4 || parse_cidr(argv[3], scd->host, + sizeof(scd->host), &scd->netmask) == NULL) return -E_COMMAND_SYNTAX; - scd->netmask = 32; - if (argc == 5) { - scd->netmask = atoi(argv[4]); - if (scd->netmask < 0 || scd->netmask > 32) - return -E_COMMAND_SYNTAX; - } - strncpy(scd->host, argv[3], sizeof(scd->host)); break; case SENDER_ADD: case SENDER_DELETE: @@@ -198,7 -194,7 +184,7 @@@ return 1; } -int com_sender(int fd, int argc, char * const * argv) +int com_sender(struct rc4_context *rc4c, int argc, char * const * argv) { int i, ret; struct sender_command_data scd; @@@ -211,7 -207,7 +197,7 @@@ free(msg); msg = tmp; } - ret = send_buffer(fd, msg); + ret = rc4_send_buffer(rc4c, msg); free(msg); return ret; } @@@ -221,7 -217,7 +207,7 @@@ if (scd.sender_num < 0) return ret; msg = senders[scd.sender_num].help(); - ret = send_buffer(fd, msg); + ret = rc4_send_buffer(rc4c, msg); free(msg); return ret; } @@@ -240,7 -236,7 +226,7 @@@ } /* server info */ -int com_si(int fd, int argc, __a_unused char * const * argv) +int com_si(struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { int i, ret; char *ut; @@@ -257,7 -253,7 +243,7 @@@ sender_list = para_strcat(sender_list, " "); } ut = uptime_str(); - ret = send_va_buffer(fd, "up: %s\nplayed: %u\n" + ret = rc4_send_va_buffer(rc4c, "up: %s\nplayed: %u\n" "server_pid: %d\n" "afs_pid: %d\n" "connections (active/accepted/total): %u/%u/%u\n" @@@ -284,37 -280,119 +270,119 @@@ } /* version */ -int com_version(int fd, int argc, __a_unused char * const * argv) +int com_version(struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; - return send_buffer(fd, VERSION_TEXT("server") + return rc4_send_buffer(rc4c, VERSION_TEXT("server") "built: " BUILD_DATE "\n" UNAME_RS ", " CC_VERSION "\n" ); } + #define EMPTY_STATUS_ITEMS \ + ITEM(PATH) \ + ITEM(DIRECTORY) \ + ITEM(BASENAME) \ + ITEM(SCORE) \ + ITEM(ATTRIBUTES_BITMAP) \ + ITEM(ATTRIBUTES_TXT) \ + ITEM(HASH) \ + ITEM(IMAGE_ID) \ + ITEM(IMAGE_NAME) \ + ITEM(LYRICS_ID) \ + ITEM(LYRICS_NAME) \ + ITEM(BITRATE) \ + ITEM(FORMAT) \ + ITEM(FREQUENCY) \ + ITEM(CHANNELS) \ + ITEM(DURATION) \ + ITEM(SECONDS_TOTAL) \ + ITEM(NUM_PLAYED) \ + ITEM(LAST_PLAYED) \ + ITEM(TECHINFO) \ + ITEM(ARTIST) \ + ITEM(TITLE) \ + ITEM(YEAR) \ + ITEM(ALBUM) \ + ITEM(COMMENT) \ + ITEM(AMPLIFICATION) + + /** + * Write a list of audio-file related status items with empty values. + * + * This is used by vss when currently no audio file is open. + */ + static char *empty_status_items(int parser_friendly) + { + if (parser_friendly) + return make_message( + #define ITEM(x) "0004 %02x:\n" + EMPTY_STATUS_ITEMS + #undef ITEM + #define ITEM(x) , SI_ ## x + EMPTY_STATUS_ITEMS + #undef ITEM + ); + return make_message( + #define ITEM(x) "%s:\n" + EMPTY_STATUS_ITEMS + #undef ITEM + #define ITEM(x) ,status_item_list[SI_ ## x] + EMPTY_STATUS_ITEMS + #undef ITEM + ); + } + #undef EMPTY_STATUS_ITEMS + /* stat */ -int com_stat(int fd, int argc, char * const * argv) +int com_stat(struct rc4_context *rc4c, int argc, char * const * argv) { - int ret, num = 0;/* status will be printed that many - * times. num <= 0 means: print forever - */ + int i, ret; struct misc_meta_data tmp, *nmmd = &tmp; char *s; + int32_t num = 0; + int parser_friendly = 0; para_sigaction(SIGUSR1, dummy); - if (argc > 1) - num = atoi(argv[1]); + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (arg[0] != '-') + break; + if (!strcmp(arg, "--")) { + i++; + break; + } + if (!strncmp(arg, "-n=", 3)) { + ret = para_atoi32(arg + 3, &num); + if (ret < 0) + return ret; + continue; + } + if (!strcmp(arg, "-p")) { + parser_friendly = 1; + continue; + } + } + if (i != argc) + return -E_COMMAND_SYNTAX; for (;;) { - mmd_dup(nmmd); - s = get_status(nmmd); + s = get_status(nmmd, parser_friendly); - ret = send_buffer(fd, s); + ret = rc4_send_buffer(rc4c, s); free(s); if (ret < 0) goto out; + if (nmmd->vss_status_flags & VSS_NEXT) { + static char *esi; + if (!esi) + esi = empty_status_items(parser_friendly); - ret = send_buffer(fd, esi); ++ ret = rc4_send_buffer(rc4c, esi); + if (ret < 0) + goto out; + } else - send_afs_status(fd, parser_friendly); ++ send_afs_status(rc4c, parser_friendly); ret = 1; if (num > 0 && !--num) goto out; @@@ -326,14 -404,14 +394,14 @@@ out return ret; } -static int send_list_of_commands(int fd, struct server_command *cmd, +static int send_list_of_commands(struct rc4_context *rc4c, struct server_command *cmd, const char *handler) { int ret, i; for (i = 1; cmd->name; cmd++, i++) { char *perms = cmd_perms_itohuman(cmd->perms); - ret = send_va_buffer(fd, "%s\t%s\t%s\t%s\n", cmd->name, + ret = rc4_send_va_buffer(rc4c, "%s\t%s\t%s\t%s\n", cmd->name, handler, perms, cmd->description); @@@ -366,7 -444,7 +434,7 @@@ static struct server_command *get_cmd_p } /* help */ -int com_help(int fd, int argc, char * const * argv) +int com_help(struct rc4_context *rc4c, int argc, char * const * argv) { struct server_command *cmd; char *perms, *handler; @@@ -374,9 -452,9 +442,9 @@@ if (argc < 2) { /* no argument given, print list of commands */ - if ((ret = send_list_of_commands(fd, server_cmds, "server")) < 0) + if ((ret = send_list_of_commands(rc4c, server_cmds, "server")) < 0) return ret; - return send_list_of_commands(fd, afs_cmds, "afs"); + return send_list_of_commands(rc4c, afs_cmds, "afs"); } /* argument given for help */ cmd = get_cmd_ptr(argv[1], &handler); @@@ -385,7 -463,7 +453,7 @@@ return -E_BAD_CMD; } perms = cmd_perms_itohuman(cmd->perms); - ret = send_va_buffer(fd, + ret = rc4_send_va_buffer(rc4c, "%s - %s\n\n" "handler: %s\n" "permissions: %s\n" @@@ -404,7 -482,7 +472,7 @@@ } /* hup */ -int com_hup(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_hup(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@@ -413,7 -491,7 +481,7 @@@ } /* term */ -int com_term(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_term(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@@ -421,7 -499,7 +489,7 @@@ return 1; } -int com_play(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_play(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@@ -434,7 -512,7 +502,7 @@@ } /* stop */ -int com_stop(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_stop(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@@ -447,7 -525,7 +515,7 @@@ } /* pause */ -int com_pause(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_pause(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@@ -462,7 -540,7 +530,7 @@@ } /* next */ -int com_next(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_next(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@@ -474,7 -552,7 +542,7 @@@ } /* nomore */ -int com_nomore(__a_unused int fd, int argc, __a_unused char * const * argv) +int com_nomore(__a_unused struct rc4_context *rc4c, int argc, __a_unused char * const * argv) { if (argc != 1) return -E_COMMAND_SYNTAX; @@@ -486,7 -564,7 +554,7 @@@ } /* ff */ -int com_ff(__a_unused int fd, int argc, char * const * argv) +int com_ff(__a_unused struct rc4_context *rc4c, int argc, char * const * argv) { long promille; int ret, backwards = 0; @@@ -525,7 -603,7 +593,7 @@@ out } /* jmp */ -int com_jmp(__a_unused int fd, int argc, char * const * argv) +int com_jmp(__a_unused struct rc4_context *rc4c, int argc, char * const * argv) { long unsigned int i; int ret; @@@ -579,7 -657,32 +647,7 @@@ static struct server_command *parse_cmd return get_cmd_ptr(buf, NULL); } -static void init_rc4_keys(void) -{ - int i; - - for (i = 0; i < 2 * RC4_KEY_LEN; i++) - rc4_buf[i] = para_random(256); - PARA_DEBUG_LOG("rc4 keys initialized (%u:%u)\n", - (unsigned char) rc4_buf[0], - (unsigned char) rc4_buf[RC4_KEY_LEN]); - RC4_set_key(&rc4_recv_key, RC4_KEY_LEN, rc4_buf); - RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN); -} - -static void rc4_recv(unsigned long len, const unsigned char *indata, - unsigned char *outdata, __a_unused void *private_data) -{ - RC4(&rc4_recv_key, len, indata, outdata); -} - -static void rc4_send(unsigned long len, const unsigned char *indata, - unsigned char *outdata, __a_unused void *private_data) -{ - RC4(&rc4_send_key, len, indata, outdata); -} - -static int read_command(int fd, char **result) +static int read_command(struct rc4_context *rc4c, char **result) { int ret; char buf[4096]; @@@ -589,7 -692,7 +657,7 @@@ size_t numbytes; char *p; - ret = recv_buffer(fd, buf, sizeof(buf)); + ret = rc4_recv_buffer(rc4c, buf, sizeof(buf)); if (ret < 0) goto out; if (!ret) @@@ -652,22 -755,22 +720,22 @@@ static void reset_signals(void */ __noreturn void handle_connect(int fd, const char *peername) { - int ret, argc, use_rc4 = 0; + int ret, argc; char buf[4096]; - unsigned char crypt_buf[MAXLINE]; + unsigned char rand_buf[CHALLENGE_SIZE + 2 * RC4_KEY_LEN]; + unsigned char challenge_sha1[HASH_SIZE]; struct user *u; struct server_command *cmd = NULL; - long unsigned challenge_nr, chall_response; char **argv = NULL; char *p, *command = NULL; size_t numbytes; + struct rc4_context rc4c = {.fd = fd}; reset_signals(); /* we need a blocking fd here as recv() might return EAGAIN otherwise. */ ret = mark_fd_blocking(fd); if (ret < 0) goto err_out; - challenge_nr = random(); /* send Welcome message */ ret = send_va_buffer(fd, "This is para_server, version " PACKAGE_VERSION ".\n" ); @@@ -677,69 -780,65 +745,69 @@@ ret = recv_buffer(fd, buf, sizeof(buf)); if (ret < 0) goto err_out; - if (ret <= 6) { - ret = -E_AUTH; + if (ret < 10) { + ret = -E_AUTH_REQUEST; goto err_out; } numbytes = ret; - ret = -E_AUTH; - if (strncmp(buf, "auth ", 5)) + ret = -E_AUTH_REQUEST; + if (strncmp(buf, AUTH_REQUEST_MSG, strlen(AUTH_REQUEST_MSG))) goto err_out; - - if (numbytes < 9 || strncmp(buf, "auth rc4 ", 9)) - p = buf + 5; /* client version < 0.2.6 */ - else { - p = buf + 9; /* client version >= 0.2.6 */ - use_rc4 = 1; - } - PARA_DEBUG_LOG("received %s request for user %s\n", - use_rc4? "rc4" : "auth", p); + p = buf + strlen(AUTH_REQUEST_MSG); + PARA_DEBUG_LOG("received auth request for user %s\n", p); ret = -E_BAD_USER; u = lookup_user(p); - if (!u) - goto err_out; - ret = para_encrypt_challenge(u->rsa, challenge_nr, crypt_buf); - if (ret <= 0) - goto err_out; - numbytes = ret; - PARA_DEBUG_LOG("sending %zu byte challenge\n", numbytes); - /* We can't use send_buffer here since buf may contain null bytes */ - ret = send_bin_buffer(fd,(char *) crypt_buf, numbytes); + if (u) { + get_random_bytes_or_die(rand_buf, sizeof(rand_buf)); + ret = para_encrypt_buffer(u->rsa, rand_buf, sizeof(rand_buf), + (unsigned char *)buf); + if (ret < 0) + goto err_out; + numbytes = ret; + } else { + /* + * We don't want to reveal our user names, so we send a + * challenge to the client even if the user does not exist, and + * fail the authentication later. + */ + numbytes = 256; + get_random_bytes_or_die((unsigned char *)buf, numbytes); + } + PARA_DEBUG_LOG("sending %zu byte challenge + rc4 keys (%u bytes)\n", + CHALLENGE_SIZE, numbytes); + ret = send_bin_buffer(fd, buf, numbytes); if (ret < 0) goto net_err; - /* recv decrypted number */ - ret = recv_buffer(fd, buf, sizeof(buf)); + /* recv challenge response */ + ret = recv_bin_buffer(fd, buf, HASH_SIZE); if (ret < 0) goto net_err; numbytes = ret; - ret = -E_AUTH; - if (!numbytes) + PARA_DEBUG_LOG("received %zu bytes challenge response\n", ret); + ret = -E_BAD_USER; + if (!u) goto net_err; - if (sscanf(buf, CHALLENGE_RESPONSE_MSG "%lu", &chall_response) < 1 - || chall_response != challenge_nr) - goto err_out; - /* auth successful, send 'Proceed' message */ - PARA_INFO_LOG("good auth for %s (%lu)\n", u->name, challenge_nr); - sprintf(buf, "%s", PROCEED_MSG); - if (use_rc4) { - init_rc4_keys(); - ret = para_encrypt_buffer(u->rsa, rc4_buf, 2 * RC4_KEY_LEN, - (unsigned char *)buf + PROCEED_MSG_LEN + 1); - if (ret <= 0) - goto err_out; - numbytes = ret + strlen(PROCEED_MSG) + 1; - } else - numbytes = strlen(buf); - ret = send_bin_buffer(fd, buf, numbytes); + /* + * The correct response is the sha1 of the first CHALLENGE_SIZE bytes + * of the random data. + */ + ret = -E_BAD_AUTH; + if (numbytes != HASH_SIZE) + goto net_err; + sha1_hash((char *)rand_buf, CHALLENGE_SIZE, challenge_sha1); + if (memcmp(challenge_sha1, buf, HASH_SIZE)) + goto net_err; + /* auth successful */ + alarm(0); + PARA_INFO_LOG("good auth for %s\n", u->name); + /* init rc4 keys with the second part of the random buffer */ + RC4_set_key(&rc4c.recv_key, RC4_KEY_LEN, rand_buf + CHALLENGE_SIZE); + RC4_set_key(&rc4c.send_key, RC4_KEY_LEN, rand_buf + CHALLENGE_SIZE + + RC4_KEY_LEN); + ret = rc4_send_buffer(&rc4c, PROCEED_MSG); if (ret < 0) goto net_err; - if (use_rc4) - enable_crypt(fd, rc4_recv, rc4_send, NULL); - ret = read_command(fd, &command); + ret = read_command(&rc4c, &command); if (ret == -E_COMMAND_SYNTAX) goto err_out; if (ret < 0) @@@ -753,17 -852,18 +821,17 @@@ if (ret < 0) goto err_out; /* valid command and sufficient perms */ - alarm(0); argc = split_args(command, &argv, "\n"); PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u->name, peername); - ret = cmd->handler(fd, argc, argv); + ret = cmd->handler(&rc4c, argc, argv); mutex_lock(mmd_mutex); mmd->num_commands++; mutex_unlock(mmd_mutex); if (ret >= 0) goto out; err_out: - send_va_buffer(fd, "%s\n", para_strerror(-ret)); + rc4_send_va_buffer(&rc4c, "%s\n", para_strerror(-ret)); net_err: PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); out: diff --combined configure.ac index b0aba937,3e423909..fde72f2a --- a/configure.ac +++ b/configure.ac @@@ -80,13 -80,13 +80,13 @@@ AC_CHECK_FUNCS([atexit dup2 memchr memm all_errlist_objs="server mp3_afh afh_common vss command net string signal time daemon stat crypt http_send close_on_fork ipc acl afh fade amp_filter - dccp_send fd user_list chunk_queue afs osl aft mood score attribute blob ringbuffer - playlist sha1 rbtree sched audiod grab_client filter_common wav_filter compress_filter + dccp_send fd user_list chunk_queue afs aft mood score attribute blob ringbuffer + playlist sha1 sched audiod grab_client filter_common wav_filter compress_filter http_recv dccp_recv recv_common write_common file_write audiod_command - client_common recv stdout filter stdin audioc write client fsck exec send_common ggo + client_common recv stdout filter stdin audioc write client exec send_common ggo udp_recv udp_send color fec fecdec_filter prebuffer_filter" - all_executables="server recv filter audioc write client fsck afh" + all_executables="server recv filter audioc write client afh" recv_cmdline_objs="recv.cmdline http_recv.cmdline dccp_recv.cmdline udp_recv.cmdline" recv_errlist_objs="http_recv recv_common recv time string net dccp_recv @@@ -111,7 -111,7 +111,7 @@@ audioc_ldflags=" audiod_cmdline_objs="audiod.cmdline grab_client.cmdline compress_filter.cmdline http_recv.cmdline dccp_recv.cmdline file_write.cmdline client.cmdline audiod_command_list amp_filter.cmdline udp_recv.cmdline - prebuffer_filter.cmdline" + prebuffer_filter.cmdline sha1" audiod_errlist_objs="audiod signal string daemon stat net time grab_client filter_common wav_filter compress_filter amp_filter http_recv dccp_recv recv_common fd sched write_common file_write audiod_command crypt fecdec_filter @@@ -126,9 -126,9 +126,9 @@@ afh_ldflags=" server_cmdline_objs="server.cmdline server_command_list afs_command_list" server_errlist_objs="server afh_common mp3_afh vss command net string signal time daemon stat crypt http_send close_on_fork - ipc dccp_send fd user_list chunk_queue afs osl aft mood score attribute - blob playlist sha1 rbtree sched acl send_common udp_send color fec" - server_ldflags="" + ipc dccp_send fd user_list chunk_queue afs aft mood score attribute + blob playlist sha1 sched acl send_common udp_send color fec" + server_ldflags="-losl" server_audio_formats=" mp3" write_cmdline_objs="write.cmdline file_write.cmdline" @@@ -138,13 -138,9 +138,10 @@@ writers=" file default_writer="FILE_WRITE" client_cmdline_objs="client.cmdline" -client_errlist_objs="client net string crypt fd sched stdin stdout client_common" +client_errlist_objs="client net string crypt fd sched stdin stdout + client_common sha1" client_ldflags="" - fsck_cmdline_objs="fsck.cmdline" - fsck_errlist_objs="osl rbtree fsck string sha1 fd" - gui_cmdline_objs="gui.cmdline" gui_errlist_objs="exec signal string stat ringbuffer fd" gui_other_objs="gui gui_theme" @@@ -194,10 -190,9 +191,9 @@@ AC_ARG_ENABLE(ssldir, [AS_HELP_STRING(- [Search for openssl also in path.])]) if test "$enable_ssldir" = "yes"; then enable_ssldir=""; fi CHECK_SSL($enable_ssldir) - server_ldflags="$srver_ldflags $SSL_LDFLAGS $SSL_LIBS" + server_ldflags="$server_ldflags $SSL_LDFLAGS $SSL_LIBS" client_ldflags="$client_ldflags $SSL_LDFLAGS $SSL_LIBS" audiod_ldflags="$audiod_ldflags $SSL_LDFLAGS $SSL_LIBS" - fsck_ldflags="$fsck_ldflags $SSL_LDFLAGS $SSL_LIBS" ########################################################################### libsocket AC_CHECK_LIB([c], [socket], @@@ -614,11 -609,12 +610,12 @@@ AC_DEFINE_UNQUOTED(DEFINE_ERRLIST_OBJEC ################################################################## status items status_items="basename status num_played mtime bitrate frequency file_size - status_flags format score audio_file_info taginfo1 taginfo2 afs_mode + status_flags format score techinfo afs_mode attributes_txt decoder_flags audiod_status play_time attributes_bitmap offset seconds_total stream_start current_time audiod_uptime image_id lyrics_id duration directory lyrics_name image_name path hash channels - last_played num_chunks chunk_time amplification" + last_played num_chunks chunk_time amplification artist title year album + comment" # $1: prefix, $2: items AC_DEFUN([make_enum_items], [$( @@@ -650,7 -646,6 +647,6 @@@ audiod_objs="$audiod_cmdline_objs $audi server_objs="$server_cmdline_objs $server_errlist_objs" write_objs="$write_cmdline_objs $write_errlist_objs" client_objs="$client_cmdline_objs $client_errlist_objs" - fsck_objs="$fsck_cmdline_objs $fsck_errlist_objs" audioc_objs="$audioc_cmdline_objs $audioc_errlist_objs" afh_objs="$afh_cmdline_objs $afh_errlist_objs" fade_objs="$fade_cmdline_objs $fade_errlist_objs" @@@ -690,11 -685,6 +686,6 @@@ AC_SUBST(client_ldflags, $client_ldflag AC_DEFINE_UNQUOTED(INIT_CLIENT_ERRLISTS, objlist_to_errlist($client_errlist_objs), errors used by para_client) - AC_SUBST(fsck_objs, add_dot_o($fsck_objs)) - AC_SUBST(fsck_ldflags, $fsck_ldflags) - AC_DEFINE_UNQUOTED(INIT_FSCK_ERRLISTS, - objlist_to_errlist($fsck_errlist_objs), errors used by para_fsck) - AC_SUBST(audioc_objs, add_dot_o($audioc_objs)) AC_SUBST(audioc_ldflags, $audioc_ldflags) AC_DEFINE_UNQUOTED(INIT_AUDIOC_ERRLISTS, diff --combined error.h index 20f6b767,a06baf21..59d0321f --- a/error.h +++ b/error.h @@@ -100,46 -100,6 +100,6 @@@ extern const char **para_errlist[] PARA_ERROR(RANGE_VIOLATION, "range violation detected, very bad"), \ PARA_ERROR(NOT_A_REGULAR_FILE, "not a regular file"), \ - - #define OSL_ERRORS \ - PARA_ERROR(BAD_DB_DIR, "invalid database directory"), \ - PARA_ERROR(NO_COLUMN_DESC, "missing column description"), \ - PARA_ERROR(BAD_NAME, "invalid name for a column/table"), \ - PARA_ERROR(BAD_STORAGE_TYPE, "invalid storage type"), \ - PARA_ERROR(BAD_STORAGE_FLAGS, "invalid storage flags"), \ - PARA_ERROR(NO_COLUMN_NAME, "missing column name"), \ - PARA_ERROR(NO_COLUMNS, "at least one column required"), \ - PARA_ERROR(BAD_COLUMN_NAME, "invalid name for a table column"), \ - PARA_ERROR(NO_UNIQUE_RBTREE_COLUMN, "need at least one mapped column with OSL_UNIQE and OSL_RBTREE OSL"), \ - PARA_ERROR(NO_RBTREE_COL, "at least one column needs an rbtree"), \ - PARA_ERROR(DUPLICATE_COL_NAME, "column name given twice"), \ - PARA_ERROR(BAD_STORAGE_SIZE, "invalid storage size"), \ - PARA_ERROR(NO_COMPARE_FUNC, "missing compare function"), \ - PARA_ERROR(BAD_DATA_SIZE, "wrong data size for fixed-size column"), \ - PARA_ERROR(NOT_MAPPED, "file not mapped"), \ - PARA_ERROR(ALREADY_MAPPED, "file already mapped"), \ - PARA_ERROR(BAD_SIZE, "invalid size specified"), \ - PARA_ERROR(TRUNC, "failed to truncate file"), \ - PARA_ERROR(BAD_TABLE, "table not open"), \ - PARA_ERROR(BAD_TABLE_DESC, "invalid table description"), \ - PARA_ERROR(RB_KEY_EXISTS, "key already exists in rbtree"), \ - PARA_ERROR(RB_KEY_NOT_FOUND, "key not found in rbtree"), \ - PARA_ERROR(BAD_ROW_NUM, "invalid row number"), \ - PARA_ERROR(INDEX_CORRUPTION, "index corruption detected"), \ - PARA_ERROR(INVALID_OBJECT, "reference to invalid object"), \ - PARA_ERROR(STAT, "can not stat file"), \ - PARA_ERROR(WRITE, "write error"), \ - PARA_ERROR(LSEEK, "lseek error"), \ - PARA_ERROR(BUSY, "table is busy"), \ - PARA_ERROR(SHORT_TABLE, "table too short"), \ - PARA_ERROR(NO_MAGIC, "missing table header magic"), \ - PARA_ERROR(VERSION_MISMATCH, "table version not supported"), \ - PARA_ERROR(BAD_COLUMN_NUM, "invalid column number"), \ - PARA_ERROR(BAD_TABLE_FLAGS, "invalid flags in table description"), \ - PARA_ERROR(BAD_ROW, "invalid row"), \ - - - #define AFS_ERRORS \ PARA_ERROR(BAD_TABLE_NAME, "invalid table"), \ PARA_ERROR(INPUT_TOO_LARGE, "input too large for stdin command"), \ @@@ -147,6 -107,7 +107,7 @@@ PARA_ERROR(AFS_SIGNAL, "afs caught deadly signal"), \ PARA_ERROR(AFS_SOCKET, "afs socket not writable"), \ PARA_ERROR(AFS_SHORT_READ, "short read from afs socket"), \ + PARA_ERROR(OSL, "osl error"), \ #define MOOD_ERRORS \ @@@ -277,6 -238,7 +238,7 @@@ #define STAT_ERRORS \ PARA_ERROR(TOO_MANY_CLIENTS, "maximal number of stat clients exceeded"), \ PARA_ERROR(UNKNOWN_STAT_ITEM, "status item not recognized"), \ + PARA_ERROR(STAT_ITEM_PARSE, "failed to parse status item"), \ #define OGGDEC_FILTER_ERRORS \ @@@ -315,6 -277,7 +277,7 @@@ PARA_ERROR(STRTOLL, "unknown strtoll error"), \ PARA_ERROR(ATOI_NO_DIGITS, "no digits found in string"), \ PARA_ERROR(ATOI_JUNK_AT_END, "further characters after number"), \ + PARA_ERROR(SIZE_PREFIX, "bad size prefix") \ #define EXEC_ERRORS \ @@@ -368,15 -331,14 +331,15 @@@ #define COMMAND_ERRORS \ PARA_ERROR(COMMAND_SYNTAX, "syntax error in command"), \ - PARA_ERROR(AUTH, "did not receive auth request"), \ + PARA_ERROR(AUTH_REQUEST, "did not receive auth request"), \ PARA_ERROR(NO_AUDIO_FILE, "no audio file"), \ PARA_ERROR(BAD_CMD, "invalid command"), \ PARA_ERROR(PERM, "permission denied"), \ PARA_ERROR(LOCK, "lock error"), \ PARA_ERROR(SENDER_CMD, "command not supported by this sender"), \ PARA_ERROR(SERVER_CRASH, "para_server crashed -- can not live without it"), \ - PARA_ERROR(BAD_USER, "you don't exist. Go away."), \ + PARA_ERROR(BAD_USER, "auth request for invalid user"), \ + PARA_ERROR(BAD_AUTH, "authentication failure"), \ #define DCCP_RECV_ERRORS \ @@@ -480,12 -442,23 +443,23 @@@ */ #define SYSTEM_ERROR_BIT 30 + /** + * Like the SYSTEM_ERROR_BIT, but indicates an error from the osl library. + */ + #define OSL_ERROR_BIT 29 + /** Check whether the system error bit is set. */ #define IS_SYSTEM_ERROR(num) (!!((num) & (1 << SYSTEM_ERROR_BIT))) + /** Check whether the osl error bit is set. */ + #define IS_OSL_ERROR(num) (!!((num) & (1 << OSL_ERROR_BIT))) + /** Set the system error bit for the given number. */ #define ERRNO_TO_PARA_ERROR(num) ((num) | (1 << SYSTEM_ERROR_BIT)) + /** Set the osl error bit for the given number. */ + #define OSL_ERRNO_TO_PARA_ERROR(num) ((num) | (1 << OSL_ERROR_BIT)) + /** Check whether a given number is a system error number. * * \param num The value to be checked. @@@ -510,11 -483,33 +484,33 @@@ _static_inline_ int is_errno(int num, i _static_inline_ const char *para_strerror(int num) { assert(num > 0); + #ifdef _OSL_H + if (IS_OSL_ERROR(num)) + return osl_strerror(num & ((1 << OSL_ERROR_BIT) - 1)); + #endif if (IS_SYSTEM_ERROR(num)) - return strerror((num) & ((1 << SYSTEM_ERROR_BIT) - 1)); - else - return para_errlist[ERRNUM_TO_SS(num)][ERRNUM_TO_INDEX(num)]; + return strerror(num & ((1 << SYSTEM_ERROR_BIT) - 1)); + return para_errlist[ERRNUM_TO_SS(num)][ERRNUM_TO_INDEX(num)]; } + + /** + * Wrapper for osl library calls. + * + * \param ret The return value of an osl library function. + * + * This should be used for all calls to osl functions that return an osl error + * code. It changes the return value appropriately so that it can be used for + * printing the correct error message vi para_strerror(). + * + * \return \a ret if \a ret >= 0, a paraslash error code otherwise. + */ + _static_inline_ int osl(int ret) + { + if (ret >= 0) + return ret; + return -OSL_ERRNO_TO_PARA_ERROR(-ret); + } + /** * Define the error list for one subsystem. # diff --combined mp3_afh.c index 2d18d5e5,f0db140d..ff133ca5 --- a/mp3_afh.c +++ b/mp3_afh.c @@@ -16,12 -16,13 +16,11 @@@ * Johannes Overmann */ + #include #include "para.h" #include "error.h" #include "afh.h" #include "string.h" --#include "afs.h" --#include "server.h" /** \cond some defines and structs which are only used in this file */ @@@ -126,62 -127,49 +125,49 @@@ static char *get_strings(struct id3_fra return NULL; } - static char *mp3_get_id3(__a_unused unsigned char *map, - __a_unused size_t numbytes, int fd) + static void mp3_get_id3(__a_unused unsigned char *map, + __a_unused size_t numbytes, int fd, struct taginfo *tags) { int i; struct id3_tag *id3_t; - char *title = NULL, *artist = NULL, *album = NULL, *year = NULL, - *comment = NULL, *result; struct id3_file *id3_f = id3_file_fdopen(fd, ID3_FILE_MODE_READONLY); if (!id3_f) - goto no_tag; + return; id3_t = id3_file_tag(id3_f); - if (!id3_t) - goto no_tag; + if (!id3_t) { + id3_file_close(id3_f); + return; + } for (i = 0; i < id3_t->nframes; i++) { struct id3_frame *fr = id3_t->frames[i]; if (!strcmp(fr->id, "TIT2")) { - if (!title) - title = get_strings(fr); + if (!tags->title) + tags->title = get_strings(fr); continue; } if (!strcmp(fr->id, "TPE1")) { - if (!artist) - artist = get_strings(fr); + if (!tags->artist) + tags->artist = get_strings(fr); continue; } if (!strcmp(fr->id, "TALB")) { - if (!album) - album = get_strings(fr); + if (!tags->album) + tags->album = get_strings(fr); continue; } if (!strcmp(fr->id, "TDRC")) { - if (!year) - year = get_strings(fr); + if (!tags->year) + tags->year = get_strings(fr); continue; } if (!strcmp(fr->id, "COMM")) { - if (!comment) - comment = get_strings(fr); + if (!tags->comment) + tags->comment = get_strings(fr); continue; } } id3_file_close(id3_f); - result = make_taginfo(title, artist, album, year, comment); - free(title); - free(artist); - free(album); - free(year); - free(comment); - return result; - no_tag: - if (id3_f) - id3_file_close(id3_f); - return make_message("%s: (no id3 v1/v2 tag)\n%s:\n", - status_item_list[SI_TAGINFO1], - status_item_list[SI_TAGINFO2]); } #else /* HAVE_LIBID3TAG */ @@@ -197,16 -185,15 +183,15 @@@ static char *unpad(char *string return string; } - static char *mp3_get_id3(unsigned char *map, size_t numbytes, __a_unused int fd) + static void mp3_get_id3(unsigned char *map, size_t numbytes, __a_unused int fd, + struct taginfo *tags) { char title[31], artist[31], album[31], year[5], comment[31]; off_t fpos; if (numbytes < 128 || strncmp("TAG", (char *)map + numbytes - 128, 3)) { PARA_DEBUG_LOG("no id3 v1 tag\n"); - return make_message("%s: (no id3 v1 tag)\n%s:\n", - status_item_list[SI_TAGINFO1], - status_item_list[SI_TAGINFO2]); + return; } fpos = numbytes - 125; memcpy(title, map + fpos, 30); @@@ -228,7 -215,11 +213,11 @@@ unpad(album); unpad(year); unpad(comment); - return make_taginfo(title, artist, album, year, comment); + tags->artist = para_strdup(artist); + tags->title = para_strdup(title); + tags->year = para_strdup(year); + tags->album = para_strdup(album); + tags->comment = para_strdup(comment); } #endif /* HAVE_LIBID3TAG */ @@@ -400,11 -391,9 +389,9 @@@ static int mp3_read_info(unsigned char unsigned chunk_table_size = 1000; /* gets increased on demand */ off_t fpos = 0; struct mp3header header; - char *taginfo; afhi->chunks_total = 0; afhi->chunk_table = para_malloc(chunk_table_size * sizeof(uint32_t)); - taginfo = mp3_get_id3(map, numbytes, fd); while (1) { int freq, br; struct timeval tmp, cct; /* current chunk time */ @@@ -460,15 -449,11 +447,11 @@@ tv_divide(afhi->chunks_total, &total_time, &afhi->chunk_tv); PARA_DEBUG_LOG("%lu chunks, each %lums\n", afhi->chunks_total, tv2ms(&afhi->chunk_tv)); - tv_scale(3, &afhi->chunk_tv, &afhi->eof_tv); - PARA_DEBUG_LOG("eof timeout: %lu\n", tv2ms(&afhi->eof_tv)); - afhi->info_string = make_message("%s: %cbr, %s\n%s", - status_item_list[SI_AUDIO_FILE_INFO], vbr? 'v' : 'c', - header_mode(&header), taginfo); - free(taginfo); + afhi->techinfo = make_message("%cbr, %s", vbr? 'v' : 'c', + header_mode(&header)); + mp3_get_id3(map, numbytes, fd, &afhi->tags); return 1; err_out: - free(taginfo); PARA_ERROR_LOG("%s\n", para_strerror(-ret)); free(afhi->chunk_table); return ret; diff --combined ogg_afh.c index 55cf4ced,e91c6c2b..f0c1e435 --- a/ogg_afh.c +++ b/ogg_afh.c @@@ -9,13 -9,14 +9,12 @@@ #include #include #include + #include #include "para.h" --#include "afh.h" #include "error.h" ++#include "afh.h" #include "string.h" --#include "afs.h" --#include "server.h" /** must be big enough to hold header */ #define CHUNK_SIZE 32768 @@@ -233,26 -234,17 +232,17 @@@ static long unsigned ogg_compute_chunk_ return num_chunks; } - static void ogg_write_info_string(OggVorbis_File *vf, struct afh_info *afhi) + static void ogg_get_vorbis_comments(OggVorbis_File *vf, struct afh_info *afhi) { - char *taginfo; vorbis_comment *vc = ov_comment(vf,-1); - if (vc) { - char *artist, *title, *album, *year, *comment; - artist = vorbis_comment_query(vc, "artist", 0); - title = vorbis_comment_query(vc, "title", 0); - album = vorbis_comment_query(vc, "album", 0); - year = vorbis_comment_query(vc, "year", 0); - comment = vorbis_comment_query(vc, "comment", 0); - taginfo = make_taginfo(title, artist, album, year, comment); - } else - taginfo = make_message("%s: (no vorbis comments found)\n%s:\n", - status_item_list[SI_TAGINFO1], - status_item_list[SI_TAGINFO2]); - afhi->info_string = make_message("%s:\n%s", - status_item_list[SI_AUDIO_FILE_INFO], taginfo); - free(taginfo); + if (!vc) + return; + afhi->tags.artist = para_strdup(vorbis_comment_query(vc, "artist", 0)); + afhi->tags.title = para_strdup(vorbis_comment_query(vc, "title", 0)); + afhi->tags.album = para_strdup(vorbis_comment_query(vc, "album", 0)); + afhi->tags.year = para_strdup(vorbis_comment_query(vc, "year", 0)); + afhi->tags.comment = para_strdup(vorbis_comment_query(vc, "comment", 0)); } /* @@@ -289,8 -281,7 +279,7 @@@ static int ogg_get_file_info(char *map afhi->chunks_total = ogg_compute_chunk_table(&of, afhi, afhi->seconds_total); afhi->chunk_tv.tv_sec = 0; afhi->chunk_tv.tv_usec = 250 * 1000; - tv_scale(10 / afhi->channels, &afhi->chunk_tv, &afhi->eof_tv); - ogg_write_info_string(&of, afhi); + ogg_get_vorbis_comments(&of, afhi); ret = 1; err: ov_clear(&of); /* keeps the file open */ diff --combined para.h index d49d7221,995bfb9d..66cf9e48 --- a/para.h +++ b/para.h @@@ -145,17 -145,16 +145,17 @@@ printf("%s", VERSION_TEXT(_prefix)); \ exit(EXIT_SUCCESS); \ } + +/* Sent by para_client to initiate the authentication procedure. */ +#define AUTH_REQUEST_MSG "auth rsa " /** sent by para_server for commands that expect a data file */ #define AWAITING_DATA_MSG "\nAwaiting Data." /** sent by para_server if authentication was successful */ -#define PROCEED_MSG "\nProceed.\n" +#define PROCEED_MSG "Proceed." /** length of the \p PROCEED_MSG string */ #define PROCEED_MSG_LEN strlen(PROCEED_MSG) /** sent by para_client to indicate the end of the command line */ #define EOC_MSG "\nEnd of Command." -/** sent by para_client, followed by the decrypted challenge number */ -#define CHALLENGE_RESPONSE_MSG "challenge_response:" /* exec */ int para_exec_cmdline_pid(pid_t *pid, const char *cmdline, int *fds); @@@ -182,9 -181,11 +182,11 @@@ extern const char *status_item_list[] /** Loop over each status item. */ #define FOR_EACH_STATUS_ITEM(i) for (i = 0; i < NUM_STAT_ITEMS; i++) int stat_item_valid(const char *item); - int stat_line_valid(const char *); - void stat_client_write(const char *msg, int itemnum); - int stat_client_add(int fd, uint64_t mask); + void stat_client_write_item(int item_num); + int stat_client_add(int fd, uint64_t mask, int parser_friendly); + int for_each_stat_item(char *item_buf, size_t num_bytes, + int (*item_handler)(int, char *)); + void clear_and_dump_items(void); __printf_2_3 void para_log(int, const char*, ...); @@@ -225,7 -226,7 +227,7 @@@ * * \return An integer between zero and \p max - 1, inclusively. */ -static inline long int para_random(unsigned max) +_static_inline_ long int para_random(unsigned max) { return ((max + 0.0) * (random() / (RAND_MAX + 1.0))); } diff --combined send_common.c index 200e59ab,12d7ee1d..a1757a51 --- a/send_common.c +++ b/send_common.c @@@ -7,6 -7,7 +7,7 @@@ /** \file send_common.c Functions used by more than one paraslash sender. */ #include + #include #include "para.h" #include "error.h" #include "string.h" @@@ -214,7 -215,7 +215,7 @@@ void init_sender_status(struct sender_s * * \return The string printed in the "si" command. */ - char *get_sender_info(struct sender_status *ss, char *name) + char *get_sender_info(struct sender_status *ss, const char *name) { char *clnts = NULL, *ret; struct sender_client *sc, *tmp_sc; @@@ -389,9 -390,8 +390,9 @@@ char *generic_sender_help(void { return make_message( "usage: {on|off}\n" - "usage: {allow|deny} IP mask\n" - "example: allow 127.0.0.1 32\n" + "usage: {allow|deny} IP[/netmask]\n" + " where mask defaults to 32\n" + "example: allow 192.168.0.1/24\n" ); } diff --combined server.c index 8c617325,e08b0661..24556263 --- a/server.c +++ b/server.c @@@ -14,7 -14,7 +14,7 @@@ * * * - The main programs: \ref server.c, \ref audiod.c, \ref client.c, - * \ref audioc.c, \ref fsck.c, \ref afh.c + * \ref audioc.c, \ref afh.c * - Server: \ref server_command, \ref sender, * - Audio file selector: \ref audio_format_handler, \ref mood, \ref afs_table, * - Client: \ref receiver, \ref receiver_node, \ref filter, \ref filter_node. @@@ -47,7 -47,6 +47,6 @@@ * - Time: \ref time.c, * - Spawning processes: \ref exec.c, * - Inter process communication: \ref ipc.c, - * - The object storage layer: \ref osl.c, * - Blob tables: \ref blob.c, * - The error subssystem: \ref error.h. * - Access control for paraslash senders: \ref acl.c, \ref acl.h. @@@ -55,7 -54,6 +54,6 @@@ * Low-level data structures: * * - Doubly linked lists: \ref list.h, - * - Red-black trees: \ref rbtree.h, \ref rbtree.c, * - Ring buffer: \ref ringbuffer.c, \ref ringbuffer.h, * - Hashing: \ref hash.h, \ref sha1.h, \ref sha1.c, * - Crypto: \ref crypt.c. @@@ -65,11 -63,10 +63,12 @@@ #include #include #include +#include + #include #include "para.h" #include "error.h" +#include "crypt.h" #include "server.cmdline.h" #include "afh.h" #include "string.h" @@@ -320,7 -317,6 +319,6 @@@ static void signal_post_select(struct s waitpid(mmd->afs_pid, NULL, 0); cleanup: free(mmd->afd.afhi.chunk_table); - free(mmd->afd.afhi.info_string); close_listed_fds(); mutex_destroy(mmd_mutex); shm_detach(mmd); @@@ -362,7 -358,6 +360,6 @@@ static void command_post_select(struct char *peer_name; pid_t child_pid; uint32_t *chunk_table; - char *info_string; if (!FD_ISSET(sct->listen_fd, &s->rfds)) return; @@@ -374,15 -369,16 +371,15 @@@ PARA_INFO_LOG("got connection from %s, forking\n", peer_name); mmd->num_connects++; mmd->active_connections++; - /* The chunk table and the info_string are pointers located in the - * mmd struct that point to dynamically allocated memory that must be - * freed by the parent and the child. However, as the mmd struct is in - * a shared memory area, there's no guarantee that after the fork these - * pointers are still valid in child context. As these two pointers are - * not used in the child anyway, we save them to local variables and - * free the memory via that copy in the child. - random(); + /* - * The chunk table is a pointer located in the mmd struct that point to - * dynamically allocated memory that must be freed by the parent and - * the child. However, as the mmd struct is in a shared memory area, - * there's no guarantee that after the fork these pointers are still - * valid in child context. As this pointer is not used in the child - * anyway, we save it to a local variable and free the memory via that - * copy in the child. ++ * The chunk table is a pointer located in the mmd struct that points ++ * to dynamically allocated memory, i.e. it must be freed by the parent ++ * and the child. However, as the mmd struct is in a shared memory ++ * area, there's no guarantee that after the fork this pointer is still ++ * valid in child context. As it is not used in the child anyway, we ++ * save it to a local variable before the fork and free the memory via ++ * that copy in the child directly after the fork. */ - info_string = mmd->afd.afhi.info_string; chunk_table = mmd->afd.afhi.chunk_table; child_pid = fork(); if (child_pid < 0) { @@@ -395,7 -391,6 +392,6 @@@ return; } /* mmd might already have changed at this point */ - free(info_string); free(chunk_table); alarm(ALARM_TIMEOUT); close_listed_fds(); @@@ -439,6 -434,35 +435,6 @@@ err exit(EXIT_FAILURE); } -static void init_random_seed(void) -{ - unsigned int seed; - int fd, ret = para_open("/dev/urandom", O_RDONLY, 0); - - if (ret < 0) - goto err; - fd = ret; - ret = read(fd, &seed, sizeof(seed)); - if (ret < 0) { - ret = -ERRNO_TO_PARA_ERROR(errno); - goto out; - } - if (ret != sizeof(seed)) { - ret = -ERRNO_TO_PARA_ERROR(EIO); - goto out; - } - srandom(seed); - ret = 1; -out: - close(fd); - if (ret >= 0) - return; -err: - PARA_EMERG_LOG("can not seed pseudo random number generator: %s\n", - para_strerror(-ret)); - exit(EXIT_FAILURE); -} - static int init_afs(void) { int ret, afs_server_socket[2]; @@@ -446,8 -470,7 +442,8 @@@ ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, afs_server_socket); if (ret < 0) exit(EXIT_FAILURE); - afs_socket_cookie = para_random((uint32_t)-1); + get_random_bytes_or_die((unsigned char *)&afs_socket_cookie, + sizeof(afs_socket_cookie)); mmd->afs_pid = fork(); if (mmd->afs_pid < 0) exit(EXIT_FAILURE); @@@ -483,7 -506,7 +479,7 @@@ static void server_init(int argc, char int afs_socket; valid_fd_012(); - init_random_seed(); + init_random_seed_or_die(); /* parse command line options */ server_cmdline_parser_ext(argc, argv, &conf, ¶ms); HANDLE_VERSION_FLAG("server", conf); diff --combined server.cmd index d574d2c8,a089060a..0c132101 --- a/server.cmd +++ b/server.cmd @@@ -3,8 -3,8 +3,8 @@@ SF: command. HC: prototypes for the server command handlers CC: array of server commands AT: server_command - SI: openssl/rc4 -IN: para error string afh afs server list user_list -SI: osl ++SI: openssl/rc4 osl +IN: para error crypt command string afh afs server list user_list SN: list of server commands --- N: ff @@@ -93,11 -93,14 +93,14 @@@ H: Print server uptime and other inform --- N: stat P: VSS_READ - D: Print status info for current audio file. - U: stat [n] - H: Without any arguments, stat continuously prints status messages - H: about the audio file being streamed. Use the optional number n - H: to let stat exit after having displayed status n times. + D: Print status info for the current audio file. + U: stat [-n num] [-p] + H: If -n is given, the command exits after having displayed the status n + H: times. Otherwise, the command runs in an endless loop. + H: + H: The -p option activates parser-friendly output: Each status item is + H: prefixed with its size in bytes and the status items identifiers are + H: printed as numerical values. --- N: stop P: VSS_READ | VSS_WRITE diff --combined string.c index d0bb60c5,38c68ecb..51985404 --- a/string.c +++ b/string.c @@@ -200,15 -200,15 +200,15 @@@ __must_check __malloc char *para_dirnam * ends with a slash. Otherwise, a pointer within \a name is returned. Caller * must not free the result. */ - __must_check const char *para_basename(const char *name) + __must_check char *para_basename(const char *name) { - const char *ret; + char *ret; if (!name || !*name) return NULL; ret = strrchr(name, '/'); if (!ret) - return name; + return (char *)name; ret++; return ret; } @@@ -231,6 -231,27 +231,6 @@@ void chop(char *buf buf[n - 1] = '\0'; } -/** - * Get a random filename. - * - * This is by no means a secure way to create temporary files in a hostile - * directory like \p /tmp. However, it is OK to use for temp files, fifos, - * sockets that are created in ~/.paraslash. Result must be freed by the - * caller. - * - * \return A pointer to a random filename. - */ -__must_check __malloc char *para_tmpname(void) -{ - struct timeval now; - unsigned int seed; - - gettimeofday(&now, NULL); - seed = now.tv_usec; - srand(seed); - return make_message("%08i", rand()); -} - /** * Get the logname of the current user. * @@@ -436,6 -457,40 +436,40 @@@ int for_each_line_ro(char *buf, size_t private_data); } + #define hex(a) (hexchar[(a) & 15]) + static void write_size_header(char *buf, int n) + { + static char hexchar[] = "0123456789abcdef"; + + buf[0] = hex(n >> 12); + buf[1] = hex(n >> 8); + buf[2] = hex(n >> 4); + buf[3] = hex(n); + buf[4] = ' '; + } + + int read_size_header(const char *buf) + { + int i, len = 0; + + for (i = 0; i < 4; i++) { + unsigned char c = buf[i]; + len <<= 4; + if (c >= '0' && c <= '9') { + len += c - '0'; + continue; + } + if (c >= 'a' && c <= 'f') { + len += c - 'a' + 10; + continue; + } + return -E_SIZE_PREFIX; + } + if (buf[4] != ' ') + return -E_SIZE_PREFIX; + return len; + } + /** * Safely print into a buffer at a given offset. * @@@ -451,7 -506,8 +485,8 @@@ * 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. + * buffer. If \a max_size_handler() returns a negative value, this value is + * returned by \a para_printf(). * * 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 @@@ -461,13 -517,15 +496,15 @@@ * initial buffer is allocated. * * \return The number of bytes printed into the buffer (not including the - * terminating \p NULL byte). + * terminating \p NULL byte) on success, negative on errors. If there is no + * size-bound on \a b, i.e. if \p b->max_size is zero, this function never + * fails. * * \sa make_message(), vsnprintf(3). */ __printf_2_3 int para_printf(struct para_buffer *b, const char *fmt, ...) { - int ret; + int ret, sz_off = (b->flags & PBF_SIZE_PREFIX)? 5 : 0; if (!b->buf) { b->buf = para_malloc(128); @@@ -478,13 -536,16 +515,16 @@@ char *p = b->buf + b->offset; size_t size = b->size - b->offset; va_list ap; - if (size) { + + if (size > sz_off) { va_start(ap, fmt); - ret = vsnprintf(p, size, fmt, ap); + ret = vsnprintf(p + sz_off, size - sz_off, fmt, ap); va_end(ap); - if (ret > -1 && ret < size) { /* success */ - b->offset += ret; - return ret; + if (ret > -1 && ret < size - sz_off) { /* success */ + b->offset += ret + sz_off; + if (sz_off) + write_size_header(p, ret); + return ret + sz_off; } } /* check if we may grow the buffer */ diff --combined string.h index a9dfae90,38e5edc9..d28b0ac4 --- a/string.h +++ b/string.h @@@ -6,6 -6,12 +6,12 @@@ /** \file string.h exported sybmols from string.c */ + /** Flags that change how content is printed into the buffer. */ + enum para_buffer_flags { + /** Prefix each buffer with its length. */ + PBF_SIZE_PREFIX = 1, + }; + /** A string buffer used for para_printf(). */ struct para_buffer { /** The buffer. May be \p NULL. */ @@@ -14,6 -20,8 +20,8 @@@ size_t size; /** The maximal size this buffer may grow. Zero means unlimited. */ size_t max_size; + /** \sa para_buffer_flags. */ + unsigned flags; /** The next para_printf() will write at this offset. */ size_t offset; /** @@@ -26,6 -34,28 +34,28 @@@ void *private_data; }; + /** + * Write the contents of a status item to a para_buffer. + * + * \param b The para_buffer. + * \param n The number of the status item. + * \param f A format string. + * + * \return The return value of the underlying call to para_printf(). + */ + #define WRITE_STATUS_ITEM(b, n, f, ...) (\ + { \ + int _ret; \ + if ((b)->flags & PBF_SIZE_PREFIX) { \ + _ret = para_printf((b), "%02x:" f, n, ## __VA_ARGS__); \ + } else { \ + _ret = para_printf((b), "%s: " f, status_item_list[(n)], \ + ## __VA_ARGS__); \ + } \ + _ret; \ + } \ + ) + __must_check __malloc void *para_realloc(void *p, size_t size); __must_check __malloc void *para_malloc(size_t size); __must_check __malloc void *para_calloc(size_t size); @@@ -33,8 -63,9 +63,8 @@@ __must_check __malloc char *para_strdup __must_check __malloc __printf_1_2 char *make_message(const char *fmt, ...); __must_check __malloc char *para_strcat(char *a, const char *b); __must_check __malloc char *para_dirname(const char *name); - __must_check const char *para_basename(const char *name); + __must_check char *para_basename(const char *name); void chop(char *buf); -__must_check __malloc char *para_tmpname(void); __must_check __malloc char *para_logname(void); __must_check __malloc char *para_homedir(void); unsigned split_args(char *args, char *** const argv_ptr, const char *delim); @@@ -49,3 -80,4 +79,4 @@@ int for_each_line_ro(char *buf, size_t int para_atoi64(const char *str, int64_t *result); int para_atoi32(const char *str, int32_t *value); int get_loglevel_by_name(const char *txt); + int read_size_header(const char *buf);