X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fudev%2Fata_id%2Fata_id.c;h=e6344f983a868a22f0b45b151597812f282c94fe;hp=488fed4ac413bc7b2df279df45a11cc33265a229;hb=3dd0bbeb153040ca59899f770e5b0714947ea3cb;hpb=1298001ec5e320f9f9b6a9b925c8939b2579396d diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c index 488fed4ac..e6344f983 100644 --- a/src/udev/ata_id/ata_id.c +++ b/src/udev/ata_id/ata_id.c @@ -43,6 +43,7 @@ #include "libudev.h" #include "libudev-private.h" +#include "udev-util.h" #include "log.h" #define COMMAND_TIMEOUT_MSEC (30 * 1000) @@ -51,65 +52,58 @@ static int disk_scsi_inquiry_command(int fd, void *buf, size_t buf_len) { - struct sg_io_v4 io_v4; - uint8_t cdb[6]; - uint8_t sense[32]; + uint8_t cdb[6] = { + /* + * INQUIRY, see SPC-4 section 6.4 + */ + [0] = 0x12, /* OPERATION CODE: INQUIRY */ + [3] = (buf_len >> 8), /* ALLOCATION LENGTH */ + [4] = (buf_len & 0xff), + }; + uint8_t sense[32] = {}; + struct sg_io_v4 io_v4 = { + .guard = 'Q', + .protocol = BSG_PROTOCOL_SCSI, + .subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD, + .request_len = sizeof(cdb), + .request = (uintptr_t) cdb, + .max_response_len = sizeof(sense), + .response = (uintptr_t) sense, + .din_xfer_len = buf_len, + .din_xferp = (uintptr_t) buf, + .timeout = COMMAND_TIMEOUT_MSEC, + }; int ret; - /* - * INQUIRY, see SPC-4 section 6.4 - */ - memset(cdb, 0, sizeof(cdb)); - cdb[0] = 0x12; /* OPERATION CODE: INQUIRY */ - cdb[3] = (buf_len >> 8); /* ALLOCATION LENGTH */ - cdb[4] = (buf_len & 0xff); - - memset(sense, 0, sizeof(sense)); - - memset(&io_v4, 0, sizeof(struct sg_io_v4)); - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof (cdb); - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof (sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buf_len; - io_v4.din_xferp = (uintptr_t) buf; - io_v4.timeout = COMMAND_TIMEOUT_MSEC; - ret = ioctl(fd, SG_IO, &io_v4); if (ret != 0) { /* could be that the driver doesn't do version 4, try version 3 */ if (errno == EINVAL) { - struct sg_io_hdr io_hdr; - - memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); - io_hdr.interface_id = 'S'; - io_hdr.cmdp = (unsigned char*) cdb; - io_hdr.cmd_len = sizeof (cdb); - io_hdr.dxferp = buf; - io_hdr.dxfer_len = buf_len; - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof (sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.timeout = COMMAND_TIMEOUT_MSEC; + struct sg_io_hdr io_hdr = { + .interface_id = 'S', + .cmdp = (unsigned char*) cdb, + .cmd_len = sizeof (cdb), + .dxferp = buf, + .dxfer_len = buf_len, + .sbp = sense, + .mx_sb_len = sizeof(sense), + .dxfer_direction = SG_DXFER_FROM_DEV, + .timeout = COMMAND_TIMEOUT_MSEC, + }; ret = ioctl(fd, SG_IO, &io_hdr); if (ret != 0) - goto out; + return ret; /* even if the ioctl succeeds, we need to check the return value */ if (!(io_hdr.status == 0 && io_hdr.host_status == 0 && io_hdr.driver_status == 0)) { errno = EIO; - ret = -1; - goto out; + return -1; } - } else { - goto out; - } + } else + return ret; } /* even if the ioctl succeeds, we need to check the return value */ @@ -117,172 +111,156 @@ static int disk_scsi_inquiry_command(int fd, io_v4.transport_status == 0 && io_v4.driver_status == 0)) { errno = EIO; - ret = -1; - goto out; + return -1; } - out: - return ret; + return 0; } static int disk_identify_command(int fd, void *buf, size_t buf_len) { - struct sg_io_v4 io_v4; - uint8_t cdb[12]; - uint8_t sense[32]; - uint8_t *desc = sense+8; + uint8_t cdb[12] = { + /* + * ATA Pass-Through 12 byte command, as described in + * + * T10 04-262r8 ATA Command Pass-Through + * + * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf + */ + [0] = 0xa1, /* OPERATION CODE: 12 byte pass through */ + [1] = 4 << 1, /* PROTOCOL: PIO Data-in */ + [2] = 0x2e, /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ + [3] = 0, /* FEATURES */ + [4] = 1, /* SECTORS */ + [5] = 0, /* LBA LOW */ + [6] = 0, /* LBA MID */ + [7] = 0, /* LBA HIGH */ + [8] = 0 & 0x4F, /* SELECT */ + [9] = 0xEC, /* Command: ATA IDENTIFY DEVICE */ + }; + uint8_t sense[32] = {}; + uint8_t *desc = sense + 8; + struct sg_io_v4 io_v4 = { + .guard = 'Q', + .protocol = BSG_PROTOCOL_SCSI, + .subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD, + .request_len = sizeof(cdb), + .request = (uintptr_t) cdb, + .max_response_len = sizeof(sense), + .response = (uintptr_t) sense, + .din_xfer_len = buf_len, + .din_xferp = (uintptr_t) buf, + .timeout = COMMAND_TIMEOUT_MSEC, + }; int ret; - /* - * ATA Pass-Through 12 byte command, as described in - * - * T10 04-262r8 ATA Command Pass-Through - * - * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf - */ - memset(cdb, 0, sizeof(cdb)); - cdb[0] = 0xa1; /* OPERATION CODE: 12 byte pass through */ - cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ - cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ - cdb[3] = 0; /* FEATURES */ - cdb[4] = 1; /* SECTORS */ - cdb[5] = 0; /* LBA LOW */ - cdb[6] = 0; /* LBA MID */ - cdb[7] = 0; /* LBA HIGH */ - cdb[8] = 0 & 0x4F; /* SELECT */ - cdb[9] = 0xEC; /* Command: ATA IDENTIFY DEVICE */; - memset(sense, 0, sizeof(sense)); - - memset(&io_v4, 0, sizeof(struct sg_io_v4)); - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof (cdb); - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof (sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buf_len; - io_v4.din_xferp = (uintptr_t) buf; - io_v4.timeout = COMMAND_TIMEOUT_MSEC; - ret = ioctl(fd, SG_IO, &io_v4); if (ret != 0) { /* could be that the driver doesn't do version 4, try version 3 */ if (errno == EINVAL) { - struct sg_io_hdr io_hdr; - - memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); - io_hdr.interface_id = 'S'; - io_hdr.cmdp = (unsigned char*) cdb; - io_hdr.cmd_len = sizeof (cdb); - io_hdr.dxferp = buf; - io_hdr.dxfer_len = buf_len; - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof (sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.timeout = COMMAND_TIMEOUT_MSEC; + struct sg_io_hdr io_hdr = { + .interface_id = 'S', + .cmdp = (unsigned char*) cdb, + .cmd_len = sizeof (cdb), + .dxferp = buf, + .dxfer_len = buf_len, + .sbp = sense, + .mx_sb_len = sizeof (sense), + .dxfer_direction = SG_DXFER_FROM_DEV, + .timeout = COMMAND_TIMEOUT_MSEC, + }; ret = ioctl(fd, SG_IO, &io_hdr); if (ret != 0) - goto out; - } else { - goto out; - } + return ret; + } else + return ret; } if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { errno = EIO; - ret = -1; - goto out; + return -1; } - out: - return ret; + return 0; } static int disk_identify_packet_device_command(int fd, void *buf, size_t buf_len) { - struct sg_io_v4 io_v4; - uint8_t cdb[16]; - uint8_t sense[32]; - uint8_t *desc = sense+8; + uint8_t cdb[16] = { + /* + * ATA Pass-Through 16 byte command, as described in + * + * T10 04-262r8 ATA Command Pass-Through + * + * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf + */ + [0] = 0x85, /* OPERATION CODE: 16 byte pass through */ + [1] = 4 << 1, /* PROTOCOL: PIO Data-in */ + [2] = 0x2e, /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ + [3] = 0, /* FEATURES */ + [4] = 0, /* FEATURES */ + [5] = 0, /* SECTORS */ + [6] = 1, /* SECTORS */ + [7] = 0, /* LBA LOW */ + [8] = 0, /* LBA LOW */ + [9] = 0, /* LBA MID */ + [10] = 0, /* LBA MID */ + [11] = 0, /* LBA HIGH */ + [12] = 0, /* LBA HIGH */ + [13] = 0, /* DEVICE */ + [14] = 0xA1, /* Command: ATA IDENTIFY PACKET DEVICE */ + [15] = 0, /* CONTROL */ + }; + uint8_t sense[32] = {}; + uint8_t *desc = sense + 8; + struct sg_io_v4 io_v4 = { + .guard = 'Q', + .protocol = BSG_PROTOCOL_SCSI, + .subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD, + .request_len = sizeof (cdb), + .request = (uintptr_t) cdb, + .max_response_len = sizeof (sense), + .response = (uintptr_t) sense, + .din_xfer_len = buf_len, + .din_xferp = (uintptr_t) buf, + .timeout = COMMAND_TIMEOUT_MSEC, + }; int ret; - /* - * ATA Pass-Through 16 byte command, as described in - * - * T10 04-262r8 ATA Command Pass-Through - * - * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf - */ - memset(cdb, 0, sizeof(cdb)); - cdb[0] = 0x85; /* OPERATION CODE: 16 byte pass through */ - cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ - cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ - cdb[3] = 0; /* FEATURES */ - cdb[4] = 0; /* FEATURES */ - cdb[5] = 0; /* SECTORS */ - cdb[6] = 1; /* SECTORS */ - cdb[7] = 0; /* LBA LOW */ - cdb[8] = 0; /* LBA LOW */ - cdb[9] = 0; /* LBA MID */ - cdb[10] = 0; /* LBA MID */ - cdb[11] = 0; /* LBA HIGH */ - cdb[12] = 0; /* LBA HIGH */ - cdb[13] = 0; /* DEVICE */ - cdb[14] = 0xA1; /* Command: ATA IDENTIFY PACKET DEVICE */; - cdb[15] = 0; /* CONTROL */ - memset(sense, 0, sizeof(sense)); - - memset(&io_v4, 0, sizeof(struct sg_io_v4)); - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof (cdb); - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof (sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buf_len; - io_v4.din_xferp = (uintptr_t) buf; - io_v4.timeout = COMMAND_TIMEOUT_MSEC; - ret = ioctl(fd, SG_IO, &io_v4); if (ret != 0) { /* could be that the driver doesn't do version 4, try version 3 */ if (errno == EINVAL) { - struct sg_io_hdr io_hdr; - - memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); - io_hdr.interface_id = 'S'; - io_hdr.cmdp = (unsigned char*) cdb; - io_hdr.cmd_len = sizeof (cdb); - io_hdr.dxferp = buf; - io_hdr.dxfer_len = buf_len; - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof (sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.timeout = COMMAND_TIMEOUT_MSEC; + struct sg_io_hdr io_hdr = { + .interface_id = 'S', + .cmdp = (unsigned char*) cdb, + .cmd_len = sizeof (cdb), + .dxferp = buf, + .dxfer_len = buf_len, + .sbp = sense, + .mx_sb_len = sizeof (sense), + .dxfer_direction = SG_DXFER_FROM_DEV, + .timeout = COMMAND_TIMEOUT_MSEC, + }; ret = ioctl(fd, SG_IO, &io_hdr); if (ret != 0) - goto out; - } else { - goto out; - } + return ret; + } else + return ret; } if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { errno = EIO; - ret = -1; - goto out; + return -1; } - out: - return ret; + return 0; } /** @@ -348,20 +326,19 @@ static void disk_identify_fixup_uint16 (uint8_t identify[512], unsigned int offs * non-zero with errno set. */ static int disk_identify(struct udev *udev, - int fd, - uint8_t out_identify[512], - int *out_is_packet_device) + int fd, + uint8_t out_identify[512], + int *out_is_packet_device) { int ret; uint8_t inquiry_buf[36]; int peripheral_device_type; int all_nul_bytes; int n; - int is_packet_device; + int is_packet_device = 0; /* init results */ - memset(out_identify, '\0', 512); - is_packet_device = 0; + memzero(out_identify, 512); /* If we were to use ATA PASS_THROUGH (12) on an ATAPI device * we could accidentally blank media. This is because MMC's BLANK @@ -425,32 +402,27 @@ static int disk_identify(struct udev *udev, out: if (out_is_packet_device != NULL) - *out_is_packet_device = is_packet_device; + *out_is_packet_device = is_packet_device; return ret; } -static void log_fn(struct udev *udev, int priority, - const char *file, int line, const char *fn, - const char *format, va_list args) -{ - vsyslog(priority, format, args); -} - int main(int argc, char *argv[]) { - struct udev *udev; + _cleanup_udev_unref_ struct udev *udev = NULL; struct hd_driveid id; - uint8_t identify[512]; - uint16_t *identify_words; + union { + uint8_t byte[512]; + uint16_t wyde[256]; + uint64_t octa[64]; + } identify; char model[41]; char model_enc[256]; char serial[21]; char revision[9]; const char *node = NULL; int export = 0; - int fd; + _cleanup_close_ int fd = -1; uint16_t word; - int rc = 0; int is_packet_device = 0; static const struct option options[] = { { "export", no_argument, NULL, 'x' }, @@ -458,12 +430,12 @@ int main(int argc, char *argv[]) {} }; + log_parse_environment(); + log_open(); + udev = udev_new(); if (udev == NULL) - goto exit; - - log_open(); - udev_set_log_fn(udev, log_fn); + return 0; while (1) { int option; @@ -480,57 +452,53 @@ int main(int argc, char *argv[]) printf("Usage: ata_id [--export] [--help] \n" " --export print values as environment keys\n" " --help print this help text\n\n"); - goto exit; + return 0; } } node = argv[optind]; if (node == NULL) { - log_error("no node specified\n"); - rc = 1; - goto exit; + log_error("no node specified"); + return 1; } - fd = open(node, O_RDONLY|O_NONBLOCK); + fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC); if (fd < 0) { - log_error("unable to open '%s'\n", node); - rc = 1; - goto exit; + log_error("unable to open '%s'", node); + return 1; } - if (disk_identify(udev, fd, identify, &is_packet_device) == 0) { + if (disk_identify(udev, fd, identify.byte, &is_packet_device) == 0) { /* * fix up only the fields from the IDENTIFY data that we are going to * use and copy it into the hd_driveid struct for convenience */ - disk_identify_fixup_string(identify, 10, 20); /* serial */ - disk_identify_fixup_string(identify, 23, 8); /* fwrev */ - disk_identify_fixup_string(identify, 27, 40); /* model */ - disk_identify_fixup_uint16(identify, 0); /* configuration */ - disk_identify_fixup_uint16(identify, 75); /* queue depth */ - disk_identify_fixup_uint16(identify, 75); /* SATA capabilities */ - disk_identify_fixup_uint16(identify, 82); /* command set supported */ - disk_identify_fixup_uint16(identify, 83); /* command set supported */ - disk_identify_fixup_uint16(identify, 84); /* command set supported */ - disk_identify_fixup_uint16(identify, 85); /* command set supported */ - disk_identify_fixup_uint16(identify, 86); /* command set supported */ - disk_identify_fixup_uint16(identify, 87); /* command set supported */ - disk_identify_fixup_uint16(identify, 89); /* time required for SECURITY ERASE UNIT */ - disk_identify_fixup_uint16(identify, 90); /* time required for enhanced SECURITY ERASE UNIT */ - disk_identify_fixup_uint16(identify, 91); /* current APM values */ - disk_identify_fixup_uint16(identify, 94); /* current AAM value */ - disk_identify_fixup_uint16(identify, 128); /* device lock function */ - disk_identify_fixup_uint16(identify, 217); /* nominal media rotation rate */ - memcpy(&id, identify, sizeof id); + disk_identify_fixup_string(identify.byte, 10, 20); /* serial */ + disk_identify_fixup_string(identify.byte, 23, 8); /* fwrev */ + disk_identify_fixup_string(identify.byte, 27, 40); /* model */ + disk_identify_fixup_uint16(identify.byte, 0); /* configuration */ + disk_identify_fixup_uint16(identify.byte, 75); /* queue depth */ + disk_identify_fixup_uint16(identify.byte, 75); /* SATA capabilities */ + disk_identify_fixup_uint16(identify.byte, 82); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 83); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 84); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 85); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 86); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 87); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 89); /* time required for SECURITY ERASE UNIT */ + disk_identify_fixup_uint16(identify.byte, 90); /* time required for enhanced SECURITY ERASE UNIT */ + disk_identify_fixup_uint16(identify.byte, 91); /* current APM values */ + disk_identify_fixup_uint16(identify.byte, 94); /* current AAM value */ + disk_identify_fixup_uint16(identify.byte, 128); /* device lock function */ + disk_identify_fixup_uint16(identify.byte, 217); /* nominal media rotation rate */ + memcpy(&id, identify.byte, sizeof id); } else { /* If this fails, then try HDIO_GET_IDENTITY */ if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) { - log_info("HDIO_GET_IDENTITY failed for '%s': %m\n", node); - rc = 2; - goto close; + log_debug_errno(errno, "HDIO_GET_IDENTITY failed for '%s': %m", node); + return 2; } } - identify_words = (uint16_t *) identify; memcpy (model, id.model, 40); model[40] = '\0'; @@ -580,8 +548,8 @@ int main(int argc, char *argv[]) } if (id.command_set_1 & (1<<5)) { - printf ("ID_ATA_WRITE_CACHE=1\n"); - printf ("ID_ATA_WRITE_CACHE_ENABLED=%d\n", (id.cfs_enable_1 & (1<<5)) ? 1 : 0); + printf("ID_ATA_WRITE_CACHE=1\n"); + printf("ID_ATA_WRITE_CACHE_ENABLED=%d\n", (id.cfs_enable_1 & (1<<5)) ? 1 : 0); } if (id.command_set_1 & (1<<10)) { printf("ID_ATA_FEATURE_SET_HPA=1\n"); @@ -644,7 +612,8 @@ int main(int argc, char *argv[]) * the device does not claim compliance with the Serial ATA specification and words * 76 through 79 are not valid and shall be ignored. */ - word = *((uint16_t *) identify + 76); + + word = identify.wyde[76]; if (word != 0x0000 && word != 0xffff) { printf("ID_ATA_SATA=1\n"); /* @@ -661,54 +630,34 @@ int main(int argc, char *argv[]) } /* Word 217 indicates the nominal media rotation rate of the device */ - word = *((uint16_t *) identify + 217); - if (word != 0x0000) { - if (word == 0x0001) { - printf ("ID_ATA_ROTATION_RATE_RPM=0\n"); /* non-rotating e.g. SSD */ - } else if (word >= 0x0401 && word <= 0xfffe) { - printf ("ID_ATA_ROTATION_RATE_RPM=%d\n", word); - } - } + word = identify.wyde[217]; + if (word == 0x0001) + printf ("ID_ATA_ROTATION_RATE_RPM=0\n"); /* non-rotating e.g. SSD */ + else if (word >= 0x0401 && word <= 0xfffe) + printf ("ID_ATA_ROTATION_RATE_RPM=%d\n", word); /* * Words 108-111 contain a mandatory World Wide Name (WWN) in the NAA IEEE Registered identifier * format. Word 108 bits (15:12) shall contain 5h, indicating that the naming authority is IEEE. * All other values are reserved. */ - word = *((uint16_t *) identify + 108); - if ((word & 0xf000) == 0x5000) { - uint64_t wwwn; - - wwwn = *((uint16_t *) identify + 108); - wwwn <<= 16; - wwwn |= *((uint16_t *) identify + 109); - wwwn <<= 16; - wwwn |= *((uint16_t *) identify + 110); - wwwn <<= 16; - wwwn |= *((uint16_t *) identify + 111); - printf("ID_WWN=0x%llx\n", (unsigned long long int) wwwn); - /* ATA devices have no vendor extension */ - printf("ID_WWN_WITH_EXTENSION=0x%llx\n", (unsigned long long int) wwwn); - } + word = identify.wyde[108]; + if ((word & 0xf000) == 0x5000) + printf("ID_WWN=0x%1$"PRIu64"x\n" + "ID_WWN_WITH_EXTENSION=0x%1$"PRIu64"x\n", + identify.octa[108/4]); /* from Linux's include/linux/ata.h */ - if (identify_words[0] == 0x848a || identify_words[0] == 0x844a) { + if (identify.wyde[0] == 0x848a || + identify.wyde[0] == 0x844a || + (identify.wyde[83] & 0xc004) == 0x4004) printf("ID_ATA_CFA=1\n"); - } else { - if ((identify_words[83] & 0xc004) == 0x4004) { - printf("ID_ATA_CFA=1\n"); - } - } } else { if (serial[0] != '\0') printf("%s_%s\n", model, serial); else printf("%s\n", model); } -close: - close(fd); -exit: - udev_unref(udev); - log_close(); - return rc; + + return 0; }