Welcome to little lamb

Code » anopa » master » tree

[master] / src / libanopa / service_start.c

/*
 * anopa - Copyright (C) 2015-2017 Olivier Brunel
 *
 * service_start.c
 * Copyright (C) 2015-2017 Olivier Brunel <jjk@jjacky.com>
 *
 * This file is part of anopa.
 *
 * anopa is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * anopa is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * anopa. If not, see http://www.gnu.org/licenses/
 */

#include <skalibs/direntry.h>
#include <skalibs/bytestr.h>
#include <anopa/service.h>
#include <anopa/ga_int_list.h>
#include <anopa/err.h>
#include <anopa/output.h>
#include <anopa/service_status.h>
#include "service_internal.h"

void
aa_unmark_service (int si)
{
    aa_service *s = aa_service (si);
    size_t i;

    if (--s->nb_mark > 0)
        return;

    for (i = 0; i < genalloc_len (int, &s->needs); ++i)
        aa_unmark_service (list_get (&s->needs, i));
    for (i = 0; i < genalloc_len (int, &s->wants); ++i)
        aa_unmark_service (list_get (&s->wants, i));

    add_to_list (&aa_tmp_list, si, 0);
    remove_from_list (&aa_main_list, si);
}

int
aa_mark_service (aa_mode mode, int si, int in_main, int no_wants, aa_autoload_cb al_cb)
{
    int r;

    r = aa_ensure_service_loaded (si, mode, no_wants, al_cb);
    if (r < 0)
    {
        if (in_main)
        {
            add_to_list (&aa_tmp_list, si, 0);
            remove_from_list (&aa_main_list, si);
        }
        return r;
    }

    if (!in_main)
    {
        add_to_list (&aa_main_list, si, 0);
        remove_from_list (&aa_tmp_list, si);
    }

    aa_service (si)->nb_mark++;
    return 0;
}

int
_name_start_needs (const char *name, struct it_data *it_data)
{
    int type;
    int sni;
    int r;

    tain_now_g ();
    type = aa_get_service (name, &sni, 1);
    if (type < 0)
        r = type;
    else
        r = aa_mark_service (it_data->mode, sni, type == AA_SERVICE_FROM_MAIN,
                it_data->no_wants, it_data->al_cb);
    if (r == -ERR_ALREADY_UP)
        return 0;
    else if (r < 0)
    {
        aa_service *s = aa_service (it_data->si);
        size_t l = genalloc_len (int, &s->needs);
        size_t i;

        for (i = 0; i < l; ++i)
            aa_unmark_service (list_get (&s->needs, i));

        if (!(it_data->mode & AA_MODE_IS_DRY))
        {
            size_t l_n = strlen (name);
            size_t l_em = strlen (errmsg[-r]);
            char buf[l_n + 2 + l_em + 1];

            byte_copy (buf, l_n, name);
            byte_copy (buf + l_n, 2, ": ");
            byte_copy (buf + l_n + 2, l_em + 1, errmsg[-r]);

            aa_service_status_set_err (&s->st, ERR_DEPEND, buf);
            if (aa_service_status_write (&s->st, aa_service_name (s)) < 0)
                aa_strerr_warnu2sys ("write service status file for ", aa_service_name (s));
        }

        r = -ERR_DEPEND;
    }

    if (r == 0)
    {
        add_to_list (&aa_service (it_data->si)->needs, sni, 0);
        add_to_list (&aa_service (it_data->si)->after, sni, 1);
    }

    if (it_data->al_cb)
        it_data->al_cb (it_data->si, AA_AUTOLOAD_NEEDS, name, -r);

    return r;
}

int
_it_start_needs (direntry *d, void *data)
{
    return _name_start_needs (d->d_name, (struct it_data *) data);
}

int
_it_start_wants (direntry *d, void *data)
{
    struct it_data *it_data = data;
    int type;
    int swi;
    int r;

    tain_now_g ();
    type = aa_get_service (d->d_name, &swi, 1);
    if (type < 0)
        r = type;
    else
        r = aa_mark_service (it_data->mode, swi, type == AA_SERVICE_FROM_MAIN,
                it_data->no_wants, it_data->al_cb);
    if (r == -ERR_ALREADY_UP)
        return 0;

    if (r == 0)
        add_to_list (&aa_service (it_data->si)->wants, swi, 0);

    if (it_data->al_cb)
        it_data->al_cb (it_data->si, AA_AUTOLOAD_WANTS, d->d_name, -r);

    return r;
}

int
_it_start_after (direntry *d, void *data)
{
    struct it_data *it_data = data;
    int sai;
    int r;

    tain_now_g ();
    r = aa_get_service (d->d_name, &sai, 0);
    if (r < 0)
        return 0;

    add_to_list (&aa_service (it_data->si)->after, sai, 1);
    return 0;
}

int
_it_start_before (direntry *d, void *data)
{
    struct it_data *it_data = data;
    int sbi;
    int r;

    tain_now_g ();
    r = aa_get_service (d->d_name, &sbi, 0);
    if (r < 0)
        return 0;

    add_to_list (&aa_service (sbi)->after, it_data->si, 1);
    return 0;
}