2022-06-06 22:04:20 +03:00
/*
* Copyright ( C ) 2022 Red Hat , Inc . All rights reserved .
*
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include "base/memory/zalloc.h"
# include "lib/misc/lib.h"
2022-08-30 23:10:52 +03:00
# include "lib/commands/toolcontext.h"
2022-06-06 22:04:20 +03:00
# include "lib/device/device.h"
2022-08-30 23:10:52 +03:00
# include "lib/device/device_id.h"
2022-06-06 22:04:20 +03:00
# include <stdio.h>
# include <unistd.h>
# include <stdint.h>
# include <stdlib.h>
# include <stdarg.h>
# include <string.h>
# include <inttypes.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <ctype.h>
# include <limits.h>
# include <dirent.h>
# include <errno.h>
# include <stdbool.h>
# include <assert.h>
/*
2023-06-15 21:58:48 +03:00
* Remove leading spaces .
* Remove trailing spaces .
* Replace each space with underscore .
* Skip quotes , non - ascii , non - printable .
*/
2023-07-13 13:32:44 +03:00
int format_general_id ( const char * in , size_t in_bytes , unsigned char * out , size_t out_bytes )
2023-06-15 21:58:48 +03:00
{
const char * end ;
2023-07-13 13:32:44 +03:00
size_t end_bytes = strlen ( in ) ;
2023-06-15 21:58:48 +03:00
int retlen = 0 ;
2023-07-13 13:32:44 +03:00
unsigned j = 0 ;
unsigned i ;
2023-06-15 21:58:48 +03:00
if ( ! end_bytes )
return 0 ;
end = in + end_bytes - 1 ;
while ( ( end > in ) & & ( * end = = ' ' ) ) {
end - - ;
end_bytes - - ;
}
for ( i = 0 ; i < end_bytes ; i + + ) {
if ( ! in [ i ] )
break ;
if ( j > = ( out_bytes - 2 ) )
break ;
/* skip leading spaces */
if ( ! retlen & & ( in [ i ] = = ' ' ) )
continue ;
/* skip non-ascii non-printable characters */
if ( ! isascii ( in [ i ] ) | | ! isprint ( in [ i ] ) )
continue ;
/* skip quote */
if ( in [ i ] = = ' " ' )
continue ;
/* replace each space with _ */
if ( in [ i ] = = ' ' )
out [ j + + ] = ' _ ' ;
else
out [ j + + ] = in [ i ] ;
retlen + + ;
}
return retlen ;
}
/*
* Remove leading spaces .
* Remove trailing spaces .
2022-06-06 22:04:20 +03:00
* Replace series of spaces with a single _ .
2023-06-15 21:58:48 +03:00
* Skip quotes , non - ascii , non - printable .
2022-06-06 22:04:20 +03:00
*/
2023-07-13 13:32:44 +03:00
int format_t10_id ( const unsigned char * in , size_t in_bytes , unsigned char * out , size_t out_bytes )
2022-06-06 22:04:20 +03:00
{
int in_space = 0 ;
int retlen = 0 ;
2023-07-13 13:32:44 +03:00
unsigned j = 0 ;
unsigned i ;
2022-06-06 22:04:20 +03:00
for ( i = 0 ; i < in_bytes ; i + + ) {
if ( ! in [ i ] )
break ;
if ( j > = ( out_bytes - 2 ) )
break ;
/* skip leading spaces */
if ( ! retlen & & ( in [ i ] = = ' ' ) )
continue ;
2023-02-06 21:18:55 +03:00
/* skip non-ascii non-printable characters */
if ( ! isascii ( in [ i ] ) | | ! isprint ( in [ i ] ) )
continue ;
/* skip quote */
if ( in [ i ] = = ' " ' )
continue ;
2022-06-06 22:04:20 +03:00
/* replace one or more spaces with _ */
if ( in [ i ] = = ' ' ) {
in_space = 1 ;
continue ;
}
/* spaces are finished so insert _ */
if ( in_space ) {
out [ j + + ] = ' _ ' ;
in_space = 0 ;
retlen + + ;
}
out [ j + + ] = in [ i ] ;
retlen + + ;
}
return retlen ;
}
static int _to_hex ( const unsigned char * in , int in_bytes , unsigned char * out , int out_bytes )
{
int off = 0 ;
int num ;
int i ;
for ( i = 0 ; i < in_bytes ; i + + ) {
num = sprintf ( ( char * ) out + off , " %02x " , in [ i ] ) ;
if ( num < 0 )
break ;
off + = num ;
if ( off + 2 > = out_bytes )
break ;
}
return off ;
}
# define ID_BUFSIZE 1024
/*
* based on linux kernel function
*/
int parse_vpd_ids ( const unsigned char * vpd_data , int vpd_datalen , struct dm_list * ids )
{
char id [ ID_BUFSIZE ] ;
unsigned char tmp_str [ ID_BUFSIZE ] ;
const unsigned char * d , * cur_id_str ;
size_t id_len = ID_BUFSIZE ;
int id_size = - 1 ;
2022-08-30 23:10:52 +03:00
int type ;
2022-06-06 22:04:20 +03:00
uint8_t cur_id_size = 0 ;
memset ( id , 0 , ID_BUFSIZE ) ;
for ( d = vpd_data + 4 ;
d < vpd_data + vpd_datalen ;
d + = d [ 3 ] + 4 ) {
memset ( tmp_str , 0 , sizeof ( tmp_str ) ) ;
switch ( d [ 1 ] & 0xf ) {
case 0x1 :
/* T10 Vendor ID */
cur_id_size = d [ 3 ] ;
2023-07-13 13:32:44 +03:00
if ( ( size_t ) ( cur_id_size + 4 ) > id_len )
2022-06-06 22:04:20 +03:00
cur_id_size = id_len - 4 ;
cur_id_str = d + 4 ;
format_t10_id ( cur_id_str , cur_id_size , tmp_str , sizeof ( tmp_str ) ) ;
id_size = snprintf ( id , ID_BUFSIZE , " t10.%s " , tmp_str ) ;
if ( id_size < 0 )
break ;
if ( id_size > = ID_BUFSIZE )
id_size = ID_BUFSIZE - 1 ;
2022-08-30 23:10:52 +03:00
dev_add_wwid ( id , 1 , ids ) ;
2022-06-06 22:04:20 +03:00
break ;
case 0x2 :
/* EUI-64 */
cur_id_size = d [ 3 ] ;
cur_id_str = d + 4 ;
switch ( cur_id_size ) {
case 8 :
_to_hex ( cur_id_str , 8 , tmp_str , sizeof ( tmp_str ) ) ;
id_size = snprintf ( id , ID_BUFSIZE , " eui.%s " , tmp_str ) ;
break ;
case 12 :
_to_hex ( cur_id_str , 12 , tmp_str , sizeof ( tmp_str ) ) ;
id_size = snprintf ( id , ID_BUFSIZE , " eui.%s " , tmp_str ) ;
break ;
case 16 :
_to_hex ( cur_id_str , 16 , tmp_str , sizeof ( tmp_str ) ) ;
id_size = snprintf ( id , ID_BUFSIZE , " eui.%s " , tmp_str ) ;
break ;
default :
break ;
}
if ( id_size < 0 )
break ;
if ( id_size > = ID_BUFSIZE )
id_size = ID_BUFSIZE - 1 ;
2022-08-30 23:10:52 +03:00
dev_add_wwid ( id , 2 , ids ) ;
2022-06-06 22:04:20 +03:00
break ;
case 0x3 :
/* NAA */
cur_id_size = d [ 3 ] ;
cur_id_str = d + 4 ;
switch ( cur_id_size ) {
case 8 :
_to_hex ( cur_id_str , 8 , tmp_str , sizeof ( tmp_str ) ) ;
id_size = snprintf ( id , ID_BUFSIZE , " naa.%s " , tmp_str ) ;
break ;
case 16 :
_to_hex ( cur_id_str , 16 , tmp_str , sizeof ( tmp_str ) ) ;
id_size = snprintf ( id , ID_BUFSIZE , " naa.%s " , tmp_str ) ;
break ;
default :
break ;
}
if ( id_size < 0 )
break ;
if ( id_size > = ID_BUFSIZE )
id_size = ID_BUFSIZE - 1 ;
2022-08-30 23:10:52 +03:00
dev_add_wwid ( id , 3 , ids ) ;
2022-06-06 22:04:20 +03:00
break ;
case 0x8 :
/* SCSI name string */
cur_id_size = d [ 3 ] ;
cur_id_str = d + 4 ;
if ( cur_id_size > = id_len )
cur_id_size = id_len - 1 ;
memcpy ( id , cur_id_str , cur_id_size ) ;
id_size = cur_id_size ;
2022-08-30 23:10:52 +03:00
/*
* if naa or eui ids are provided as scsi names ,
* consider them to be naa / eui types .
*/
if ( ! memcmp ( id , " eui. " , 4 ) )
type = 2 ;
else if ( ! memcmp ( id , " naa. " , 4 ) )
type = 3 ;
else
type = 8 ;
2022-06-06 22:04:20 +03:00
/*
* Not in the kernel version , copying multipath code ,
* which checks if this string begins with naa or eui
* and if so does tolower ( ) on the chars .
*/
2022-08-30 23:10:52 +03:00
if ( ( type = = 2 ) | | ( type = = 3 ) ) {
2023-07-13 13:32:44 +03:00
unsigned i ;
2022-08-30 23:10:52 +03:00
for ( i = 0 ; i < strlen ( id ) ; i + + )
2022-06-06 22:04:20 +03:00
id [ i ] = tolower ( id [ i ] ) ;
}
2022-08-30 23:10:52 +03:00
dev_add_wwid ( id , type , ids ) ;
2022-06-06 22:04:20 +03:00
break ;
default :
break ;
}
}
return id_size ;
}
2022-10-25 00:23:36 +03:00
2023-07-13 13:32:44 +03:00
int parse_vpd_serial ( const unsigned char * in , char * out , size_t outsize )
2022-10-25 00:23:36 +03:00
{
2023-07-13 13:32:44 +03:00
uint8_t len_buf [ 2 ] __attribute__ ( ( aligned ( 8 ) ) ) = { 0 } ;
2022-10-25 00:23:36 +03:00
size_t len ;
/* parsing code from multipath tools */
/* ignore in[0] and in[1] */
/* len is in[2] and in[3] */
/* serial begins at in[4] */
len_buf [ 0 ] = in [ 2 ] ;
len_buf [ 1 ] = in [ 3 ] ;
len = len_buf [ 0 ] < < 8 | len_buf [ 1 ] ;
if ( outsize = = 0 )
return 0 ;
if ( len > DEV_WWID_SIZE )
len = DEV_WWID_SIZE ;
/*
* Strip leading and trailing whitespace
*/
while ( len > 0 & & in [ len + 3 ] = = ' ' )
- - len ;
while ( len > 0 & & in [ 4 ] = = ' ' ) {
+ + in ;
- - len ;
}
if ( len > = outsize )
len = outsize - 1 ;
if ( len > 0 ) {
memcpy ( out , in + 4 , len ) ;
out [ len ] = ' \0 ' ;
}
return len ;
}