It is usually a critical error if an afs event handler returns an
error. Currently we only print a log message an continue in this
case. The callers of afs_event() which trigger the event have no way
to tell that something went wrong, since this function returns void.
By returning int instead of void the callers can abort in the error
case. Most of the callers are afs callbacks. These can propagate the
error code to the command handler process, which will translate the
error code into a string and send it to the client. All callbacks
are changed in this way.
* \param pb May be \p NULL.
* \param data Type depends on \a event.
*
* \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;
void *data)
{
int i, ret;
if (!t->event_handler)
continue;
ret = t->event_handler(event, pb, data);
if (!t->event_handler)
continue;
ret = t->event_handler(event, pb, data);
PARA_CRIT_LOG("table %s, event %d: %s\n", t->name,
event, para_strerror(-ret));
PARA_CRIT_LOG("table %s, event %d: %s\n", t->name,
event, para_strerror(-ret));
}
__noreturn void afs_init(uint32_t cookie, int socket_fd);
}
__noreturn void afs_init(uint32_t cookie, int socket_fd);
-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 send_callback_request(callback_function *f, struct osl_object *query,
callback_result_handler *result_handler,
void *data);
int send_callback_request(callback_function *f, struct osl_object *query,
callback_result_handler *result_handler,
* No need to update the status items as the AFSI_CHANGE event will
* recreate them.
*/
* No need to update the status items as the AFSI_CHANGE event will
* recreate them.
*/
- afs_event(AFSI_CHANGE, NULL, &aced);
+ ret = afs_event(AFSI_CHANGE, NULL, &aced);
+ if (ret < 0)
+ goto out;
ret = save_afd(afd);
out:
free(afd->afhi.chunk_table);
ret = save_afd(afd);
out:
free(afd->afhi.chunk_table);
if (pb) { /* hs trumps pb, remove pb */
if (flags & ADD_FLAG_VERBOSE)
para_printf(&msg, "removing %s\n", path);
if (pb) { /* hs trumps pb, remove pb */
if (flags & ADD_FLAG_VERBOSE)
para_printf(&msg, "removing %s\n", path);
- afs_event(AUDIO_FILE_REMOVE, &msg, pb);
+ ret = afs_event(AUDIO_FILE_REMOVE, &msg, pb);
+ if (ret < 0)
+ goto out;
ret = osl(osl_del_row(audio_file_table, pb));
if (ret < 0)
goto out;
ret = osl(osl_del_row(audio_file_table, pb));
if (ret < 0)
goto out;
&objs[AFTCOL_PATH]));
if (ret < 0)
goto out;
&objs[AFTCOL_PATH]));
if (ret < 0)
goto out;
- afs_event(AUDIO_FILE_RENAME, &msg, hs);
+ ret = afs_event(AUDIO_FILE_RENAME, &msg, hs);
+ if (ret < 0)
+ goto out;
if (!(flags & ADD_FLAG_FORCE))
goto out;
}
if (!(flags & ADD_FLAG_FORCE))
goto out;
}
&objs[AFTCOL_CHUNKS]));
if (ret < 0)
goto out;
&objs[AFTCOL_CHUNKS]));
if (ret < 0)
goto out;
- afs_event(AFHI_CHANGE, &msg, row);
+ ret = afs_event(AFHI_CHANGE, &msg, row);
+ if (ret < 0)
+ goto out;
goto out;
}
/* new entry, use default afsi */
goto out;
}
/* new entry, use default afsi */
objs[AFTCOL_AFSI].size = AFSI_SIZE;
save_afsi(&default_afsi, &objs[AFTCOL_AFSI]);
ret = osl(osl_add_and_get_row(audio_file_table, objs, &aft_row));
objs[AFTCOL_AFSI].size = AFSI_SIZE;
save_afsi(&default_afsi, &objs[AFTCOL_AFSI]);
ret = osl(osl_add_and_get_row(audio_file_table, objs, &aft_row));
- afs_event(AUDIO_FILE_ADD, &msg, aft_row);
+ ret = afs_event(AUDIO_FILE_ADD, &msg, aft_row);
out:
if (ret < 0)
para_printf(&msg, "could not add %s\n", path);
out:
if (ret < 0)
para_printf(&msg, "could not add %s\n", path);
save_afsi(&new_afsi, &obj); /* in-place update */
aced.aft_row = row;
aced.old_afsi = &old_afsi;
save_afsi(&new_afsi, &obj); /* in-place update */
aced.aft_row = row;
aced.old_afsi = &old_afsi;
- afs_event(AFSI_CHANGE, &tad->pb, &aced);
- return 1;
+ return afs_event(AFSI_CHANGE, &tad->pb, &aced);
}
static int com_touch_callback(int fd, const struct osl_object *query)
}
static int com_touch_callback(int fd, const struct osl_object *query)
if (crd->flags & RM_FLAG_VERBOSE)
para_printf(&crd->pb, "removing %s\n", name);
if (crd->flags & RM_FLAG_VERBOSE)
para_printf(&crd->pb, "removing %s\n", name);
- afs_event(AUDIO_FILE_REMOVE, &crd->pb, row);
+ ret = afs_event(AUDIO_FILE_REMOVE, &crd->pb, row);
+ if (ret < 0)
+ return ret;
ret = osl(osl_del_row(audio_file_table, row));
if (ret < 0)
para_printf(&crd->pb, "cannot remove %s\n", name);
ret = osl(osl_del_row(audio_file_table, row));
if (ret < 0)
para_printf(&crd->pb, "cannot remove %s\n", name);
para_printf(&cad->pb, "copied afsi to %s\n", name);
aced.aft_row = row;
aced.old_afsi = &old_afsi;
para_printf(&cad->pb, "copied afsi to %s\n", name);
aced.aft_row = row;
aced.old_afsi = &old_afsi;
- afs_event(AFSI_CHANGE, &cad->pb, &aced);
- return 1;
+ return afs_event(AFSI_CHANGE, &cad->pb, &aced);
}
static int com_cpsi_callback(int fd, const struct osl_object *query)
}
static int com_cpsi_callback(int fd, const struct osl_object *query)
new_afsi.attributes |= cad->add_mask;
new_afsi.attributes &= ~cad->del_mask;
save_afsi(&new_afsi, &obj); /* in-place update */
new_afsi.attributes |= cad->add_mask;
new_afsi.attributes &= ~cad->del_mask;
save_afsi(&new_afsi, &obj); /* in-place update */
- afs_event(AFSI_CHANGE, &cad->pb, &aced);
- return 1;
+ return afs_event(AFSI_CHANGE, &cad->pb, &aced);
}
static int com_setatt_callback(int fd, const struct osl_object *query)
}
static int com_setatt_callback(int fd, const struct osl_object *query)
goto out;
aed.name = p;
aed.bitnum = bitnum;
goto out;
aed.name = p;
aed.bitnum = bitnum;
- afs_event(ATTRIBUTE_ADD, &pb, &aed);
+ ret = afs_event(ATTRIBUTE_ADD, &pb, &aed);
+ if (ret < 0)
+ goto out;
greatest_att_bitnum = PARA_MAX(greatest_att_bitnum, (int)bitnum);
}
out:
greatest_att_bitnum = PARA_MAX(greatest_att_bitnum, (int)bitnum);
}
out:
if (ret < 0)
para_printf(&pb, "cannot rename %s to %s\n", old, new);
else
if (ret < 0)
para_printf(&pb, "cannot rename %s to %s\n", old, new);
else
- afs_event(ATTRIBUTE_RENAME, &pb, NULL);
+ ret = afs_event(ATTRIBUTE_RENAME, &pb, NULL);
flush_and_free_pb(&pb);
return ret;
}
flush_and_free_pb(&pb);
return ret;
}
para_printf(pb, "cannot remove %s\n", name);
return ret;
}
para_printf(pb, "cannot remove %s\n", name);
return ret;
}
- afs_event(ATTRIBUTE_REMOVE, pb, &red);
- return 1;
+ return afs_event(ATTRIBUTE_REMOVE, pb, &red);
}
static int com_rmatt_callback(int fd, const struct osl_object *query)
}
static int com_rmatt_callback(int fd, const struct osl_object *query)
ret = -E_NO_MATCH;
else {
para_printf(&pb, "removed %d blob(s)\n", pmd.num_matches);
ret = -E_NO_MATCH;
else {
para_printf(&pb, "removed %d blob(s)\n", pmd.num_matches);
- afs_event(BLOB_RENAME, NULL, table);
+ ret = afs_event(BLOB_RENAME, NULL, table);
}
out:
flush_and_free_pb(&pb);
}
out:
flush_and_free_pb(&pb);
ret = osl(osl_add_row(table, objs));
if (ret < 0)
goto out;
ret = osl(osl_add_row(table, objs));
if (ret < 0)
goto out;
- afs_event(BLOB_ADD, NULL, table);
+ ret = afs_event(BLOB_ADD, NULL, table);
out:
if (ret < 0)
msg_len = xasprintf(&msg, "cannot add %s\n", name);
out:
if (ret < 0)
msg_len = xasprintf(&msg, "cannot add %s\n", name);
para_printf(&pb, "cannot rename blob %s to %s\n", src, dest);
goto out;
}
para_printf(&pb, "cannot rename blob %s to %s\n", src, dest);
goto out;
}
- afs_event(BLOB_RENAME, NULL, table);
+ ret = afs_event(BLOB_RENAME, NULL, table);
out:
flush_and_free_pb(&pb);
return ret;
out:
flush_and_free_pb(&pb);
return ret;