199ca880aSopenharmony_ci/***
299ca880aSopenharmony_ci  This file is part of systemd.
399ca880aSopenharmony_ci
499ca880aSopenharmony_ci  Copyright 2008-2014 Kay Sievers <kay@vrfy.org>
599ca880aSopenharmony_ci
699ca880aSopenharmony_ci  systemd is free software; you can redistribute it and/or modify it
799ca880aSopenharmony_ci  under the terms of the GNU Lesser General Public License as published by
899ca880aSopenharmony_ci  the Free Software Foundation; either version 2.1 of the License, or
999ca880aSopenharmony_ci  (at your option) any later version.
1099ca880aSopenharmony_ci
1199ca880aSopenharmony_ci  systemd is distributed in the hope that it will be useful, but
1299ca880aSopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1399ca880aSopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1499ca880aSopenharmony_ci  Lesser General Public License for more details.
1599ca880aSopenharmony_ci
1699ca880aSopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1799ca880aSopenharmony_ci  along with systemd; If not, see <http://www.gnu.org/licenses/>.
1899ca880aSopenharmony_ci***/
1999ca880aSopenharmony_ci
2099ca880aSopenharmony_ci#include <stdio.h>
2199ca880aSopenharmony_ci#include <stdlib.h>
2299ca880aSopenharmony_ci#include <stddef.h>
2399ca880aSopenharmony_ci#include <stdarg.h>
2499ca880aSopenharmony_ci#include <unistd.h>
2599ca880aSopenharmony_ci#include <errno.h>
2699ca880aSopenharmony_ci#include <string.h>
2799ca880aSopenharmony_ci#include <ctype.h>
2899ca880aSopenharmony_ci#include <time.h>
2999ca880aSopenharmony_ci
3099ca880aSopenharmony_ci#include "libudev.h"
3199ca880aSopenharmony_ci#include "libudev-private.h"
3299ca880aSopenharmony_ci#include "missing.h"
3399ca880aSopenharmony_ci
3499ca880aSopenharmony_ci/**
3599ca880aSopenharmony_ci * SECTION:libudev
3699ca880aSopenharmony_ci * @short_description: libudev context
3799ca880aSopenharmony_ci *
3899ca880aSopenharmony_ci * The context contains the default values read from the udev config file,
3999ca880aSopenharmony_ci * and is passed to all library operations.
4099ca880aSopenharmony_ci */
4199ca880aSopenharmony_ci
4299ca880aSopenharmony_ci/**
4399ca880aSopenharmony_ci * udev:
4499ca880aSopenharmony_ci *
4599ca880aSopenharmony_ci * Opaque object representing the library context.
4699ca880aSopenharmony_ci */
4799ca880aSopenharmony_cistruct udev {
4899ca880aSopenharmony_ci        int refcount;
4999ca880aSopenharmony_ci        void (*log_fn)(struct udev *udev,
5099ca880aSopenharmony_ci                       int priority, const char *file, int line, const char *fn,
5199ca880aSopenharmony_ci                       const char *format, va_list args);
5299ca880aSopenharmony_ci        void *userdata;
5399ca880aSopenharmony_ci};
5499ca880aSopenharmony_ci
5599ca880aSopenharmony_ci/**
5699ca880aSopenharmony_ci * udev_get_userdata:
5799ca880aSopenharmony_ci * @udev: udev library context
5899ca880aSopenharmony_ci *
5999ca880aSopenharmony_ci * Retrieve stored data pointer from library context. This might be useful
6099ca880aSopenharmony_ci * to access from callbacks.
6199ca880aSopenharmony_ci *
6299ca880aSopenharmony_ci * Returns: stored userdata
6399ca880aSopenharmony_ci **/
6499ca880aSopenharmony_ci_public_ void *udev_get_userdata(struct udev *udev) {
6599ca880aSopenharmony_ci        if (udev == NULL)
6699ca880aSopenharmony_ci                return NULL;
6799ca880aSopenharmony_ci        return udev->userdata;
6899ca880aSopenharmony_ci}
6999ca880aSopenharmony_ci
7099ca880aSopenharmony_ci/**
7199ca880aSopenharmony_ci * udev_set_userdata:
7299ca880aSopenharmony_ci * @udev: udev library context
7399ca880aSopenharmony_ci * @userdata: data pointer
7499ca880aSopenharmony_ci *
7599ca880aSopenharmony_ci * Store custom @userdata in the library context.
7699ca880aSopenharmony_ci **/
7799ca880aSopenharmony_ci_public_ void udev_set_userdata(struct udev *udev, void *userdata) {
7899ca880aSopenharmony_ci        if (udev == NULL)
7999ca880aSopenharmony_ci                return;
8099ca880aSopenharmony_ci        udev->userdata = userdata;
8199ca880aSopenharmony_ci}
8299ca880aSopenharmony_ci
8399ca880aSopenharmony_ci/**
8499ca880aSopenharmony_ci * udev_new:
8599ca880aSopenharmony_ci *
8699ca880aSopenharmony_ci * Create udev library context. This reads the udev configuration
8799ca880aSopenharmony_ci * file, and fills in the default values.
8899ca880aSopenharmony_ci *
8999ca880aSopenharmony_ci * The initial refcount is 1, and needs to be decremented to
9099ca880aSopenharmony_ci * release the resources of the udev library context.
9199ca880aSopenharmony_ci *
9299ca880aSopenharmony_ci * Returns: a new udev library context
9399ca880aSopenharmony_ci **/
9499ca880aSopenharmony_ci_public_ struct udev *udev_new(void) {
9599ca880aSopenharmony_ci        struct udev *udev;
9699ca880aSopenharmony_ci        _cleanup_fclose_ FILE *f = NULL;
9799ca880aSopenharmony_ci
9899ca880aSopenharmony_ci        udev = new0(struct udev, 1);
9999ca880aSopenharmony_ci        if (udev == NULL)
10099ca880aSopenharmony_ci                return NULL;
10199ca880aSopenharmony_ci        udev->refcount = 1;
10299ca880aSopenharmony_ci
10399ca880aSopenharmony_ci        f = fopen( UDEV_CONF_FILE, "re");
10499ca880aSopenharmony_ci        if (f != NULL) {
10599ca880aSopenharmony_ci                char line[UTIL_LINE_SIZE];
10699ca880aSopenharmony_ci                unsigned line_nr = 0;
10799ca880aSopenharmony_ci
10899ca880aSopenharmony_ci                while (fgets(line, sizeof(line), f)) {
10999ca880aSopenharmony_ci                        size_t len;
11099ca880aSopenharmony_ci                        char *key;
11199ca880aSopenharmony_ci                        char *val;
11299ca880aSopenharmony_ci
11399ca880aSopenharmony_ci                        line_nr++;
11499ca880aSopenharmony_ci
11599ca880aSopenharmony_ci                        /* find key */
11699ca880aSopenharmony_ci                        key = line;
11799ca880aSopenharmony_ci                        while (isspace(key[0]))
11899ca880aSopenharmony_ci                                key++;
11999ca880aSopenharmony_ci
12099ca880aSopenharmony_ci                        /* comment or empty line */
12199ca880aSopenharmony_ci                        if (key[0] == '#' || key[0] == '\0')
12299ca880aSopenharmony_ci                                continue;
12399ca880aSopenharmony_ci
12499ca880aSopenharmony_ci                        /* split key/value */
12599ca880aSopenharmony_ci                        val = strchr(key, '=');
12699ca880aSopenharmony_ci                        if (val == NULL) {
12799ca880aSopenharmony_ci                                log_debug(UDEV_CONF_FILE ":%u: missing assignment,  skipping line.", line_nr);
12899ca880aSopenharmony_ci                                continue;
12999ca880aSopenharmony_ci                        }
13099ca880aSopenharmony_ci                        val[0] = '\0';
13199ca880aSopenharmony_ci                        val++;
13299ca880aSopenharmony_ci
13399ca880aSopenharmony_ci                        /* find value */
13499ca880aSopenharmony_ci                        while (isspace(val[0]))
13599ca880aSopenharmony_ci                                val++;
13699ca880aSopenharmony_ci
13799ca880aSopenharmony_ci                        /* terminate key */
13899ca880aSopenharmony_ci                        len = strlen(key);
13999ca880aSopenharmony_ci                        if (len == 0)
14099ca880aSopenharmony_ci                                continue;
14199ca880aSopenharmony_ci                        while (isspace(key[len-1]))
14299ca880aSopenharmony_ci                                len--;
14399ca880aSopenharmony_ci                        key[len] = '\0';
14499ca880aSopenharmony_ci
14599ca880aSopenharmony_ci                        /* terminate value */
14699ca880aSopenharmony_ci                        len = strlen(val);
14799ca880aSopenharmony_ci                        if (len == 0)
14899ca880aSopenharmony_ci                                continue;
14999ca880aSopenharmony_ci                        while (isspace(val[len-1]))
15099ca880aSopenharmony_ci                                len--;
15199ca880aSopenharmony_ci                        val[len] = '\0';
15299ca880aSopenharmony_ci
15399ca880aSopenharmony_ci                        if (len == 0)
15499ca880aSopenharmony_ci                                continue;
15599ca880aSopenharmony_ci
15699ca880aSopenharmony_ci                        /* unquote */
15799ca880aSopenharmony_ci                        if (val[0] == '"' || val[0] == '\'') {
15899ca880aSopenharmony_ci                                if (val[len-1] != val[0]) {
15999ca880aSopenharmony_ci                                        log_debug(UDEV_CONF_FILE ":%u: inconsistent quoting, skipping line.", line_nr);
16099ca880aSopenharmony_ci                                        continue;
16199ca880aSopenharmony_ci                                }
16299ca880aSopenharmony_ci                                val[len-1] = '\0';
16399ca880aSopenharmony_ci                                val++;
16499ca880aSopenharmony_ci                        }
16599ca880aSopenharmony_ci
16699ca880aSopenharmony_ci                        if (streq(key, "udev_log")) {
16799ca880aSopenharmony_ci                                int prio;
16899ca880aSopenharmony_ci
16999ca880aSopenharmony_ci                                prio = util_log_priority(val);
17099ca880aSopenharmony_ci                                if (prio < 0)
17199ca880aSopenharmony_ci                                        log_debug("/etc/udev/udev.conf:%u: invalid log level '%s', ignoring.", line_nr, val);
17299ca880aSopenharmony_ci                                else
17399ca880aSopenharmony_ci                                        log_set_max_level(prio);
17499ca880aSopenharmony_ci                                continue;
17599ca880aSopenharmony_ci                        }
17699ca880aSopenharmony_ci                }
17799ca880aSopenharmony_ci        }
17899ca880aSopenharmony_ci
17999ca880aSopenharmony_ci        return udev;
18099ca880aSopenharmony_ci}
18199ca880aSopenharmony_ci
18299ca880aSopenharmony_ci/**
18399ca880aSopenharmony_ci * udev_ref:
18499ca880aSopenharmony_ci * @udev: udev library context
18599ca880aSopenharmony_ci *
18699ca880aSopenharmony_ci * Take a reference of the udev library context.
18799ca880aSopenharmony_ci *
18899ca880aSopenharmony_ci * Returns: the passed udev library context
18999ca880aSopenharmony_ci **/
19099ca880aSopenharmony_ci_public_ struct udev *udev_ref(struct udev *udev) {
19199ca880aSopenharmony_ci        if (udev == NULL)
19299ca880aSopenharmony_ci                return NULL;
19399ca880aSopenharmony_ci        udev->refcount++;
19499ca880aSopenharmony_ci        return udev;
19599ca880aSopenharmony_ci}
19699ca880aSopenharmony_ci
19799ca880aSopenharmony_ci/**
19899ca880aSopenharmony_ci * udev_unref:
19999ca880aSopenharmony_ci * @udev: udev library context
20099ca880aSopenharmony_ci *
20199ca880aSopenharmony_ci * Drop a reference of the udev library context. If the refcount
20299ca880aSopenharmony_ci * reaches zero, the resources of the context will be released.
20399ca880aSopenharmony_ci *
20499ca880aSopenharmony_ci * Returns: the passed udev library context if it has still an active reference, or #NULL otherwise.
20599ca880aSopenharmony_ci **/
20699ca880aSopenharmony_ci_public_ struct udev *udev_unref(struct udev *udev) {
20799ca880aSopenharmony_ci        if (udev == NULL)
20899ca880aSopenharmony_ci                return NULL;
20999ca880aSopenharmony_ci        udev->refcount--;
21099ca880aSopenharmony_ci        if (udev->refcount > 0)
21199ca880aSopenharmony_ci                return udev;
21299ca880aSopenharmony_ci        free(udev);
21399ca880aSopenharmony_ci        return NULL;
21499ca880aSopenharmony_ci}
21599ca880aSopenharmony_ci
21699ca880aSopenharmony_ci/**
21799ca880aSopenharmony_ci * udev_set_log_fn:
21899ca880aSopenharmony_ci * @udev: udev library context
21999ca880aSopenharmony_ci * @log_fn: function to be called for log messages
22099ca880aSopenharmony_ci *
22199ca880aSopenharmony_ci * This function is deprecated.
22299ca880aSopenharmony_ci *
22399ca880aSopenharmony_ci **/
22499ca880aSopenharmony_ci_public_ void udev_set_log_fn(struct udev *udev,
22599ca880aSopenharmony_ci                     void (*log_fn)(struct udev *udev,
22699ca880aSopenharmony_ci                                    int priority, const char *file, int line, const char *fn,
22799ca880aSopenharmony_ci                                    const char *format, va_list args)) {
22899ca880aSopenharmony_ci        return;
22999ca880aSopenharmony_ci}
23099ca880aSopenharmony_ci
23199ca880aSopenharmony_ci/**
23299ca880aSopenharmony_ci * udev_get_log_priority:
23399ca880aSopenharmony_ci * @udev: udev library context
23499ca880aSopenharmony_ci *
23599ca880aSopenharmony_ci * This function is deprecated.
23699ca880aSopenharmony_ci *
23799ca880aSopenharmony_ci **/
23899ca880aSopenharmony_ci_public_ int udev_get_log_priority(struct udev *udev) {
23999ca880aSopenharmony_ci        return log_get_max_level();
24099ca880aSopenharmony_ci}
24199ca880aSopenharmony_ci
24299ca880aSopenharmony_ci/**
24399ca880aSopenharmony_ci * udev_set_log_priority:
24499ca880aSopenharmony_ci * @udev: udev library context
24599ca880aSopenharmony_ci * @priority: the new log priority
24699ca880aSopenharmony_ci *
24799ca880aSopenharmony_ci * This function is deprecated.
24899ca880aSopenharmony_ci *
24999ca880aSopenharmony_ci **/
25099ca880aSopenharmony_ci_public_ void udev_set_log_priority(struct udev *udev, int priority) {
25199ca880aSopenharmony_ci        log_set_max_level(priority);
25299ca880aSopenharmony_ci}
253