/src/udev-builtin-blkid.c (baafd8d85c93055d43ce4672b55d9ffe619a9fd5) (6167 bytes) (mode 100644) (type blob)

/*
 * probe disks for filesystems and partitions
 *
 * Copyright (C) 2020 Sylvain BERTRAND <sylvain.bertrand@legeek.net>
 *
 * 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include "udev.h"
#define loop for(;;)
#define u8 char
struct busybox_blkid_t {
	char *type;
	char *uuid;
	char *label;
};
static void busybox_blkid_exec(struct udev_device *dev, int s)
{
	struct udev *udev = udev_device_get_udev(dev);
	const char *devnode;
	int r;

	devnode = udev_device_get_devnode(dev);
	close(0);
	r = dup2(s, 1);
	if (r == -1) {
		err(udev, "blkid:unable to duplicate socket filedescriptor on standart output\n");
		exit(1);
	}
	loop {
		errno = 0;
		info(udev, "blkid:exec for %s\n", devnode);
		execlp("blkid", "blkid", devnode, 0);
		if (errno != EAGAIN) {
			err(udev, "blkid:unable to exec\n");
			exit(1);
		}
		/* EAGAIN */
	}
	/* unreachable */
}
static void busybox_blkid_output_field(char *buf, char *key_name,
							char **value_dup)
{
	char *key;
	char *value;
	char *value_end;

	key = strstr(buf, key_name);
	if (key == 0)
		return;
	value = strchr(key, '=');
	if (value == 0)
		return;
	if (value[1] == 0 || value[1] != '"')
		return;
	value += 2;
	value_end = strchr(value, '"');
	if (value_end == 0)
		return;
	*value_end = 0;
	*value_dup = strdup(value);
	*value_end = '"';
}
static int busybox_blkid_output_parse(struct udev *udev, int s,
						struct busybox_blkid_t *props)
{
	u8 buf[BUFSIZ + 1]; /* zero terminating char in worst case scenario */
	u8 *buf_end;
	u8 *p_end;

	buf_end = buf + BUFSIZ;
	p_end = buf;
	loop {
		struct pollfd pfd; 	
		int r;
		pfd.fd = s;
		pfd.events = POLLIN;
		pfd.revents = 0;
		errno = 0;
		r = poll(&pfd, 1, 2000); /* timeout of 2 secs */
		if (r == -1) {
			if (errno == EINTR || errno == EAGAIN)
				continue;
			err(udev, "blkid:something went wrong while polling the unix socket\n");
			return EXIT_FAILURE;
		} else if (r == 0) {
			err(udev, "blkid:timeout occured while polling the unix socket\n");
			return EXIT_FAILURE;
		}
		/* r >= 0 */
		if ((pfd.revents & POLLIN) != 0) {
			loop {
				errno = 0;
				r = recv(s, p_end, buf_end - p_end, 0);
				/*
				 * when dealing with sockets, you can get
				 * 0-length messages, just use the generalized
				 * case
				 */
				if (r >= 0) {
					p_end += r;
					break;
				} else if (r == -1 && errno == EINTR)
					continue;
				/* r < -1 || (r == -1 && errno != EINTR) */
				err(udev, "blkid:something went wrong while reading from the unix socket\n");
				return EXIT_FAILURE;
			}
			if (p_end == buf_end)
				break; /* try to process the buf data */
		}
		if ((pfd.revents & (POLLERR | POLLHUP)) != 0)
			break; /* try to process the buf data */
	}
	*p_end = 0;
	/*====================================================================*/
	busybox_blkid_output_field(buf, "TYPE", &props->type);
	info(udev, "blkid:extracted filesystem \"%s\"\n", props->type ? props->type : "unknown");
	busybox_blkid_output_field(buf, "UUID", &props->uuid);
	info(udev, "blkid:extracted uuid \"%s\"\n", props->uuid ? props->uuid : "unknown");
	busybox_blkid_output_field(buf, "LABEL", &props->label);
	info(udev, "blkid:extracted label \"%s\"\n", props->label ? props->label : "unknown");
	return EXIT_SUCCESS;
}
static int busybox_blkid_fork(struct udev_device *dev,
						struct busybox_blkid_t *props)
{
	struct udev *udev = udev_device_get_udev(dev);
	int r;
	int parse_r;
	int sv[2];
	pid_t blkid_pid;
	int blkid_status;

