/** * _nih_error_raise_printf: * @filename: filename where the error was raised, * @line: line number of @filename where the error was raised, * @function: function name the error was raised within, * @number: numeric identifier, * @format: format string for human-readable message. * * Raises an error with the given details in the current error context, * if an unhandled error already exists then an error message is emmitted * through the logging system; you should try to avoid this. * * The human-readable message for the error is parsed according to @format, * and allocated as a child of the error object so that it is freed. * * This function should never be called directly, instead use the * nih_error_raise_printf() macro to pass the correct arguments for @filename, * @line and @function. **/ void _nih_error_raise_printf (const char *filename, int line, const char *function, int number, const char *format, ...) { NihError *error; va_list args; nih_assert (filename != NULL); nih_assert (line > 0); nih_assert (function != NULL); nih_assert (number > 0); nih_assert (format != NULL); nih_error_init (); error = NIH_MUST (nih_new (NULL, NihError)); error->number = number; va_start (args, format); error->message = NIH_MUST (nih_vsprintf (error, format, args)); va_end (args); _nih_error_raise_error (filename, line, function, error); }
/** * type_var_new: * @parent: parent object for new structure, * @type: C type, * @name: variable name. * * Allocates and returns a new TypeVar structure with the C type @type * and variable name @name, the strucure is not placed into any linked * list but will be removed from its containing list when freed. * * If @parent is not NULL, it should be a pointer to another object which * will be used as a parent for the returned structure. When all parents * of the returned structure are freed, the returned structure will also be * freed. * * Returns: the new TypeVar structure or NULL if insufficient memory. **/ TypeVar * type_var_new (const void *parent, const char *type, const char *name) { TypeVar *var; nih_assert (type != NULL); nih_assert (name != NULL); var = nih_new (parent, TypeVar); if (! var) return NULL; nih_list_init (&var->entry); var->type = nih_strdup (var, type); if (! var->type) { nih_free (var); return NULL; } var->name = nih_strdup (var, name); if (! var->name) { nih_free (var); return NULL; } var->array = FALSE; nih_alloc_set_destructor (var, nih_list_destroy); return var; }
/** * nih_error_push_context: * * Creates a new context in which errors can occur without disturbing any * previous unhandled error, useful for touring a particular piece of * processing that handles its own errors and may be triggered as a result * of another error. **/ void nih_error_push_context (void) { NihErrorCtx *new_context; nih_error_init (); new_context = NIH_MUST (nih_new (context_stack, NihErrorCtx)); nih_list_init (&new_context->entry); new_context->error = NULL; nih_list_add (context_stack, &new_context->entry); }
/** * nih_dbus_error_raise: * @name: D-Bus name for error, * @message: Human-readable error message. * * Raises an error which includes a D-Bus name so that it may be sent as * a reply to a method call, the error type is fixed to NIH_DBUS_ERROR. * * You may use this in D-Bus handlers and return a negative number to * automatically have this error returned as the method reply. It is also * useful when mixing D-Bus and libnih function calls in your own methods * to return consistent error forms, in which case pass the name and message * members of the DBusError structure before freeing it. **/ void nih_dbus_error_raise (const char *name, const char *message) { NihDBusError *err; nih_assert (name != NULL); nih_assert (message != NULL); err = NIH_MUST (nih_new (NULL, NihDBusError)); err->number = NIH_DBUS_ERROR; err->name = NIH_MUST (nih_strdup (err, name)); err->message = NIH_MUST (nih_strdup (err, message)); nih_error_raise_error ((NihError *)err); }
/** * nih_dbus_error_raise_printf: * @name: D-Bus name for error, * @format: format string for human-readable message. * * Raises an error which includes a D-Bus name so that it may be sent as * a reply to a method call, the error type is fixed to NIH_DBUS_ERROR. * * The human-readable message for the error is parsed according to @format, * and allocated as a child of the error object so that it is freed. * * You may use this in D-Bus handlers and return a negative number to * automatically have this error returned as the method reply. It is also * useful when mixing D-Bus and libnih function calls in your own methods * to return consistent error forms, in which case pass the name and message * members of the DBusError structure before freeing it. **/ void nih_dbus_error_raise_printf (const char *name, const char *format, ...) { NihDBusError *err; va_list args; nih_assert (name != NULL); nih_assert (format != NULL); err = NIH_MUST (nih_new (NULL, NihDBusError)); err->number = NIH_DBUS_ERROR; err->name = NIH_MUST (nih_strdup (err, name)); va_start (args, format); err->message = NIH_MUST (nih_vsprintf (err, format, args)); va_end (args); nih_error_raise_error ((NihError *)err); }
/** * session_new: * @parent: parent, * @chroot: full chroot path, * @user: user id. * * Create a new session. * * Return new Session, or NULL on error. **/ Session * session_new (const void *parent, const char *chroot, uid_t user) { Session *session; nih_assert ((chroot != NULL) || (user != 0)); session_init (); session = nih_new (parent, Session); if (! session) return NULL; nih_list_init (&session->entry); if (chroot) { session->chroot = nih_strdup (session, chroot); if (! session->chroot) { nih_free (session); return NULL; } } else { session->chroot = NULL; } session->user = user; session->conf_path = NULL; nih_alloc_set_destructor (session, nih_list_destroy); nih_list_add (sessions, &session->entry); return session; }
/** * _nih_error_raise_system: * @filename: filename where the error was raised, * @line: line number of @filename where the error was raised, * @function: function name the error was raised within. * * Raises an error with details taken from the current value of errno, * if an unhandled error already exists then an error message is emmitted * through the logging system; you should try to avoid this. * * This function should never be called directly, instead use the * nih_error_raise_system() macro to pass the correct arguments for @filename, * @line and @function. **/ void _nih_error_raise_system (const char *filename, int line, const char *function) { NihError *error; int saved_errno; nih_assert (filename != NULL); nih_assert (line > 0); nih_assert (function != NULL); nih_assert (errno > 0); saved_errno = errno; nih_error_init (); error = NIH_MUST (nih_new (NULL, NihError)); error->number = saved_errno; error->message = NIH_MUST (nih_strdup (error, strerror (saved_errno))); _nih_error_raise_error (filename, line, function, error); errno = saved_errno; }
/** * _nih_error_raise: * @filename: filename where the error was raised, * @line: line number of @filename where the error was raised, * @function: function name the error was raised within, * @number: numeric identifier, * @message: human-readable message. * * Raises an error with the given details in the current error context, * if an unhandled error already exists then an error message is emmitted * through the logging system; you should try to avoid this. * * @message should be a static string, as it will not be freed when the * error object is. * * This function should never be called directly, instead use the * nih_error_raise() macro to pass the correct arguments for @filename, * @line and @function. **/ void _nih_error_raise (const char *filename, int line, const char *function, int number, const char *message) { NihError *error; nih_assert (filename != NULL); nih_assert (line > 0); nih_assert (function != NULL); nih_assert (number > 0); nih_assert (message != NULL); nih_error_init (); error = NIH_MUST (nih_new (NULL, NihError)); error->number = number; error->message = message; _nih_error_raise_error (filename, line, function, error); }
void test_free (void) { void * ptr1; void * ptr2; Parent *parent; int ret; TEST_FUNCTION ("nih_free"); /* Check that nih_free works if the block has no parent. The * destructor should get called and nih_free should return that * return value. */ TEST_FEATURE ("with no parent"); ptr1 = nih_alloc (NULL, 10); nih_alloc_set_destructor (ptr1, destructor_called); destructor_was_called = 0; ret = nih_free (ptr1); TEST_TRUE (destructor_was_called); TEST_EQ (ret, 2); /* Check that nih_free works if the block has a parent. The * destructor should get called and nih_free should return that * return value. */ TEST_FEATURE ("with parent"); ptr2 = nih_alloc (NULL, 20); ptr1 = nih_alloc (ptr2, 10); nih_alloc_set_destructor (ptr1, destructor_called); destructor_was_called = 0; ret = nih_free (ptr1); TEST_TRUE (destructor_was_called); TEST_EQ (ret, 2); nih_free (ptr2); /* Check that the destructor on any children also gets called, which * is as good a indication as any that the children are being freed. */ TEST_FEATURE ("with destructor on child"); ptr1 = nih_alloc (NULL, 10); ptr2 = nih_alloc (ptr1, 10); nih_alloc_set_destructor (ptr2, child_destructor_called); child_destructor_was_called = 0; ret = nih_free (ptr1); TEST_TRUE (child_destructor_was_called); TEST_EQ (ret, 0); /* Check that both destructors on parent and children are called, * and that the return value from nih_free is that of the parent's. */ TEST_FEATURE ("with child and destructors"); ptr1 = nih_alloc (NULL, 10); ptr2 = nih_alloc (ptr1, 10); nih_alloc_set_destructor (ptr1, destructor_called); nih_alloc_set_destructor (ptr2, child_destructor_called); destructor_was_called = 0; child_destructor_was_called = 0; ret = nih_free (ptr1); TEST_TRUE (destructor_was_called); TEST_TRUE (child_destructor_was_called); TEST_EQ (ret, 2); /* Check that a child of an object may be included in a sibling * linked list allocated earlier. At the point the child destructor * is called, the sibling must not have been freed otherwise it * cannot cut itself out. */ TEST_FEATURE ("with child in older sibling list"); parent = nih_new (NULL, Parent); __nih_malloc = my_list_head_malloc; parent->list = nih_new (parent, NihList); nih_list_init (parent->list); __nih_malloc = malloc; parent->child = nih_new (parent, Child); nih_list_init (&parent->child->entry); nih_list_add (parent->list, &parent->child->entry); nih_alloc_set_destructor (parent->child, child_destructor_test); __nih_free = my_list_head_free; nih_free (parent); __nih_free = free; /* Check that a child of an object may be included in a sibling * linked list allocated later. At the point the child destructor * is called, the sibling must not have been freed otherwise it * cannot cut itself out. */ TEST_FEATURE ("with child in younger sibling list"); parent = nih_new (NULL, Parent); parent->child = nih_new (parent, Child); nih_list_init (&parent->child->entry); __nih_malloc = my_list_head_malloc; parent->list = nih_new (parent, NihList); nih_list_init (parent->list); __nih_malloc = malloc; nih_list_add (parent->list, &parent->child->entry); nih_alloc_set_destructor (parent->child, child_destructor_test); __nih_free = my_list_head_free; nih_free (parent); __nih_free = free; }
int my_method_sync (const void * parent, NihDBusProxy * proxy, MyMethodStructure **structure) { DBusMessage * method_call; DBusMessageIter iter; DBusError error; DBusMessage * reply; MyMethodStructure *structure_local; DBusMessageIter structure_local_iter; const char * structure_local_item0_dbus; char * structure_local_item0; uint32_t structure_local_item1; nih_assert (proxy != NULL); nih_assert (structure != NULL); /* Construct the method call message. */ method_call = dbus_message_new_method_call (proxy->name, proxy->path, "com.netsplit.Nih.Test", "Method"); if (! method_call) nih_return_no_memory_error (-1); dbus_message_set_auto_start (method_call, proxy->auto_start); dbus_message_iter_init_append (method_call, &iter); /* Send the message, and wait for the reply. */ dbus_error_init (&error); reply = dbus_connection_send_with_reply_and_block (proxy->connection, method_call, -1, &error); if (! reply) { dbus_message_unref (method_call); if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { nih_error_raise_no_memory (); } else { nih_dbus_error_raise (error.name, error.message); } dbus_error_free (&error); return -1; } dbus_message_unref (method_call); /* Iterate the arguments of the reply */ dbus_message_iter_init (reply, &iter); do { __label__ enomem; /* Demarshal a structure from the message */ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRUCT) { dbus_message_unref (reply); nih_return_error (-1, NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); } dbus_message_iter_recurse (&iter, &structure_local_iter); structure_local = nih_new (parent, MyMethodStructure); if (! structure_local) { *structure = NULL; goto enomem; } /* Demarshal a char * from the message */ if (dbus_message_iter_get_arg_type (&structure_local_iter) != DBUS_TYPE_STRING) { nih_free (structure_local); dbus_message_unref (reply); nih_return_error (-1, NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); } dbus_message_iter_get_basic (&structure_local_iter, &structure_local_item0_dbus); structure_local_item0 = nih_strdup (structure_local, structure_local_item0_dbus); if (! structure_local_item0) { nih_free (structure_local); *structure = NULL; goto enomem; } dbus_message_iter_next (&structure_local_iter); structure_local->item0 = structure_local_item0; /* Demarshal a uint32_t from the message */ if (dbus_message_iter_get_arg_type (&structure_local_iter) != DBUS_TYPE_UINT32) { nih_free (structure_local); dbus_message_unref (reply); nih_return_error (-1, NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); } dbus_message_iter_get_basic (&structure_local_iter, &structure_local_item1); dbus_message_iter_next (&structure_local_iter); structure_local->item1 = structure_local_item1; if (dbus_message_iter_get_arg_type (&structure_local_iter) != DBUS_TYPE_INVALID) { nih_free (structure_local); dbus_message_unref (reply); nih_return_error (-1, NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); } dbus_message_iter_next (&iter); *structure = structure_local; enomem: __attribute__ ((unused)); } while (! *structure); if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID) { nih_free (structure_local); *structure = NULL; dbus_message_unref (reply); nih_return_error (-1, NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); } dbus_message_unref (reply); return 0; }
void my_com_netsplit_Nih_Test_get_all_notify (DBusPendingCall * pending_call, NihDBusPendingData *pending_data) { DBusMessage * reply; DBusMessageIter iter; DBusMessageIter arrayiter; DBusMessageIter dictiter; DBusMessageIter variter; NihDBusMessage *message; DBusError error; const char * property; MyProperties * properties; size_t property_count; char * name; const char * name_dbus; uint32_t size; nih_assert (pending_call != NULL); nih_assert (pending_data != NULL); nih_assert (dbus_pending_call_get_completed (pending_call)); /* Steal the reply from the pending call. */ reply = dbus_pending_call_steal_reply (pending_call); nih_assert (reply != NULL); /* Handle error replies */ if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { message = NIH_MUST (nih_dbus_message_new (pending_data, pending_data->connection, reply)); dbus_error_init (&error); dbus_set_error_from_message (&error, message->message); nih_error_push_context (); nih_dbus_error_raise (error.name, error.message); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); dbus_error_free (&error); nih_free (message); dbus_message_unref (reply); return; } nih_assert (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN); /* Create a message context for the reply, and iterate * over and recurse into the arguments. */ message = NIH_MUST (nih_dbus_message_new (pending_data, pending_data->connection, reply)); /* Iterate the method arguments, recursing into the array */ dbus_message_iter_init (reply, &iter); if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) { nih_error_push_context (); nih_error_raise (NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); return; } properties = NIH_MUST (nih_new (message, MyProperties)); property_count = 0; dbus_message_iter_recurse (&iter, &arrayiter); while (dbus_message_iter_get_arg_type (&arrayiter) != DBUS_TYPE_INVALID) { __label__ enomem; if (dbus_message_iter_get_arg_type (&arrayiter) != DBUS_TYPE_DICT_ENTRY) { nih_error_push_context (); nih_error_raise (NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); return; } dbus_message_iter_recurse (&arrayiter, &dictiter); if (dbus_message_iter_get_arg_type (&dictiter) != DBUS_TYPE_STRING) { nih_error_push_context (); nih_error_raise (NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); return; } dbus_message_iter_get_basic (&dictiter, &property); dbus_message_iter_next (&dictiter); if (dbus_message_iter_get_arg_type (&dictiter) != DBUS_TYPE_VARIANT) { nih_error_push_context (); nih_error_raise (NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); return; } dbus_message_iter_recurse (&dictiter, &variter); if (! strcmp (property, "name")) { /* Demarshal a char * from the message */ if (dbus_message_iter_get_arg_type (&variter) != DBUS_TYPE_STRING) { nih_error_push_context (); nih_error_raise (NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); return; } dbus_message_iter_get_basic (&variter, &name_dbus); name = nih_strdup (properties, name_dbus); if (! name) { goto enomem; } dbus_message_iter_next (&variter); properties->name = name; nih_assert (++property_count); } if (! strcmp (property, "size")) { /* Demarshal a uint32_t from the message */ if (dbus_message_iter_get_arg_type (&variter) != DBUS_TYPE_UINT32) { nih_error_push_context (); nih_error_raise (NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); return; } dbus_message_iter_get_basic (&variter, &size); dbus_message_iter_next (&variter); properties->size = size; nih_assert (++property_count); } dbus_message_iter_next (&dictiter); if (dbus_message_iter_get_arg_type (&dictiter) != DBUS_TYPE_INVALID) { nih_error_push_context (); nih_error_raise (NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); return; } dbus_message_iter_next (&arrayiter); enomem: __attribute__ ((unused)); } dbus_message_iter_next (&iter); if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID) { nih_error_push_context (); nih_error_raise (NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); return; } if (property_count < 2) { nih_error_push_context (); nih_error_raise (NIH_DBUS_INVALID_ARGS, _(NIH_DBUS_INVALID_ARGS_STR)); pending_data->error_handler (pending_data->data, message); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); return; } /* Call the handler function */ nih_error_push_context (); ((MyGetAllReply)pending_data->handler) (pending_data->data, message, properties); nih_error_pop_context (); nih_free (message); dbus_message_unref (reply); }