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