199ca880aSopenharmony_ci/***
299ca880aSopenharmony_ci  This file is part of systemd.
399ca880aSopenharmony_ci
499ca880aSopenharmony_ci  Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
599ca880aSopenharmony_ci  Copyright 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
699ca880aSopenharmony_ci
799ca880aSopenharmony_ci  systemd is free software; you can redistribute it and/or modify it
899ca880aSopenharmony_ci  under the terms of the GNU Lesser General Public License as published by
999ca880aSopenharmony_ci  the Free Software Foundation; either version 2.1 of the License, or
1099ca880aSopenharmony_ci  (at your option) any later version.
1199ca880aSopenharmony_ci
1299ca880aSopenharmony_ci  systemd is distributed in the hope that it will be useful, but
1399ca880aSopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1499ca880aSopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1599ca880aSopenharmony_ci  Lesser General Public License for more details.
1699ca880aSopenharmony_ci
1799ca880aSopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1899ca880aSopenharmony_ci  along with systemd; If not, see <http://www.gnu.org/licenses/>.
1999ca880aSopenharmony_ci***/
2099ca880aSopenharmony_ci
2199ca880aSopenharmony_ci#include <stdio.h>
2299ca880aSopenharmony_ci#include <stdlib.h>
2399ca880aSopenharmony_ci#include <stddef.h>
2499ca880aSopenharmony_ci#include <unistd.h>
2599ca880aSopenharmony_ci#include <errno.h>
2699ca880aSopenharmony_ci#include <string.h>
2799ca880aSopenharmony_ci#include <limits.h>
2899ca880aSopenharmony_ci#include <sys/stat.h>
2999ca880aSopenharmony_ci#include <sys/inotify.h>
3099ca880aSopenharmony_ci
3199ca880aSopenharmony_ci#include "libudev.h"
3299ca880aSopenharmony_ci#include "libudev-private.h"
3399ca880aSopenharmony_ci
3499ca880aSopenharmony_ci/**
3599ca880aSopenharmony_ci * SECTION:libudev-queue
3699ca880aSopenharmony_ci * @short_description: access to currently active events
3799ca880aSopenharmony_ci *
3899ca880aSopenharmony_ci * This exports the current state of the udev processing queue.
3999ca880aSopenharmony_ci */
4099ca880aSopenharmony_ci
4199ca880aSopenharmony_ci/**
4299ca880aSopenharmony_ci * udev_queue:
4399ca880aSopenharmony_ci *
4499ca880aSopenharmony_ci * Opaque object representing the current event queue in the udev daemon.
4599ca880aSopenharmony_ci */
4699ca880aSopenharmony_cistruct udev_queue {
4799ca880aSopenharmony_ci        struct udev *udev;
4899ca880aSopenharmony_ci        int refcount;
4999ca880aSopenharmony_ci        int fd;
5099ca880aSopenharmony_ci};
5199ca880aSopenharmony_ci
5299ca880aSopenharmony_ci/**
5399ca880aSopenharmony_ci * udev_queue_new:
5499ca880aSopenharmony_ci * @udev: udev library context
5599ca880aSopenharmony_ci *
5699ca880aSopenharmony_ci * The initial refcount is 1, and needs to be decremented to
5799ca880aSopenharmony_ci * release the resources of the udev queue context.
5899ca880aSopenharmony_ci *
5999ca880aSopenharmony_ci * Returns: the udev queue context, or #NULL on error.
6099ca880aSopenharmony_ci **/
6199ca880aSopenharmony_ci_public_ struct udev_queue *udev_queue_new(struct udev *udev)
6299ca880aSopenharmony_ci{
6399ca880aSopenharmony_ci        struct udev_queue *udev_queue;
6499ca880aSopenharmony_ci
6599ca880aSopenharmony_ci        if (udev == NULL)
6699ca880aSopenharmony_ci                return NULL;
6799ca880aSopenharmony_ci
6899ca880aSopenharmony_ci        udev_queue = new0(struct udev_queue, 1);
6999ca880aSopenharmony_ci        if (udev_queue == NULL)
7099ca880aSopenharmony_ci                return NULL;
7199ca880aSopenharmony_ci
7299ca880aSopenharmony_ci        udev_queue->refcount = 1;
7399ca880aSopenharmony_ci        udev_queue->udev = udev;
7499ca880aSopenharmony_ci        udev_queue->fd = -1;
7599ca880aSopenharmony_ci        return udev_queue;
7699ca880aSopenharmony_ci}
7799ca880aSopenharmony_ci
7899ca880aSopenharmony_ci/**
7999ca880aSopenharmony_ci * udev_queue_ref:
8099ca880aSopenharmony_ci * @udev_queue: udev queue context
8199ca880aSopenharmony_ci *
8299ca880aSopenharmony_ci * Take a reference of a udev queue context.
8399ca880aSopenharmony_ci *
8499ca880aSopenharmony_ci * Returns: the same udev queue context.
8599ca880aSopenharmony_ci **/
8699ca880aSopenharmony_ci_public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
8799ca880aSopenharmony_ci{
8899ca880aSopenharmony_ci        if (udev_queue == NULL)
8999ca880aSopenharmony_ci                return NULL;
9099ca880aSopenharmony_ci
9199ca880aSopenharmony_ci        udev_queue->refcount++;
9299ca880aSopenharmony_ci        return udev_queue;
9399ca880aSopenharmony_ci}
9499ca880aSopenharmony_ci
9599ca880aSopenharmony_ci/**
9699ca880aSopenharmony_ci * udev_queue_unref:
9799ca880aSopenharmony_ci * @udev_queue: udev queue context
9899ca880aSopenharmony_ci *
9999ca880aSopenharmony_ci * Drop a reference of a udev queue context. If the refcount reaches zero,
10099ca880aSopenharmony_ci * the resources of the queue context will be released.
10199ca880aSopenharmony_ci *
10299ca880aSopenharmony_ci * Returns: #NULL
10399ca880aSopenharmony_ci **/
10499ca880aSopenharmony_ci_public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
10599ca880aSopenharmony_ci{
10699ca880aSopenharmony_ci        if (udev_queue == NULL)
10799ca880aSopenharmony_ci                return NULL;
10899ca880aSopenharmony_ci
10999ca880aSopenharmony_ci        udev_queue->refcount--;
11099ca880aSopenharmony_ci        if (udev_queue->refcount > 0)
11199ca880aSopenharmony_ci                return NULL;
11299ca880aSopenharmony_ci
11399ca880aSopenharmony_ci        safe_close(udev_queue->fd);
11499ca880aSopenharmony_ci
11599ca880aSopenharmony_ci        free(udev_queue);
11699ca880aSopenharmony_ci        return NULL;
11799ca880aSopenharmony_ci}
11899ca880aSopenharmony_ci
11999ca880aSopenharmony_ci/**
12099ca880aSopenharmony_ci * udev_queue_get_udev:
12199ca880aSopenharmony_ci * @udev_queue: udev queue context
12299ca880aSopenharmony_ci *
12399ca880aSopenharmony_ci * Retrieve the udev library context the queue context was created with.
12499ca880aSopenharmony_ci *
12599ca880aSopenharmony_ci * Returns: the udev library context.
12699ca880aSopenharmony_ci **/
12799ca880aSopenharmony_ci_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
12899ca880aSopenharmony_ci{
12999ca880aSopenharmony_ci        if (udev_queue == NULL)
13099ca880aSopenharmony_ci                return NULL;
13199ca880aSopenharmony_ci        return udev_queue->udev;
13299ca880aSopenharmony_ci}
13399ca880aSopenharmony_ci
13499ca880aSopenharmony_ci/**
13599ca880aSopenharmony_ci * udev_queue_get_kernel_seqnum:
13699ca880aSopenharmony_ci * @udev_queue: udev queue context
13799ca880aSopenharmony_ci *
13899ca880aSopenharmony_ci * This function is deprecated.
13999ca880aSopenharmony_ci *
14099ca880aSopenharmony_ci * Returns: 0.
14199ca880aSopenharmony_ci **/
14299ca880aSopenharmony_ci_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
14399ca880aSopenharmony_ci{
14499ca880aSopenharmony_ci        return 0;
14599ca880aSopenharmony_ci}
14699ca880aSopenharmony_ci
14799ca880aSopenharmony_ci/**
14899ca880aSopenharmony_ci * udev_queue_get_udev_seqnum:
14999ca880aSopenharmony_ci * @udev_queue: udev queue context
15099ca880aSopenharmony_ci *
15199ca880aSopenharmony_ci * This function is deprecated.
15299ca880aSopenharmony_ci *
15399ca880aSopenharmony_ci * Returns: 0.
15499ca880aSopenharmony_ci **/
15599ca880aSopenharmony_ci_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
15699ca880aSopenharmony_ci{
15799ca880aSopenharmony_ci        return 0;
15899ca880aSopenharmony_ci}
15999ca880aSopenharmony_ci
16099ca880aSopenharmony_ci/**
16199ca880aSopenharmony_ci * udev_queue_get_udev_is_active:
16299ca880aSopenharmony_ci * @udev_queue: udev queue context
16399ca880aSopenharmony_ci *
16499ca880aSopenharmony_ci * Check if udev is active on the system.
16599ca880aSopenharmony_ci *
16699ca880aSopenharmony_ci * Returns: a flag indicating if udev is active.
16799ca880aSopenharmony_ci **/
16899ca880aSopenharmony_ci_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
16999ca880aSopenharmony_ci{
17099ca880aSopenharmony_ci        return access(UDEV_ROOT_RUN "/udev/control", F_OK) >= 0;
17199ca880aSopenharmony_ci}
17299ca880aSopenharmony_ci
17399ca880aSopenharmony_ci/**
17499ca880aSopenharmony_ci * udev_queue_get_queue_is_empty:
17599ca880aSopenharmony_ci * @udev_queue: udev queue context
17699ca880aSopenharmony_ci *
17799ca880aSopenharmony_ci * Check if udev is currently processing any events.
17899ca880aSopenharmony_ci *
17999ca880aSopenharmony_ci * Returns: a flag indicating if udev is currently handling events.
18099ca880aSopenharmony_ci **/
18199ca880aSopenharmony_ci_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
18299ca880aSopenharmony_ci{
18399ca880aSopenharmony_ci        return access(UDEV_ROOT_RUN "/udev/queue", F_OK) < 0;
18499ca880aSopenharmony_ci}
18599ca880aSopenharmony_ci
18699ca880aSopenharmony_ci/**
18799ca880aSopenharmony_ci * udev_queue_get_seqnum_sequence_is_finished:
18899ca880aSopenharmony_ci * @udev_queue: udev queue context
18999ca880aSopenharmony_ci * @start: first event sequence number
19099ca880aSopenharmony_ci * @end: last event sequence number
19199ca880aSopenharmony_ci *
19299ca880aSopenharmony_ci * This function is deprecated, it just returns the result of
19399ca880aSopenharmony_ci * udev_queue_get_queue_is_empty().
19499ca880aSopenharmony_ci *
19599ca880aSopenharmony_ci * Returns: a flag indicating if udev is currently handling events.
19699ca880aSopenharmony_ci **/
19799ca880aSopenharmony_ci_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
19899ca880aSopenharmony_ci                                               unsigned long long int start, unsigned long long int end)
19999ca880aSopenharmony_ci{
20099ca880aSopenharmony_ci        return udev_queue_get_queue_is_empty(udev_queue);
20199ca880aSopenharmony_ci}
20299ca880aSopenharmony_ci
20399ca880aSopenharmony_ci/**
20499ca880aSopenharmony_ci * udev_queue_get_seqnum_is_finished:
20599ca880aSopenharmony_ci * @udev_queue: udev queue context
20699ca880aSopenharmony_ci * @seqnum: sequence number
20799ca880aSopenharmony_ci *
20899ca880aSopenharmony_ci * This function is deprecated, it just returns the result of
20999ca880aSopenharmony_ci * udev_queue_get_queue_is_empty().
21099ca880aSopenharmony_ci *
21199ca880aSopenharmony_ci * Returns: a flag indicating if udev is currently handling events.
21299ca880aSopenharmony_ci **/
21399ca880aSopenharmony_ci_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
21499ca880aSopenharmony_ci{
21599ca880aSopenharmony_ci        return udev_queue_get_queue_is_empty(udev_queue);
21699ca880aSopenharmony_ci}
21799ca880aSopenharmony_ci
21899ca880aSopenharmony_ci/**
21999ca880aSopenharmony_ci * udev_queue_get_queued_list_entry:
22099ca880aSopenharmony_ci * @udev_queue: udev queue context
22199ca880aSopenharmony_ci *
22299ca880aSopenharmony_ci * This function is deprecated.
22399ca880aSopenharmony_ci *
22499ca880aSopenharmony_ci * Returns: NULL.
22599ca880aSopenharmony_ci **/
22699ca880aSopenharmony_ci_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
22799ca880aSopenharmony_ci{
22899ca880aSopenharmony_ci        return NULL;
22999ca880aSopenharmony_ci}
23099ca880aSopenharmony_ci
23199ca880aSopenharmony_ci/**
23299ca880aSopenharmony_ci * udev_queue_get_fd:
23399ca880aSopenharmony_ci * @udev_queue: udev queue context
23499ca880aSopenharmony_ci *
23599ca880aSopenharmony_ci * Returns: a file descriptor to watch for a queue to become empty.
23699ca880aSopenharmony_ci */
23799ca880aSopenharmony_ci_public_ int udev_queue_get_fd(struct udev_queue *udev_queue) {
23899ca880aSopenharmony_ci        int fd;
23999ca880aSopenharmony_ci        int r;
24099ca880aSopenharmony_ci
24199ca880aSopenharmony_ci        if (udev_queue->fd >= 0)
24299ca880aSopenharmony_ci                return udev_queue->fd;
24399ca880aSopenharmony_ci
24499ca880aSopenharmony_ci        fd = inotify_init1(IN_CLOEXEC);
24599ca880aSopenharmony_ci        if (fd < 0)
24699ca880aSopenharmony_ci                return -errno;
24799ca880aSopenharmony_ci
24899ca880aSopenharmony_ci        r = inotify_add_watch(fd, UDEV_ROOT_RUN "/udev" , IN_DELETE);
24999ca880aSopenharmony_ci        if (r < 0) {
25099ca880aSopenharmony_ci                r = -errno;
25199ca880aSopenharmony_ci                close(fd);
25299ca880aSopenharmony_ci                return r;
25399ca880aSopenharmony_ci        }
25499ca880aSopenharmony_ci
25599ca880aSopenharmony_ci        udev_queue->fd = fd;
25699ca880aSopenharmony_ci        return fd;
25799ca880aSopenharmony_ci}
25899ca880aSopenharmony_ci
25999ca880aSopenharmony_ci/**
26099ca880aSopenharmony_ci * udev_queue_flush:
26199ca880aSopenharmony_ci * @udev_queue: udev queue context
26299ca880aSopenharmony_ci *
26399ca880aSopenharmony_ci * Returns: the result of clearing the watch for queue changes.
26499ca880aSopenharmony_ci */
26599ca880aSopenharmony_ci_public_ int udev_queue_flush(struct udev_queue *udev_queue) {
26699ca880aSopenharmony_ci        if (udev_queue->fd < 0)
26799ca880aSopenharmony_ci                return -EINVAL;
26899ca880aSopenharmony_ci
26999ca880aSopenharmony_ci        return flush_fd(udev_queue->fd);
27099ca880aSopenharmony_ci}
271