/**************************************************************************** * * * Copyright 2004-2011 NetApp Inc. All rights reserved. This file is * * confidential and a trade secret of NetApp Inc. The receipt or * * possession of this file does not convey any rights to reproduce or * * disclose its contents or to manufacture, use, or sell anything it may * * describe, in whole, or in part, without the specific written consent of * * NetApp Inc. * * * ****************************************************************************/ /**************************************************************************** * * * NAME hddLib.c * * SUMMARY * * VERSION %version: % * * UPDATE DATE %date_modified: % * * PROGRAMMER %created_by: Merck Hung % * * * * Copyright 2002-2011 NetApp Inc. All Rights Reserved. * * * * DESCRIPTION: * * * ****************************************************************************/ #include #include #include #include #include #include #include #include #include "hddMgr.h" static unsigned char ebbet_b[] = { 2 , 30, 29, 28, 6 , 1 , 0 , 31, 7 , 5 , 4 , 3 }; static unsigned char ebbet_a[] = { 7 , 6 , 1 , 28, 5 , 4 , 0 , 29, 3 , 2 , 31, 30 }; static unsigned char joshua_b[] = { 2 , 3 , 28, 29, 5 , 4 , 31, 30, 7 , 6 , 1 , 0 }; static unsigned char joshua_a[] = { 6 , 7 , 1 , 28, 4 , 5 , 0 , 29, 3 , 2 , 31, 30 }; static unsigned char camden_b[] = { 2, 3, 4, 7, 6, 5, 1, 0, 31, 28, 29, 30, 39, 38, 37, 36, 35, 34, 33, 32, 27, 26, 24, 25 }; static unsigned char camden_a[] = { 7, 6, 5, 4, 3, 2, 1, 0, 38, 39, 28, 29, 35, 31, 30, 36, 34, 37, 33, 25, 24, 26, 27, 32 }; static unsigned char alder_b[] = { 7, 6, 5, 4, 3, 2, 1, 0, 31, 30, 29, 28, 34, 35, 36, 37, 38, 39, 33, 32, 27, 26, 25, 24 }; static unsigned char alder_a[] = { 7, 6, 5, 4, 3, 2, 34, 35, 36, 37, 38, 39, 1, 0, 31, 30, 29, 28, 33, 32, 27, 26, 25, 24 }; static unsigned char wsas_a[] = { // Drawer #1 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, // Drawer #4 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // Drawer #2 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Drawer #5 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // Drawer #3 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, }; static unsigned char wsas_b[] = { // Drawer #2 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Drawer #5 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // Drawer #1 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, // Drawer #4 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // Drawer #3 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, }; //For Trafford static unsigned char tsas_a[] = { // Drawer #1 4, 0, 7, 11, 3, 6, 10, 9, 8, 5, 2, 1, // Drawer #4 40, 36, 43, 47, 39, 42, 46, 45, 44, 41, 38, 37, // Drawer #2 16, 12, 19, 23, 15, 18, 22, 21, 20, 17, 14, 13, // Drawer #5 52, 48, 55, 59, 51, 54, 58, 57, 56, 53, 50, 49, // Drawer #3 28, 24, 31, 35, 27, 30, 34, 33, 32, 29, 26, 25, }; static unsigned char tsas_b[] = { // Drawer #2 22, 17, 20, 23, 12, 13, 15, 18, 16, 14, 21, 19, // Drawer #5 58, 53, 56, 59, 48, 49, 51, 54, 52, 50, 57, 55, // Drawer #1 10, 5, 8, 11, 0, 1, 3, 6, 4, 2, 9, 7, // Drawer #4 46, 41, 44, 47, 36, 37, 39, 42, 40, 38, 45, 43, // Drawer #3 34, 29, 32, 35, 24, 25, 27, 30, 28, 26, 33, 31, }; static enclosure_t enclosureTbl[] = { { ENCLOSURE_EBBETS, 12, { [ CTL_SLOT_A ] = ebbet_a, [ CTL_SLOT_B ] = ebbet_b, }, }, { ENCLOSURE_JOSHUA, 12, { [ CTL_SLOT_A ] = joshua_a, [ CTL_SLOT_B ] = joshua_b, }, }, { ENCLOSURE_CAMDEN, 24, { [ CTL_SLOT_A ] = camden_a, [ CTL_SLOT_B ] = camden_b, }, }, { ENCLOSURE_ALDER, 24, { [ CTL_SLOT_A ] = alder_a, [ CTL_SLOT_B ] = alder_b, }, }, { ENCLOSURE_WSAS, 60, { [ CTL_SLOT_A ] = wsas_a, [ CTL_SLOT_B ] = wsas_b, }, }, { ENCLOSURE_TSAS, 60, { [ CTL_SLOT_A ] = tsas_a, [ CTL_SLOT_B ] = tsas_b, }, }, }; int findCtlSlot( void ) { FILE *diag_env = NULL; char in_value[25]; int type = -1; if ( (diag_env = fopen( DIAG_ENV_FILE, "r")) == NULL ) // Can't open diag_env file { printf("Can not open diag_env file to get ctl slot\n"); } while (fgets(in_value, sizeof(in_value), diag_env )) { if ( strstr(in_value, "CTLR_SLOT") != NULL ) // Parse CTLR_SLOT=xxx to get chassis type { if ( strstr(in_value, "0") != NULL ) type = CTL_SLOT_A; else type = CTL_SLOT_B; break; } } if ( diag_env ) fclose( diag_env ); return type; } int findEnclosure( void ) { int type = -1; FILE *diag_env = NULL; char in_value[25]; if ( (diag_env = fopen( DIAG_ENV_FILE, "r")) == NULL ) // Can't open diag_env file { printf("Can not open diag_env file to get chassis type\n"); } while (fgets(in_value, sizeof(in_value), diag_env )) { if ( strstr(in_value, "MIDPLANE_TYPE") != NULL ) // Parse MIDPLANE_TYPE=xxx to get chassis type { if ( strstr(in_value, "Alder") != NULL ) type = ENCLOSURE_ALDER; else if ( strstr(in_value, "Camden") != NULL ) type = ENCLOSURE_CAMDEN; else if ( strstr(in_value, "Ebbets") != NULL ) type = ENCLOSURE_EBBETS; else if ( strstr(in_value, "Joshua") != NULL ) type = ENCLOSURE_JOSHUA; else if ( strstr(in_value, "TestMP") != NULL ) type = ENCLOSURE_TESTMP; else if ( strstr(in_value, "Trafford") != NULL ) type = ENCLOSURE_TSAS; else if ( strstr(in_value, "Wembley") != NULL ) type = ENCLOSURE_WSAS; else type = ENCLOSURE_UNKNOWN; break; } } if ( diag_env ) fclose( diag_env ); return type; } int findHicType( void ) { int fd; char val = 0; fd = open( CTL_HICTYPE_PATH, O_RDONLY ); if( fd < 0 ) return fd; if( read( fd, &val, 1 ) <= 0 ) { close( fd ); return -1; } close( fd ); switch( val ) { case '4': return HOST_CARD_SAS; case '3': return HOST_CARD_IB; case '2': return HOST_CARD_ISCSI; case '1': return HOST_CARD_FC; case '0': return HOST_CARD_NONE; } return -1; } int findHicId( void ) { int fd; char val[10]; fd = open( CTL_HIC_ID_PATH, O_RDONLY ); if( fd < 0 ) return fd; if( read( fd, &val, 4 ) <= 0 ) { close( fd ); return -1; } close( fd ); return strtol(val, NULL, 0); } int findWsasDrvByExpAndPhy( unsigned int slot, unsigned int expNo, unsigned int phyNo ) { unsigned char *p = NULL; int i; if( slot != CTL_SLOT_A && slot != CTL_SLOT_B ) return -1; if( expNo >= MAX_DCM_EXP_NUM || phyNo >= MAX_DCM_PHY_NUM ) return -1; for( i = 0; i < ARRAY_SIZE( enclosureTbl ); i++) { if( enclosureTbl[ i ].enclosureId == ENCLOSURE_WSAS ) { p = (enclosureTbl[ i ]).sasDrvPhyMap[ slot ]; break; } } return (int)*(p + (expNo * MAX_DCM_PHY_NUM) + phyNo); } int findTsasDrvByExpAndPhy( unsigned int slot, unsigned int expNo, unsigned int phyNo ) { unsigned char *p = NULL; int i; if( slot != CTL_SLOT_A && slot != CTL_SLOT_B ) return -1; // if( expNo >= MAX_DCM_EXP_NUM || phyNo >= MAX_DCM_PHY_NUM ) if( expNo >= MAX_DCM_EXP_NUM || phyNo >= 24 ) //Jim return -1; for( i = 0; i < ARRAY_SIZE( enclosureTbl ); i++) { if( enclosureTbl[ i ].enclosureId == ENCLOSURE_TSAS) { p = (enclosureTbl[ i ]).sasDrvPhyMap[ slot ]; break; } } //Jim, for Trafford P2 drawer mapping. //DCM A uses phy 0~3, 8~11, 20~23 //DCM B uses phy 0~3, 12~15, 20~23 if( phyNo >= 8 && phyNo < 12 ){ //for TOP controller phyNo -= 4; } else if( phyNo >= 12 && phyNo < 16 ){ //for Bottom controller phyNo -= 8; } else if( phyNo >= 20 ){ phyNo -= 12; } //printf("[Jim] p: %d, DrvSeqNo: %d \n", *p, phyNo); return (int)*(p + (expNo * MAX_DCM_PHY_NUM) + phyNo); } int findSasDrvByPhy( unsigned int enclosureId, unsigned int slot, unsigned int phyNum ) { unsigned char *p = NULL; int i,j; if( enclosureId >= ARRAY_SIZE( enclosureTbl ) ) return -1; if( slot != CTL_SLOT_A && slot != CTL_SLOT_B ) return -1; for( i = 0; i < ARRAY_SIZE( enclosureTbl ); i++) { if( enclosureTbl[ i ].enclosureId == enclosureId) { p = (enclosureTbl[ i ]).sasDrvPhyMap[ slot ]; break; } } if( p == NULL) return -1; for( j = 0 ; j < (enclosureTbl[ i ]).numOfHardDrive ; j++ ) { if( phyNum == p[ j ] ) return j; } return -1; } int testFile( char *file ) { int fd, ret = 0; fd = open( file, O_RDONLY ); if( fd < 0 ) ret = fd; close( fd ); return ret; } int obtainMajorMinorNo( char *file, int *major, int *minor ) { int fd, ret = 0, r; char buf[ 40 ], *p; // Open file fd = open( file, O_RDONLY ); if( fd < 0 ) return fd; // "?:?", at least >= 3 r = read( fd, buf, sizeof( buf ) ); if( r < 3 ) { ret = -1; goto ErrExit; } // Parse p = index( buf, ':' ); if( !p ) { ret = -1; goto ErrExit; } // Truncate *p = 0; p++; // Return Major & Minor numbers *major = atoi( buf ); *minor = atoi( p ); ErrExit: close( fd ); return ret; } int findSasIocNo( char *p ) { // "sas?disk?" if( strlen( p ) < 9 ) return -1; // Check prefix string if( strncmp( p, HDD_PREFIX_SAS, strlen( HDD_PREFIX_SAS ) ) ) return -1; return atoi( p + 3 ); } void removeOldHddNodesByIoc(int sas0_local, int sas0_remote, int sas1_port0, int sas1_port1) { char path[ MAX_BUF_SIZE ]; int ioc, num; if (sas0_local) for( num = 0 ; num < MAX_HDD_NUM ; num++ ) { // SAS snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s%d%s%d_local", HDD_PREFIX_SAS, ioc, HDD_SUFFIX_SYS, num); // Delete any way unlink( path ); } if (sas0_remote) for( num = 0 ; num < MAX_HDD_NUM ; num++ ) { // SAS snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s%d%s%d_reomte", HDD_PREFIX_SAS, ioc, HDD_SUFFIX_SYS, num); // Delete any way unlink( path ); } if (sas1_port0) for( num = 0 ; num < MAX_HDD_NUM ; num++ ) { // SAS snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s%d%s%d_p0", HDD_PREFIX_SAS, ioc, HDD_SUFFIX_SYS, num); // Delete any way unlink( path ); } if (sas1_port1) for( num = 0 ; num < MAX_HDD_NUM ; num++ ) { // SAS snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s%d%s%d_p1", HDD_PREFIX_SAS, ioc, HDD_SUFFIX_SYS, num); // Delete any way unlink( path ); } for( ioc = 0 ; ioc < MAX_SAS_NUM ; ioc++ ) for( num = 0 ; num < MAX_HDD_NUM ; num++ ) { // RAMDISK snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s%d%s%d", HDD_PREFIX_RAM, ioc, HDD_SUFFIX, num ); // Delete any way unlink( path ); } } void removeOldHddNodes( void ) { char path[ MAX_BUF_SIZE ]; int ioc, num; for( ioc = 0 ; ioc < MAX_SAS_NUM ; ioc++ ) for( num = 0 ; num < MAX_HDD_NUM ; num++ ) { // SAS snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s%d%s%d", HDD_PREFIX_SAS, ioc, HDD_SUFFIX_SYS, num); // Delete any way unlink( path ); // RAMDISK snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s%d%s%d", HDD_PREFIX_RAM, ioc, HDD_SUFFIX, num ); // Delete any way unlink( path ); } } int getOrderNumOfExp( char *path, int ch1, int ch2 ) { DIR *top; struct dirent *dir; int chk1, chk2; int order = -1; // Open the top directory top = opendir( path ); if( !top ) return -1; for( dir = readdir( top ) ; dir ; dir = readdir( top ) ) { // Skip "." & ".." if( !strcmp( dir->d_name, "." ) || !strcmp( dir->d_name, ".." ) ) continue; // Get CH & ID sscanf( dir->d_name, EXPANDER_PREFIX "%d:%d", &chk1, &chk2 ); if( chk1 == ch1 ) order++; if( chk1 == ch1 && chk2 == ch2 ) { closedir( top ); return order; } } closedir( top ); return -1; } int writeDriveMap( unsigned int value ) { int fd, ret = 0; char buf[ 9 ]; // Open Drive Map fd = open( CTL_DRVMAP_PATH, O_WRONLY ); if( fd < 0 ) return fd; // Prepare the buffer snprintf( buf, sizeof( buf ), "%X", value ); if( write( fd, buf, strlen( buf ) ) != strlen( buf ) ) ret = -1; // Close close( fd ); // Return return ret; } int writeSasCtlMap( int exp_phy8_11, int exp_phy12_15, int exp_phy16_19, int exp_phy20_23 ) { int fd, ret = 0, val = 0; char buf[ 9 ]; // Open Drive Map fd = open( CTL_SASMAP_PATH, O_WRONLY ); if( fd < 0 ) return fd; if( exp_phy8_11 ) val |= 0xF00; if( exp_phy12_15 ) val |= 0xF000; if( exp_phy16_19 ) val |= 0xF0000; if( exp_phy20_23 ) val |= 0xF00000; // Prepare the buffer snprintf( buf, sizeof( buf ), "%X", val ); if( write( fd, buf, strlen( buf ) ) != strlen( buf ) ) ret = -1; // Close close( fd ); // Return return ret; } int delayForAllHddPresent( unsigned int encl, int sas0_local, int sas0_remote, int sas1_port0, int sas1_port1 ) { unsigned int numHdd; char path[ MAX_BUF_SIZE ]; int ioc, num, multiple = 0, lost = 0, i; // Sanity check if( encl != ENCLOSURE_EBBETS && encl != ENCLOSURE_CAMDEN && encl != ENCLOSURE_WSAS ) return -1; // Obtain the number of HDD numHdd = (enclosureTbl[ encl ]).numOfHardDrive; printf("Waiting for all HDDs being presented...!\n"); // Special delay for WSAS if( encl == ENCLOSURE_WSAS ) sleep( 8 ); else sleep( 5 ); if( sas0_local && sas0_remote && sas1_port0 && sas1_port1) sleep( 5 ); // Retry count for( i = 60 ; i ; i-- ) { lost = 0; multiple = sas0_local + sas0_remote; ioc = 0; for( num = 0 ; num < numHdd * multiple ; num++ ) { // SAS snprintf( path, MAX_BUF_SIZE, "/sys/block/%s%d%s%d/dev", HDD_PREFIX_SAS, ioc, HDD_SUFFIX, num ); // Check for present if( testFile( path ) < 0 ) lost = 1; } ioc = 1; multiple = sas1_port0 + sas1_port1; for( num = 0 ; num < numHdd * multiple ; num++ ) { // SAS snprintf( path, MAX_BUF_SIZE, "/sys/block/%s%d%s%d/dev", HDD_PREFIX_SAS, ioc, HDD_SUFFIX, num ); // Check for present if( testFile( path ) < 0 ) lost = 1; } if( lost ) sleep( 1 ); } return lost; } #if 0 int findSasNum( hostNo, hicType ) { char *tbl; int cell; if( hicType == HOST_CARD_SAS ) { tbl = hostNoMatchWithHicTbl; cell = cellHostNoMatchWithHicTbl; } else { tbl = hostNoMatchWithoutHicTbl; cell = cellHostNoMatchWithoutHicTbl; } // Check range if( hostNo >= cell ) return -1; return tbl[ hostNo ]; } int newCreateHddNodes( int sas0, int sas1, int sas2 ) { sasPhyAttr_t devNode, *pDevNode; char path[ MAX_BUF_SIZE ]; struct dirent *dir; DIR *top, *testdir; int slot, encl, hic, cnt; // Obtain info of Ctl slot slot = findCtlSlot(); encl = findEnclosure(); hic = findHicType(); if( slot != CTL_SLOT_A && slot != CTL_SLOT_B ) { if( !silent || verbose ) fprintf( stderr, "Internal error: slot = %d\n", slot ); return -1; } if( encl != ENCLOSURE_EBBETS && encl != ENCLOSURE_CAMDEN && encl != ENCLOSURE_WSAS ) { if( !silent || verbose ) fprintf( stderr, "Internal error: enclosure = %d\n", encl ); return -1; } // Open the top directory top = opendir( SASPHY_PATH ); if( !top ) return -1; // Walk through SAS PHY class for( dir = readdir( top ) ; dir ; dir = readdir( top ) ) { // Omit "." & ".." if( !strcmp( dir->d_name, "." ) || !strcmp( dir->d_name, ".." ) ) continue; // Clear Buffer memset( &devNode, 0, sizeof( sasPhyAttr_t ) ); strncpy( devNode.phyName, dir->d_name, MAX_BLKNAME_SIZE ); // "phy-?:?" if( sscanf( dir->d_name, PHY_PREFIX "%d:%d:%d", &devNode.hostNo, &devNode.tgtNo, &devNode.numNo ) == 3 ) { // EXP or EXPDCM devNode.phyType = SASPHY_TYPE_EXPDCM; devNode.sasNo = findSasNum( devNode.hostNo, hic ); // Test for EXP type snprintf( path, MAX_BUF_SIZE, SASPHY_PATH "/" PHY_PREFIX "%d:%d:37", devNode.hostNo, devNode.tgtNo ); testdir = opendir( path ); if( testdir ) { devNode.phyType = SASPHY_TYPE_EXP; closedir( testdir ); } // Handle SAS0 remote path if( devNode.sasNo == SCSI_HOST_SAS0 ) if( slot == CTL_SLOT_A ) slot = CTL_SLOT_B; else slot = CTL_SLOT_A; if( devNode.phyType == SASPHY_TYPE_EXP && encl != ENCLOSURE_WSAS ) { // CAMDEN & EBBETS // Find out slot number devNode.slotNo = findSasDrvByPhy( encl, slot, devNode.numNo ); } else if ( devNode.phyType == SASPHY_TYPE_EXPDCM && encl == ENCLOSURE_WSAS ) { // WSAS60 // Find out slot number cnt = getOrderNumOfExp( EXPANDER_PATH, devNode.hostNo, devNode.tgtNo ); devNode.slotNo = findWsasDrvByExpAndPhy( slot, cnt - 1, devNode.numNo ); if( devNode.slotNo < 0 ) continue; printf( "SAS %d SLOT %d\n", devNode.sasNo, devNode.slotNo ); } } else if( sscanf( dir->d_name, PHY_PREFIX "%d:%d", &devNode.hostNo, &devNode.numNo ) == 2 ) { // IOC PHY //printf( "IOC PHY: %s\n", dir->d_name ); devNode.phyType = SASPHY_TYPE_IOC; devNode.sasNo = findSasNum( devNode.hostNo, hic ); } else { printf( "Unknown PHY name : %s\n", dir->d_name ); continue; } } // Close the top directory closedir( top ); return 0; } #endif int createRamdiskNodes( void ) { char path[ MAX_BUF_SIZE ]; int major, minor; DIR *top; struct dirent *dir; // Open the top directory top = opendir( BLOCK_DEV_PATH ); if( !top ) return -1; // Scan all block devices for( dir = readdir( top ) ; dir ; dir = readdir( top ) ) { // Skip "." & "..", and length < 9 (ram?disk?) if( !strcmp( dir->d_name, "." ) || !strcmp( dir->d_name, ".." ) || strlen( dir->d_name ) < 9 ) continue; // Start with "ram" if( strncmp( dir->d_name, HDD_PREFIX_RAM, strlen( HDD_PREFIX_RAM ) ) || strncmp( dir->d_name + 4, HDD_SUFFIX, strlen( HDD_SUFFIX ) ) ) continue; // Obtain major & minor numbers snprintf( path, sizeof( path ), BLOCK_DEV_PATH "/%s/dev", dir->d_name ); if( obtainMajorMinorNo( path, &major, &minor ) ) continue; // Make device node snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s", dir->d_name ); unlink( path ); mknod( path, S_IFBLK | 0660, makedev( major, minor ) ); } // Close the folder closedir( top ); return 0; } int createSataNodes( void ) { char path[ MAX_BUF_SIZE ]; int major, minor; DIR *top; struct dirent *dir; // Open the top directory top = opendir( BLOCK_DEV_PATH ); if( !top ) return -1; // Scan all block devices for( dir = readdir( top ) ; dir ; dir = readdir( top ) ) { // Skip "." & "..", and length < 9 (satadisk?) if( !strcmp( dir->d_name, "." ) || !strcmp( dir->d_name, ".." ) || strlen( dir->d_name ) < 9 ) continue; // Start with "satadisk" if( strncmp( dir->d_name, HDD_PREFIX_SATA HDD_SUFFIX , strlen( HDD_PREFIX_SATA HDD_SUFFIX ) ) ) continue; // Obtain major & minor numbers snprintf( path, sizeof( path ), BLOCK_DEV_PATH "/%s/dev", dir->d_name ); if( obtainMajorMinorNo( path, &major, &minor ) ) continue; // Make device node snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s", dir->d_name ); unlink( path ); mknod( path, S_IFBLK | 0660, makedev( major, minor ) ); } // Close the folder closedir( top ); return 0; } int createUsbNodes( void ) { char path[ MAX_BUF_SIZE ]; int major, minor; DIR *top; struct dirent *dir; // Open the top directory top = opendir( BLOCK_DEV_PATH ); if( !top ) return -1; // Scan all block devices for( dir = readdir( top ) ; dir ; dir = readdir( top ) ) { // Skip "." & "..", and length < 8 (usbdisk?) if( !strcmp( dir->d_name, "." ) || !strcmp( dir->d_name, ".." ) || strlen( dir->d_name ) < 8 ) continue; // Start with "satadisk" if( strncmp( dir->d_name, HDD_PREFIX_USB HDD_SUFFIX , strlen( HDD_PREFIX_USB HDD_SUFFIX ) ) ) continue; // Obtain major & minor numbers snprintf( path, sizeof( path ), BLOCK_DEV_PATH "/%s/dev", dir->d_name ); if( obtainMajorMinorNo( path, &major, &minor ) ) continue; // Make device node snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%s", dir->d_name ); unlink( path ); mknod( path, S_IFBLK | 0660, makedev( major, minor ) ); // Make device node of first partition snprintf( path, MAX_BUF_SIZE, DEV_BASE_PATH "/%sp1", dir->d_name ); unlink( path ); mknod( path, S_IFBLK | 0660, makedev( major, minor + 1 ) ); } // Close the folder closedir( top ); return 0; } char *readFileToNewBuffer( const char *basePath ) { int fd, len; char *p = NULL, path[ MAX_BUF_SIZE ]; // Open the file fd = open( basePath, O_RDONLY ); if( fd < 0 ) return NULL; // Read result len = read( fd, path, MAX_BUF_SIZE ); if( len <= 0 ) goto ErrExit; path[ len ] = 0; // Strip '\n' if( path[ len - 1 ] == '\n' ) { path[ len - 1 ] = 0; len--; } // Allocate a buffer p = malloc( len + 1 ); if( !p ) goto ErrExit; // Copy the string strncpy( p, path, len + 1 ); ErrExit: // Close close( fd ); return p; }