udev: drop collect
This commit is contained in:
parent
3c83f15967
commit
a168792c2d
2
TODO
2
TODO
|
@ -15,8 +15,6 @@ Janitorial Clean-ups:
|
||||||
* rework mount.c and swap.c to follow proper state enumeration/deserialization
|
* rework mount.c and swap.c to follow proper state enumeration/deserialization
|
||||||
semantics, like we do for device.c now
|
semantics, like we do for device.c now
|
||||||
|
|
||||||
* udev: drop "collect", it's nonsense
|
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
* optionally, if a per-partition GPT flag is set for the root/home/… partitions
|
* optionally, if a per-partition GPT flag is set for the root/home/… partitions
|
||||||
|
|
|
@ -1,478 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
||||||
/*
|
|
||||||
* Collect variables across events.
|
|
||||||
*
|
|
||||||
* usage: collect [--add|--remove] <checkpoint> <id> <idlist>
|
|
||||||
*
|
|
||||||
* Adds ID <id> to the list governed by <checkpoint>.
|
|
||||||
* <id> must be part of the ID list <idlist>.
|
|
||||||
* If all IDs given by <idlist> are listed (ie collect has been
|
|
||||||
* invoked for each ID in <idlist>) collect returns 0, the
|
|
||||||
* number of missing IDs otherwise.
|
|
||||||
* A negative number is returned on error.
|
|
||||||
*
|
|
||||||
* Copyright © 2007, Hannes Reinecke <hare@suse.de>
|
|
||||||
*
|
|
||||||
* This program 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 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "alloc-util.h"
|
|
||||||
#include "libudev-private.h"
|
|
||||||
#include "macro.h"
|
|
||||||
#include "stdio-util.h"
|
|
||||||
#include "string-util.h"
|
|
||||||
#include "udev-util.h"
|
|
||||||
|
|
||||||
#define BUFSIZE 16
|
|
||||||
#define UDEV_ALARM_TIMEOUT 180
|
|
||||||
|
|
||||||
enum collect_state {
|
|
||||||
STATE_NONE,
|
|
||||||
STATE_OLD,
|
|
||||||
STATE_CONFIRMED,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _mate {
|
|
||||||
struct udev_list_node node;
|
|
||||||
char *name;
|
|
||||||
enum collect_state state;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct udev_list_node bunch;
|
|
||||||
static int debug;
|
|
||||||
|
|
||||||
/* This can increase dynamically */
|
|
||||||
static size_t bufsize = BUFSIZE;
|
|
||||||
|
|
||||||
static inline struct _mate *node_to_mate(struct udev_list_node *node)
|
|
||||||
{
|
|
||||||
return container_of(node, struct _mate, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
_noreturn_ static void sig_alrm(int signo)
|
|
||||||
{
|
|
||||||
_exit(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usage(void)
|
|
||||||
{
|
|
||||||
printf("%s [options] <checkpoint> <id> <idlist>\n\n"
|
|
||||||
"Collect variables across events.\n\n"
|
|
||||||
" -h --help Print this message\n"
|
|
||||||
" -a --add Add ID <id> to the list <idlist>\n"
|
|
||||||
" -r --remove Remove ID <id> from the list <idlist>\n"
|
|
||||||
" -d --debug Debug to stderr\n\n"
|
|
||||||
" Adds ID <id> to the list governed by <checkpoint>.\n"
|
|
||||||
" <id> must be part of the list <idlist>.\n"
|
|
||||||
" If all IDs given by <idlist> are listed (ie collect has been\n"
|
|
||||||
" invoked for each ID in <idlist>) collect returns 0, the\n"
|
|
||||||
" number of missing IDs otherwise.\n"
|
|
||||||
" On error a negative number is returned.\n\n"
|
|
||||||
, program_invocation_short_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* prepare
|
|
||||||
*
|
|
||||||
* Prepares the database file
|
|
||||||
*/
|
|
||||||
static int prepare(char *dir, char *filename)
|
|
||||||
{
|
|
||||||
char buf[PATH_MAX];
|
|
||||||
int r, fd;
|
|
||||||
|
|
||||||
r = mkdir(dir, 0700);
|
|
||||||
if (r < 0 && errno != EEXIST)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
snprintf(buf, sizeof buf, "%s/%s", dir, filename);
|
|
||||||
|
|
||||||
fd = open(buf, O_RDWR|O_CREAT|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
|
||||||
if (fd < 0)
|
|
||||||
fprintf(stderr, "Cannot open %s: %m\n", buf);
|
|
||||||
|
|
||||||
if (lockf(fd,F_TLOCK,0) < 0) {
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "Lock taken, wait for %d seconds\n", UDEV_ALARM_TIMEOUT);
|
|
||||||
if (IN_SET(errno, EAGAIN, EACCES)) {
|
|
||||||
alarm(UDEV_ALARM_TIMEOUT);
|
|
||||||
lockf(fd, F_LOCK, 0);
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "Acquired lock on %s\n", buf);
|
|
||||||
} else {
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "Could not get lock on %s: %m\n", buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read checkpoint file
|
|
||||||
*
|
|
||||||
* Tricky reading this. We allocate a buffer twice as large
|
|
||||||
* as we're going to read. Then we read into the upper half
|
|
||||||
* of that buffer and start parsing.
|
|
||||||
* Once we do _not_ find end-of-work terminator (whitespace
|
|
||||||
* character) we move the upper half to the lower half,
|
|
||||||
* adjust the read pointer and read the next bit.
|
|
||||||
* Quite clever methinks :-)
|
|
||||||
* I should become a programmer ...
|
|
||||||
*
|
|
||||||
* Yes, one could have used fgets() for this. But then we'd
|
|
||||||
* have to use freopen etc which I found quite tedious.
|
|
||||||
*/
|
|
||||||
static int checkout(int fd)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
_cleanup_free_ char *buf = NULL;
|
|
||||||
char *ptr, *word = NULL;
|
|
||||||
struct _mate *him;
|
|
||||||
|
|
||||||
restart:
|
|
||||||
len = bufsize >> 1;
|
|
||||||
buf = malloc(bufsize + 1);
|
|
||||||
if (!buf)
|
|
||||||
return log_oom();
|
|
||||||
memset(buf, ' ', bufsize);
|
|
||||||
buf[bufsize] = '\0';
|
|
||||||
|
|
||||||
ptr = buf + len;
|
|
||||||
while ((read(fd, buf + len, len)) > 0) {
|
|
||||||
while (ptr && *ptr) {
|
|
||||||
word = ptr;
|
|
||||||
ptr = strpbrk(word," \n\t\r");
|
|
||||||
if (!ptr && word < (buf + len)) {
|
|
||||||
bufsize = bufsize << 1;
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "ID overflow, restarting with size %zu\n", bufsize);
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
if (ptr) {
|
|
||||||
*ptr = '\0';
|
|
||||||
ptr++;
|
|
||||||
if (isempty(word))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "Found word %s\n", word);
|
|
||||||
him = malloc(sizeof (struct _mate));
|
|
||||||
if (!him)
|
|
||||||
return log_oom();
|
|
||||||
him->name = strdup(word);
|
|
||||||
if (!him->name) {
|
|
||||||
free(him);
|
|
||||||
return log_oom();
|
|
||||||
}
|
|
||||||
him->state = STATE_OLD;
|
|
||||||
udev_list_node_append(&him->node, &bunch);
|
|
||||||
word = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memcpy(buf, buf + len, len);
|
|
||||||
memset(buf + len, ' ', len);
|
|
||||||
|
|
||||||
if (!ptr)
|
|
||||||
ptr = word;
|
|
||||||
ptr -= len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* invite
|
|
||||||
*
|
|
||||||
* Adds a new ID 'us' to the internal list,
|
|
||||||
* marks it as confirmed.
|
|
||||||
*/
|
|
||||||
static void invite(char *us)
|
|
||||||
{
|
|
||||||
struct udev_list_node *him_node;
|
|
||||||
struct _mate *who = NULL;
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "Adding ID '%s'\n", us);
|
|
||||||
|
|
||||||
udev_list_node_foreach(him_node, &bunch) {
|
|
||||||
struct _mate *him = node_to_mate(him_node);
|
|
||||||
|
|
||||||
if (streq(him->name, us)) {
|
|
||||||
him->state = STATE_CONFIRMED;
|
|
||||||
who = him;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug && !who)
|
|
||||||
fprintf(stderr, "ID '%s' not in database\n", us);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* reject
|
|
||||||
*
|
|
||||||
* Marks the ID 'us' as invalid,
|
|
||||||
* causing it to be removed when the
|
|
||||||
* list is written out.
|
|
||||||
*/
|
|
||||||
static void reject(char *us)
|
|
||||||
{
|
|
||||||
struct udev_list_node *him_node;
|
|
||||||
struct _mate *who = NULL;
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "Removing ID '%s'\n", us);
|
|
||||||
|
|
||||||
udev_list_node_foreach(him_node, &bunch) {
|
|
||||||
struct _mate *him = node_to_mate(him_node);
|
|
||||||
|
|
||||||
if (streq(him->name, us)) {
|
|
||||||
him->state = STATE_NONE;
|
|
||||||
who = him;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug && !who)
|
|
||||||
fprintf(stderr, "ID '%s' not in database\n", us);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* kickout
|
|
||||||
*
|
|
||||||
* Remove all IDs in the internal list which are not part
|
|
||||||
* of the list passed via the command line.
|
|
||||||
*/
|
|
||||||
static void kickout(void)
|
|
||||||
{
|
|
||||||
struct udev_list_node *him_node;
|
|
||||||
struct udev_list_node *tmp;
|
|
||||||
|
|
||||||
udev_list_node_foreach_safe(him_node, tmp, &bunch) {
|
|
||||||
struct _mate *him = node_to_mate(him_node);
|
|
||||||
|
|
||||||
if (him->state == STATE_OLD) {
|
|
||||||
udev_list_node_remove(&him->node);
|
|
||||||
free(him->name);
|
|
||||||
free(him);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* missing
|
|
||||||
*
|
|
||||||
* Counts all missing IDs in the internal list.
|
|
||||||
*/
|
|
||||||
static int missing(int fd)
|
|
||||||
{
|
|
||||||
char *buf;
|
|
||||||
int ret = 0;
|
|
||||||
struct udev_list_node *him_node;
|
|
||||||
|
|
||||||
buf = malloc(bufsize);
|
|
||||||
if (!buf)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
udev_list_node_foreach(him_node, &bunch) {
|
|
||||||
struct _mate *him = node_to_mate(him_node);
|
|
||||||
|
|
||||||
if (him->state == STATE_NONE) {
|
|
||||||
ret++;
|
|
||||||
} else {
|
|
||||||
while (strlen(him->name)+1 >= bufsize) {
|
|
||||||
char *tmpbuf;
|
|
||||||
|
|
||||||
bufsize = bufsize << 1;
|
|
||||||
tmpbuf = realloc(buf, bufsize);
|
|
||||||
if (!tmpbuf) {
|
|
||||||
free(buf);
|
|
||||||
return log_oom();
|
|
||||||
}
|
|
||||||
buf = tmpbuf;
|
|
||||||
}
|
|
||||||
snprintf(buf, strlen(him->name)+2, "%s ", him->name);
|
|
||||||
if (write(fd, buf, strlen(buf)) < 0) {
|
|
||||||
free(buf);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* everybody
|
|
||||||
*
|
|
||||||
* Prints out the status of the internal list.
|
|
||||||
*/
|
|
||||||
static void everybody(void)
|
|
||||||
{
|
|
||||||
struct udev_list_node *him_node;
|
|
||||||
const char *state = "";
|
|
||||||
|
|
||||||
udev_list_node_foreach(him_node, &bunch) {
|
|
||||||
struct _mate *him = node_to_mate(him_node);
|
|
||||||
|
|
||||||
switch (him->state) {
|
|
||||||
case STATE_NONE:
|
|
||||||
state = "none";
|
|
||||||
break;
|
|
||||||
case STATE_OLD:
|
|
||||||
state = "old";
|
|
||||||
break;
|
|
||||||
case STATE_CONFIRMED:
|
|
||||||
state = "confirmed";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "ID: %s=%s\n", him->name, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
static const struct option options[] = {
|
|
||||||
{ "add", no_argument, NULL, 'a' },
|
|
||||||
{ "remove", no_argument, NULL, 'r' },
|
|
||||||
{ "debug", no_argument, NULL, 'd' },
|
|
||||||
{ "help", no_argument, NULL, 'h' },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
int argi;
|
|
||||||
char *checkpoint, *us;
|
|
||||||
int fd;
|
|
||||||
int i;
|
|
||||||
int ret = EXIT_SUCCESS;
|
|
||||||
int prune = 0;
|
|
||||||
char tmpdir[UTIL_PATH_SIZE];
|
|
||||||
|
|
||||||
log_set_target(LOG_TARGET_AUTO);
|
|
||||||
udev_parse_config();
|
|
||||||
log_parse_environment();
|
|
||||||
log_open();
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
int option;
|
|
||||||
|
|
||||||
option = getopt_long(argc, argv, "ardh", options, NULL);
|
|
||||||
if (option == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (option) {
|
|
||||||
case 'a':
|
|
||||||
prune = 0;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
prune = 1;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
debug = 1;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
usage();
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argi = optind;
|
|
||||||
if (argi + 2 > argc) {
|
|
||||||
printf("Missing parameter(s)\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
checkpoint = argv[argi++];
|
|
||||||
us = argv[argi++];
|
|
||||||
|
|
||||||
if (signal(SIGALRM, sig_alrm) == SIG_ERR) {
|
|
||||||
fprintf(stderr, "Cannot set SIGALRM: %m\n");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
udev_list_node_init(&bunch);
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "Using checkpoint '%s'\n", checkpoint);
|
|
||||||
|
|
||||||
strscpyl(tmpdir, sizeof(tmpdir), "/run/udev/collect", NULL);
|
|
||||||
fd = prepare(tmpdir, checkpoint);
|
|
||||||
if (fd < 0) {
|
|
||||||
ret = 3;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkout(fd) < 0) {
|
|
||||||
ret = 2;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = argi; i < argc; i++) {
|
|
||||||
struct udev_list_node *him_node;
|
|
||||||
struct _mate *who;
|
|
||||||
|
|
||||||
who = NULL;
|
|
||||||
udev_list_node_foreach(him_node, &bunch) {
|
|
||||||
struct _mate *him = node_to_mate(him_node);
|
|
||||||
|
|
||||||
if (streq(him->name, argv[i]))
|
|
||||||
who = him;
|
|
||||||
}
|
|
||||||
if (!who) {
|
|
||||||
struct _mate *him;
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "ID %s: not in database\n", argv[i]);
|
|
||||||
him = new(struct _mate, 1);
|
|
||||||
if (!him) {
|
|
||||||
ret = ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
him->name = strdup(argv[i]);
|
|
||||||
if (!him->name) {
|
|
||||||
free(him);
|
|
||||||
ret = ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
him->state = STATE_NONE;
|
|
||||||
udev_list_node_append(&him->node, &bunch);
|
|
||||||
} else {
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "ID %s: found in database\n", argv[i]);
|
|
||||||
who->state = STATE_CONFIRMED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prune)
|
|
||||||
reject(us);
|
|
||||||
else
|
|
||||||
invite(us);
|
|
||||||
|
|
||||||
if (debug) {
|
|
||||||
everybody();
|
|
||||||
fprintf(stderr, "Prune lists\n");
|
|
||||||
}
|
|
||||||
kickout();
|
|
||||||
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
ftruncate(fd, 0);
|
|
||||||
ret = missing(fd);
|
|
||||||
|
|
||||||
lockf(fd, F_ULOCK, 0);
|
|
||||||
close(fd);
|
|
||||||
out:
|
|
||||||
if (debug)
|
|
||||||
everybody();
|
|
||||||
if (ret >= 0)
|
|
||||||
printf("COLLECT_%s=%d\n", checkpoint, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
|
@ -159,7 +159,6 @@ libudev_core = static_library(
|
||||||
|
|
||||||
foreach prog : [['ata_id/ata_id.c'],
|
foreach prog : [['ata_id/ata_id.c'],
|
||||||
['cdrom_id/cdrom_id.c'],
|
['cdrom_id/cdrom_id.c'],
|
||||||
['collect/collect.c'],
|
|
||||||
['scsi_id/scsi_id.c',
|
['scsi_id/scsi_id.c',
|
||||||
'scsi_id/scsi_id.h',
|
'scsi_id/scsi_id.h',
|
||||||
'scsi_id/scsi_serial.c',
|
'scsi_id/scsi_serial.c',
|
||||||
|
|
Loading…
Reference in New Issue