Merge branch 'refs/heads/t/strerror'
authorAndre Noll <maan@tuebingen.mpg.de>
Tue, 8 Dec 2015 06:39:04 +0000 (07:39 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Tue, 8 Dec 2015 06:39:04 +0000 (07:39 +0100)
Was cooking in next since 2015-09-27.

* refs/heads/t/strerror:
  error.h: Never call (para_)strerror() on osl errors.
  Clarify para_strerror().
  error.h: Remove is_errno().

1  2 
afs.c
error.h

diff --combined afs.c
--- 1/afs.c
--- 2/afs.c
+++ b/afs.c
@@@ -130,7 -130,7 +130,7 @@@ extern uint32_t afs_socket_cookie
   */
  struct callback_query {
        /** The function to be called. */
 -      callback_function *handler;
 +      afs_callback *handler;
        /** The number of bytes of the query */
        size_t query_size;
  };
@@@ -166,8 -166,13 +166,8 @@@ static int dispatch_result(int result_s
        }
        result.size = cr->result_size;
        result.data = result_shm + sizeof(*cr);
 -      if (result.size) {
 -              assert(handler);
 -              ret = handler(&result, cr->band, private_result_data);
 -              if (ret < 0)
 -                      PARA_NOTICE_LOG("result handler error: %s\n",
 -                              para_strerror(-ret));
 -      }
 +      assert(handler);
 +      ret = handler(&result, cr->band, private_result_data);
        ret2 = shm_detach(result_shm);
        if (ret2 < 0) {
                PARA_ERROR_LOG("detach failed: %s\n", para_strerror(-ret2));
   *
   * \sa send_option_arg_callback_request(), send_standard_callback_request().
   */
 -int send_callback_request(callback_function *f, struct osl_object *query,
 +int send_callback_request(afs_callback *f, struct osl_object *query,
                callback_result_handler *result_handler,
                void *private_result_data)
  {
                ret = *(int *) buf;
                assert(ret > 0);
                result_shmid = ret;
 -              if (!dispatch_error) {
 -                      ret = dispatch_result(result_shmid, result_handler,
 -                              private_result_data);
 -                      if (ret < 0)
 -                              dispatch_error = 1;
 -              }
 +              ret = dispatch_result(result_shmid, result_handler,
 +                      private_result_data);
 +              if (ret < 0 && dispatch_error >= 0)
 +                      dispatch_error = ret;
                ret = shm_destroy(result_shmid);
                if (ret < 0)
                        PARA_CRIT_LOG("destroy result failed: %s\n",
@@@ -271,11 -278,8 +271,11 @@@ out
                PARA_CRIT_LOG("shm destroy error\n");
        if (fd >= 0)
                close(fd);
 -//    PARA_DEBUG_LOG("callback_ret: %d\n", ret);
 -      return ret < 0? ret : num_dispatched;
 +      if (dispatch_error < 0)
 +              return dispatch_error;
 +      if (ret < 0)
 +              return ret;
 +      return num_dispatched;
  }
  
  /**
   * \sa send_standard_callback_request(), send_callback_request().
   */
  int send_option_arg_callback_request(struct osl_object *options,
 -              int argc,  char * const * const argv, callback_function *f,
 +              int argc,  char * const * const argv, afs_callback *f,
                callback_result_handler *result_handler,
                void *private_result_data)
  {
   * send_option_arg_callback_request().
   */
  int send_standard_callback_request(int argc,  char * const * const argv,
 -              callback_function *f, callback_result_handler *result_handler,
 +              afs_callback *f, callback_result_handler *result_handler,
                void *private_result_data)
  {
        return send_option_arg_callback_request(NULL, argc, argv, f, result_handler,
@@@ -501,7 -505,6 +501,7 @@@ static int activate_mood_or_playlist(ch
        enum play_mode mode;
        int ret;
  
 +      PARA_INFO_LOG("new playlist: %s\n", arg);
        if (!arg) {
                ret = change_current_mood(NULL); /* always successful */
                mode = PLAY_MODE_MOOD;
@@@ -556,70 -559,52 +556,70 @@@ int afs_cb_result_handler(struct osl_ob
        struct command_context *cc = private;
  
        assert(cc);
 -      if (!result->size)
 -              return 1;
 -      return send_sb(&cc->scc, result->data, result->size, band, true);
 +      switch (band) {
 +      case SBD_OUTPUT:
 +      case SBD_DEBUG_LOG:
 +      case SBD_INFO_LOG:
 +      case SBD_NOTICE_LOG:
 +      case SBD_WARNING_LOG:
 +      case SBD_ERROR_LOG:
 +      case SBD_CRIT_LOG:
 +      case SBD_EMERG_LOG:
 +              assert(result->size > 0);
 +              return send_sb(&cc->scc, result->data, result->size, band, true);
 +      case SBD_AFS_CB_FAILURE:
 +              return *(int *)(result->data);
 +      default:
 +              return -E_BAD_BAND;
 +      }
  }
  
 -static void com_select_callback(int fd, const struct osl_object *query)
 +static void flush_and_free_pb(struct para_buffer *pb)
  {
 -      struct para_buffer pb = {
 -              .max_size = shm_get_shmmax(),
 -              .private_data = &(struct afs_max_size_handler_data) {
 -                      .fd = fd,
 -                      .band = SBD_OUTPUT
 -              },
 -              .max_size_handler = afs_max_size_handler,
 -      };
 -      char *arg = query->data;
 -      int num_admissible, ret, ret2;
 +      int ret;
 +      struct afs_max_size_handler_data *amshd = pb->private_data;
 +
 +      if (pb->buf && pb->size > 0) {
 +              ret = pass_buffer_as_shm(amshd->fd, amshd->band, pb->buf,
 +                      pb->offset);
 +              if (ret < 0)
 +                      PARA_ERROR_LOG("%s\n", para_strerror(-ret));
 +      }
 +      free(pb->buf);
 +}
 +
 +static int com_select_callback(struct afs_callback_arg *aca)
 +{
 +      char *arg = aca->query.data;
 +      int num_admissible, ret;
  
        ret = clear_score_table();
        if (ret < 0) {
 -              ret2 = para_printf(&pb, "%s\n", para_strerror(-ret));
 -              goto out;
 +              para_printf(&aca->pbout, "could not clear score table: %s\n",
 +                      para_strerror(-ret));
 +              return ret;
        }
        if (current_play_mode == PLAY_MODE_MOOD)
                close_current_mood();
        else
                playlist_close();
        ret = activate_mood_or_playlist(arg, &num_admissible);
 -      if (ret < 0) {
 -              ret2 = para_printf(&pb, "%s\nswitching back to %s\n",
 -                      para_strerror(-ret), current_mop?
 -                      current_mop : "dummy");
 -              ret = activate_mood_or_playlist(current_mop, &num_admissible);
 -              if (ret < 0) {
 -                      if (ret2 >= 0)
 -                              ret2 = para_printf(&pb, "failed, switching to dummy\n");
 -                      activate_mood_or_playlist(NULL, &num_admissible);
 -              }
 -      } else
 -              ret2 = para_printf(&pb, "activated %s (%d admissible files)\n",
 -                      current_mop?  current_mop : "dummy mood",
 -                      num_admissible);
 +      if (ret >= 0)
 +              goto out;
 +      /* ignore subsequent errors (but log them) */
 +      para_printf(&aca->pbout, "could not activate %s: %s\n"
 +              "switching back to %s\n",
 +              arg, para_strerror(-ret), current_mop? current_mop : "dummy");
 +      ret = activate_mood_or_playlist(current_mop, &num_admissible);
 +      if (ret >= 0)
 +              goto out;
 +      para_printf(&aca->pbout, "could not activate %s: %s\nswitching to dummy\n",
 +              current_mop, para_strerror(-ret));
 +      activate_mood_or_playlist(NULL, &num_admissible);
  out:
 -      if (ret2 >= 0 && pb.offset)
 -              pass_buffer_as_shm(fd, SBD_OUTPUT, pb.buf, pb.offset);
 -      free(pb.buf);
 +      para_printf(&aca->pbout, "activated %s (%d admissible files)\n",
 +              current_mop? current_mop : "dummy mood", num_admissible);
 +      return ret;
  }
  
  int com_select(struct command_context *cc)
@@@ -693,7 -678,7 +693,7 @@@ static int make_database_dir(void
  
        get_database_dir();
        ret = para_mkdir(database_dir, 0777);
-       if (ret >= 0 || is_errno(-ret, EEXIST))
+       if (ret >= 0 || ret == -ERRNO_TO_PARA_ERROR(EEXIST))
                return 1;
        return ret;
  }
@@@ -810,8 -795,8 +810,8 @@@ int pass_buffer_as_shm(int fd, uint8_t 
        void *shm;
        struct callback_result *cr;
  
 -      if (!buf || !size)
 -              return 0;
 +      if (size == 0)
 +              assert(band != SBD_OUTPUT);
        ret = shm_new(size + sizeof(*cr));
        if (ret < 0)
                return ret;
        cr = shm;
        cr->result_size = size;
        cr->band = band;
 -      memcpy(shm + sizeof(*cr), buf, size);
 +      if (size > 0)
 +              memcpy(shm + sizeof(*cr), buf, size);
        ret = shm_detach(shm);
        if (ret < 0)
                goto err;
@@@ -836,43 -820,26 +836,43 @@@ err
        return ret;
  }
  
 -/*
 - * On errors, negative value is written to fd.
 - * On success: If query produced a result, the result_shmid is written to fd.
 - * Otherwise, zero is written.
 - */
  static int call_callback(int fd, int query_shmid)
  {
        void *query_shm;
        struct callback_query *cq;
 -      struct osl_object query;
 -      int ret;
 +      int ret, ret2;
 +      struct afs_callback_arg aca = {.fd = fd};
  
        ret = shm_attach(query_shmid, ATTACH_RW, &query_shm);
        if (ret < 0)
                return ret;
        cq = query_shm;
 -      query.data = (char *)query_shm + sizeof(*cq);
 -      query.size = cq->query_size;
 -      cq->handler(fd, &query);
 -      return shm_detach(query_shm);
 +      aca.query.data = (char *)query_shm + sizeof(*cq);
 +      aca.query.size = cq->query_size;
 +      aca.pbout.max_size = shm_get_shmmax();
 +      aca.pbout.max_size_handler = afs_max_size_handler;
 +      aca.pbout.private_data = &(struct afs_max_size_handler_data) {
 +              .fd = fd,
 +              .band = SBD_OUTPUT
 +      };
 +      ret = cq->handler(&aca);
 +      ret2 = shm_detach(query_shm);
 +      if (ret2 < 0) {
 +              if (ret < 0) /* ignore (but log) detach error */
 +                      PARA_ERROR_LOG("could not detach sma: %s\n",
 +                              para_strerror(-ret2));
 +              else
 +                      ret = ret2;
 +      }
 +      flush_and_free_pb(&aca.pbout);
 +      if (ret < 0) {
 +              ret2 = pass_buffer_as_shm(fd, SBD_AFS_CB_FAILURE,
 +                      (const char *)&ret, sizeof(ret));
 +              if (ret2 < 0)
 +                      PARA_ERROR_LOG("could not pass cb failure packet: %s\n",
 +                              para_strerror(-ret));
 +      }
 +      return ret;
  }
  
  static int execute_server_command(fd_set *rfds)
        exit(EXIT_FAILURE);
  }
  
 -static void create_tables_callback(int fd, const struct osl_object *query)
 +static int com_init_callback(struct afs_callback_arg *aca)
  {
 -      uint32_t table_mask = *(uint32_t *)query->data;
 +      uint32_t table_mask = *(uint32_t *)aca->query.data;
        int i, ret;
 -      struct para_buffer pb = {
 -              .max_size = shm_get_shmmax(),
 -              .private_data = &(struct afs_max_size_handler_data) {
 -                      .fd = fd,
 -                      .band = SBD_OUTPUT
 -              }
 -      };
  
        close_afs_tables();
        for (i = 0; i < NUM_AFS_TABLES; i++) {
                if (!t->create)
                        continue;
                ret = t->create(database_dir);
 -              if (ret < 0)
 +              if (ret < 0) {
 +                      para_printf(&aca->pbout, "cannot create table %s\n",
 +                              t->name);
                        goto out;
 -              para_printf(&pb, "successfully created %s table\n", t->name);
 +              }
 +              para_printf(&aca->pbout, "successfully created %s table\n",
 +                      t->name);
        }
        ret = open_afs_tables();
 -out:
        if (ret < 0)
 -              para_printf(&pb, "%s\n", para_strerror(-ret));
 -      if (pb.buf)
 -              pass_buffer_as_shm(fd, SBD_OUTPUT, pb.buf, pb.offset);
 -      free(pb.buf);
 +              para_printf(&aca->pbout, "cannot open afs tables\n");
 +out:
 +      return ret;
  }
  
  int com_init(struct command_context *cc)
                                return -E_BAD_TABLE_NAME;
                }
        }
 -      ret = send_callback_request(create_tables_callback, &query,
 +      return send_callback_request(com_init_callback, &query,
                afs_cb_result_handler, cc);
 -      return ret;
  }
  
  /**
@@@ -1100,9 -1073,7 +1100,9 @@@ enum com_check_flags 
        /** Check the mood table. */
        CHECK_MOODS = 2,
        /** Check the playlist table. */
 -      CHECK_PLAYLISTS = 4
 +      CHECK_PLAYLISTS = 4,
 +      /** Check the attribute table against the audio file table. */
 +      CHECK_ATTS = 8
  };
  
  int com_check(struct command_context *cc)
                        flags |= CHECK_AFT;
                        continue;
                }
 +              if (!strcmp(arg, "-A")) {
 +                      flags |= CHECK_ATTS;
 +                      continue;
 +              }
                if (!strcmp(arg, "-p")) {
                        flags |= CHECK_PLAYLISTS;
                        continue;
                if (ret < 0)
                        return ret;
        }
 +      if (flags & CHECK_ATTS) {
 +              ret = send_callback_request(attribute_check_callback, NULL,
 +                      afs_cb_result_handler, cc);
 +              if (ret < 0)
 +                      return ret;
 +      }
        if (flags & CHECK_PLAYLISTS) {
                ret = send_callback_request(playlist_check_callback,
                        NULL, afs_cb_result_handler, cc);
   * \param pb May be \p NULL.
   * \param data Type depends on \a event.
   *
 - * This function calls the table handlers of all tables and passes \a pb and \a
 - * data verbatim. It's up to the handlers to interpret the \a data pointer.
 + * This function calls each table event handler, passing \a pb and \a data
 + * verbatim. It's up to the handlers to interpret the \a data pointer. If a
 + * handler returns negative, the loop is aborted.
 + *
 + * \return The (negative) error code of the first handler that failed, or non-negative
 + * if all handlers succeeded.
   */
 -void afs_event(enum afs_events event, struct para_buffer *pb,
 +__must_check int afs_event(enum afs_events event, struct para_buffer *pb,
                void *data)
  {
        int i, ret;
                if (!t->event_handler)
                        continue;
                ret = t->event_handler(event, pb, data);
 -              if (ret < 0)
 +              if (ret < 0) {
                        PARA_CRIT_LOG("table %s, event %d: %s\n", t->name,
                                event, para_strerror(-ret));
 +                      return ret;
 +              }
        }
 +      return 1;
  }
  
  /**
diff --combined error.h
+++ b/error.h
@@@ -279,7 -279,6 +279,7 @@@ extern const char **para_errlist[]
        PARA_ERROR(NO_AFHI, "audio format handler info required"), \
        PARA_ERROR(AFT_SYNTAX, "audio file table syntax error"), \
        PARA_ERROR(HASH_MISMATCH, "hash mismatch, consider re-add"), \
 +      PARA_ERROR(NO_MATCH, "no matches"), \
  
  
  #define USER_LIST_ERRORS \
  /** 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.
-  * \param _errno The system error number.
-  *
-  * \return True if \a num is paraslash's representation of the system
-  * error identified by \a _errno.
-  */
- _static_inline_ bool is_errno(int num, int _errno)
- {
-       assert(num > 0 && _errno > 0);
-       return ERRNO_TO_PARA_ERROR(_errno) == num;
- }
  
+ static const char *weak_osl_strerror(int) __attribute__ ((weakref("osl_strerror")));
  /**
   * Paraslash's version of strerror(3).
   *
  _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_OSL_ERROR(num)) {
+               assert(weak_osl_strerror);
+               return weak_osl_strerror(num & ~(1U << OSL_ERROR_BIT));
+       }
        if (IS_SYSTEM_ERROR(num))
-               return strerror(num & ((1 << SYSTEM_ERROR_BIT) - 1));
+               return strerror(num & ~(1U << SYSTEM_ERROR_BIT));
        return para_errlist[ERRNUM_TO_SS(num)][ERRNUM_TO_INDEX(num)];
  }