Merge pull request #26785 from keszybz/udev-distcheck

Implement --help/--version in all udev builtins
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2023-03-24 13:38:54 +01:00
committed by GitHub
8 changed files with 306 additions and 230 deletions

View File

@@ -739,6 +739,7 @@
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
</refsect2>

View File

@@ -23,14 +23,20 @@
#include <sys/types.h>
#include <unistd.h>
#include "build.h"
#include "device-nodes.h"
#include "fd-util.h"
#include "log.h"
#include "main-func.h"
#include "memory-util.h"
#include "udev-util.h"
#include "unaligned.h"
#define COMMAND_TIMEOUT_MSEC (30 * 1000)
static bool arg_export = false;
static const char *arg_device = NULL;
static int disk_scsi_inquiry_command(
int fd,
void *buf,
@@ -55,45 +61,39 @@ static int disk_scsi_inquiry_command(
.din_xferp = (uintptr_t) buf,
.timeout = COMMAND_TIMEOUT_MSEC,
};
int ret;
ret = ioctl(fd, SG_IO, &io_v4);
if (ret != 0) {
if (ioctl(fd, SG_IO, &io_v4) != 0) {
if (errno != EINVAL)
return log_debug_errno(errno, "ioctl v4 failed: %m");
/* could be that the driver doesn't do version 4, try version 3 */
if (errno == EINVAL) {
struct sg_io_hdr io_hdr = {
.interface_id = 'S',
.cmdp = (unsigned char*) cdb,
.cmd_len = sizeof (cdb),
.dxferp = buf,
.dxfer_len = buf_len,
.sbp = sense,
.mx_sb_len = sizeof(sense),
.dxfer_direction = SG_DXFER_FROM_DEV,
.timeout = COMMAND_TIMEOUT_MSEC,
};
struct sg_io_hdr io_hdr = {
.interface_id = 'S',
.cmdp = (unsigned char*) cdb,
.cmd_len = sizeof (cdb),
.dxferp = buf,
.dxfer_len = buf_len,
.sbp = sense,
.mx_sb_len = sizeof(sense),
.dxfer_direction = SG_DXFER_FROM_DEV,
.timeout = COMMAND_TIMEOUT_MSEC,
};
ret = ioctl(fd, SG_IO, &io_hdr);
if (ret != 0)
return ret;
if (ioctl(fd, SG_IO, &io_hdr) != 0)
return log_debug_errno(errno, "ioctl v3 failed: %m");
/* even if the ioctl succeeds, we need to check the return value */
if (!(io_hdr.status == 0 &&
io_hdr.host_status == 0 &&
io_hdr.driver_status == 0)) {
errno = EIO;
return -1;
}
} else
return ret;
}
/* even if the ioctl succeeds, we need to check the return value */
if (io_hdr.status != 0 ||
io_hdr.host_status != 0 ||
io_hdr.driver_status != 0)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v3 failed");
/* even if the ioctl succeeds, we need to check the return value */
if (!(io_v4.device_status == 0 &&
io_v4.transport_status == 0 &&
io_v4.driver_status == 0)) {
errno = EIO;
return -1;
} else {
/* even if the ioctl succeeds, we need to check the return value */
if (io_v4.device_status != 0 ||
io_v4.transport_status != 0 ||
io_v4.driver_status != 0)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v4 failed");
}
return 0;
@@ -137,35 +137,30 @@ static int disk_identify_command(
.din_xferp = (uintptr_t) buf,
.timeout = COMMAND_TIMEOUT_MSEC,
};
int ret;
ret = ioctl(fd, SG_IO, &io_v4);
if (ret != 0) {
if (ioctl(fd, SG_IO, &io_v4) != 0) {
if (errno != EINVAL)
return log_debug_errno(errno, "ioctl v4 failed: %m");
/* could be that the driver doesn't do version 4, try version 3 */
if (errno == EINVAL) {
struct sg_io_hdr io_hdr = {
.interface_id = 'S',
.cmdp = (unsigned char*) cdb,
.cmd_len = sizeof (cdb),
.dxferp = buf,
.dxfer_len = buf_len,
.sbp = sense,
.mx_sb_len = sizeof (sense),
.dxfer_direction = SG_DXFER_FROM_DEV,
.timeout = COMMAND_TIMEOUT_MSEC,
};
struct sg_io_hdr io_hdr = {
.interface_id = 'S',
.cmdp = (unsigned char*) cdb,
.cmd_len = sizeof (cdb),
.dxferp = buf,
.dxfer_len = buf_len,
.sbp = sense,
.mx_sb_len = sizeof (sense),
.dxfer_direction = SG_DXFER_FROM_DEV,
.timeout = COMMAND_TIMEOUT_MSEC,
};
ret = ioctl(fd, SG_IO, &io_hdr);
if (ret != 0)
return ret;
} else
return ret;
}
if (!((sense[0] & 0x7f) == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c) &&
!((sense[0] & 0x7f) == 0x70 && sense[12] == 0x00 && sense[13] == 0x1d)) {
errno = EIO;
return -1;
if (ioctl(fd, SG_IO, &io_hdr) != 0)
return log_debug_errno(errno, "ioctl v3 failed: %m");
} else {
if (!((sense[0] & 0x7f) == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c) &&
!((sense[0] & 0x7f) == 0x70 && sense[12] == 0x00 && sense[13] == 0x1d))
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v4 failed: %m");
}
return 0;
@@ -215,34 +210,29 @@ static int disk_identify_packet_device_command(
.din_xferp = (uintptr_t) buf,
.timeout = COMMAND_TIMEOUT_MSEC,
};
int ret;
ret = ioctl(fd, SG_IO, &io_v4);
if (ret != 0) {
if (ioctl(fd, SG_IO, &io_v4) != 0) {
if (errno != EINVAL)
return log_debug_errno(errno, "ioctl v4 failed: %m");
/* could be that the driver doesn't do version 4, try version 3 */
if (errno == EINVAL) {
struct sg_io_hdr io_hdr = {
.interface_id = 'S',
.cmdp = (unsigned char*) cdb,
.cmd_len = sizeof (cdb),
.dxferp = buf,
.dxfer_len = buf_len,
.sbp = sense,
.mx_sb_len = sizeof (sense),
.dxfer_direction = SG_DXFER_FROM_DEV,
.timeout = COMMAND_TIMEOUT_MSEC,
};
struct sg_io_hdr io_hdr = {
.interface_id = 'S',
.cmdp = (unsigned char*) cdb,
.cmd_len = sizeof (cdb),
.dxferp = buf,
.dxfer_len = buf_len,
.sbp = sense,
.mx_sb_len = sizeof (sense),
.dxfer_direction = SG_DXFER_FROM_DEV,
.timeout = COMMAND_TIMEOUT_MSEC,
};
ret = ioctl(fd, SG_IO, &io_hdr);
if (ret != 0)
return ret;
} else
return ret;
}
if (!((sense[0] & 0x7f) == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) {
errno = EIO;
return -1;
if (ioctl(fd, SG_IO, &io_hdr) != 0)
return log_debug_errno(errno, "ioctl v3 failed: %m");
} else {
if ((sense[0] & 0x7f) != 0x72 || desc[0] != 0x9 || desc[1] != 0x0c)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v4 failed: %m");
}
return 0;
@@ -282,26 +272,25 @@ static void disk_identify_fixup_string(
uint8_t identify[512],
unsigned offset_words,
size_t len) {
assert(offset_words < 512/2);
disk_identify_get_string(identify, offset_words,
(char *) identify + offset_words * 2, len);
}
static void disk_identify_fixup_uint16 (uint8_t identify[512], unsigned offset_words) {
uint16_t *p;
p = (uint16_t *) identify;
p[offset_words] = le16toh (p[offset_words]);
static void disk_identify_fixup_uint16(uint8_t identify[512], unsigned offset_words) {
assert(offset_words < 512/2);
unaligned_write_ne16(identify + offset_words * 2,
unaligned_read_le16(identify + offset_words * 2));
}
/**
* disk_identify:
* @fd: File descriptor for the block device.
* @out_identify: Return location for IDENTIFY data.
* @out_is_packet_device: Return location for whether returned data is from an IDENTIFY PACKET DEVICE.
*
* Sends the IDENTIFY DEVICE or IDENTIFY PACKET DEVICE command to the
* device represented by @fd. If successful, then the result will be
* copied into @out_identify and @out_is_packet_device.
* copied into @out_identify.
*
* This routine is based on code from libatasmart, LGPL v2.1.
*
@@ -309,14 +298,9 @@ static void disk_identify_fixup_uint16 (uint8_t identify[512], unsigned offset_w
* non-zero with errno set.
*/
static int disk_identify(int fd,
uint8_t out_identify[512],
int *out_is_packet_device) {
int ret;
uint8_t out_identify[512]) {
uint8_t inquiry_buf[36];
int peripheral_device_type;
int all_nul_bytes;
int n;
int is_packet_device = 0;
int peripheral_device_type, r;
/* init results */
memzero(out_identify, 512);
@@ -342,110 +326,103 @@ static int disk_identify(int fd,
* the original bug-fix and see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635
* for the original bug-report.)
*/
ret = disk_scsi_inquiry_command (fd, inquiry_buf, sizeof (inquiry_buf));
if (ret != 0)
goto out;
r = disk_scsi_inquiry_command(fd, inquiry_buf, sizeof inquiry_buf);
if (r < 0)
return r;
/* SPC-4, section 6.4.2: Standard INQUIRY data */
peripheral_device_type = inquiry_buf[0] & 0x1f;
if (peripheral_device_type == 0x05)
{
is_packet_device = 1;
ret = disk_identify_packet_device_command(fd, out_identify, 512);
goto check_nul_bytes;
}
if (!IN_SET(peripheral_device_type, 0x00, 0x14)) {
ret = -1;
errno = EIO;
goto out;
if (peripheral_device_type == 0x05) {
r = disk_identify_packet_device_command(fd, out_identify, 512);
if (r < 0)
return r;
} else {
if (!IN_SET(peripheral_device_type, 0x00, 0x14))
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Unsupported device type.");
/* OK, now issue the IDENTIFY DEVICE command */
r = disk_identify_command(fd, out_identify, 512);
if (r < 0)
return r;
}
/* OK, now issue the IDENTIFY DEVICE command */
ret = disk_identify_command(fd, out_identify, 512);
if (ret != 0)
goto out;
check_nul_bytes:
/* Check if IDENTIFY data is all NUL bytes - if so, bail */
all_nul_bytes = 1;
for (n = 0; n < 512; n++) {
bool all_nul_bytes = true;
for (size_t n = 0; n < 512; n++)
if (out_identify[n] != '\0') {
all_nul_bytes = 0;
all_nul_bytes = false;
break;
}
}
if (all_nul_bytes) {
ret = -1;
errno = EIO;
goto out;
}
if (all_nul_bytes)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "IDENTIFY data is all zeroes.");
out:
if (out_is_packet_device)
*out_is_packet_device = is_packet_device;
return ret;
return 0;
}
int main(int argc, char *argv[]) {
static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "export", no_argument, NULL, 'x' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{}
};
int c;
while ((c = getopt_long(argc, argv, "xh", options, NULL)) >= 0)
switch (c) {
case 'x':
arg_export = true;
break;
case 'h':
printf("%s [OPTIONS...] DEVICE\n\n"
" -x --export Print values as environment keys\n"
" -h --help Show this help text\n"
" --version Show package version\n",
program_invocation_short_name);
return 0;
case 'v':
return version();
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (!argv[optind])
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"DEVICE argument missing.");
arg_device = argv[optind];
return 1;
}
static int run(int argc, char *argv[]) {
struct hd_driveid id;
union {
uint8_t byte[512];
uint16_t wyde[256];
} identify;
char model[41];
char model_enc[256];
char serial[21];
char revision[9];
const char *node = NULL;
int export = 0;
char model[41], model_enc[256], serial[21], revision[9];
_cleanup_close_ int fd = -EBADF;
uint16_t word;
int is_packet_device = 0;
static const struct option options[] = {
{ "export", no_argument, NULL, 'x' },
{ "help", no_argument, NULL, 'h' },
{}
};
int r;
log_set_target(LOG_TARGET_AUTO);
udev_parse_config();
log_parse_environment();
log_open();
for (;;) {
int option;
r = parse_argv(argc, argv);
if (r <= 0)
return r;
option = getopt_long(argc, argv, "xh", options, NULL);
if (option == -1)
break;
fd = open(ASSERT_PTR(arg_device), O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Cannot open %s: %m", arg_device);
switch (option) {
case 'x':
export = 1;
break;
case 'h':
printf("Usage: %s [--export] [--help] <device>\n"
" -x,--export print values as environment keys\n"
" -h,--help print this help text\n\n",
program_invocation_short_name);
return 0;
}
}
node = argv[optind];
if (!node) {
log_error("no node specified");
return 1;
}
fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
if (fd < 0) {
log_error("unable to open '%s'", node);
return 1;
}
if (disk_identify(fd, identify.byte, &is_packet_device) == 0) {
if (disk_identify(fd, identify.byte) >= 0) {
/*
* fix up only the fields from the IDENTIFY data that we are going to
* use and copy it into the hd_driveid struct for convenience
@@ -475,10 +452,8 @@ int main(int argc, char *argv[]) {
memcpy(&id, identify.byte, sizeof id);
} else {
/* If this fails, then try HDIO_GET_IDENTITY */
if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) {
log_debug_errno(errno, "HDIO_GET_IDENTITY failed for '%s': %m", node);
return 2;
}
if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0)
return log_debug_errno(errno, "%s: HDIO_GET_IDENTITY failed: %m", arg_device);
}
memcpy(model, id.model, 40);
@@ -491,7 +466,7 @@ int main(int argc, char *argv[]) {
udev_replace_whitespace((char *) id.fw_rev, revision, 8);
udev_replace_chars(revision, NULL);
if (export) {
if (arg_export) {
/* Set this to convey the disk speaks the ATA protocol */
printf("ID_ATA=1\n");
@@ -649,3 +624,5 @@ int main(int argc, char *argv[]) {
return 0;
}
DEFINE_MAIN_FUNCTION(run);

View File

@@ -10,6 +10,7 @@
#include <sys/ioctl.h>
#include <unistd.h>
#include "build.h"
#include "fd-util.h"
#include "main-func.h"
#include "memory-util.h"
@@ -897,13 +898,13 @@ static void print_properties(const Context *c) {
}
static int help(void) {
printf("Usage: %s [options] <device>\n"
" -l --lock-media lock the media (to enable eject request events)\n"
" -u --unlock-media unlock the media\n"
" -e --eject-media eject the media\n"
" -d --debug print debug messages to stderr\n"
" -h --help print this help text\n"
"\n",
printf("%s [OPTIONS...] DEVICE\n\n"
" -l --lock-media Lock the media (to enable eject request events)\n"
" -u --unlock-media Unlock the media\n"
" -e --eject-media Eject the media\n"
" -d --debug Print debug messages to stderr\n"
" -h --help Show this help text\n"
" --version Show package version\n",
program_invocation_short_name);
return 0;
@@ -916,6 +917,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "eject-media", no_argument, NULL, 'e' },
{ "debug", no_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{}
};
int c;
@@ -938,6 +940,10 @@ static int parse_argv(int argc, char *argv[]) {
break;
case 'h':
return help();
case 'v':
return version();
case '?':
return -EINVAL;
default:
assert_not_reached();
}

View File

@@ -45,6 +45,7 @@
#include <getopt.h>
#include "alloc-util.h"
#include "build.h"
#include "fileio.h"
#include "main-func.h"
#include "string-util.h"
@@ -638,9 +639,10 @@ static int legacy_decode(const uint8_t *buf, const char *devmem, bool no_file_of
}
static int help(void) {
printf("Usage: %s [options]\n"
" -F,--from-dump FILE read DMI information from a binary file\n"
" -h,--help print this help text\n\n",
printf("%s [OPTIONS...]\n\n"
" -F --from-dump FILE Read DMI information from a binary file\n"
" -h --help Show this help text\n"
" --version Show package version\n",
program_invocation_short_name);
return 0;
}
@@ -650,6 +652,7 @@ static int parse_argv(int argc, char * const *argv) {
{ "from-dump", required_argument, NULL, 'F' },
{ "version", no_argument, NULL, 'V' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{}
};
int c;
@@ -666,6 +669,8 @@ static int parse_argv(int argc, char * const *argv) {
return help();
case '?':
return -EINVAL;
case 'v':
return version();
default:
assert_not_reached();
}

View File

@@ -8,12 +8,14 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/hid.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "build.h"
#include "device-private.h"
#include "device-util.h"
#include "fd-util.h"
@@ -25,16 +27,47 @@
#include "string-util.h"
#include "udev-util.h"
static const char *arg_device = NULL;
static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{}
};
int c;
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
switch (c) {
case 'h':
printf("%s [OPTIONS...] SYSFS_PATH\n\n"
" -h --help Show this help text\n"
" --version Show package version\n",
program_invocation_short_name);
return 0;
case 'v':
return version();
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (argc > 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error: unexpected argument.");
arg_device = argv[optind];
return 1;
}
static int run(int argc, char **argv) {
_cleanup_(sd_device_unrefp) struct sd_device *device = NULL;
_cleanup_free_ char *desc_path = NULL;
_cleanup_close_ int fd = -EBADF;
struct sd_device *hid_device;
const char *sys_path;
uint8_t desc[HID_MAX_DESCRIPTOR_SIZE];
ssize_t desc_len;
int r;
log_set_target(LOG_TARGET_AUTO);
@@ -42,17 +75,18 @@ static int run(int argc, char **argv) {
log_parse_environment();
log_open();
if (argc > 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Usage: %s [SYSFS_PATH]", program_invocation_short_name);
r = parse_argv(argc, argv);
if (r <= 0)
return r;
if (argc == 1) {
if (arg_device) {
r = sd_device_new_from_syspath(&device, arg_device);
if (r < 0)
return log_error_errno(r, "Failed to get device from syspath %s: %m", arg_device);
} else {
r = device_new_from_strv(&device, environ);
if (r < 0)
return log_error_errno(r, "Failed to get current device from environment: %m");
} else {
r = sd_device_new_from_syspath(&device, argv[1]);
if (r < 0)
return log_error_errno(r, "Failed to get device from syspath: %m");
}
r = sd_device_get_parent(device, &hid_device);

View File

@@ -143,6 +143,7 @@ foreach prog : udev_progs
install_dir : udevlibexecdir)
udev_prog_paths += {name : exe}
public_programs += exe
endforeach
if install_sysconfdir_samples

View File

@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <mtd/mtd-user.h>
#include <stdio.h>
#include <stdlib.h>
@@ -29,31 +30,61 @@
#include <unistd.h>
#include "alloc-util.h"
#include "build.h"
#include "fd-util.h"
#include "main-func.h"
#include "mtd_probe.h"
int main(int argc, char** argv) {
static const char *arg_device = NULL;
static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{}
};
int c;
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
switch (c) {
case 'h':
printf("%s /dev/mtd[n]\n\n"
" -h --help Show this help text\n"
" --version Show package version\n",
program_invocation_short_name);
return 0;
case 'v':
return version();
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (argc > 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error: unexpected argument.");
arg_device = argv[optind];
return 1;
}
static int run(int argc, char** argv) {
_cleanup_close_ int mtd_fd = -EBADF;
mtd_info_t mtd_info;
int r;
if (argc != 2) {
printf("usage: mtd_probe /dev/mtd[n]\n");
return EXIT_FAILURE;
}
r = parse_argv(argc, argv);
if (r <= 0)
return r;
mtd_fd = open(argv[1], O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (mtd_fd < 0) {
log_error_errno(errno, "Failed to open: %m");
return EXIT_FAILURE;
}
if (mtd_fd < 0)
return log_error_errno(errno, "Failed to open: %m");
if (ioctl(mtd_fd, MEMGETINFO, &mtd_info) < 0) {
log_error_errno(errno, "Failed to issue MEMGETINFO ioctl: %m");
return EXIT_FAILURE;
}
if (ioctl(mtd_fd, MEMGETINFO, &mtd_info) < 0)
return log_error_errno(errno, "MEMGETINFO ioctl failed: %m");
if (probe_smart_media(mtd_fd, &mtd_info) < 0)
return EXIT_FAILURE;
return EXIT_SUCCESS;
return probe_smart_media(mtd_fd, &mtd_info);
}
DEFINE_MAIN_FUNCTION(run);

View File

@@ -26,51 +26,70 @@
#include <unistd.h>
#include <linux/videodev2.h>
#include "build.h"
#include "fd-util.h"
#include "main-func.h"
int main(int argc, char *argv[]) {
static const char *arg_device = NULL;
static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{}
};
_cleanup_close_ int fd = -EBADF;
char *device;
struct v4l2_capability v2cap;
int c;
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
switch (c) {
case 'h':
printf("%s [-h,--help] <device file>\n\n"
printf("%s [OPTIONS...] DEVICE\n\n"
"Video4Linux device identification.\n\n"
" -h Print this message\n",
" -h --help Show this help text\n"
" --version Show package version\n",
program_invocation_short_name);
return 0;
case 'v':
return version();
case '?':
return -EINVAL;
default:
assert_not_reached();
}
device = argv[optind];
if (!device)
return 2;
if (!argv[optind])
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"DEVICE argument missing.");
fd = open(device, O_RDONLY);
arg_device = argv[optind];
return 1;
}
static int run(int argc, char *argv[]) {
_cleanup_close_ int fd = -EBADF;
struct v4l2_capability v2cap;
int r;
r = parse_argv(argc, argv);
if (r <= 0)
return r;
fd = open(arg_device, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return 3;
return log_error_errno(errno, "Failed to open %s: %m", arg_device);
if (ioctl(fd, VIDIOC_QUERYCAP, &v2cap) == 0) {
int capabilities;
printf("ID_V4L_VERSION=2\n");
printf("ID_V4L_PRODUCT=%s\n", v2cap.card);
printf("ID_V4L_CAPABILITIES=:");
if (v2cap.capabilities & V4L2_CAP_DEVICE_CAPS)
capabilities = v2cap.device_caps;
else
capabilities = v2cap.capabilities;
if ((capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0 ||
(capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) > 0)
printf("capture:");
@@ -90,3 +109,5 @@ int main(int argc, char *argv[]) {
return 0;
}
DEFINE_MAIN_FUNCTION(run);