	r = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
	if (r == -1) {
		err(udev, "blkid:unable to create a socket pair for invokation\n");
		return EXIT_FAILURE;
	}
	blkid_pid = fork();
	if (blkid_pid == -1) {
		close(sv[0]);
		close(sv[1]);
		err(udev, "blkid:unable to fork in order to exec\n");
		return EXIT_FAILURE;
	} else if (blkid_pid == 0) {
		close(sv[0]);
		busybox_blkid_exec(dev, sv[1]);
		/* unreachable */
	} 
	close(sv[1]);
	parse_r = busybox_blkid_output_parse(udev, sv[0], props);
	close(sv[0]);
	/*--------------------------------------------------------------------*/
	r = waitpid(blkid_pid, &blkid_status, 0);
	if (r == -1) {
		err(udev, "blkid:unable to wait for on pid %d\n", blkid_pid);
		return parse_r;
	}
	if (WIFEXITED(blkid_status)) {
		if (WEXITSTATUS(blkid_status) != 0) {
			err(udev, "blkid:exit status %d\n", WEXITSTATUS(blkid_status));
			return EXIT_FAILURE;
		}
		/* WEXITSTATUS(blkid_status) == 0 */
		return parse_r;
	} 
	err(udev, "blkid:exited abnormally\n");
	return EXIT_FAILURE;
}

static int builtin_blkid(struct udev_device *dev, int argc, char *argv[],
								bool test)
{
        int r;
	struct busybox_blkid_t props;

	memset(&props, 0, sizeof(props));
	r = busybox_blkid_fork(dev, &props);
	if (r == EXIT_FAILURE)
		return EXIT_FAILURE;
       	if (props.type != 0) {
       	        udev_builtin_add_property(dev, test, "ID_FS_TYPE", props.type);
		free(props.type);
       	}
	if (props.uuid != 0) {
               	udev_builtin_add_property(dev, test, "ID_FS_UUID", props.uuid);
		free(props.uuid);
	}
	if (props.label != 0) {
               	udev_builtin_add_property(dev, test, "ID_FS_LABEL",
								props.label);
		free(props.label);
	}
	return EXIT_SUCCESS;
}

const struct udev_builtin udev_builtin_blkid = {
        .name = "blkid",
        .cmd = builtin_blkid,
        .help = "filesystem and partition probing",
        .run_once = true,
};


Mode Type Size Ref File
100644 blob 18092 d159169d1050894d3ea3b98e1c965c4058208fe1 COPYING-GPL
100644 blob 26525 d2e31278b0ee6fef16025fe44061062ad9acece4 COPYING-LGPL
100644 blob 6035 c1a2782caf56be5ae9fc1dbafe0568a99edbb78b README
100644 blob 14 2430e121d55dea637b402ee33da9b2b9d2b7553e TODO
100755 blob 10096 e770b37da1d18f6a5f1f255435a538a020467992 make
100644 blob 1340 307eda511fd9f87338d1cb44a7a920beee7e9d79 make.libudev.sh
100644 blob 2995 850cc113476c3d734d6c63ce5e4b690b73a9a31b make.udevd.sh
040000 tree - 1e20d200b76becb71a8bc5bd8d56381c2ed3cd8f rules
040000 tree - 6855eb6c4e5205055b820aae4e3b0e26400707d9 src
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/sylware/mudev

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/sylware/mudev

Clone this repository using git:
git clone git://git.rocketgit.com/user/sylware/mudev

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main