The Shutdown callback function is a user callback that is invoked when the server is about to restart or shutdown.


This callback is invoked before any data structures and components have been cleaned up and their data destroyed. It can be used to perform on-exit tasks that are not related to a specific YANG module.

The following function template definition is used for Shutdown callback functions:


/* Typedef of the agt_shutdown_cb_t callback
*
* The Shutdown callback is the user/system callback
* that is invoked at the start of a normal agt_cleanup
* A normal shutdown or restart is in progress. This callback
* is not invoked if the server crashes.
*
* Max Callbacks: No limit (except available heap memory)
*
* INPUTS:
*    none
*
* OUTPUTS:
*    none
*
* RETURNS:
*    none
*/
typedef void
    (*agt_cb_shutdown_t) (void);



The agt_cb_shutdown_register function is used to declare the Shutdown callback. The registration can be done during the Initialization Phase 2, before or after the running configuration has been loaded from the startup file.

Initialization function with the Shutdown callback registration may look as follows:


status_t y_yumaworks_server_init (
    const xmlChar *modname,
    const xmlChar *revision)
{
    status_t res = NO_ERR;

    // … load module, etc.

    res = agt_cb_shutdown_register(server_shutdown_cb);
    return res;
}


There is no cleanup function for this callback. The cleanup will be done automatically by the server.



Example


The following example code illustrates how the Shutdown callback may look like. 



/********************************************************************
* FUNCTION server_shutdown_cb
*
* Save the server CLI parms if configured to do that
* Either --config=filespec of default config used
* If --no-startup used then the changed params will not
* be saved on exit or restart
*
* INPUTS:
*   none
* RETURNS:
*   none
********************************************************************/
static void server_shutdown_cb (void)
{
    if (!edits_done) {
        return;
    }

    /* get the run-time values that may have been changed since boot-time */
    status_t res = NO_ERR;
    val_value_t *server_val =
        agt_init_cache(y_yumaworks_server_M_yumaworks_server,
                       y_yumaworks_server_N_server,
                       &res);
    if ((server_val == NULL) || (res != NO_ERR)) {
        if (LOGDEBUG3) {
            log_debug3("\nyumaworks-server write config skipped "
                       "(no server_val)");
        }
        return;
    }

    /* hack: need container named netconfd-pro,
     * so use VAL_OBJ for the CLI valset
     */
    val_value_t *cli_val = agt_cli_get_valset();
    if (cli_val == NULL) {
        if (LOGDEBUG3) {
            log_debug3("\nyumaworks-server write config skipped "
                       "(no cli_val)");
        }
        return;
    }

    /* get the conf filespec */
    const xmlChar *confspec = agt_cli_get_confspec();
    if (confspec == NULL) {
        /* --no-config used or no default conf file found */
        if (LOGDEBUG3) {
            log_debug3("\nyumaworks-server write config skipped "
                       "(no confspec)");
        }
        return;
    }

    /* make sure the filespec is expanded to an absolute path */
    xmlChar *fullspec = ncx_get_source(confspec, &res);
    if ((fullspec == NULL) || (res != NO_ERR)) {
        m__free(fullspec);
        if (res == NO_ERR) {
            res = ERR_NCX_OPERATION_FAILED;
        }
        if (LOGDEBUG) {
            log_debug("\nyumaworks-server write config skipped "
                      "(get source failed) (%s)",
                      get_error_string(res));
        }
        return;
    }

    /* make a netconfd-pro container */
    val_value_t *copyval = val_new_value();
    if (copyval == NULL) {
        m__free(fullspec);
        return;
    }
    val_init_from_template(copyval, VAL_OBJ(cli_val));

    /* move all the children */
    val_move_children(server_val, copyval);

    /* open the config file for writing */
    res = log_alt_open_ex((const char *)fullspec, TRUE);  // overwrite
    if (res == NO_ERR) {
        /* write the value tree as a config file without default leafs */
        val_dump_value_full2(copyval,
                             0,   /* startindent */
                             NCX_DEF_INDENT,  /* indent_amount */
                             DUMP_VAL_ALT_LOG, /* dumpmode */
                             NCX_DISPLAY_MODE_PLAIN,
                             FALSE,    /* withmeta */
                             TRUE,   /* configonly */
                             TRUE,    /* conf_mode */
                             FALSE,   /* expand_varexpr */
                             FALSE,   /* withdef */
                             DWRT,    /* lvl */
                             NULL);   /* overrideOutput */
        log_alt_close();
        if (LOGDEBUG3) {
            log_debug3("\nyumaworks-server write config (%s) done",
                       fullspec);
        }
    } else {
        log_warn("\nWarning: config file '%s' could "
                 "not be opened for writing (%s)",
                 fullspec, get_error_string(res));
    }

    /* move all the CLI parms back */
    val_move_children(copyval, server_val);

    m__free(fullspec);
    val_free_value(copyval);

}  /* server_shutdown_cb */