2017-09-17 15:33:25 +01:00
/*************************************************************************
* Copyright ( C ) 2017 by Andrius Š tikonas < andrius @ stikonas . eu > *
* *
* This program is free software ; you can redistribute it and / or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation ; either version 3 of *
* the License , or ( at your option ) any later version . *
* *
* This program 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 General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program . If not , see < http : //www.gnu.org/licenses/>.*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "plugins/sfdisk/sfdiskpartitiontable.h"
# include "backend/corebackend.h"
# include "backend/corebackendmanager.h"
# include "core/partition.h"
# include "core/device.h"
2018-07-11 03:03:21 +01:00
# include "core/raid/softwareraid.h"
2017-09-17 15:33:25 +01:00
# include "fs/filesystem.h"
# include "util/report.h"
# include "util/externalcommand.h"
# include <QJsonArray>
# include <QJsonDocument>
# include <QJsonObject>
# include <QRegularExpression>
# include <KLocalizedString>
2017-12-07 20:50:54 +00:00
SfdiskPartitionTable : : SfdiskPartitionTable ( const Device * d ) :
2017-09-17 15:33:25 +01:00
CoreBackendPartitionTable ( ) ,
2017-12-07 20:50:54 +00:00
m_device ( d )
2017-09-17 15:33:25 +01:00
{
}
SfdiskPartitionTable : : ~ SfdiskPartitionTable ( )
{
}
bool SfdiskPartitionTable : : open ( )
{
return true ;
}
bool SfdiskPartitionTable : : commit ( quint32 timeout )
{
2018-07-24 07:12:02 +01:00
if ( m_device - > type ( ) = = Device : : Type : : SoftwareRAID_Device )
ExternalCommand ( QStringLiteral ( " udevadm " ) , { QStringLiteral ( " control " ) , QStringLiteral ( " --stop-exec-queue " ) } ) . run ( ) ;
2018-04-13 13:54:51 +01:00
ExternalCommand ( QStringLiteral ( " udevadm " ) , { QStringLiteral ( " settle " ) , QStringLiteral ( " --timeout= " ) + QString : : number ( timeout ) } ) . run ( ) ;
ExternalCommand ( QStringLiteral ( " blockdev " ) , { QStringLiteral ( " --rereadpt " ) , m_device - > deviceNode ( ) } ) . run ( ) ;
ExternalCommand ( QStringLiteral ( " udevadm " ) , { QStringLiteral ( " trigger " ) } ) . run ( ) ;
2017-09-17 15:33:25 +01:00
2018-07-24 07:12:02 +01:00
if ( m_device - > type ( ) = = Device : : Type : : SoftwareRAID_Device )
ExternalCommand ( QStringLiteral ( " udevadm " ) , { QStringLiteral ( " control " ) , QStringLiteral ( " --start-exec-queue " ) } ) . run ( ) ;
2017-09-17 15:33:25 +01:00
return true ;
}
QString SfdiskPartitionTable : : createPartition ( Report & report , const Partition & partition )
{
if ( ! ( partition . roles ( ) . has ( PartitionRole : : Extended ) | | partition . roles ( ) . has ( PartitionRole : : Logical ) | | partition . roles ( ) . has ( PartitionRole : : Primary ) ) ) {
report . line ( ) < < xi18nc ( " @info:progress " , " Unknown partition role for new partition <filename>%1</filename> (roles: %2) " , partition . deviceNode ( ) , partition . roles ( ) . toString ( ) ) ;
return QString ( ) ;
}
2017-12-16 12:55:34 +00:00
QByteArray type = QByteArray ( ) ;
2017-09-17 15:33:25 +01:00
if ( partition . roles ( ) . has ( PartitionRole : : Extended ) )
type = QByteArrayLiteral ( " type=5 " ) ;
// NOTE: at least on GPT partition types "are" partition flags
ExternalCommand createCommand ( report , QStringLiteral ( " sfdisk " ) , { QStringLiteral ( " --force " ) , QStringLiteral ( " --append " ) , partition . devicePath ( ) } ) ;
2017-11-07 22:55:28 +00:00
if ( createCommand . write ( QByteArrayLiteral ( " start= " ) + QByteArray : : number ( partition . firstSector ( ) ) +
2017-09-17 15:33:25 +01:00
type +
2018-07-21 21:19:31 +01:00
QByteArrayLiteral ( " size= " ) + QByteArray : : number ( partition . length ( ) ) + QByteArrayLiteral ( " \n write \n " ) ) & & createCommand . start ( - 1 ) ) {
2018-07-11 23:36:20 +01:00
QRegularExpression re ( QStringLiteral ( " Created a new partition ( \\ d+) " )) ;
2017-09-17 15:33:25 +01:00
QRegularExpressionMatch rem = re . match ( createCommand . output ( ) ) ;
2018-07-11 03:03:21 +01:00
2018-07-11 23:36:20 +01:00
if ( rem . hasMatch ( ) ) {
2018-07-18 23:23:34 +01:00
if ( partition . devicePath ( ) . back ( ) . isDigit ( ) )
2018-07-11 23:36:20 +01:00
return partition . devicePath ( ) + QLatin1Char ( ' p ' ) + rem . captured ( 1 ) ;
else
return partition . devicePath ( ) + rem . captured ( 1 ) ;
}
2017-09-17 15:33:25 +01:00
}
2017-12-07 20:50:54 +00:00
report . line ( ) < < xi18nc ( " @info:progress " , " Failed to add partition <filename>%1</filename> to device <filename>%2</filename>. " , partition . deviceNode ( ) , m_device - > deviceNode ( ) ) ;
2017-09-17 15:33:25 +01:00
return QString ( ) ;
}
bool SfdiskPartitionTable : : deletePartition ( Report & report , const Partition & partition )
{
ExternalCommand deleteCommand ( report , QStringLiteral ( " sfdisk " ) , { QStringLiteral ( " --force " ) , QStringLiteral ( " --delete " ) , partition . devicePath ( ) , QString : : number ( partition . number ( ) ) } ) ;
if ( deleteCommand . run ( - 1 ) & & deleteCommand . exitCode ( ) = = 0 )
return true ;
report . line ( ) < < xi18nc ( " @info:progress " , " Could not delete partition <filename>%1</filename>. " , partition . devicePath ( ) ) ;
return false ;
}
bool SfdiskPartitionTable : : updateGeometry ( Report & report , const Partition & partition , qint64 sectorStart , qint64 sectorEnd )
{
ExternalCommand sfdiskCommand ( report , QStringLiteral ( " sfdisk " ) , { QStringLiteral ( " --force " ) , partition . devicePath ( ) , QStringLiteral ( " -N " ) , QString : : number ( partition . number ( ) ) } ) ;
2017-11-07 22:55:28 +00:00
if ( sfdiskCommand . write ( QByteArrayLiteral ( " start= " ) + QByteArray : : number ( sectorStart ) +
2017-09-17 15:33:25 +01:00
QByteArrayLiteral ( " size= " ) + QByteArray : : number ( sectorEnd - sectorStart + 1 ) +
QByteArrayLiteral ( " \n Y \n " ) )
2018-07-21 21:19:31 +01:00
& & sfdiskCommand . start ( - 1 ) & & sfdiskCommand . exitCode ( ) = = 0 ) {
2017-09-17 15:33:25 +01:00
return true ;
}
report . line ( ) < < xi18nc ( " @info:progress " , " Could not set geometry for partition <filename>%1</filename> while trying to resize/move it. " , partition . devicePath ( ) ) ;
return false ;
}
bool SfdiskPartitionTable : : clobberFileSystem ( Report & report , const Partition & partition )
{
ExternalCommand wipeCommand ( report , QStringLiteral ( " wipefs " ) , { QStringLiteral ( " --all " ) , partition . partitionPath ( ) } ) ;
if ( wipeCommand . run ( - 1 ) & & wipeCommand . exitCode ( ) = = 0 )
return true ;
report . line ( ) < < xi18nc ( " @info:progress " , " Failed to erase filesystem signature on partition <filename>%1</filename>. " , partition . partitionPath ( ) ) ;
return false ;
}
bool SfdiskPartitionTable : : resizeFileSystem ( Report & report , const Partition & partition , qint64 newLength )
{
// sfdisk does not have any partition resize capabilities
2017-11-07 22:55:28 +00:00
Q_UNUSED ( report )
Q_UNUSED ( partition )
Q_UNUSED ( newLength )
2017-09-17 15:33:25 +01:00
return false ;
}
FileSystem : : Type SfdiskPartitionTable : : detectFileSystemBySector ( Report & report , const Device & device , qint64 sector )
{
2018-04-07 19:54:30 +01:00
FileSystem : : Type type = FileSystem : : Type : : Unknown ;
2017-09-17 15:33:25 +01:00
ExternalCommand jsonCommand ( QStringLiteral ( " sfdisk " ) , { QStringLiteral ( " --json " ) , device . deviceNode ( ) } ) ;
if ( jsonCommand . run ( - 1 ) & & jsonCommand . exitCode ( ) = = 0 ) {
2017-12-04 21:18:37 +00:00
const QJsonArray partitionTable = QJsonDocument : : fromJson ( jsonCommand . rawOutput ( ) ) . object ( ) [ QLatin1String ( " partitiontable " ) ] . toObject ( ) [ QLatin1String ( " partitions " ) ] . toArray ( ) ;
2017-09-17 15:33:25 +01:00
for ( const auto & partition : partitionTable ) {
const QJsonObject partitionObject = partition . toObject ( ) ;
const qint64 start = partitionObject [ QLatin1String ( " start " ) ] . toVariant ( ) . toLongLong ( ) ;
if ( start = = sector ) {
const QString deviceNode = partitionObject [ QLatin1String ( " node " ) ] . toString ( ) ;
type = CoreBackendManager : : self ( ) - > backend ( ) - > detectFileSystem ( deviceNode ) ;
return type ;
}
}
}
report . line ( ) < < xi18nc ( " @info:progress " , " Could not determine file system of partition at sector %1 on device <filename>%2</filename>. " , sector , device . deviceNode ( ) ) ;
return type ;
}
2017-12-07 23:24:03 +00:00
static struct {
FileSystem : : Type type ;
QLatin1String partitionType [ 2 ] ; // GPT, MBR
} typemap [ ] = {
2018-04-07 19:54:30 +01:00
{ FileSystem : : Type : : Btrfs , { QLatin1String ( " 0FC63DAF-8483-4772-8E79-3D69D8477DE4 " ) , QLatin1String ( " 83 " ) } } ,
{ FileSystem : : Type : : Ext2 , { QLatin1String ( " 0FC63DAF-8483-4772-8E79-3D69D8477DE4 " ) , QLatin1String ( " 83 " ) } } ,
{ FileSystem : : Type : : Ext3 , { QLatin1String ( " 0FC63DAF-8483-4772-8E79-3D69D8477DE4 " ) , QLatin1String ( " 83 " ) } } ,
{ FileSystem : : Type : : Ext4 , { QLatin1String ( " 0FC63DAF-8483-4772-8E79-3D69D8477DE4 " ) , QLatin1String ( " 83 " ) } } ,
{ FileSystem : : Type : : LinuxSwap , { QLatin1String ( " 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F " ) , QLatin1String ( " 82 " ) } } ,
{ FileSystem : : Type : : Fat12 , { QLatin1String ( " EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 " ) , QLatin1String ( " 6 " ) } } ,
{ FileSystem : : Type : : Fat16 , { QLatin1String ( " EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 " ) , QLatin1String ( " 6 " ) } } ,
{ FileSystem : : Type : : Fat32 , { QLatin1String ( " EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 " ) , QLatin1String ( " 7 " ) } } ,
{ FileSystem : : Type : : Nilfs2 , { QLatin1String ( " 0FC63DAF-8483-4772-8E79-3D69D8477DE4 " ) , QLatin1String ( " 83 " ) } } ,
{ FileSystem : : Type : : Ntfs , { QLatin1String ( " EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 " ) , QLatin1String ( " 7 " ) } } ,
{ FileSystem : : Type : : Exfat , { QLatin1String ( " EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 " ) , QLatin1String ( " 7 " ) } } ,
{ FileSystem : : Type : : ReiserFS , { QLatin1String ( " 0FC63DAF-8483-4772-8E79-3D69D8477DE4 " ) , QLatin1String ( " 83 " ) } } ,
{ FileSystem : : Type : : Reiser4 , { QLatin1String ( " 0FC63DAF-8483-4772-8E79-3D69D8477DE4 " ) , QLatin1String ( " 83 " ) } } ,
{ FileSystem : : Type : : Xfs , { QLatin1String ( " 0FC63DAF-8483-4772-8E79-3D69D8477DE4 " ) , QLatin1String ( " 83 " ) } } ,
{ FileSystem : : Type : : Jfs , { QLatin1String ( " 0FC63DAF-8483-4772-8E79-3D69D8477DE4 " ) , QLatin1String ( " 83 " ) } } ,
{ FileSystem : : Type : : Hfs , { QLatin1String ( " 48465300-0000-11AA-AA11-00306543ECAC " ) , QLatin1String ( " af " ) } } ,
{ FileSystem : : Type : : HfsPlus , { QLatin1String ( " 48465300-0000-11AA-AA11-00306543ECAC " ) , QLatin1String ( " af " ) } } ,
{ FileSystem : : Type : : Udf , { QLatin1String ( " EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 " ) , QLatin1String ( " 7 " ) } }
2017-12-07 23:24:03 +00:00
// Add ZFS too
} ;
static QLatin1String getPartitionType ( FileSystem : : Type t , PartitionTable : : TableType tableType )
2017-09-17 15:33:25 +01:00
{
2017-12-07 23:24:03 +00:00
quint8 type ;
switch ( tableType ) {
2018-09-01 18:40:10 +01:00
case PartitionTable : : TableType : : gpt :
2017-12-07 23:24:03 +00:00
type = 0 ;
break ;
2018-09-01 18:40:10 +01:00
case PartitionTable : : TableType : : msdos :
case PartitionTable : : TableType : : msdos_sectorbased :
2017-12-07 23:24:03 +00:00
type = 1 ;
break ;
default : ;
2018-01-31 14:58:43 +00:00
return QLatin1String ( ) ;
2017-12-07 23:24:03 +00:00
}
for ( quint32 i = 0 ; i < sizeof ( typemap ) / sizeof ( typemap [ 0 ] ) ; i + + )
if ( typemap [ i ] . type = = t )
return typemap [ i ] . partitionType [ type ] ;
2017-11-07 22:55:28 +00:00
2017-12-07 23:24:03 +00:00
return QLatin1String ( ) ;
}
bool SfdiskPartitionTable : : setPartitionSystemType ( Report & report , const Partition & partition )
{
2017-12-09 19:19:36 +00:00
QString partitionType = getPartitionType ( partition . fileSystem ( ) . type ( ) , m_device - > partitionTable ( ) - > type ( ) ) ;
if ( partitionType . isEmpty ( ) )
return true ;
2017-12-07 23:24:03 +00:00
ExternalCommand sfdiskCommand ( report , QStringLiteral ( " sfdisk " ) , { QStringLiteral ( " --part-type " ) , m_device - > deviceNode ( ) , QString : : number ( partition . number ( ) ) ,
2017-12-09 19:19:36 +00:00
partitionType } ) ;
2017-12-07 23:24:03 +00:00
return sfdiskCommand . run ( - 1 ) & & sfdiskCommand . exitCode ( ) = = 0 ;
2017-11-07 22:55:28 +00:00
}
2017-11-08 00:01:24 +00:00
bool SfdiskPartitionTable : : setFlag ( Report & report , const Partition & partition , PartitionTable : : Flag flag , bool state )
2017-11-07 22:55:28 +00:00
{
2018-09-01 21:27:05 +01:00
if ( m_device - > partitionTable ( ) - > type ( ) = = PartitionTable : : TableType : : msdos | |
m_device - > partitionTable ( ) - > type ( ) = = PartitionTable : : TableType : : msdos_sectorbased ) {
// We only allow setting one active partition per device
if ( flag = = PartitionTable : : Flag : : FlagBoot & & state = = true ) {
ExternalCommand sfdiskCommand ( report , QStringLiteral ( " sfdisk " ) , { QStringLiteral ( " --activate " ) , m_device - > deviceNode ( ) , QString : : number ( partition . number ( ) ) } ) ;
if ( sfdiskCommand . run ( - 1 ) & & sfdiskCommand . exitCode ( ) = = 0 )
return true ;
else
return false ;
} else if ( flag = = PartitionTable : : Flag : : FlagBoot & & state = = false ) {
ExternalCommand sfdiskCommand ( report , QStringLiteral ( " sfdisk " ) , { QStringLiteral ( " --activate " ) , m_device - > deviceNode ( ) , QStringLiteral ( " - " ) } ) ;
if ( sfdiskCommand . run ( - 1 ) & & sfdiskCommand . exitCode ( ) = = 0 )
return true ;
else
return false ;
}
2017-11-08 00:01:24 +00:00
}
2018-09-01 21:27:05 +01:00
if ( flag = = PartitionTable : : Flag : : FlagBoot & & state = = true ) {
2017-12-07 20:50:54 +00:00
ExternalCommand sfdiskCommand ( report , QStringLiteral ( " sfdisk " ) , { QStringLiteral ( " --part-type " ) , m_device - > deviceNode ( ) , QString : : number ( partition . number ( ) ) ,
2017-11-08 00:01:24 +00:00
QStringLiteral ( " C12A7328-F81F-11D2-BA4B-00A0C93EC93B " ) } ) ;
if ( sfdiskCommand . run ( - 1 ) & & sfdiskCommand . exitCode ( ) = = 0 )
return true ;
else
return false ;
}
2018-09-01 21:27:05 +01:00
if ( flag = = PartitionTable : : Flag : : FlagBoot & & state = = false )
2017-11-08 00:01:24 +00:00
setPartitionSystemType ( report , partition ) ;
2018-09-01 18:40:10 +01:00
if ( flag = = PartitionTable : : Flag : : FlagBiosGrub & & state = = true ) {
2017-12-07 20:50:54 +00:00
ExternalCommand sfdiskCommand ( report , QStringLiteral ( " sfdisk " ) , { QStringLiteral ( " --part-type " ) , m_device - > deviceNode ( ) , QString : : number ( partition . number ( ) ) ,
2017-11-08 00:01:24 +00:00
QStringLiteral ( " 21686148-6449-6E6F-744E-656564454649 " ) } ) ;
if ( sfdiskCommand . run ( - 1 ) & & sfdiskCommand . exitCode ( ) = = 0 )
return true ;
else
return false ;
}
2018-09-01 18:40:10 +01:00
if ( flag = = PartitionTable : : Flag : : FlagBiosGrub & & state = = false )
2017-11-08 00:01:24 +00:00
setPartitionSystemType ( report , partition ) ;
2017-09-17 15:33:25 +01:00
return true ;
}