New upstream version 1.90.7+git1

This commit is contained in:
Marco Trevisan (Treviño)
2021-01-21 19:13:37 +01:00
37 changed files with 2154 additions and 536 deletions
+9
View File
@@ -109,6 +109,15 @@ test_indent:
- git diff - git diff
- "! git status -s | grep -q ." - "! git status -s | grep -q ."
test_unsupported_list:
stage: check-source
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
allow_failure: true
script:
- tests/hwdb-check-unsupported.py
flatpak: flatpak:
stage: flatpak stage: flatpak
extends: .flatpak extends: .flatpak
+263
View File
@@ -0,0 +1,263 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# This file has been generated using fprint-list-udev-hwdb with all drivers enabled
# Supported by libfprint driver aes1610
usb:v08FFp1600*
ID_AUTOSUSPEND=1
# Supported by libfprint driver aes1660
usb:v08FFp1660*
usb:v08FFp1680*
usb:v08FFp1681*
usb:v08FFp1682*
usb:v08FFp1683*
usb:v08FFp1684*
usb:v08FFp1685*
usb:v08FFp1686*
usb:v08FFp1687*
usb:v08FFp1688*
usb:v08FFp1689*
usb:v08FFp168A*
usb:v08FFp168B*
usb:v08FFp168C*
usb:v08FFp168D*
usb:v08FFp168E*
usb:v08FFp168F*
ID_AUTOSUSPEND=1
# Supported by libfprint driver aes2501
usb:v08FFp2500*
usb:v08FFp2580*
ID_AUTOSUSPEND=1
# Supported by libfprint driver aes2550
usb:v08FFp2550*
usb:v08FFp2810*
ID_AUTOSUSPEND=1
# Supported by libfprint driver aes2660
usb:v08FFp2660*
usb:v08FFp2680*
usb:v08FFp2681*
usb:v08FFp2682*
usb:v08FFp2683*
usb:v08FFp2684*
usb:v08FFp2685*
usb:v08FFp2686*
usb:v08FFp2687*
usb:v08FFp2688*
usb:v08FFp2689*
usb:v08FFp268A*
usb:v08FFp268B*
usb:v08FFp268C*
usb:v08FFp268D*
usb:v08FFp268E*
usb:v08FFp268F*
usb:v08FFp2691*
ID_AUTOSUSPEND=1
# Supported by libfprint driver aes3500
usb:v08FFp5731*
ID_AUTOSUSPEND=1
# Supported by libfprint driver aes4000
usb:v5501p08FF*
ID_AUTOSUSPEND=1
# Supported by libfprint driver elan
usb:v04F3p0903*
usb:v04F3p0907*
usb:v04F3p0C01*
usb:v04F3p0C02*
usb:v04F3p0C03*
usb:v04F3p0C04*
usb:v04F3p0C05*
usb:v04F3p0C06*
usb:v04F3p0C07*
usb:v04F3p0C08*
usb:v04F3p0C09*
usb:v04F3p0C0A*
usb:v04F3p0C0B*
usb:v04F3p0C0C*
usb:v04F3p0C0D*
usb:v04F3p0C0E*
usb:v04F3p0C0F*
usb:v04F3p0C10*
usb:v04F3p0C11*
usb:v04F3p0C12*
usb:v04F3p0C13*
usb:v04F3p0C14*
usb:v04F3p0C15*
usb:v04F3p0C16*
usb:v04F3p0C17*
usb:v04F3p0C18*
usb:v04F3p0C19*
usb:v04F3p0C1A*
usb:v04F3p0C1B*
usb:v04F3p0C1C*
usb:v04F3p0C1D*
usb:v04F3p0C1E*
usb:v04F3p0C1F*
usb:v04F3p0C20*
usb:v04F3p0C21*
usb:v04F3p0C22*
usb:v04F3p0C23*
usb:v04F3p0C24*
usb:v04F3p0C25*
usb:v04F3p0C26*
usb:v04F3p0C27*
usb:v04F3p0C28*
usb:v04F3p0C29*
usb:v04F3p0C2A*
usb:v04F3p0C2B*
usb:v04F3p0C2C*
usb:v04F3p0C2D*
usb:v04F3p0C2E*
usb:v04F3p0C2F*
usb:v04F3p0C30*
usb:v04F3p0C31*
usb:v04F3p0C32*
usb:v04F3p0C33*
usb:v04F3p0C42*
usb:v04F3p0C4D*
ID_AUTOSUSPEND=1
# Supported by libfprint driver etes603
usb:v1C7Ap0603*
ID_AUTOSUSPEND=1
# Supported by libfprint driver goodixmoc
usb:v27C6p5840*
usb:v27C6p6496*
usb:v27C6p60A2*
usb:v27C6p63AC*
usb:v27C6p639C*
ID_AUTOSUSPEND=1
# Supported by libfprint driver synaptics
usb:v06CBp00BD*
usb:v06CBp00E9*
usb:v06CBp00DF*
usb:v06CBp00F9*
usb:v06CBp00FC*
usb:v06CBp00C2*
usb:v06CBp00C9*
usb:v06CBp00E7*
ID_AUTOSUSPEND=1
# Supported by libfprint driver upeksonly
usb:v147Ep2016*
usb:v147Ep1000*
usb:v147Ep1001*
ID_AUTOSUSPEND=1
# Supported by libfprint driver upektc
usb:v0483p2015*
usb:v147Ep3001*
ID_AUTOSUSPEND=1
# Supported by libfprint driver upektc_img
usb:v147Ep2020*
ID_AUTOSUSPEND=1
# Supported by libfprint driver uru4000
usb:v045Ep00BC*
usb:v045Ep00BD*
usb:v045Ep00CA*
usb:v05BAp0007*
usb:v05BAp0008*
usb:v05BAp000A*
ID_AUTOSUSPEND=1
# Supported by libfprint driver vcom5s
usb:v061Ap0110*
ID_AUTOSUSPEND=1
# Supported by libfprint driver vfs0050
usb:v138Ap0050*
ID_AUTOSUSPEND=1
# Supported by libfprint driver vfs101
usb:v138Ap0001*
ID_AUTOSUSPEND=1
# Supported by libfprint driver vfs301
usb:v138Ap0005*
usb:v138Ap0008*
ID_AUTOSUSPEND=1
# Supported by libfprint driver vfs5011
usb:v138Ap0010*
usb:v138Ap0011*
usb:v138Ap0015*
usb:v138Ap0017*
usb:v138Ap0018*
ID_AUTOSUSPEND=1
# Known unsupported devices
usb:v04F3p036B*
usb:v04F3p0C00*
usb:v04F3p0C4B*
usb:v04F3p0C4C*
usb:v04F3p0C4F*
usb:v04F3p0C57*
usb:v04F3p2706*
usb:v06CBp0081*
usb:v06CBp0088*
usb:v06CBp008A*
usb:v06CBp009A*
usb:v06CBp009B*
usb:v06CBp00A2*
usb:v06CBp00B7*
usb:v06CBp00BB*
usb:v06CBp00BE*
usb:v06CBp00CB*
usb:v06CBp00D8*
usb:v06CBp00DA*
usb:v0A5Cp5801*
usb:v0A5Cp5805*
usb:v0A5Cp5834*
usb:v0A5Cp5843*
usb:v10A5p0007*
usb:v1188p9545*
usb:v138Ap0007*
usb:v138Ap003A*
usb:v138Ap003C*
usb:v138Ap003D*
usb:v138Ap003F*
usb:v138Ap0090*
usb:v138Ap0091*
usb:v138Ap0092*
usb:v138Ap0094*
usb:v138Ap0097*
usb:v138Ap009D*
usb:v138Ap00AB*
usb:v147Ep1002*
usb:v1491p0088*
usb:v16D1p1027*
usb:v1C7Ap0300*
usb:v1C7Ap0570*
usb:v1C7Ap0575*
usb:v27C6p5042*
usb:v27C6p5110*
usb:v27C6p5117*
usb:v27C6p5201*
usb:v27C6p521D*
usb:v27C6p5301*
usb:v27C6p530C*
usb:v27C6p532D*
usb:v27C6p533C*
usb:v27C6p5381*
usb:v27C6p5385*
usb:v27C6p538C*
usb:v27C6p538D*
usb:v27C6p5395*
usb:v27C6p5584*
usb:v27C6p55A2*
usb:v27C6p55A4*
usb:v27C6p55B4*
usb:v27C6p5740*
usb:v2808p9338*
usb:v298Dp2033*
usb:v3538p0930*
ID_AUTOSUSPEND=1
+9
View File
@@ -0,0 +1,9 @@
if get_option('udev_rules')
# This file has to be updated using
# ninja -C <builddir> libfprint/sync-udev-hwdb
install_data('autosuspend.hwdb',
rename: '60-autosuspend-@0@.hwdb'.format(versioned_libname),
install_dir: udev_hwdb_dir,
)
endif
+2
View File
@@ -22,6 +22,8 @@
#define AES1660_FRAME_SIZE 0x244 #define AES1660_FRAME_SIZE 0x244
/* *INDENT-OFF* */
/* First init sequence, 0x07 cmd returns following before INIT1: /* First init sequence, 0x07 cmd returns following before INIT1:
* { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 } * { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 }
*/ */
+2
View File
@@ -21,6 +21,8 @@
#define AES2660_FRAME_SIZE 0x354 #define AES2660_FRAME_SIZE 0x354
/* *INDENT-OFF* */
/* First init sequence, 0x07 cmd returns following before INIT1: /* First init sequence, 0x07 cmd returns following before INIT1:
* { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 } * { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 }
*/ */
+1 -1
View File
@@ -127,7 +127,7 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
} }
gx_proto_crc32_calc (transfer->buffer, PACKAGE_HEADER_SIZE + header.len, (uint8_t *) &crc32_calc); gx_proto_crc32_calc (transfer->buffer, PACKAGE_HEADER_SIZE + header.len, (uint8_t *) &crc32_calc);
if(crc32_calc != *(uint32_t *) (transfer->buffer + PACKAGE_HEADER_SIZE + header.len)) if(crc32_calc != GUINT32_FROM_LE (*(uint32_t *) (transfer->buffer + PACKAGE_HEADER_SIZE + header.len)))
{ {
fpi_ssm_mark_failed (transfer->ssm, fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
+54 -29
View File
@@ -141,8 +141,11 @@ crc32_update (gf_crc32_context *ctx, const uint8_t *message, uint32_t n_bytes)
static void static void
crc32_final (gf_crc32_context *ctx, uint8_t *md) crc32_final (gf_crc32_context *ctx, uint8_t *md)
{ {
uint32_t crc = 0;
ctx->crc = (REFLECT_REMAINDER (ctx->crc) ^ FINAL_XOR_VALUE); ctx->crc = (REFLECT_REMAINDER (ctx->crc) ^ FINAL_XOR_VALUE);
memcpy (md, &ctx->crc, 4); crc = GUINT32_TO_LE (ctx->crc);
memcpy (md, &crc, 4);
} }
uint8_t uint8_t
@@ -184,7 +187,7 @@ init_pack_header (
pheader->cmd1 = LOBYTE (cmd); pheader->cmd1 = LOBYTE (cmd);
pheader->packagenum = packagenum; pheader->packagenum = packagenum;
pheader->reserved = dump_seq++; pheader->reserved = dump_seq++;
pheader->len = len + PACKAGE_CRC_SIZE; pheader->len = GUINT16_TO_LE (len + PACKAGE_CRC_SIZE);
pheader->crc8 = gx_proto_crc8_calc ((uint8_t *) pheader, 6); pheader->crc8 = gx_proto_crc8_calc ((uint8_t *) pheader, 6);
pheader->rev_crc8 = ~pheader->crc8; pheader->rev_crc8 = ~pheader->crc8;
} }
@@ -224,14 +227,14 @@ gx_proto_parse_header (
{ {
if (!buffer || !pheader) if (!buffer || !pheader)
return -1; return -1;
if (buffer_len < PACKAGE_HEADER_SIZE) if (buffer_len < PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE)
return -1; return -1;
memcpy (pheader, buffer, sizeof (pack_header)); memcpy (pheader, buffer, sizeof (pack_header));
pheader->len = GUINT16_FROM_LE (pheader->len);
pheader->len = GUINT16_FROM_LE ( *(uint16_t *) (buffer + 4)); if (buffer_len < pheader->len + PACKAGE_HEADER_SIZE)
return -1;
pheader->len -= PACKAGE_CRC_SIZE; pheader->len -= PACKAGE_CRC_SIZE;
return 0; return 0;
} }
@@ -248,7 +251,7 @@ gx_proto_parse_fingerid (
if (!template || !fid_buffer) if (!template || !fid_buffer)
return -1; return -1;
if (fid_buffer_size < 70) if (fid_buffer_size < G_STRUCT_OFFSET (template_format_t, payload) + sizeof (uint32_t))
return -1; return -1;
buffer = fid_buffer; buffer = fid_buffer;
@@ -256,28 +259,30 @@ gx_proto_parse_fingerid (
if (buffer[Offset++] != 67) if (buffer[Offset++] != 67)
return -1; return -1;
fid_buffer_size--;
template->type = buffer[Offset++]; template->type = buffer[Offset++];
fid_buffer_size--;
template->finger_index = buffer[Offset++]; template->finger_index = buffer[Offset++];
fid_buffer_size--;
Offset++; Offset++;
memcpy (template->accountid, &buffer[Offset], sizeof (template->accountid));
memcpy (template->accountid, &buffer[Offset], 32); Offset += sizeof (template->accountid);
Offset += 32; memcpy (template->tid, &buffer[Offset], sizeof (template->tid));
Offset += sizeof (template->tid); // Offset == 68
memcpy (template->tid, &buffer[Offset], 32);
Offset += 32; // Offset == 68
template->payload.size = buffer[Offset++]; template->payload.size = buffer[Offset++];
memset (template->payload.data, 0, 56); if (template->payload.size > sizeof (template->payload.data))
return -1;
memset (template->payload.data, 0, template->payload.size);
memcpy (template->payload.data, &buffer[Offset], template->payload.size); memcpy (template->payload.data, &buffer[Offset], template->payload.size);
return 0; return 0;
} }
int int
gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_cmd_response_t presp) gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_cmd_response_t presp)
{ {
uint32_t offset = 0; uint16_t offset = 0;
uint8_t *fingerlist = NULL; uint8_t *fingerlist = NULL;
if (!buffer || !presp) if (!buffer || !presp)
@@ -289,6 +294,8 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c
{ {
case RESPONSE_PACKAGE_CMD: case RESPONSE_PACKAGE_CMD:
{ {
if (buffer_len < sizeof (gxfp_parse_msg_t) + 1)
return -1;
presp->parse_msg.ack_cmd = buffer[1]; presp->parse_msg.ack_cmd = buffer[1];
} }
break; break;
@@ -296,32 +303,46 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c
case MOC_CMD0_UPDATE_CONFIG: case MOC_CMD0_UPDATE_CONFIG:
{ {
presp->finger_config.status = buffer[0]; presp->finger_config.status = buffer[0];
if (buffer_len >= 3)
presp->finger_config.max_stored_prints = buffer[2]; presp->finger_config.max_stored_prints = buffer[2];
else
/* to compatiable old version firmware */
presp->finger_config.max_stored_prints = FP_MAX_FINGERNUM;
} }
break; break;
case MOC_CMD0_COMMITENROLLMENT: case MOC_CMD0_COMMITENROLLMENT:
case MOC_CMD0_DELETETEMPLATE: case MOC_CMD0_DELETETEMPLATE:
/* just check result */
break; break;
case MOC_CMD0_GET_VERSION: case MOC_CMD0_GET_VERSION:
if (buffer_len < sizeof (gxfp_version_info_t) + 1)
return -1;
memcpy (&presp->version_info, buffer + 1, sizeof (gxfp_version_info_t)); memcpy (&presp->version_info, buffer + 1, sizeof (gxfp_version_info_t));
break; break;
case MOC_CMD0_CAPTURE_DATA: case MOC_CMD0_CAPTURE_DATA:
if (LOBYTE (cmd) == MOC_CMD1_DEFAULT) if (LOBYTE (cmd) == MOC_CMD1_DEFAULT)
{ {
if (buffer_len < sizeof (gxfp_capturedata_t) + 1)
return -1;
presp->capture_data_resp.img_quality = buffer[1]; presp->capture_data_resp.img_quality = buffer[1];
presp->capture_data_resp.img_coverage = buffer[2]; presp->capture_data_resp.img_coverage = buffer[2];
} }
break; break;
case MOC_CMD0_ENROLL_INIT: case MOC_CMD0_ENROLL_INIT:
if (buffer_len < sizeof (gxfp_enroll_init_t) + 1)
return -1;
if (presp->result == GX_SUCCESS) if (presp->result == GX_SUCCESS)
memcpy (&presp->enroll_init.tid, &buffer[1], TEMPLATE_ID_SIZE); memcpy (&presp->enroll_init.tid, &buffer[1], TEMPLATE_ID_SIZE);
break; break;
case MOC_CMD0_ENROLL: case MOC_CMD0_ENROLL:
if (buffer_len < sizeof (gxfp_enroll_update_t))
return -1;
presp->enroll_update.rollback = (buffer[0] < 0x80) ? false : true; presp->enroll_update.rollback = (buffer[0] < 0x80) ? false : true;
presp->enroll_update.img_overlay = buffer[1]; presp->enroll_update.img_overlay = buffer[1];
presp->enroll_update.img_preoverlay = buffer[2]; presp->enroll_update.img_preoverlay = buffer[2];
@@ -331,7 +352,11 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c
presp->check_duplicate_resp.duplicate = (presp->result == 0) ? false : true; presp->check_duplicate_resp.duplicate = (presp->result == 0) ? false : true;
if (presp->check_duplicate_resp.duplicate) if (presp->check_duplicate_resp.duplicate)
{ {
uint16_t tid_size = GUINT16_FROM_LE (*(buffer + 1)); if (buffer_len < 3)
return -1;
uint16_t tid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + 1));
if ((buffer_len < tid_size + 3) || (buffer_len > sizeof (template_format_t)) + 3)
return -1;
memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size); memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size);
} }
break; break;
@@ -339,18 +364,16 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c
case MOC_CMD0_GETFINGERLIST: case MOC_CMD0_GETFINGERLIST:
if (presp->result != GX_SUCCESS) if (presp->result != GX_SUCCESS)
break; break;
if (buffer_len < 2)
return -1;
presp->finger_list_resp.finger_num = buffer[1]; presp->finger_list_resp.finger_num = buffer[1];
if (presp->finger_list_resp.finger_num > FP_MAX_FINGERNUM)
{
presp->finger_list_resp.finger_num = 0;
presp->result = GX_ERROR_NO_AVAILABLE_SPACE;
break;
}
fingerlist = buffer + 2; fingerlist = buffer + 2;
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++) for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
{ {
uint16_t fingerid_length = GUINT16_FROM_LE (*(fingerlist + offset)); uint16_t fingerid_length = GUINT16_FROM_LE (*(uint16_t *) (fingerlist + offset));
offset += 2; offset += 2;
if (buffer_len < fingerid_length + offset + 2)
return -1;
if (gx_proto_parse_fingerid (fingerlist + offset, if (gx_proto_parse_fingerid (fingerlist + offset,
fingerid_length, fingerid_length,
&presp->finger_list_resp.finger_list[num]) != 0) &presp->finger_list_resp.finger_list[num]) != 0)
@@ -372,14 +395,16 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c
presp->verify.match = (buffer[0] == 0) ? true : false; presp->verify.match = (buffer[0] == 0) ? true : false;
if (presp->verify.match) if (presp->verify.match)
{ {
if (buffer_len < sizeof (template_format_t) + 10)
return -1;
offset += 1; offset += 1;
presp->verify.rejectdetail = GUINT16_FROM_LE (*(buffer + offset)); presp->verify.rejectdetail = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
offset += 2; offset += 2;
score = GUINT32_FROM_LE (*(buffer + offset)); score = GUINT32_FROM_LE (*(uint32_t *) (buffer + offset));
offset += 4; offset += 4;
study = GUINT16_FROM_LE (*(buffer + offset)); study = buffer[offset];
offset += 1; offset += 1;
fingerid_size = GUINT16_FROM_LE (*(buffer + offset)); fingerid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
offset += 2; offset += 2;
if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0) if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0)
{ {
+2 -2
View File
@@ -89,7 +89,7 @@ typedef struct _gxfp_version_info
uint8_t interface[GX_VERSION_LEN]; uint8_t interface[GX_VERSION_LEN];
uint8_t protocol[GX_VERSION_LEN]; uint8_t protocol[GX_VERSION_LEN];
uint8_t flashVersion[GX_VERSION_LEN]; uint8_t flashVersion[GX_VERSION_LEN];
uint8_t reserved[62]; uint8_t reserved[38];
} gxfp_version_info_t, *pgxfp_version_info_t; } gxfp_version_info_t, *pgxfp_version_info_t;
@@ -225,7 +225,7 @@ int gx_proto_parse_header (uint8_t *buffer,
int gx_proto_parse_body (uint16_t cmd, int gx_proto_parse_body (uint16_t cmd,
uint8_t *buffer, uint8_t *buffer,
uint32_t buffer_len, uint16_t buffer_len,
pgxfp_cmd_response_t presponse); pgxfp_cmd_response_t presponse);
int gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig); int gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig);
+2
View File
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/* *INDENT-OFF* */
#pragma once #pragma once
#define UPEKTC_CMD_LEN 0x40 #define UPEKTC_CMD_LEN 0x40
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/* *INDENT-OFF* */
/* There are many similar blocks in the data below, also the data are /* There are many similar blocks in the data below, also the data are
* self-similar (looks like some config blocks? pokes like in vfs101?) */ * self-similar (looks like some config blocks? pokes like in vfs101?) */
+2
View File
@@ -1,5 +1,7 @@
#pragma once #pragma once
/* *INDENT-OFF* */
#define VFS5011_LINE_SIZE 240 #define VFS5011_LINE_SIZE 240
#define VFS5011_IMAGE_WIDTH 160 #define VFS5011_IMAGE_WIDTH 160
+355
View File
@@ -0,0 +1,355 @@
/*
* Socket utilities for "simple" device debugging
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "virtual_device_connection"
#include "fpi-log.h"
#include <glib/gstdio.h>
#include <gio/gunixsocketaddress.h>
#include "virtual-device-private.h"
struct _FpDeviceVirtualListener
{
GSocketListener parent_instance;
GSocketConnection *connection;
GCancellable *cancellable;
guint cancellable_id;
FpDeviceVirtualListenerConnectionCb ready_cb;
gpointer ready_cb_data;
gint socket_fd;
gint client_fd;
};
G_DEFINE_TYPE (FpDeviceVirtualListener, fp_device_virtual_listener, G_TYPE_SOCKET_LISTENER)
static void start_listen (FpDeviceVirtualListener *self);
FpDeviceVirtualListener *
fp_device_virtual_listener_new (void)
{
return g_object_new (fp_device_virtual_listener_get_type (), NULL);
}
static void
fp_device_virtual_listener_dispose (GObject *object)
{
FpDeviceVirtualListener *self = FP_DEVICE_VIRTUAL_LISTENER (object);
if (self->cancellable_id)
{
g_cancellable_disconnect (self->cancellable, self->cancellable_id);
self->cancellable_id = 0;
}
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
g_clear_object (&self->connection);
self->ready_cb = NULL;
G_OBJECT_CLASS (fp_device_virtual_listener_parent_class)->dispose (object);
}
static void
fp_device_virtual_listener_class_init (FpDeviceVirtualListenerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = fp_device_virtual_listener_dispose;
}
static void
fp_device_virtual_listener_init (FpDeviceVirtualListener *self)
{
}
static void
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
g_autoptr(GError) error = NULL;
FpDeviceVirtualListener *self = user_data;
GSocketConnection *connection;
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
res,
NULL,
&error);
if (!connection)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Error accepting a new connection: %s", error->message);
start_listen (self);
return;
}
/* Always allow further connections.
* If we get a new one, we generally just close the old connection. */
start_listen (self);
if (self->connection)
{
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
}
self->connection = connection;
fp_dbg ("Got a new connection!");
self->ready_cb (self, self->ready_cb_data);
}
static void
start_listen (FpDeviceVirtualListener *self)
{
g_socket_listener_accept_async (G_SOCKET_LISTENER (self),
self->cancellable,
new_connection_cb,
self);
}
static void
on_cancelled (GCancellable *cancellable,
FpDeviceVirtualListener *self)
{
fp_device_virtual_listener_connection_close (self);
g_socket_listener_close (G_SOCKET_LISTENER (self));
g_clear_object (&self->cancellable);
self->ready_cb = NULL;
}
gboolean
fp_device_virtual_listener_start (FpDeviceVirtualListener *self,
const char *address,
GCancellable *cancellable,
FpDeviceVirtualListenerConnectionCb cb,
gpointer user_data,
GError **error)
{
g_autoptr(GSocketAddress) addr = NULL;
G_DEBUG_HERE ();
g_return_val_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
g_return_val_if_fail (cb != NULL, FALSE);
g_return_val_if_fail (self->ready_cb == NULL, FALSE);
self->client_fd = -1;
g_socket_listener_set_backlog (G_SOCKET_LISTENER (self), 1);
/* Remove any left over socket. */
g_unlink (address);
addr = g_unix_socket_address_new (address);
if (!g_socket_listener_add_address (G_SOCKET_LISTENER (self),
addr,
G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_DEFAULT,
NULL,
NULL,
error))
{
g_warning ("Could not listen on unix socket: %s", (*error)->message);
return FALSE;
}
self->ready_cb = cb;
self->ready_cb_data = user_data;
self->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
if (self->cancellable)
self->cancellable_id = g_cancellable_connect (self->cancellable,
G_CALLBACK (on_cancelled), self, NULL);
start_listen (self);
return TRUE;
}
gboolean
fp_device_virtual_listener_connection_close (FpDeviceVirtualListener *self)
{
g_return_val_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
if (!self->connection)
return FALSE;
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
return TRUE;
}
static void
on_stream_read_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr(GError) error = NULL;
g_autoptr(GTask) task = user_data;
FpDeviceVirtualListener *self = g_task_get_source_object (task);
gboolean all;
gboolean success;
gsize bytes;
all = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "all"));
if (all)
{
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
}
else
{
gssize sbytes;
sbytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error);
bytes = sbytes;
success = (sbytes >= 0);
}
if (g_task_return_error_if_cancelled (task))
return;
/* If we are cancelled, just return immediately. */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
{
g_task_return_int (task, 0);
return;
}
/* If this error is for an old connection (that should be closed already),
* then just give up immediately with a CLOSED error.
*/
if (self->connection &&
g_io_stream_get_input_stream (G_IO_STREAM (self->connection)) != G_INPUT_STREAM (source_object))
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_CLOSED,
"Error on old connection, ignoring.");
return;
}
if (!success || bytes == 0)
{
/* We accept it if someone tries to read twice and just return that error. */
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
{
if (self->connection)
{
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
}
}
if (error)
{
g_task_return_error (task, g_steal_pointer (&error));
return;
}
else
{
// g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Got empty data");
return;
}
}
g_task_return_int (task, bytes);
}
void
fp_device_virtual_listener_read (FpDeviceVirtualListener *self,
gboolean all,
void *buffer,
gsize count,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
GInputStream *stream;
g_return_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self));
task = g_task_new (self, self->cancellable, callback, user_data);
g_object_set_data (G_OBJECT (task), "all", GINT_TO_POINTER (all));
if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection)))
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED,
"Listener not connected to any stream");
return;
}
stream = g_io_stream_get_input_stream (G_IO_STREAM (self->connection));
if (all)
{
g_input_stream_read_all_async (stream, buffer, count,
G_PRIORITY_DEFAULT,
self->cancellable,
on_stream_read_cb,
g_steal_pointer (&task));
}
else
{
g_input_stream_read_async (stream, buffer, count,
G_PRIORITY_DEFAULT,
self->cancellable,
on_stream_read_cb,
g_steal_pointer (&task));
}
}
gsize
fp_device_virtual_listener_read_finish (FpDeviceVirtualListener *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, self), 0);
return g_task_propagate_int (G_TASK (result), error);
}
gboolean
fp_device_virtual_listener_write_sync (FpDeviceVirtualListener *self,
const char *buffer,
gsize count,
GError **error)
{
if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection)))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED,
"Listener not connected to any stream");
return FALSE;
}
return g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (self->connection)),
buffer,
count,
NULL,
self->cancellable,
error);
}
@@ -0,0 +1,93 @@
/*
* Virtual driver for "simple" device debugging
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* This is a virtual driver to debug the non-image based drivers. A small
* python script is provided to connect to it via a socket, allowing
* prints to registered programmatically.
* Using this, it is possible to test libfprint and fprintd.
*/
#include <gio/gio.h>
#include "fpi-device.h"
#define MAX_LINE_LEN 1024
G_DECLARE_FINAL_TYPE (FpDeviceVirtualListener, fp_device_virtual_listener, FP, DEVICE_VIRTUAL_LISTENER, GSocketListener)
typedef void (*FpDeviceVirtualListenerConnectionCb) (FpDeviceVirtualListener *listener,
gpointer user_data);
FpDeviceVirtualListener * fp_device_virtual_listener_new (void);
gboolean fp_device_virtual_listener_start (FpDeviceVirtualListener *listener,
const char *address,
GCancellable *cancellable,
FpDeviceVirtualListenerConnectionCb cb,
gpointer user_data,
GError **error);
gboolean fp_device_virtual_listener_connection_close (FpDeviceVirtualListener *listener);
void fp_device_virtual_listener_read (FpDeviceVirtualListener *listener,
gboolean all,
void *buffer,
gsize count,
GAsyncReadyCallback callback,
gpointer user_data);
gsize fp_device_virtual_listener_read_finish (FpDeviceVirtualListener *listener,
GAsyncResult *result,
GError **error);
gboolean fp_device_virtual_listener_write_sync (FpDeviceVirtualListener *self,
const char *buffer,
gsize count,
GError **error);
struct _FpDeviceVirtualDevice
{
FpDevice parent;
FpDeviceVirtualListener *listener;
GCancellable *cancellable;
char recv_buf[MAX_LINE_LEN];
GPtrArray *pending_commands;
GHashTable *prints_storage;
};
/* Not really final here, but we can do this to share the FpDeviceVirtualDevice
* contents without having to use a shared private struct instead. */
G_DECLARE_FINAL_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP, DEVICE_VIRTUAL_DEVICE, FpDevice)
struct _FpDeviceVirtualDeviceStorage
{
FpDeviceVirtualDevice parent;
};
G_DECLARE_FINAL_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, FP, DEVICE_VIRTUAL_DEVICE_STORAGE, FpDeviceVirtualDevice)
char * process_cmds (FpDeviceVirtualDevice * self, gboolean scan, GError **error);
+181
View File
@@ -0,0 +1,181 @@
/*
* Virtual driver for "simple" device debugging with storage
*
* Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* This is a virtual driver to debug the non-image based drivers. A small
* python script is provided to connect to it via a socket, allowing
* prints to registered programmatically.
* Using this, it is possible to test libfprint and fprintd.
*/
#define FP_COMPONENT "virtual_device_storage"
#include "virtual-device-private.h"
#include "fpi-log.h"
G_DEFINE_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, fpi_device_virtual_device_get_type ())
static void
dev_identify (FpDevice *dev)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
GPtrArray *prints;
GError *error = NULL;
g_autofree char *scan_id = NULL;
fpi_device_get_identify_data (dev, &prints);
scan_id = process_cmds (self, TRUE, &error);
if (scan_id)
{
GVariant *data = NULL;
FpPrint *new_scan;
FpPrint *match = NULL;
guint idx;
new_scan = fp_print_new (dev);
fpi_print_set_type (new_scan, FPI_PRINT_RAW);
if (self->prints_storage)
fpi_print_set_device_stored (new_scan, TRUE);
data = g_variant_new_string (scan_id);
g_object_set (new_scan, "fpi-data", data, NULL);
if (g_ptr_array_find_with_equal_func (prints,
new_scan,
(GEqualFunc) fp_print_equal,
&idx))
match = g_ptr_array_index (prints, idx);
fpi_device_identify_report (dev,
match,
new_scan,
NULL);
}
fpi_device_identify_complete (dev, error);
}
struct ListData
{
FpDevice *dev;
GPtrArray *res;
};
static void
dev_list_insert_print (gpointer key,
gpointer value,
gpointer user_data)
{
struct ListData *data = user_data;
FpPrint *print = fp_print_new (data->dev);
GVariant *var = NULL;
fpi_print_fill_from_user_id (print, key);
fpi_print_set_type (print, FPI_PRINT_RAW);
var = g_variant_new_string (key);
g_object_set (print, "fpi-data", var, NULL);
g_object_ref_sink (print);
g_ptr_array_add (data->res, print);
}
static void
dev_list (FpDevice *dev)
{
g_autoptr(GPtrArray) prints_list = NULL;
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
struct ListData data;
process_cmds (vdev, FALSE, NULL);
prints_list = g_ptr_array_new_full (g_hash_table_size (vdev->prints_storage), NULL);
data.dev = dev;
data.res = prints_list;
g_hash_table_foreach (vdev->prints_storage, dev_list_insert_print, &data);
fpi_device_list_complete (dev, g_steal_pointer (&prints_list), NULL);
}
static void
dev_delete (FpDevice *dev)
{
g_autoptr(GVariant) data = NULL;
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
FpPrint *print = NULL;
const char *id = NULL;
process_cmds (vdev, FALSE, NULL);
fpi_device_get_delete_data (dev, &print);
g_object_get (print, "fpi-data", &data, NULL);
if (data == NULL)
{
fpi_device_delete_complete (dev,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return;
}
id = g_variant_get_string (data, NULL);
fp_dbg ("Deleting print %s for user %s",
id,
fp_print_get_username (print));
if (g_hash_table_remove (vdev->prints_storage, id))
fpi_device_delete_complete (dev, NULL);
else
fpi_device_delete_complete (dev,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
}
static void
fpi_device_virtual_device_storage_init (FpDeviceVirtualDeviceStorage *self)
{
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (self);
vdev->prints_storage = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
}
static const FpIdEntry driver_ids[] = {
{ .virtual_envvar = "FP_VIRTUAL_DEVICE_STORAGE" },
{ .virtual_envvar = "FP_VIRTUAL_DEVICE_IDENT" },
{ .virtual_envvar = NULL }
};
static void
fpi_device_virtual_device_storage_class_init (FpDeviceVirtualDeviceStorageClass *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
dev_class->id = FP_COMPONENT;
dev_class->full_name = "Virtual device with storage and identification for debugging";
dev_class->id_table = driver_ids;
dev_class->identify = dev_identify;
dev_class->list = dev_list;
dev_class->delete = dev_delete;
}
+331
View File
@@ -0,0 +1,331 @@
/*
* Virtual driver for "simple" device debugging
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* This is a virtual driver to debug the non-image based drivers. A small
* python script is provided to connect to it via a socket, allowing
* prints to registered programmatically.
* Using this, it is possible to test libfprint and fprintd.
*/
#define FP_COMPONENT "virtual_device"
#include "virtual-device-private.h"
#include "fpi-log.h"
G_DEFINE_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP_TYPE_DEVICE)
#define INSERT_CMD_PREFIX "INSERT "
#define REMOVE_CMD_PREFIX "REMOVE "
#define SCAN_CMD_PREFIX "SCAN "
#define ERROR_CMD_PREFIX "ERROR "
#define LIST_CMD "LIST"
char *
process_cmds (FpDeviceVirtualDevice * self, gboolean scan, GError * *error)
{
while (self->pending_commands->len > 0)
{
gchar *cmd = g_ptr_array_index (self->pending_commands, 0);
/* These are always processed. */
if (g_str_has_prefix (cmd, INSERT_CMD_PREFIX))
{
g_assert (self->prints_storage);
g_hash_table_add (self->prints_storage,
g_strdup (cmd + strlen (INSERT_CMD_PREFIX)));
g_ptr_array_remove_index (self->pending_commands, 0);
continue;
}
else if (g_str_has_prefix (cmd, REMOVE_CMD_PREFIX))
{
g_assert (self->prints_storage);
if (!g_hash_table_remove (self->prints_storage,
cmd + strlen (REMOVE_CMD_PREFIX)))
g_warning ("ID %s was not found in storage", cmd + strlen (REMOVE_CMD_PREFIX));
g_ptr_array_remove_index (self->pending_commands, 0);
continue;
}
/* If we are not scanning, then we have to stop here. */
if (!scan)
break;
if (g_str_has_prefix (cmd, SCAN_CMD_PREFIX))
{
char *res = g_strdup (cmd + strlen (SCAN_CMD_PREFIX));
g_ptr_array_remove_index (self->pending_commands, 0);
return res;
}
else if (g_str_has_prefix (cmd, ERROR_CMD_PREFIX))
{
g_propagate_error (error,
fpi_device_error_new (g_ascii_strtoull (cmd + strlen (ERROR_CMD_PREFIX), NULL, 10)));
g_ptr_array_remove_index (self->pending_commands, 0);
return NULL;
}
else
{
g_warning ("Could not process command: %s", cmd);
g_ptr_array_remove_index (self->pending_commands, 0);
}
}
/* No commands left, throw a timeout error. */
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "No commands left that can be run!");
return NULL;
}
static void
write_key_to_listener (void *key, void *val, void *user_data)
{
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (user_data);
if (!fp_device_virtual_listener_write_sync (listener, key, strlen (key), NULL) ||
!fp_device_virtual_listener_write_sync (listener, "\n", 1, NULL))
g_warning ("Error writing reply to LIST command");
}
static void
recv_instruction_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr(GError) error = NULL;
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object);
gsize bytes;
bytes = fp_device_virtual_listener_read_finish (listener, res, &error);
fp_dbg ("Got instructions of length %ld\n", bytes);
if (error)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Error receiving instruction data: %s", error->message);
return;
}
if (bytes > 0)
{
FpDeviceVirtualDevice *self;
g_autofree char *cmd = NULL;
self = FP_DEVICE_VIRTUAL_DEVICE (user_data);
cmd = g_strndup (self->recv_buf, bytes);
if (g_str_has_prefix (cmd, LIST_CMD))
{
if (self->prints_storage)
g_hash_table_foreach (self->prints_storage, write_key_to_listener, listener);
}
else
{
g_ptr_array_add (self->pending_commands, g_steal_pointer (&cmd));
}
}
fp_device_virtual_listener_connection_close (listener);
}
static void
recv_instruction (FpDeviceVirtualDevice *self)
{
fp_device_virtual_listener_read (self->listener,
FALSE,
self->recv_buf,
sizeof (self->recv_buf),
recv_instruction_cb,
self);
}
static void
on_listener_connected (FpDeviceVirtualListener *listener,
gpointer user_data)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (user_data);
recv_instruction (self);
}
static void
dev_init (FpDevice *dev)
{
g_autoptr(GError) error = NULL;
g_autoptr(GCancellable) cancellable = NULL;
g_autoptr(FpDeviceVirtualListener) listener = NULL;
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
G_DEBUG_HERE ();
listener = fp_device_virtual_listener_new ();
cancellable = g_cancellable_new ();
if (!fp_device_virtual_listener_start (listener,
fpi_device_get_virtual_env (FP_DEVICE (self)),
cancellable,
on_listener_connected,
self,
&error))
{
fpi_device_open_complete (dev, g_steal_pointer (&error));
return;
}
self->listener = g_steal_pointer (&listener);
self->cancellable = g_steal_pointer (&cancellable);
fpi_device_open_complete (dev, NULL);
}
static void
dev_verify (FpDevice *dev)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
FpPrint *print;
GError *error = NULL;
g_autofree char *scan_id = NULL;
fpi_device_get_verify_data (dev, &print);
scan_id = process_cmds (self, TRUE, &error);
if (scan_id)
{
GVariant *data = NULL;
FpPrint *new_scan;
gboolean success;
g_debug ("Virtual device scanned print %s", scan_id);
new_scan = fp_print_new (dev);
fpi_print_set_type (new_scan, FPI_PRINT_RAW);
if (self->prints_storage)
fpi_print_set_device_stored (new_scan, TRUE);
data = g_variant_new_string (scan_id);
g_object_set (new_scan, "fpi-data", data, NULL);
success = fp_print_equal (print, new_scan);
fpi_device_verify_report (dev,
success ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL,
new_scan,
NULL);
}
else
{
g_debug ("Virtual device scann failed with error: %s", error->message);
}
fpi_device_verify_complete (dev, error);
}
static void
dev_enroll (FpDevice *dev)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
GError *error = NULL;
FpPrint *print = NULL;
g_autofree char *id = NULL;
fpi_device_get_enroll_data (dev, &print);
id = process_cmds (self, TRUE, &error);
if (id)
{
GVariant *data;
fpi_print_set_type (print, FPI_PRINT_RAW);
data = g_variant_new_string (id);
g_object_set (print, "fpi-data", data, NULL);
if (self->prints_storage)
{
g_hash_table_add (self->prints_storage, g_strdup (id));
fpi_print_set_device_stored (print, TRUE);
}
fpi_device_enroll_complete (dev, g_object_ref (print), error);
}
else
{
fpi_device_enroll_complete (dev, NULL, error);
}
}
static void
dev_deinit (FpDevice *dev)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
g_clear_object (&self->listener);
g_clear_object (&self->listener);
fpi_device_close_complete (dev, NULL);
}
static void
fpi_device_virtual_device_finalize (GObject *object)
{
G_DEBUG_HERE ();
}
static void
fpi_device_virtual_device_init (FpDeviceVirtualDevice *self)
{
self->pending_commands = g_ptr_array_new_with_free_func (g_free);
}
static const FpIdEntry driver_ids[] = {
{ .virtual_envvar = "FP_VIRTUAL_DEVICE", },
{ .virtual_envvar = NULL }
};
static void
fpi_device_virtual_device_class_init (FpDeviceVirtualDeviceClass *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = fpi_device_virtual_device_finalize;
dev_class->id = FP_COMPONENT;
dev_class->full_name = "Virtual device for debugging";
dev_class->type = FP_DEVICE_TYPE_VIRTUAL;
dev_class->id_table = driver_ids;
dev_class->nr_enroll_stages = 5;
dev_class->open = dev_init;
dev_class->close = dev_deinit;
dev_class->verify = dev_verify;
dev_class->enroll = dev_enroll;
}
+53 -167
View File
@@ -29,25 +29,18 @@
#include "fpi-log.h" #include "fpi-log.h"
#include "virtual-device-private.h"
#include "../fpi-image.h" #include "../fpi-image.h"
#include "../fpi-image-device.h" #include "../fpi-image-device.h"
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <gio/gunixsocketaddress.h>
struct _FpDeviceVirtualImage struct _FpDeviceVirtualImage
{ {
FpImageDevice parent; FpImageDevice parent;
GSocketListener *listener; FpDeviceVirtualListener *listener;
GSocketConnection *connection;
GCancellable *listen_cancellable;
GCancellable *cancellable; GCancellable *cancellable;
gint socket_fd;
gint client_fd;
gboolean automatic_finger; gboolean automatic_finger;
FpImage *recv_img; FpImage *recv_img;
gint recv_img_hdr[2]; gint recv_img_hdr[2];
@@ -56,9 +49,7 @@ struct _FpDeviceVirtualImage
G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice) G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice)
G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE) G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE)
static void start_listen (FpDeviceVirtualImage *dev); static void recv_image (FpDeviceVirtualImage *self);
static void recv_image (FpDeviceVirtualImage *dev,
GInputStream *stream);
static void static void
recv_image_img_recv_cb (GObject *source_object, recv_image_img_recv_cb (GObject *source_object,
@@ -66,35 +57,20 @@ recv_image_img_recv_cb (GObject *source_object,
gpointer user_data) gpointer user_data)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object);
FpDeviceVirtualImage *self; FpDeviceVirtualImage *self;
FpImageDevice *device; FpImageDevice *device;
gboolean success; gsize bytes;
gsize bytes = 0;
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error); bytes = fp_device_virtual_listener_read_finish (listener, res, &error);
/* Can't use self if the operation was cancelled. */ if (!bytes || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
return; return;
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
device = FP_IMAGE_DEVICE (self); device = FP_IMAGE_DEVICE (self);
/* Consider success if we received the right amount of data, otherwise
* an error must have happened. */
if (bytes < self->recv_img->width * self->recv_img->height)
{
if (!success)
g_warning ("Error receiving image data: %s", error->message);
else
g_warning ("Error receiving image data: end of stream before all data was read");
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
return;
}
if (self->automatic_finger) if (self->automatic_finger)
fpi_image_device_report_finger_status (device, TRUE); fpi_image_device_report_finger_status (device, TRUE);
fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img)); fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img));
@@ -102,7 +78,7 @@ recv_image_img_recv_cb (GObject *source_object,
fpi_image_device_report_finger_status (device, FALSE); fpi_image_device_report_finger_status (device, FALSE);
/* And, listen for more images from the same client. */ /* And, listen for more images from the same client. */
recv_image (self, G_INPUT_STREAM (source_object)); recv_image (self);
} }
static void static void
@@ -112,37 +88,30 @@ recv_image_hdr_recv_cb (GObject *source_object,
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
FpDeviceVirtualImage *self; FpDeviceVirtualImage *self;
gboolean success; FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object);
gsize bytes; gsize bytes;
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error); bytes = fp_device_virtual_listener_read_finish (listener, res, &error);
if (!success || bytes != sizeof (self->recv_img_hdr)) if (error)
{
if (!success)
{ {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
return; return;
g_warning ("Error receiving header for image data: %s", error->message); g_warning ("Error receiving header for image data: %s", error->message);
} return;
else if (bytes != 0)
{
g_warning ("Received incomplete header before end of stream.");
} }
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); if (!bytes)
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
return; return;
}
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000) if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000)
{ {
g_warning ("Image header suggests an unrealistically large image, disconnecting client."); g_warning ("Image header suggests an unrealistically large image, disconnecting client.");
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); fp_device_virtual_listener_connection_close (listener);
g_clear_object (&self->connection);
} }
if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0) if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0)
@@ -178,153 +147,80 @@ recv_image_hdr_recv_cb (GObject *source_object,
default: default:
/* disconnect client, it didn't play fair */ /* disconnect client, it didn't play fair */
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); fp_device_virtual_listener_connection_close (listener);
g_clear_object (&self->connection);
} }
/* And, listen for more images from the same client. */ /* And, listen for more images from the same client. */
recv_image (self, G_INPUT_STREAM (source_object)); recv_image (self);
return; return;
} }
self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]); self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]);
g_debug ("image data: %p", self->recv_img->data); g_debug ("image data: %p", self->recv_img->data);
g_input_stream_read_all_async (G_INPUT_STREAM (source_object), fp_device_virtual_listener_read (listener,
TRUE,
(guint8 *) self->recv_img->data, (guint8 *) self->recv_img->data,
self->recv_img->width * self->recv_img->height, self->recv_img->width * self->recv_img->height,
G_PRIORITY_DEFAULT,
self->cancellable,
recv_image_img_recv_cb, recv_image_img_recv_cb,
self); self);
} }
static void static void
recv_image (FpDeviceVirtualImage *self, GInputStream *stream) recv_image (FpDeviceVirtualImage *self)
{ {
FpiImageDeviceState state; fp_device_virtual_listener_read (self->listener,
TRUE,
g_object_get (self, "fpi-image-device-state", &state, NULL);
g_debug ("Starting image receive (if active), state is: %i", state);
/* Only register if the state is active. */
if (state >= FPI_IMAGE_DEVICE_STATE_IDLE)
{
g_input_stream_read_all_async (stream,
self->recv_img_hdr, self->recv_img_hdr,
sizeof (self->recv_img_hdr), sizeof (self->recv_img_hdr),
G_PRIORITY_DEFAULT,
self->cancellable,
recv_image_hdr_recv_cb, recv_image_hdr_recv_cb,
self); self);
}
} }
static void static void
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) on_listener_connected (FpDeviceVirtualListener *listener,
gpointer user_data)
{ {
g_autoptr(GError) error = NULL; FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
GSocketConnection *connection; FpiImageDeviceState state;
GInputStream *stream;
FpDeviceVirtualImage *dev = user_data;
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object), self->automatic_finger = TRUE;
res,
NULL, g_object_get (self,
&error); "fpi-image-device-state", &state,
if (!connection) NULL);
{ /* Only read if we are in AWAIT_FINGER_* or CAPTURE states */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) if (state <= FPI_IMAGE_DEVICE_STATE_DEACTIVATING)
return; return;
g_warning ("Error accepting a new connection: %s", error->message); recv_image (self);
start_listen (dev);
}
/* Always accept further connections (but we disconnect them immediately
* if we already have a connection). */
start_listen (dev);
if (dev->connection)
{
/* We may not have noticed that the stream was closed,
* if the device is deactivated.
* Cancel any ongoing operation on the old connection. */
g_cancellable_cancel (dev->cancellable);
g_clear_object (&dev->cancellable);
dev->cancellable = g_cancellable_new ();
g_clear_object (&dev->connection);
}
if (dev->connection)
{
g_warning ("Rejecting new connection");
g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
g_object_unref (connection);
return;
}
dev->connection = connection;
dev->automatic_finger = TRUE;
stream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
fp_dbg ("Got a new connection!");
recv_image (dev, stream);
}
static void
start_listen (FpDeviceVirtualImage *dev)
{
g_socket_listener_accept_async (dev->listener,
dev->listen_cancellable,
new_connection_cb,
dev);
} }
static void static void
dev_init (FpImageDevice *dev) dev_init (FpImageDevice *dev)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(GSocketListener) listener = NULL; g_autoptr(FpDeviceVirtualListener) listener = NULL;
g_autoptr(GCancellable) cancellable = NULL;
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
const char *env;
g_autoptr(GSocketAddress) addr = NULL;
G_DEBUG_HERE (); G_DEBUG_HERE ();
self->client_fd = -1; listener = fp_device_virtual_listener_new ();
cancellable = g_cancellable_new ();
env = fpi_device_get_virtual_env (FP_DEVICE (self)); if (!fp_device_virtual_listener_start (listener,
fpi_device_get_virtual_env (FP_DEVICE (self)),
listener = g_socket_listener_new (); cancellable,
g_socket_listener_set_backlog (listener, 1); on_listener_connected,
self,
/* Remove any left over socket. */
g_unlink (env);
addr = g_unix_socket_address_new (env);
if (!g_socket_listener_add_address (listener,
addr,
G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_DEFAULT,
NULL,
NULL,
&error)) &error))
{ {
g_warning ("Could not listen on unix socket: %s", error->message); fpi_image_device_open_complete (dev, g_steal_pointer (&error));
fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), g_steal_pointer (&error));
return; return;
} }
self->listener = g_steal_pointer (&listener); self->listener = g_steal_pointer (&listener);
self->cancellable = g_cancellable_new (); self->cancellable = g_steal_pointer (&cancellable);
self->listen_cancellable = g_cancellable_new ();
start_listen (self);
/* Delay result to open up the possibility of testing race conditions. */ /* Delay result to open up the possibility of testing race conditions. */
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_open_complete, NULL, NULL); fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_open_complete, NULL, NULL);
@@ -338,11 +234,8 @@ dev_deinit (FpImageDevice *dev)
G_DEBUG_HERE (); G_DEBUG_HERE ();
g_cancellable_cancel (self->cancellable); g_cancellable_cancel (self->cancellable);
g_cancellable_cancel (self->listen_cancellable);
g_clear_object (&self->cancellable); g_clear_object (&self->cancellable);
g_clear_object (&self->listen_cancellable);
g_clear_object (&self->listener); g_clear_object (&self->listener);
g_clear_object (&self->connection);
/* Delay result to open up the possibility of testing race conditions. */ /* Delay result to open up the possibility of testing race conditions. */
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_close_complete, NULL, NULL); fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_close_complete, NULL, NULL);
@@ -353,23 +246,16 @@ dev_activate (FpImageDevice *dev)
{ {
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
fpi_image_device_activate_complete (dev, NULL); /* Start reading (again). */
recv_image (self);
if (self->connection) fpi_image_device_activate_complete (dev, NULL);
recv_image (self, g_io_stream_get_input_stream (G_IO_STREAM (self->connection)));
} }
static void static void
dev_deactivate (FpImageDevice *dev) dev_deactivate (FpImageDevice *dev)
{ {
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); fpi_image_device_deactivate_complete (dev, NULL);
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
self->cancellable = g_cancellable_new ();
/* XXX: Need to wait for the operation to be cancelled. */
fpi_device_add_timeout (FP_DEVICE (dev), 10, (FpTimeoutFunc) fpi_image_device_deactivate_complete, NULL, NULL);
} }
static void static void
+2 -2
View File
@@ -187,7 +187,7 @@ fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer,
* fpi_usb_transfer_fill_bulk_full: * fpi_usb_transfer_fill_bulk_full:
* @transfer: The #FpiUsbTransfer * @transfer: The #FpiUsbTransfer
* @endpoint: The endpoint to send the transfer to * @endpoint: The endpoint to send the transfer to
* @buffer: The data to send. A buffer will be created and managed for you if you pass NULL. * @buffer: The data to send.
* @length: The size of @buffer * @length: The size of @buffer
* @free_func: (destroy buffer): Destroy notify for @buffer * @free_func: (destroy buffer): Destroy notify for @buffer
* *
@@ -275,7 +275,7 @@ fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer,
* fpi_usb_transfer_fill_interrupt_full: * fpi_usb_transfer_fill_interrupt_full:
* @transfer: The #FpiUsbTransfer * @transfer: The #FpiUsbTransfer
* @endpoint: The endpoint to send the transfer to * @endpoint: The endpoint to send the transfer to
* @buffer: The data to send. A buffer will be created and managed for you if you pass NULL. * @buffer: The data to send.
* @length: The size of @buffer * @length: The size of @buffer
* @free_func: (destroy buffer): Destroy notify for @buffer * @free_func: (destroy buffer): Destroy notify for @buffer
* *
@@ -45,12 +45,9 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x06cb, .pid = 0x00b7 }, { .vid = 0x06cb, .pid = 0x00b7 },
{ .vid = 0x06cb, .pid = 0x00bb }, { .vid = 0x06cb, .pid = 0x00bb },
{ .vid = 0x06cb, .pid = 0x00be }, { .vid = 0x06cb, .pid = 0x00be },
{ .vid = 0x06cb, .pid = 0x00c2 },
{ .vid = 0x06cb, .pid = 0x00c9 },
{ .vid = 0x06cb, .pid = 0x00cb }, { .vid = 0x06cb, .pid = 0x00cb },
{ .vid = 0x06cb, .pid = 0x00d8 }, { .vid = 0x06cb, .pid = 0x00d8 },
{ .vid = 0x06cb, .pid = 0x00da }, { .vid = 0x06cb, .pid = 0x00da },
{ .vid = 0x06cb, .pid = 0x00e7 },
{ .vid = 0x0a5c, .pid = 0x5801 }, { .vid = 0x0a5c, .pid = 0x5801 },
{ .vid = 0x0a5c, .pid = 0x5805 }, { .vid = 0x0a5c, .pid = 0x5805 },
{ .vid = 0x0a5c, .pid = 0x5834 }, { .vid = 0x0a5c, .pid = 0x5834 },
@@ -110,6 +107,7 @@ static const FpIdEntry blacklist_id_table[] = {
static const FpDeviceClass whitelist = { static const FpDeviceClass whitelist = {
.type = FP_DEVICE_TYPE_USB, .type = FP_DEVICE_TYPE_USB,
.id_table = whitelist_id_table, .id_table = whitelist_id_table,
.id = "whitelist",
.full_name = "Hardcoded whitelist" .full_name = "Hardcoded whitelist"
}; };
@@ -140,33 +138,56 @@ print_driver (const FpDeviceClass *cls)
if (g_hash_table_lookup (printed, key) != NULL) if (g_hash_table_lookup (printed, key) != NULL)
{ {
if (cls == &whitelist)
g_warning ("%s implemented by driver %s",
key, (const char *) g_hash_table_lookup (printed, key));
g_free (key); g_free (key);
continue; continue;
} }
g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); g_hash_table_insert (printed, key, (void *) cls->id);
if (num_printed == 0) if (num_printed == 0)
g_print ("# %s\n", cls->full_name); {
if (cls != &whitelist)
g_print ("\n# Supported by libfprint driver %s\n", cls->id);
else
g_print ("\n# Known unsupported devices\n");
}
g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", g_print ("usb:v%04Xp%04X*\n",
entry->vid, entry->pid); entry->vid, entry->pid);
g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n",
entry->vid, entry->pid, cls->full_name);
num_printed++; num_printed++;
} }
if (num_printed > 0) if (num_printed > 0)
g_print ("\n"); g_print (" ID_AUTOSUSPEND=1\n");
}
static int
driver_compare (gconstpointer p1, gconstpointer p2)
{
g_autoptr(FpDeviceClass) cls1 = g_type_class_ref (*(GType *) p1);
g_autoptr(FpDeviceClass) cls2 = g_type_class_ref (*(GType *) p2);
return g_strcmp0 (cls1->id, cls2->id);
} }
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
g_autoptr(GArray) drivers = fpi_get_driver_types (); g_autoptr(GArray) drivers = fpi_get_driver_types ();
g_autofree char *program_name = NULL;
guint i; guint i;
program_name = g_path_get_basename (argv[0]);
g_print ("# SPDX-License-Identifier: LGPL-2.1-or-later\n");
g_print ("# This file has been generated using %s with all drivers enabled\n",
program_name);
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_array_sort (drivers, driver_compare);
for (i = 0; i < drivers->len; i++) for (i = 0; i < drivers->len; i++)
{ {
+29 -10
View File
@@ -155,6 +155,15 @@ foreach driver: drivers
if driver == 'virtual_image' if driver == 'virtual_image'
drivers_sources += [ 'drivers/virtual-image.c' ] drivers_sources += [ 'drivers/virtual-image.c' ]
endif endif
if driver == 'virtual_device'
drivers_sources += [ 'drivers/virtual-device.c' ]
endif
if driver == 'virtual_device_storage'
drivers_sources += [ 'drivers/virtual-device-storage.c' ]
endif
if driver.startswith('virtual_')
drivers_sources += [ 'drivers/virtual-device-listener.c' ]
endif
if driver == 'synaptics' if driver == 'synaptics'
drivers_sources += [ drivers_sources += [
'drivers/synaptics/synaptics.c', 'drivers/synaptics/synaptics.c',
@@ -258,7 +267,7 @@ libfprint_drivers = static_library('fprint-drivers',
mapfile = files('libfprint.ver') mapfile = files('libfprint.ver')
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0]) vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0])
libfprint = library(versioned_libname.split('lib')[1], libfprint = shared_library(versioned_libname.split('lib')[1],
sources: [ sources: [
fp_enums, fp_enums,
libfprint_sources, libfprint_sources,
@@ -295,20 +304,30 @@ libfprint_private_dep = declare_dependency(
] ]
) )
udev_rules = executable('fprint-list-udev-rules', udev_hwdb = executable('fprint-list-udev-hwdb',
'fprint-list-udev-rules.c', 'fprint-list-udev-hwdb.c',
dependencies: libfprint_private_dep, dependencies: libfprint_private_dep,
link_with: libfprint_drivers, link_with: libfprint_drivers,
install: false) install: false)
if get_option('udev_rules') udev_hwdb_generator = custom_target('udev-hwdb',
custom_target('udev-rules', output: 'autosuspend.hwdb',
output: '60-@0@-autosuspend.rules'.format(versioned_libname), depend_files: drivers_sources,
capture: true, capture: true,
command: [ udev_rules ], command: [ udev_hwdb ],
install: true, install: false,
install_dir: udev_rules_dir) )
endif
custom_target('sync-udev-hwdb',
depends: udev_hwdb_generator,
output: 'sync-udev-hwdb',
install: false,
command: [
'cp', '-v',
udev_hwdb_generator.full_path(),
meson.source_root() / 'data'
]
)
supported_devices = executable('fprint-list-supported-devices', supported_devices = executable('fprint-list-supported-devices',
'fprint-list-supported-devices.c', 'fprint-list-supported-devices.c',
+46 -5
View File
@@ -88,7 +88,12 @@ cairo_dep = dependency('cairo', required: false)
# Drivers # Drivers
drivers = get_option('drivers').split(',') drivers = get_option('drivers').split(',')
virtual_drivers = [ 'virtual_image' ] virtual_drivers = [
'virtual_image',
'virtual_device',
'virtual_device_storage',
]
default_drivers = [ default_drivers = [
'upektc_img', 'upektc_img',
'vfs5011', 'vfs5011',
@@ -113,6 +118,13 @@ default_drivers = [
'goodixmoc', 'goodixmoc',
] ]
# FIXME: All the drivers should be fixed by adjusting the byte order.
# See https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/236
endian_independent_drivers = virtual_drivers + [
'aes3500',
'synaptics',
]
all_drivers = default_drivers + virtual_drivers all_drivers = default_drivers + virtual_drivers
if drivers == [ 'all' ] if drivers == [ 'all' ]
@@ -127,6 +139,18 @@ if drivers.length() == 0 or drivers[0] == ''
error('Cannot build libfprint without drivers, please specify a valid value for the drivers option') error('Cannot build libfprint without drivers, please specify a valid value for the drivers option')
endif endif
if drivers == all_drivers or drivers == default_drivers
default_drivers_are_enabled = true
else
default_drivers_are_enabled = true
foreach driver: default_drivers
if driver not in drivers
default_drivers_are_enabled = false
break
endif
endforeach
endif
nss_dep = dependency('', required: false) nss_dep = dependency('', required: false)
imaging_dep = dependency('', required: false) imaging_dep = dependency('', required: false)
libfprint_conf.set10('HAVE_PIXMAN', false) libfprint_conf.set10('HAVE_PIXMAN', false)
@@ -150,6 +174,20 @@ foreach driver: drivers
endif endif
endforeach endforeach
supported_drivers = []
foreach driver: drivers
if build_machine.endian() == 'little' or driver in endian_independent_drivers
supported_drivers += driver
else
warning('Driver @0@ is not supported by big endian cpu @1@. Please, fix it!'.format(
driver, build_machine.cpu()))
endif
endforeach
if default_drivers_are_enabled and supported_drivers != drivers
default_drivers_are_enabled = false
endif
# Export the drivers' types to the core code # Export the drivers' types to the core code
drivers_type_list = [] drivers_type_list = []
drivers_type_func = [] drivers_type_func = []
@@ -162,7 +200,7 @@ drivers_type_func += '{'
drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));' drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));'
drivers_type_func += ' GType t;' drivers_type_func += ' GType t;'
drivers_type_func += '' drivers_type_func += ''
foreach driver: drivers foreach driver: supported_drivers
drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);' drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);'
drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();' drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();'
drivers_type_func += ' g_array_append_val (drivers, t);' drivers_type_func += ' g_array_append_val (drivers, t);'
@@ -175,12 +213,14 @@ drivers_type_func += '}'
root_inc = include_directories('.') root_inc = include_directories('.')
if get_option('udev_rules') if get_option('udev_rules')
udev_rules_dir = get_option('udev_rules_dir') udev_hwdb_dir = get_option('udev_hwdb_dir')
if udev_rules_dir == 'auto' if udev_hwdb_dir == 'auto'
udev_dep = dependency('udev') udev_dep = dependency('udev')
udev_rules_dir = udev_dep.get_pkgconfig_variable('udevdir') + '/rules.d' udev_hwdb_dir = udev_dep.get_pkgconfig_variable('udevdir') + '/hwdb.d'
endif endif
else
udev_hwdb_dir = false
endif endif
if get_option('gtk-examples') if get_option('gtk-examples')
@@ -204,6 +244,7 @@ if get_option('gtk-examples')
subdir('demo') subdir('demo')
endif endif
subdir('data')
subdir('tests') subdir('tests')
pkgconfig = import('pkgconfig') pkgconfig = import('pkgconfig')
+2 -2
View File
@@ -10,8 +10,8 @@ option('udev_rules',
description: 'Whether to create a udev rules file', description: 'Whether to create a udev rules file',
type: 'boolean', type: 'boolean',
value: true) value: true)
option('udev_rules_dir', option('udev_hwdb_dir',
description: 'Installation path for udev rules', description: 'Installation path for udev hwdb',
type: 'string', type: 'string',
value: 'auto') value: 'auto')
option('gtk-examples', option('gtk-examples',
+8 -8
View File
@@ -35,11 +35,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0000 A: bcdDevice=0000
A: bmAttributes=80 A: bmAttributes=80
A: busnum=3 A: busnum=3\n
A: configuration= A: configuration=
H: descriptors=12011001FFFFFF08FF0831570000000100010902200001010080320904000002FFFFFF000705810240000007050202080000 H: descriptors=12011001FFFFFF08FF0831570000000100010902200001010080320904000002FFFFFF000705810240000007050202080000
A: dev=189:259 A: dev=189:259
A: devnum=4 A: devnum=4\n
A: devpath=1.1.3 A: devpath=1.1.3
L: driver=../../../../../../../../../../bus/usb/drivers/usb L: driver=../../../../../../../../../../bus/usb/drivers/usb
A: idProduct=5731 A: idProduct=5731
@@ -106,11 +106,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=9100 A: bcdDevice=9100
A: bmAttributes=e0 A: bmAttributes=e0
A: busnum=3 A: busnum=3\n
A: configuration= A: configuration=
H: descriptors=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C H: descriptors=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C
A: dev=189:258 A: dev=189:258
A: devnum=3 A: devnum=3\n
A: devpath=1.1 A: devpath=1.1
L: driver=../../../../../../../../../bus/usb/drivers/usb L: driver=../../../../../../../../../bus/usb/drivers/usb
A: idProduct=0006 A: idProduct=0006
@@ -186,11 +186,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=9100 A: bcdDevice=9100
A: bmAttributes=e0 A: bmAttributes=e0
A: busnum=3 A: busnum=3\n
A: configuration= A: configuration=
H: descriptors=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C H: descriptors=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C
A: dev=189:257 A: dev=189:257
A: devnum=2 A: devnum=2\n
A: devpath=1 A: devpath=1
L: driver=../../../../../../../../bus/usb/drivers/usb L: driver=../../../../../../../../bus/usb/drivers/usb
A: idProduct=0006 A: idProduct=0006
@@ -270,11 +270,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0415 A: bcdDevice=0415
A: bmAttributes=e0 A: bmAttributes=e0
A: busnum=3 A: busnum=3\n
A: configuration= A: configuration=
H: descriptors=12010002090001406B1D020015040302010109021900010100E0000904000001090000000705810304000C H: descriptors=12010002090001406B1D020015040302010109021900010100E0000904000001090000000705810304000C
A: dev=189:256 A: dev=189:256
A: devnum=1 A: devnum=1\n
A: devpath=0 A: devpath=0
L: driver=../../../../../../../bus/usb/drivers/usb L: driver=../../../../../../../bus/usb/drivers/usb
A: idProduct=0002 A: idProduct=0002
+6 -6
View File
@@ -36,11 +36,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0140 A: bcdDevice=0140
A: bmAttributes=80 A: bmAttributes=80
A: busnum=1 A: busnum=1\n
A: configuration= A: configuration=
H: descriptors=1201000200000008F304260C40010102000109023E0001010080320904000005FF0000000921100100012215000705810240000107050102400001070582024000010705830240000107050302400001 H: descriptors=1201000200000008F304260C40010102000109023E0001010080320904000005FF0000000921100100012215000705810240000107050102400001070582024000010705830240000107050302400001
A: dev=189:93 A: dev=189:93
A: devnum=94 A: devnum=94\n
A: devpath=4.4 A: devpath=4.4
L: driver=../../../../../../bus/usb/drivers/usb L: driver=../../../../../../bus/usb/drivers/usb
A: idProduct=0c26 A: idProduct=0c26
@@ -107,11 +107,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=5284 A: bcdDevice=5284
A: bmAttributes=e0 A: bmAttributes=e0
A: busnum=1 A: busnum=1\n
A: configuration= A: configuration=
H: descriptors=1201100209000140EF17181084520102000109021900010100E0000904000001090000000705810301000C H: descriptors=1201100209000140EF17181084520102000109021900010100E0000904000001090000000705810301000C
A: dev=189:82 A: dev=189:82
A: devnum=83 A: devnum=83\n
A: devpath=4 A: devpath=4
L: driver=../../../../../bus/usb/drivers/usb L: driver=../../../../../bus/usb/drivers/usb
A: idProduct=1018 A: idProduct=1018
@@ -189,11 +189,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0503 A: bcdDevice=0503
A: bmAttributes=e0 A: bmAttributes=e0
A: busnum=1 A: busnum=1\n
A: configuration= A: configuration=
H: descriptors=12010002090001406B1D020003050302010109021900010100E0000904000001090000000705810304000C H: descriptors=12010002090001406B1D020003050302010109021900010100E0000904000001090000000705810304000C
A: dev=189:0 A: dev=189:0
A: devnum=1 A: devnum=1\n
A: devpath=0 A: devpath=0
L: driver=../../../../bus/usb/drivers/usb L: driver=../../../../bus/usb/drivers/usb
A: idProduct=0002 A: idProduct=0002
+4 -4
View File
@@ -37,11 +37,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0100 A: bcdDevice=0100
A: bmAttributes=a0 A: bmAttributes=a0
A: busnum=1 A: busnum=1\n
A: configuration=UIDCBEE4D7B_XXXX_MOC_B0 A: configuration=UIDCBEE4D7B_XXXX_MOC_B0
H: descriptors=12010002EF000040C627A26000010102030109022000010103A0320904000002FF0000040705830240000007050102400000 H: descriptors=12010002EF000040C627A26000010102030109022000010103A0320904000002FF0000040705830240000007050102400000
A: dev=189:2 A: dev=189:2
A: devnum=3 A: devnum=3\n
A: devpath=8 A: devpath=8
L: driver=../../../../../bus/usb/drivers/usb L: driver=../../../../../bus/usb/drivers/usb
A: idProduct=60a2 A: idProduct=60a2
@@ -125,11 +125,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0504 A: bcdDevice=0504
A: bmAttributes=e0 A: bmAttributes=e0
A: busnum=1 A: busnum=1\n
A: configuration= A: configuration=
H: descriptors=12010002090001406B1D020004050302010109021900010100E0000904000001090000000705810304000C H: descriptors=12010002090001406B1D020004050302010109021900010100E0000904000001090000000705810304000C
A: dev=189:0 A: dev=189:0
A: devnum=1 A: devnum=1\n
A: devpath=0 A: devpath=0
L: driver=../../../../bus/usb/drivers/usb L: driver=../../../../bus/usb/drivers/usb
A: idProduct=0002 A: idProduct=0002
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
import os
import sys
import urllib
import urllib.request
import re
error = False
try:
response = urllib.request.urlopen('https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md')
except:
print("Could not download current list of unsupported devices, skipping test.")
sys.exit(77)
data = response.read().decode('utf-8')
devices = []
devices_re = re.compile(r'^.*([0-9a-fA-F]{4}):([0-9a-fA-F]{4}).*$', re.MULTILINE)
for m in devices_re.finditer(data):
vid = m.group(1)
pid = m.group(2)
devices.append((vid, pid))
generator = open(os.path.join(os.path.dirname(__file__), '..', 'libfprint', 'fprint-list-udev-hwdb.c')).read()
id_re = re.compile(' { .vid = 0x([a-fA-F0-9]*), .pid = 0x([a-fA-F0-9]*) }')
# Check everything is the same
started = False
for l in generator.split('\n'):
m = id_re.match(l)
if m is None:
# Stop on the first line that does not match anymore
if started:
break
continue
else:
started = True
vid_pid = (m.group(1), m.group(2))
try:
devices.remove(vid_pid)
except ValueError:
print("Generator has entry that is not on wiki: {}:{}".format(*vid_pid))
error = True
for vid_pid in devices:
print("New entry from wiki is missing: {}:{}".format(*vid_pid))
error = True
if error:
sys.exit(1)
else:
sys.exit(0)
+31 -10
View File
@@ -5,6 +5,7 @@ envs.set('G_MESSAGES_DEBUG', 'all')
# Setup paths # Setup paths
envs.set('MESON_SOURCE_ROOT', meson.source_root()) envs.set('MESON_SOURCE_ROOT', meson.source_root())
envs.set('MESON_BUILD_ROOT', meson.build_root())
envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint')) envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint'))
# Set FP_DEVICE_EMULATION so that drivers can adapt (e.g. to use fixed # Set FP_DEVICE_EMULATION so that drivers can adapt (e.g. to use fixed
@@ -12,7 +13,11 @@ envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint'))
envs.set('FP_DEVICE_EMULATION', '1') envs.set('FP_DEVICE_EMULATION', '1')
# Set a colon-separated list of native drivers we enable in tests # Set a colon-separated list of native drivers we enable in tests
envs.set('FP_DRIVERS_WHITELIST', 'virtual_image') envs.set('FP_DRIVERS_WHITELIST', ':'.join([
'virtual_image',
'virtual_device',
'virtual_device_storage',
]))
envs.set('NO_AT_BRIDGE', '1') envs.set('NO_AT_BRIDGE', '1')
@@ -28,20 +33,27 @@ drivers_tests = [
if get_option('introspection') if get_option('introspection')
envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint')) envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint'))
virtual_devices_tests = [
'virtual-image',
'virtual-device',
]
if 'virtual_image' in drivers
python3 = find_program('python3')
unittest_inspector = find_program('unittest_inspector.py') unittest_inspector = find_program('unittest_inspector.py')
base_args = files('virtual-image.py')
suite = []
r = run_command(unittest_inspector, files('virtual-image.py')) foreach vdtest: virtual_devices_tests
driver_name = '_'.join(vdtest.split('-'))
if driver_name in drivers
python3 = find_program('python3')
base_args = files(vdtest + '.py')
suite = ['virtual-driver']
r = run_command(unittest_inspector, files(vdtest + '.py'))
unit_tests = r.stdout().strip().split('\n') unit_tests = r.stdout().strip().split('\n')
if r.returncode() == 0 and unit_tests.length() > 0 if r.returncode() == 0 and unit_tests.length() > 0
suite += 'virtual-image' suite += vdtest
else else
unit_tests = ['virtual-image'] unit_tests = [vdtest]
endif endif
foreach ut: unit_tests foreach ut: unit_tests
@@ -60,17 +72,19 @@ if get_option('introspection')
) )
endforeach endforeach
else else
test('virtual-image', test(vdtest,
find_program('sh'), find_program('sh'),
args: ['-c', 'exit 77'] args: ['-c', 'exit 77']
) )
endif endif
endforeach
foreach driver_test: drivers_tests foreach driver_test: drivers_tests
driver_envs = envs driver_envs = envs
driver_envs.set('FP_DRIVERS_WHITELIST', driver_test) driver_envs.set('FP_DRIVERS_WHITELIST', driver_test)
if driver_test in drivers and gusb_dep.version().version_compare('>= 0.3.0') if (driver_test in supported_drivers and
gusb_dep.version().version_compare('>= 0.3.0'))
test(driver_test, test(driver_test,
find_program('umockdev-test.py'), find_program('umockdev-test.py'),
args: join_paths(meson.current_source_dir(), driver_test), args: join_paths(meson.current_source_dir(), driver_test),
@@ -168,6 +182,13 @@ foreach test_name: unit_tests
) )
endforeach endforeach
# Run udev rule generator with fatal warnings
envs.set('UDEV_HWDB', udev_hwdb.full_path())
envs.set('UDEV_HWDB_CHECK_CONTENTS', default_drivers_are_enabled ? '1' : '0')
test('udev-hwdb',
find_program('test-generated-hwdb.sh'),
env: envs)
gdb = find_program('gdb', required: false) gdb = find_program('gdb', required: false)
if gdb.found() if gdb.found()
add_test_setup('gdb', add_test_setup('gdb',
+2 -2
View File
@@ -34,11 +34,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0000 A: bcdDevice=0000
A: bmAttributes=a0 A: bmAttributes=a0
A: busnum=1 A: busnum=1\n
A: configuration= A: configuration=
H: descriptors=12010002FF10FF08CB06BD0000000000010109022700010100A0320904000003FF000000070501024000000705810240000007058303080004 H: descriptors=12010002FF10FF08CB06BD0000000000010109022700010100A0320904000003FF000000070501024000000705810240000007058303080004
A: dev=189:69 A: dev=189:69
A: devnum=70 A: devnum=70\n
A: devpath=1 A: devpath=1
L: driver=../../../../../bus/usb/drivers/usb L: driver=../../../../../bus/usb/drivers/usb
A: idProduct=00bd A: idProduct=00bd
+7 -7
View File
@@ -50,7 +50,7 @@ test_context_has_virtual_device (void)
GPtrArray *devices; GPtrArray *devices;
unsigned int i; unsigned int i;
fpt_setup_virtual_device_environment (); fpt_setup_virtual_device_environment (FPT_VIRTUAL_DEVICE_IMAGE);
context = fp_context_new (); context = fp_context_new ();
devices = fp_context_get_devices (context); devices = fp_context_get_devices (context);
@@ -82,7 +82,7 @@ test_context_enumerates_new_devices (void)
context = fp_context_new (); context = fp_context_new ();
fpt_setup_virtual_device_environment (); fpt_setup_virtual_device_environment (FPT_VIRTUAL_DEVICE_IMAGE);
fp_context_enumerate (context); fp_context_enumerate (context);
devices = fp_context_get_devices (context); devices = fp_context_get_devices (context);
@@ -120,7 +120,7 @@ context_device_removed_cb (FpContext *ctx, FpDevice *device, FptContext *tctx)
static void static void
test_context_remove_device_closed (void) test_context_remove_device_closed (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
gboolean removed; gboolean removed;
tctx->user_data = NULL; tctx->user_data = NULL;
@@ -162,7 +162,7 @@ close_done_cb (GObject *device, GAsyncResult *res, gpointer user_data)
static void static void
test_context_remove_device_closing (void) test_context_remove_device_closing (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
g_autoptr(GError) close_error = NULL; g_autoptr(GError) close_error = NULL;
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
gboolean removed; gboolean removed;
@@ -207,7 +207,7 @@ test_context_remove_device_closing (void)
static void static void
test_context_remove_device_open (void) test_context_remove_device_open (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
gboolean removed = FALSE; gboolean removed = FALSE;
@@ -267,7 +267,7 @@ open_done_cb (GObject *device, GAsyncResult *res, gpointer user_data)
static void static void
test_context_remove_device_opening (void) test_context_remove_device_opening (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
g_autoptr(GError) close_error = NULL; g_autoptr(GError) close_error = NULL;
gboolean open_done = FALSE; gboolean open_done = FALSE;
gboolean removed; gboolean removed;
@@ -327,7 +327,7 @@ enroll_done_cb (GObject *device, GAsyncResult *res, gpointer user_data)
static void static void
test_context_remove_device_active (void) test_context_remove_device_active (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(GCancellable) cancellable = NULL; g_autoptr(GCancellable) cancellable = NULL;
g_autoptr(GError) enroll_error = NULL; g_autoptr(GError) enroll_error = NULL;
+15 -15
View File
@@ -36,7 +36,7 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, FptContext *tctx)
static void static void
test_device_open_async (void) test_device_open_async (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open (tctx->device, NULL, (GAsyncReadyCallback) on_device_opened, tctx); fp_device_open (tctx->device, NULL, (GAsyncReadyCallback) on_device_opened, tctx);
@@ -59,7 +59,7 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, FptContext *tctx)
static void static void
test_device_close_async (void) test_device_close_async (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open (tctx->device, NULL, (GAsyncReadyCallback) on_device_opened, tctx); fp_device_open (tctx->device, NULL, (GAsyncReadyCallback) on_device_opened, tctx);
while (!tctx->user_data) while (!tctx->user_data)
@@ -76,7 +76,7 @@ static void
test_device_open_sync (void) test_device_open_sync (void)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, &error); fp_device_open_sync (tctx->device, NULL, &error);
g_assert_no_error (error); g_assert_no_error (error);
@@ -97,7 +97,7 @@ static void
test_device_open_sync_notify (void) test_device_open_sync_notify (void)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
g_signal_connect (tctx->device, "notify::open", G_CALLBACK (on_open_notify), tctx); g_signal_connect (tctx->device, "notify::open", G_CALLBACK (on_open_notify), tctx);
fp_device_open_sync (tctx->device, NULL, &error); fp_device_open_sync (tctx->device, NULL, &error);
@@ -109,7 +109,7 @@ static void
test_device_close_sync (void) test_device_close_sync (void)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
fp_device_close_sync (tctx->device, NULL, &error); fp_device_close_sync (tctx->device, NULL, &error);
@@ -131,7 +131,7 @@ static void
test_device_close_sync_notify (void) test_device_close_sync_notify (void)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
@@ -144,7 +144,7 @@ test_device_close_sync_notify (void)
static void static void
test_device_get_driver (void) test_device_get_driver (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
g_assert_cmpstr (fp_device_get_driver (tctx->device), ==, "virtual_image"); g_assert_cmpstr (fp_device_get_driver (tctx->device), ==, "virtual_image");
@@ -153,7 +153,7 @@ test_device_get_driver (void)
static void static void
test_device_get_device_id (void) test_device_get_device_id (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
g_assert_cmpstr (fp_device_get_device_id (tctx->device), ==, "0"); g_assert_cmpstr (fp_device_get_device_id (tctx->device), ==, "0");
@@ -162,7 +162,7 @@ test_device_get_device_id (void)
static void static void
test_device_get_name (void) test_device_get_name (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
g_assert_cmpstr (fp_device_get_name (tctx->device), ==, g_assert_cmpstr (fp_device_get_name (tctx->device), ==,
@@ -172,7 +172,7 @@ test_device_get_name (void)
static void static void
test_device_get_scan_type (void) test_device_get_scan_type (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
g_assert_cmpint (fp_device_get_scan_type (tctx->device), ==, FP_SCAN_TYPE_SWIPE); g_assert_cmpint (fp_device_get_scan_type (tctx->device), ==, FP_SCAN_TYPE_SWIPE);
@@ -181,7 +181,7 @@ test_device_get_scan_type (void)
static void static void
test_device_get_finger_status (void) test_device_get_finger_status (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
g_assert_cmpint (fp_device_get_finger_status (tctx->device), ==, FP_FINGER_STATUS_NONE); g_assert_cmpint (fp_device_get_finger_status (tctx->device), ==, FP_FINGER_STATUS_NONE);
@@ -190,7 +190,7 @@ test_device_get_finger_status (void)
static void static void
test_device_get_nr_enroll_stages (void) test_device_get_nr_enroll_stages (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
g_assert_cmpuint (fp_device_get_nr_enroll_stages (tctx->device), ==, 5); g_assert_cmpuint (fp_device_get_nr_enroll_stages (tctx->device), ==, 5);
@@ -199,7 +199,7 @@ test_device_get_nr_enroll_stages (void)
static void static void
test_device_supports_identify (void) test_device_supports_identify (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
g_assert_true (fp_device_supports_identify (tctx->device)); g_assert_true (fp_device_supports_identify (tctx->device));
@@ -208,7 +208,7 @@ test_device_supports_identify (void)
static void static void
test_device_supports_capture (void) test_device_supports_capture (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
g_assert_true (fp_device_supports_capture (tctx->device)); g_assert_true (fp_device_supports_capture (tctx->device));
@@ -217,7 +217,7 @@ test_device_supports_capture (void)
static void static void
test_device_has_storage (void) test_device_has_storage (void)
{ {
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
fp_device_open_sync (tctx->device, NULL, NULL); fp_device_open_sync (tctx->device, NULL, NULL);
g_assert_false (fp_device_has_storage (tctx->device)); g_assert_false (fp_device_has_storage (tctx->device));
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -e
[ -x "$UDEV_HWDB" ] || exit 1
if [ "$UDEV_HWDB_CHECK_CONTENTS" == 1 ]; then
generated_rules=$(mktemp "${TMPDIR:-/tmp}/libfprint-XXXXXX.hwdb")
else
generated_rules=/dev/null
fi
$UDEV_HWDB > "$generated_rules"
if [ "$UDEV_HWDB_CHECK_CONTENTS" != 1 ]; then
exit 77
fi
if ! diff -u "$MESON_SOURCE_ROOT/data/autosuspend.hwdb" "$generated_rules"; then
echo "E: Autosuspend file needs to be re-generated!"
echo " ninja -C $MESON_BUILD_ROOT libfprint/sync-udev-hwdb"
exit 1
fi
rm "$generated_rules"
+31 -9
View File
@@ -22,16 +22,31 @@
#include "test-utils.h" #include "test-utils.h"
struct
{
const char *envvar;
const char *driver_id;
const char *device_id;
} devtype_vars[FPT_NUM_VIRTUAL_DEVICE_TYPES] = {
{ "FP_VIRTUAL_IMAGE", "virtual_image", "virtual_image" }, /* FPT_VIRTUAL_DEVICE_IMAGE */
{ "FP_VIRTUAL_DEVICE", "virtual_device", "virtual_device" }, /* FPT_VIRTUAL_DEVICE_NONIMAGE */
{ "FP_VIRTUAL_DEVICE_STORAGE", "virtual_device_storage", "virtual_device_storage" } /* FPT_VIRTUAL_DEVICE_NONIMAGE_STORAGE */
};
static FptVirtualDeviceType global_devtype;
void void
fpt_teardown_virtual_device_environment (void) fpt_teardown_virtual_device_environment (void)
{ {
const char *path = g_getenv ("FP_VIRTUAL_IMAGE"); const char *path;
path = g_getenv (devtype_vars[global_devtype].envvar);
if (path) if (path)
{ {
g_autofree char *temp_dir = g_path_get_dirname (path); g_autofree char *temp_dir = g_path_get_dirname (path);
g_unsetenv ("FP_VIRTUAL_IMAGE"); g_unsetenv (devtype_vars[global_devtype].envvar);
g_unlink (path); g_unlink (path);
g_rmdir (temp_dir); g_rmdir (temp_dir);
} }
@@ -44,19 +59,23 @@ on_signal_event (int sig)
} }
void void
fpt_setup_virtual_device_environment (void) fpt_setup_virtual_device_environment (FptVirtualDeviceType devtype)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autofree char *temp_dir = NULL; g_autofree char *temp_dir = NULL;
g_autofree char *temp_path = NULL; g_autofree char *temp_path = NULL;
g_autofree char *filename = NULL;
g_assert_null (g_getenv ("FP_VIRTUAL_IMAGE")); g_assert_null (g_getenv (devtype_vars[devtype].envvar));
temp_dir = g_dir_make_tmp ("libfprint-XXXXXX", &error); temp_dir = g_dir_make_tmp ("libfprint-XXXXXX", &error);
g_assert_no_error (error); g_assert_no_error (error);
temp_path = g_build_filename (temp_dir, "virtual-image.socket", NULL); filename = g_strdup_printf ("%s.socket", devtype_vars[devtype].device_id);
g_setenv ("FP_VIRTUAL_IMAGE", temp_path, TRUE); temp_path = g_build_filename (temp_dir, filename, NULL);
g_setenv (devtype_vars[devtype].envvar, temp_path, TRUE);
global_devtype = devtype;
signal (SIGKILL, on_signal_event); signal (SIGKILL, on_signal_event);
signal (SIGABRT, on_signal_event); signal (SIGABRT, on_signal_event);
@@ -78,13 +97,16 @@ fpt_context_new (void)
} }
FptContext * FptContext *
fpt_context_new_with_virtual_imgdev (void) fpt_context_new_with_virtual_device (FptVirtualDeviceType devtype)
{ {
FptContext *tctx; FptContext *tctx;
GPtrArray *devices; GPtrArray *devices;
unsigned int i; unsigned int i;
fpt_setup_virtual_device_environment (); g_assert_true (devtype >= FPT_VIRTUAL_DEVICE_IMAGE &&
devtype < FPT_NUM_VIRTUAL_DEVICE_TYPES);
fpt_setup_virtual_device_environment (devtype);
tctx = fpt_context_new (); tctx = fpt_context_new ();
devices = fp_context_get_devices (tctx->fp_context); devices = fp_context_get_devices (tctx->fp_context);
@@ -96,7 +118,7 @@ fpt_context_new_with_virtual_imgdev (void)
{ {
FpDevice *device = devices->pdata[i]; FpDevice *device = devices->pdata[i];
if (g_strcmp0 (fp_device_get_driver (device), "virtual_image") == 0) if (g_strcmp0 (fp_device_get_driver (device), devtype_vars[devtype].driver_id) == 0)
{ {
tctx->device = device; tctx->device = device;
break; break;
+9 -2
View File
@@ -19,7 +19,14 @@
#include <glib.h> #include <glib.h>
void fpt_setup_virtual_device_environment (void); typedef enum {
FPT_VIRTUAL_DEVICE_IMAGE = 0,
FPT_VIRTUAL_DEVICE_NONIMAGE,
FPT_VIRTUAL_DEVICE_NONIMAGE_STORAGE,
FPT_NUM_VIRTUAL_DEVICE_TYPES
} FptVirtualDeviceType;
void fpt_setup_virtual_device_environment (FptVirtualDeviceType devtype);
void fpt_teardown_virtual_device_environment (void); void fpt_teardown_virtual_device_environment (void);
typedef struct _FptContext typedef struct _FptContext
@@ -30,7 +37,7 @@ typedef struct _FptContext
} FptContext; } FptContext;
FptContext * fpt_context_new (void); FptContext * fpt_context_new (void);
FptContext * fpt_context_new_with_virtual_imgdev (void); FptContext * fpt_context_new_with_virtual_device (FptVirtualDeviceType devtype);
void fpt_context_free (FptContext *test_context); void fpt_context_free (FptContext *test_context);
Regular → Executable
View File
+2 -2
View File
@@ -38,11 +38,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0060 A: bcdDevice=0060
A: bmAttributes=a0 A: bmAttributes=a0
A: busnum=1 A: busnum=1\n
A: configuration= A: configuration=
H: descriptors=12011001FF10FF088A13500060000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004 H: descriptors=12011001FF10FF088A13500060000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004
A: dev=189:3 A: dev=189:3
A: devnum=4 A: devnum=4\n
A: devpath=9 A: devpath=9
L: driver=../../../../../bus/usb/drivers/usb L: driver=../../../../../bus/usb/drivers/usb
A: idProduct=0050 A: idProduct=0050
+6 -6
View File
@@ -37,11 +37,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0c90 A: bcdDevice=0c90
A: bmAttributes=a0 A: bmAttributes=a0
A: busnum=2 A: busnum=2\n
A: configuration= A: configuration=
H: descriptors=12011001FF10FF088A130500900C0000000109022700010100A0320904000003FF000000070501024000000705810240000007058202400000 H: descriptors=12011001FF10FF088A130500900C0000000109022700010100A0320904000003FF000000070501024000000705810240000007058202400000
A: dev=189:132 A: dev=189:132
A: devnum=5 A: devnum=5\n
A: devpath=1.3 A: devpath=1.3
L: driver=../../../../../../bus/usb/drivers/usb L: driver=../../../../../../bus/usb/drivers/usb
A: idProduct=0005 A: idProduct=0005
@@ -120,11 +120,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0000 A: bcdDevice=0000
A: bmAttributes=e0 A: bmAttributes=e0
A: busnum=2 A: busnum=2\n
A: configuration= A: configuration=
H: descriptors=12010002090001408780200000000000000109021900010100E0000904000001090000000705810302000C H: descriptors=12010002090001408780200000000000000109021900010100E0000904000001090000000705810302000C
A: dev=189:129 A: dev=189:129
A: devnum=2 A: devnum=2\n
A: devpath=1 A: devpath=1
L: driver=../../../../../bus/usb/drivers/usb L: driver=../../../../../bus/usb/drivers/usb
A: idProduct=0020 A: idProduct=0020
@@ -204,11 +204,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0504 A: bcdDevice=0504
A: bmAttributes=e0 A: bmAttributes=e0
A: busnum=2 A: busnum=2\n
A: configuration= A: configuration=
H: descriptors=12010002090000406B1D020004050302010109021900010100E0000904000001090000000705810304000C H: descriptors=12010002090000406B1D020004050302010109021900010100E0000904000001090000000705810304000C
A: dev=189:128 A: dev=189:128
A: devnum=1 A: devnum=1\n
A: devpath=0 A: devpath=0
L: driver=../../../../bus/usb/drivers/usb L: driver=../../../../bus/usb/drivers/usb
A: idProduct=0002 A: idProduct=0002
+2 -2
View File
@@ -35,11 +35,11 @@ A: bNumConfigurations=1
A: bNumInterfaces= 1 A: bNumInterfaces= 1
A: bcdDevice=0078 A: bcdDevice=0078
A: bmAttributes=a0 A: bmAttributes=a0
A: busnum=2 A: busnum=2\n
A: configuration= A: configuration=
H: descriptors=12011001FF11FF088A13170078000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004 H: descriptors=12011001FF11FF088A13170078000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004
A: dev=189:144 A: dev=189:144
A: devnum=17 A: devnum=17\n
A: devpath=6 A: devpath=6
L: driver=../../../../../bus/usb/drivers/usb L: driver=../../../../../bus/usb/drivers/usb
A: idProduct=0017 A: idProduct=0017
+247
View File
@@ -0,0 +1,247 @@
#!/usr/bin/env python3
import sys
try:
import gi
import re
import os
from gi.repository import GLib, Gio
import unittest
import socket
import struct
import subprocess
import shutil
import glob
import tempfile
except Exception as e:
print("Missing dependencies: %s" % str(e))
sys.exit(77)
FPrint = None
# Re-run the test with the passed wrapper if set
wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER')
if wrapper:
wrap_cmd = wrapper.split(' ') + [sys.executable, os.path.abspath(__file__)] + \
sys.argv[1:]
os.unsetenv('LIBFPRINT_TEST_WRAPPER')
sys.exit(subprocess.check_call(wrap_cmd))
ctx = GLib.main_context_default()
class Connection:
def __init__(self, addr):
self.addr = addr
def __enter__(self):
self.con = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.con.connect(self.addr)
return self.con
def __exit__(self, exc_type, exc_val, exc_tb):
self.con.close()
del self.con
class VirtualDevice(unittest.TestCase):
@classmethod
def setUpClass(cls):
unittest.TestCase.setUpClass()
cls.tmpdir = tempfile.mkdtemp(prefix='libfprint-')
driver_name = cls.driver_name if hasattr(cls, 'driver_name') else None
if not driver_name:
driver_name = re.compile(r'(?<!^)(?=[A-Z])').sub(
'_', cls.__name__).lower()
sock_name = driver_name.replace('_', '-')
cls.sockaddr = os.path.join(cls.tmpdir, '{}.socket'.format(sock_name))
os.environ['FP_{}'.format(driver_name.upper())] = cls.sockaddr
cls.ctx = FPrint.Context()
cls.dev = None
for dev in cls.ctx.get_devices():
# We might have a USB device in the test system that needs skipping
if dev.get_driver() == driver_name:
cls.dev = dev
break
assert cls.dev is not None, "You need to compile with {} for testing".format(driver_name)
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls.tmpdir)
del cls.dev
del cls.ctx
unittest.TestCase.tearDownClass()
def setUp(self):
super().setUp()
self.assertFalse(self.dev.is_open())
self.dev.open_sync()
self.assertTrue(self.dev.is_open())
def tearDown(self):
self.assertTrue(self.dev.is_open())
self.dev.close_sync()
self.assertFalse(self.dev.is_open())
super().tearDown()
def send_command(self, command, *args):
self.assertIn(command, ['INSERT', 'REMOVE', 'SCAN', 'ERROR'])
with Connection(self.sockaddr) as con:
params = ' '.join(str(p) for p in args)
con.sendall('{} {}'.format(command, params).encode('utf-8'))
while ctx.pending():
ctx.iteration(False)
def enroll_print(self, nick, finger, username='testuser'):
self._enrolled = None
def done_cb(dev, res):
print("Enroll done")
self._enrolled = dev.enroll_finish(res)
self.send_command('SCAN', nick)
template = FPrint.Print.new(self.dev)
template.set_finger(finger)
template.set_username(username)
self.dev.enroll(template, None, None, tuple(), done_cb)
while self._enrolled is None:
ctx.iteration(False)
self.assertEqual(self._enrolled.get_device_stored(),
self.dev.has_storage())
return self._enrolled
def check_verify(self, p, scan_nick, match):
self._verify_match = None
self._verify_fp = None
self._verify_error = None
if isinstance(scan_nick, str):
self.send_command('SCAN', scan_nick)
else:
self.send_command('ERROR', scan_nick)
def verify_cb(dev, res):
try:
self._verify_match, self._verify_fp = dev.verify_finish(res)
except gi.repository.GLib.Error as e:
self._verify_error = e
self.dev.verify(p, callback=verify_cb)
while self._verify_match is None and self._verify_error is None:
ctx.iteration(True)
if match:
assert self._verify_fp.equal(p)
if isinstance(scan_nick, str):
self.assertEqual(self._verify_fp.props.fpi_data.get_string(), scan_nick)
if self._verify_error is not None:
raise self._verify_error
def test_device_properties(self):
self.assertEqual(self.dev.get_driver(), 'virtual_device')
self.assertEqual(self.dev.get_device_id(), '0')
self.assertEqual(self.dev.get_name(), 'Virtual device for debugging')
self.assertTrue(self.dev.is_open())
self.assertEqual(self.dev.get_scan_type(), FPrint.ScanType.SWIPE)
self.assertEqual(self.dev.get_nr_enroll_stages(), 5)
self.assertFalse(self.dev.supports_identify())
self.assertFalse(self.dev.supports_capture())
self.assertFalse(self.dev.has_storage())
def test_enroll(self):
matching = self.enroll_print('testprint', FPrint.Finger.LEFT_LITTLE)
self.assertEqual(matching.get_username(), 'testuser')
self.assertEqual(matching.get_finger(), FPrint.Finger.LEFT_LITTLE)
def test_enroll_verify_match(self):
matching = self.enroll_print('testprint', FPrint.Finger.LEFT_THUMB)
self.check_verify(matching, 'testprint', match=True)
def test_enroll_verify_no_match(self):
matching = self.enroll_print('testprint', FPrint.Finger.LEFT_RING)
self.check_verify(matching, 'not-testprint', match=False)
def test_enroll_verify_error(self):
matching = self.enroll_print('testprint', FPrint.Finger.LEFT_RING)
with self.assertRaisesRegex(GLib.Error, r"An unspecified error occurred"):
self.check_verify(matching, 0, match=False)
class VirtualDeviceStorage(VirtualDevice):
def cleanup_device_storage(self):
for print in self.dev.list_prints_sync():
self.assertTrue(self.dev.delete_print_sync(print, None))
def test_device_properties(self):
self.assertEqual(self.dev.get_driver(), 'virtual_device_storage')
self.assertEqual(self.dev.get_device_id(), '0')
self.assertEqual(self.dev.get_name(),
'Virtual device with storage and identification for debugging')
self.assertTrue(self.dev.is_open())
self.assertEqual(self.dev.get_scan_type(), FPrint.ScanType.SWIPE)
self.assertEqual(self.dev.get_nr_enroll_stages(), 5)
self.assertTrue(self.dev.supports_identify())
self.assertFalse(self.dev.supports_capture())
self.assertTrue(self.dev.has_storage())
def test_list_empty(self):
self.cleanup_device_storage()
self.assertFalse(self.dev.list_prints_sync())
def test_list_populated(self):
self.cleanup_device_storage()
self.send_command('INSERT', 'p1')
print2 = self.enroll_print('p2', FPrint.Finger.LEFT_LITTLE)
self.assertEqual({'p1', 'p2'}, {p.props.fpi_data.get_string() for p in self.dev.list_prints_sync()})
def test_list_delete(self):
self.cleanup_device_storage()
p = self.enroll_print('testprint', FPrint.Finger.RIGHT_THUMB)
l = self.dev.list_prints_sync()
print(l[0])
self.assertEqual(len(l), 1)
print('blub', p.props.fpi_data, type(l[0].props.fpi_data))
assert p.equal(l[0])
self.dev.delete_print_sync(p)
self.assertFalse(self.dev.list_prints_sync())
def test_list_delete_missing(self):
self.cleanup_device_storage()
p = self.enroll_print('testprint', FPrint.Finger.RIGHT_THUMB)
self.send_command('REMOVE', 'testprint')
with self.assertRaisesRegex(GLib.GError, 'Print was not found'):
self.dev.delete_print_sync(p)
if __name__ == '__main__':
try:
gi.require_version('FPrint', '2.0')
from gi.repository import FPrint
except Exception as e:
print("Missing dependencies: %s" % str(e))
sys.exit(77)
# avoid writing to stderr
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))