Merge branch 'move-permissions' into calamares
This commit is contained in:
commit
92938f63f8
@ -76,6 +76,7 @@ set( libSources
|
|||||||
utils/Dirs.cpp
|
utils/Dirs.cpp
|
||||||
utils/Entropy.cpp
|
utils/Entropy.cpp
|
||||||
utils/Logger.cpp
|
utils/Logger.cpp
|
||||||
|
utils/Permissions.cpp
|
||||||
utils/PluginFactory.cpp
|
utils/PluginFactory.cpp
|
||||||
utils/Retranslator.cpp
|
utils/Retranslator.cpp
|
||||||
utils/String.cpp
|
utils/String.cpp
|
||||||
|
124
src/libcalamares/utils/Permissions.cpp
Normal file
124
src/libcalamares/utils/Permissions.cpp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2018 Scott Harvey <scott@spharvey.me>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* License-Filename: LICENSE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Permissions.h"
|
||||||
|
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
namespace CalamaresUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
Permissions::Permissions()
|
||||||
|
: m_username()
|
||||||
|
, m_group()
|
||||||
|
, m_value( 0 )
|
||||||
|
, m_valid( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Permissions::Permissions( QString const& p )
|
||||||
|
: Permissions()
|
||||||
|
{
|
||||||
|
parsePermissions( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Permissions::parsePermissions( QString const& p )
|
||||||
|
{
|
||||||
|
|
||||||
|
QStringList segments = p.split( ":" );
|
||||||
|
|
||||||
|
if ( segments.length() != 3 )
|
||||||
|
{
|
||||||
|
m_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( segments[ 0 ].isEmpty() || segments[ 1 ].isEmpty() )
|
||||||
|
{
|
||||||
|
m_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
int octal = segments[ 2 ].toInt( &ok, 8 );
|
||||||
|
if ( !ok || octal == 0 )
|
||||||
|
{
|
||||||
|
m_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_value = octal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have exactly three segments and the third is valid octal,
|
||||||
|
// so we can declare the string valid and set the user and group names
|
||||||
|
m_valid = true;
|
||||||
|
m_username = segments[ 0 ];
|
||||||
|
m_group = segments[ 1 ];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Permissions::apply( const QString& path, int mode )
|
||||||
|
{
|
||||||
|
// We **don't** use QFile::setPermissions() here because it takes
|
||||||
|
// a Qt flags object that subtlely does not align with POSIX bits.
|
||||||
|
// The Qt flags are **hex** based, so 0x755 for rwxr-xr-x, while
|
||||||
|
// our integer (mode_t) stores **octal** based flags.
|
||||||
|
//
|
||||||
|
// Call chmod(2) directly, that's what Qt would be doing underneath
|
||||||
|
// anyway.
|
||||||
|
int r = chmod( path.toUtf8().constData(), mode_t( mode ) );
|
||||||
|
if ( r )
|
||||||
|
{
|
||||||
|
cDebug() << Logger::SubEntry << "Could not set permissions of" << path << "to" << QString::number( mode, 8 );
|
||||||
|
}
|
||||||
|
return r == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Permissions::apply( const QString& path, const CalamaresUtils::Permissions& p )
|
||||||
|
{
|
||||||
|
if ( !p.isValid() )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool r = apply( path, p.value() );
|
||||||
|
if ( r )
|
||||||
|
{
|
||||||
|
// We don't use chgrp(2) or chown(2) here because then we need to
|
||||||
|
// go through the users list (which one, target or source?) to get
|
||||||
|
// uid_t and gid_t values to pass to that system call.
|
||||||
|
//
|
||||||
|
// Do a lame cop-out and let the chown(8) utility do the heavy lifting.
|
||||||
|
if ( QProcess::execute( "chown", { p.username() + ':' + p.group(), path } ) )
|
||||||
|
{
|
||||||
|
r = false;
|
||||||
|
cDebug() << Logger::SubEntry << "Could not set owner of" << path << "to"
|
||||||
|
<< ( p.username() + ':' + p.group() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( r )
|
||||||
|
{
|
||||||
|
/* NOTUSED */ apply( path, p.value() );
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace CalamaresUtils
|
92
src/libcalamares/utils/Permissions.h
Normal file
92
src/libcalamares/utils/Permissions.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2018 Scott Harvey <scott@spharvey.me>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* License-Filename: LICENSE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBCALAMARES_PERMISSIONS_H
|
||||||
|
#define LIBCALAMARES_PERMISSIONS_H
|
||||||
|
|
||||||
|
#include "DllMacro.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace CalamaresUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Permissions class takes a QString @p in the form of
|
||||||
|
* <user>:<group>:<permissions>, checks it for validity, and makes the three
|
||||||
|
* components available indivdually.
|
||||||
|
*/
|
||||||
|
class DLLEXPORT Permissions
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** @brief Constructor
|
||||||
|
*
|
||||||
|
* Splits the string @p at the colon (":") into separate elements for
|
||||||
|
* <user>, <group>, and <value> (permissions), where <value> is interpreted
|
||||||
|
* as an **octal** integer. That is, "root:wheel:755" will give
|
||||||
|
* you an integer value of four-hundred-ninety-three (493),
|
||||||
|
* corresponding to the UNIX file permissions rwxr-xr-x,
|
||||||
|
* as one would expect from chmod and other command-line utilities.
|
||||||
|
*/
|
||||||
|
Permissions( QString const& p );
|
||||||
|
|
||||||
|
/// @brief Default constructor of an invalid Permissions.
|
||||||
|
Permissions();
|
||||||
|
|
||||||
|
/// @brief Was the Permissions object constructed from valid data?
|
||||||
|
bool isValid() const { return m_valid; }
|
||||||
|
/// @brief The user (first component, e.g. "root" in "root:wheel:755")
|
||||||
|
QString username() const { return m_username; }
|
||||||
|
/// @brief The group (second component, e.g. "wheel" in "root:wheel:755")
|
||||||
|
QString group() const { return m_group; }
|
||||||
|
/** @brief The value (file permission) as an integer.
|
||||||
|
*
|
||||||
|
* Bear in mind that input is in octal, but integers are just integers;
|
||||||
|
* naively printing them will get decimal results (e.g. 493 from the
|
||||||
|
* input of "root:wheel:755"). This is suitable to pass to apply().
|
||||||
|
*/
|
||||||
|
int value() const { return m_value; }
|
||||||
|
/** @brief The value (file permission) as octal string
|
||||||
|
*
|
||||||
|
* This is suitable for passing to chmod-the-program, or for
|
||||||
|
* recreating the original Permissions string.
|
||||||
|
*/
|
||||||
|
QString octal() const { return QString::number( value(), 8 ); }
|
||||||
|
|
||||||
|
/** @brief Sets the file-access @p mode of @p path
|
||||||
|
*
|
||||||
|
* Pass a path that is relative (or absolute) in the **host** system.
|
||||||
|
*/
|
||||||
|
static bool apply( const QString& path, int mode );
|
||||||
|
/** @brief Do both chmod and chown on @p path
|
||||||
|
*
|
||||||
|
* Note that interpreting user- and group- names for applying the
|
||||||
|
* permissions can be different between the host system and the target
|
||||||
|
* system; the target might not have a "live" user, for instance, and
|
||||||
|
* the host won't have the user-entered username for the installation.
|
||||||
|
*
|
||||||
|
* For this call, the names are interpreted in the **host** system.
|
||||||
|
* Pass a path that is relative (or absolute) in the **host** system.
|
||||||
|
*/
|
||||||
|
static bool apply( const QString& path, const Permissions& p );
|
||||||
|
/// Convenience method for apply(const QString&, const Permissions& )
|
||||||
|
bool apply( const QString& path ) const { return apply( path, *this ); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void parsePermissions( QString const& p );
|
||||||
|
|
||||||
|
QString m_username;
|
||||||
|
QString m_group;
|
||||||
|
int m_value;
|
||||||
|
bool m_valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CalamaresUtils
|
||||||
|
|
||||||
|
#endif // LIBCALAMARES_PERMISSIONS_H
|
@ -4,7 +4,6 @@ calamares_add_plugin( preservefiles
|
|||||||
TYPE job
|
TYPE job
|
||||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
SOURCES
|
SOURCES
|
||||||
permissions.cpp
|
|
||||||
PreserveFiles.cpp
|
PreserveFiles.cpp
|
||||||
LINK_PRIVATE_LIBRARIES
|
LINK_PRIVATE_LIBRARIES
|
||||||
calamares
|
calamares
|
||||||
|
@ -1,39 +1,28 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* License-Filename: LICENSE
|
||||||
*
|
*
|
||||||
* Calamares 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.
|
|
||||||
*
|
|
||||||
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PreserveFiles.h"
|
#include "PreserveFiles.h"
|
||||||
|
|
||||||
#include "permissions.h"
|
|
||||||
|
|
||||||
#include "CalamaresVersion.h"
|
#include "CalamaresVersion.h"
|
||||||
#include "JobQueue.h"
|
|
||||||
#include "GlobalStorage.h"
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
#include "utils/CommandList.h"
|
#include "utils/CommandList.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Permissions.h"
|
||||||
#include "utils/Units.h"
|
#include "utils/Units.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
using CalamaresUtils::operator""_MiB;
|
using CalamaresUtils::operator""_MiB;
|
||||||
|
|
||||||
QString targetPrefix()
|
QString
|
||||||
|
targetPrefix()
|
||||||
{
|
{
|
||||||
if ( CalamaresUtils::System::instance()->doChroot() )
|
if ( CalamaresUtils::System::instance()->doChroot() )
|
||||||
{
|
{
|
||||||
@ -42,10 +31,14 @@ QString targetPrefix()
|
|||||||
{
|
{
|
||||||
QString r = gs->value( "rootMountPoint" ).toString();
|
QString r = gs->value( "rootMountPoint" ).toString();
|
||||||
if ( !r.isEmpty() )
|
if ( !r.isEmpty() )
|
||||||
|
{
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
cDebug() << "RootMountPoint is empty";
|
cDebug() << "RootMountPoint is empty";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cDebug() << "No rootMountPoint defined, preserving files to '/'";
|
cDebug() << "No rootMountPoint defined, preserving files to '/'";
|
||||||
@ -55,16 +48,21 @@ QString targetPrefix()
|
|||||||
return QLatin1String( "/" );
|
return QLatin1String( "/" );
|
||||||
}
|
}
|
||||||
|
|
||||||
QString atReplacements( QString s )
|
QString
|
||||||
|
atReplacements( QString s )
|
||||||
{
|
{
|
||||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
QString root( "/" );
|
QString root( "/" );
|
||||||
QString user;
|
QString user;
|
||||||
|
|
||||||
if ( gs && gs->contains( "rootMountPoint" ) )
|
if ( gs && gs->contains( "rootMountPoint" ) )
|
||||||
|
{
|
||||||
root = gs->value( "rootMountPoint" ).toString();
|
root = gs->value( "rootMountPoint" ).toString();
|
||||||
|
}
|
||||||
if ( gs && gs->contains( "username" ) )
|
if ( gs && gs->contains( "username" ) )
|
||||||
|
{
|
||||||
user = gs->value( "username" ).toString();
|
user = gs->value( "username" ).toString();
|
||||||
|
}
|
||||||
|
|
||||||
return s.replace( "@@ROOT@@", root ).replace( "@@USER@@", user );
|
return s.replace( "@@ROOT@@", root ).replace( "@@USER@@", user );
|
||||||
}
|
}
|
||||||
@ -74,9 +72,7 @@ PreserveFiles::PreserveFiles( QObject* parent )
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PreserveFiles::~PreserveFiles()
|
PreserveFiles::~PreserveFiles() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QString
|
QString
|
||||||
PreserveFiles::prettyName() const
|
PreserveFiles::prettyName() const
|
||||||
@ -107,8 +103,7 @@ copy_file( const QString& source, const QString& dest )
|
|||||||
{
|
{
|
||||||
b = sourcef.read( 1_MiB );
|
b = sourcef.read( 1_MiB );
|
||||||
destf.write( b );
|
destf.write( b );
|
||||||
}
|
} while ( b.count() > 0 );
|
||||||
while ( b.count() > 0 );
|
|
||||||
|
|
||||||
sourcef.close();
|
sourcef.close();
|
||||||
destf.close();
|
destf.close();
|
||||||
@ -116,14 +111,19 @@ copy_file( const QString& source, const QString& dest )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Calamares::JobResult PreserveFiles::exec()
|
Calamares::JobResult
|
||||||
|
PreserveFiles::exec()
|
||||||
{
|
{
|
||||||
if ( m_items.isEmpty() )
|
if ( m_items.isEmpty() )
|
||||||
|
{
|
||||||
return Calamares::JobResult::error( tr( "No files configured to save for later." ) );
|
return Calamares::JobResult::error( tr( "No files configured to save for later." ) );
|
||||||
|
}
|
||||||
|
|
||||||
QString prefix = targetPrefix();
|
QString prefix = targetPrefix();
|
||||||
if ( !prefix.endsWith( '/' ) )
|
if ( !prefix.endsWith( '/' ) )
|
||||||
|
{
|
||||||
prefix.append( '/' );
|
prefix.append( '/' );
|
||||||
|
}
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for ( const auto& it : m_items )
|
for ( const auto& it : m_items )
|
||||||
@ -133,37 +133,34 @@ Calamares::JobResult PreserveFiles::exec()
|
|||||||
QString dest = prefix + bare_dest;
|
QString dest = prefix + bare_dest;
|
||||||
|
|
||||||
if ( it.type == ItemType::Log )
|
if ( it.type == ItemType::Log )
|
||||||
|
{
|
||||||
source = Logger::logFile();
|
source = Logger::logFile();
|
||||||
|
}
|
||||||
if ( it.type == ItemType::Config )
|
if ( it.type == ItemType::Config )
|
||||||
{
|
{
|
||||||
if ( Calamares::JobQueue::instance()->globalStorage()->save( dest ) )
|
if ( Calamares::JobQueue::instance()->globalStorage()->save( dest ) )
|
||||||
|
{
|
||||||
cWarning() << "Could not write config for" << dest;
|
cWarning() << "Could not write config for" << dest;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if ( source.isEmpty() )
|
else if ( source.isEmpty() )
|
||||||
|
{
|
||||||
cWarning() << "Skipping unnamed source file for" << dest;
|
cWarning() << "Skipping unnamed source file for" << dest;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( copy_file( source, dest ) )
|
if ( copy_file( source, dest ) )
|
||||||
{
|
{
|
||||||
if ( it.perm.isValid() )
|
if ( it.perm.isValid() )
|
||||||
{
|
{
|
||||||
auto s_p = CalamaresUtils::System::instance();
|
if ( !it.perm.apply( CalamaresUtils::System::instance()->targetPath( bare_dest ) ) )
|
||||||
|
{
|
||||||
int r;
|
cWarning() << "Could not set attributes of" << bare_dest;
|
||||||
|
}
|
||||||
r = s_p->targetEnvCall( QStringList{ "chown", it.perm.username(), bare_dest } );
|
|
||||||
if ( r )
|
|
||||||
cWarning() << "Could not chown target" << bare_dest;
|
|
||||||
|
|
||||||
r = s_p->targetEnvCall( QStringList{ "chgrp", it.perm.group(), bare_dest } );
|
|
||||||
if ( r )
|
|
||||||
cWarning() << "Could not chgrp target" << bare_dest;
|
|
||||||
|
|
||||||
r = s_p->targetEnvCall( QStringList{ "chmod", it.perm.octal(), bare_dest } );
|
|
||||||
if ( r )
|
|
||||||
cWarning() << "Could not chmod target" << bare_dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
@ -171,12 +168,13 @@ Calamares::JobResult PreserveFiles::exec()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return count == m_items.count() ?
|
return count == m_items.count()
|
||||||
Calamares::JobResult::ok() :
|
? Calamares::JobResult::ok()
|
||||||
Calamares::JobResult::error( tr( "Not all of the configured files could be preserved." ) );
|
: Calamares::JobResult::error( tr( "Not all of the configured files could be preserved." ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
|
void
|
||||||
|
PreserveFiles::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
{
|
{
|
||||||
auto files = configurationMap[ "files" ];
|
auto files = configurationMap[ "files" ];
|
||||||
if ( !files.isValid() )
|
if ( !files.isValid() )
|
||||||
@ -193,7 +191,9 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
|
|||||||
|
|
||||||
QString defaultPermissions = configurationMap[ "perm" ].toString();
|
QString defaultPermissions = configurationMap[ "perm" ].toString();
|
||||||
if ( defaultPermissions.isEmpty() )
|
if ( defaultPermissions.isEmpty() )
|
||||||
|
{
|
||||||
defaultPermissions = QStringLiteral( "root:root:0400" );
|
defaultPermissions = QStringLiteral( "root:root:0400" );
|
||||||
|
}
|
||||||
|
|
||||||
QVariantList l = files.toList();
|
QVariantList l = files.toList();
|
||||||
unsigned int c = 0;
|
unsigned int c = 0;
|
||||||
@ -203,22 +203,23 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
|
|||||||
{
|
{
|
||||||
QString filename = li.toString();
|
QString filename = li.toString();
|
||||||
if ( !filename.isEmpty() )
|
if ( !filename.isEmpty() )
|
||||||
m_items.append( Item{ filename, filename, Permissions( defaultPermissions ), ItemType::Path } );
|
m_items.append( Item { filename, filename, CalamaresUtils::Permissions( defaultPermissions ), ItemType::Path } );
|
||||||
else
|
else
|
||||||
|
{
|
||||||
cDebug() << "Empty filename for preservefiles, item" << c;
|
cDebug() << "Empty filename for preservefiles, item" << c;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if ( li.type() == QVariant::Map )
|
else if ( li.type() == QVariant::Map )
|
||||||
{
|
{
|
||||||
const auto map = li.toMap();
|
const auto map = li.toMap();
|
||||||
QString dest = map[ "dest" ].toString();
|
QString dest = map[ "dest" ].toString();
|
||||||
QString from = map[ "from" ].toString();
|
QString from = map[ "from" ].toString();
|
||||||
ItemType t =
|
ItemType t = ( from == "log" ) ? ItemType::Log : ( from == "config" ) ? ItemType::Config : ItemType::None;
|
||||||
( from == "log" ) ? ItemType::Log :
|
|
||||||
( from == "config" ) ? ItemType::Config :
|
|
||||||
ItemType::None;
|
|
||||||
QString perm = map[ "perm" ].toString();
|
QString perm = map[ "perm" ].toString();
|
||||||
if ( perm.isEmpty() )
|
if ( perm.isEmpty() )
|
||||||
|
{
|
||||||
perm = defaultPermissions;
|
perm = defaultPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
if ( dest.isEmpty() )
|
if ( dest.isEmpty() )
|
||||||
{
|
{
|
||||||
@ -230,15 +231,16 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_items.append( Item{ QString(), dest, Permissions( perm ), t } );
|
m_items.append( Item { QString(), dest, CalamaresUtils::Permissions( perm ), t } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
cDebug() << "Invalid type for preservefiles, item" << c;
|
cDebug() << "Invalid type for preservefiles, item" << c;
|
||||||
|
}
|
||||||
|
|
||||||
++c;
|
++c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( PreserveFilesFactory, registerPlugin<PreserveFiles>(); )
|
CALAMARES_PLUGIN_FACTORY_DEFINITION( PreserveFilesFactory, registerPlugin< PreserveFiles >(); )
|
||||||
|
|
||||||
|
@ -1,35 +1,23 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* License-Filename: LICENSE
|
||||||
*
|
*
|
||||||
* Calamares 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.
|
|
||||||
*
|
|
||||||
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PRESERVEFILES_H
|
#ifndef PRESERVEFILES_H
|
||||||
#define PRESERVEFILES_H
|
#define PRESERVEFILES_H
|
||||||
|
|
||||||
|
#include "CppJob.h"
|
||||||
|
#include "DllMacro.h"
|
||||||
|
#include "utils/Permissions.h"
|
||||||
|
#include "utils/PluginFactory.h"
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVariantMap>
|
#include <QVariantMap>
|
||||||
|
|
||||||
#include "CppJob.h"
|
|
||||||
#include "DllMacro.h"
|
|
||||||
|
|
||||||
#include "utils/PluginFactory.h"
|
|
||||||
|
|
||||||
#include "permissions.h"
|
|
||||||
|
|
||||||
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
|
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -40,15 +28,15 @@ class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
|
|||||||
Path,
|
Path,
|
||||||
Log,
|
Log,
|
||||||
Config
|
Config
|
||||||
} ;
|
};
|
||||||
|
|
||||||
struct Item
|
struct Item
|
||||||
{
|
{
|
||||||
QString source;
|
QString source;
|
||||||
QString dest;
|
QString dest;
|
||||||
Permissions perm;
|
CalamaresUtils::Permissions perm;
|
||||||
ItemType type;
|
ItemType type;
|
||||||
} ;
|
};
|
||||||
|
|
||||||
using ItemList = QList< Item >;
|
using ItemList = QList< Item >;
|
||||||
|
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 Scott Harvey <scott@spharvey.me>
|
|
||||||
*
|
|
||||||
* 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 <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include "permissions.h"
|
|
||||||
|
|
||||||
Permissions::Permissions() :
|
|
||||||
m_username(),
|
|
||||||
m_group(),
|
|
||||||
m_valid(false),
|
|
||||||
m_value(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Permissions::Permissions(QString p) : Permissions()
|
|
||||||
{
|
|
||||||
parsePermissions(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Permissions::parsePermissions(const QString& p) {
|
|
||||||
|
|
||||||
QStringList segments = p.split(":");
|
|
||||||
|
|
||||||
if (segments.length() != 3) {
|
|
||||||
m_valid = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segments[0].isEmpty() || segments[1].isEmpty()) {
|
|
||||||
m_valid = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok;
|
|
||||||
int octal = segments[2].toInt(&ok, 8);
|
|
||||||
if (!ok || octal == 0) {
|
|
||||||
m_valid = false;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
m_value = octal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have exactly three segments and the third is valid octal,
|
|
||||||
// so we can declare the string valid and set the user and group names
|
|
||||||
m_valid = true;
|
|
||||||
m_username = segments[0];
|
|
||||||
m_group = segments[1];
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 Scott Harvey <scott@spharvey.me>
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PERMISSIONS_H
|
|
||||||
#define PERMISSIONS_H
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The Permissions class takes a QString @p in the form of
|
|
||||||
* <user>:<group>:<permissions>, checks it for validity, and makes the three
|
|
||||||
* components available indivdually.
|
|
||||||
*/
|
|
||||||
class Permissions
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** @brief Constructor
|
|
||||||
*
|
|
||||||
* Splits the string @p at the colon (":") into separate elements for
|
|
||||||
* <user>, <group>, and <value> (permissions), where <value> is returned as
|
|
||||||
* an **octal** integer.
|
|
||||||
*/
|
|
||||||
Permissions(QString p);
|
|
||||||
|
|
||||||
/** @brief Default constructor of an invalid Permissions. */
|
|
||||||
Permissions();
|
|
||||||
|
|
||||||
bool isValid() const { return m_valid; }
|
|
||||||
QString username() const { return m_username; }
|
|
||||||
QString group() const { return m_group; }
|
|
||||||
int value() const { return m_value; }
|
|
||||||
QString octal() const { return QString::number( m_value, 8 ); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void parsePermissions(QString const &p);
|
|
||||||
|
|
||||||
QString m_username;
|
|
||||||
QString m_group;
|
|
||||||
bool m_valid;
|
|
||||||
int m_value;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PERMISSIONS_H
|
|
@ -49,6 +49,13 @@ calamares_add_test(
|
|||||||
${CRYPT_LIBRARIES}
|
${CRYPT_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
calamares_add_test(
|
||||||
|
userscreatetest
|
||||||
|
SOURCES
|
||||||
|
CreateUserTests.cpp
|
||||||
|
CreateUserJob.cpp
|
||||||
|
)
|
||||||
|
|
||||||
calamares_add_test(
|
calamares_add_test(
|
||||||
userstest
|
userstest
|
||||||
SOURCES
|
SOURCES
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Permissions.h"
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -54,6 +55,109 @@ CreateUserJob::prettyStatusMessage() const
|
|||||||
return tr( "Creating user %1." ).arg( m_userName );
|
return tr( "Creating user %1." ).arg( m_userName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATICTEST QStringList
|
||||||
|
groupsInTargetSystem( const QDir& targetRoot )
|
||||||
|
{
|
||||||
|
QFileInfo groupsFi( targetRoot.absoluteFilePath( "etc/group" ) );
|
||||||
|
QFile groupsFile( groupsFi.absoluteFilePath() );
|
||||||
|
if ( !groupsFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
||||||
|
{
|
||||||
|
return QStringList();
|
||||||
|
}
|
||||||
|
QString groupsData = QString::fromLocal8Bit( groupsFile.readAll() );
|
||||||
|
QStringList groupsLines = groupsData.split( '\n' );
|
||||||
|
QStringList::iterator it = groupsLines.begin();
|
||||||
|
while ( it != groupsLines.end() )
|
||||||
|
{
|
||||||
|
if ( it->startsWith( '#' ) )
|
||||||
|
{
|
||||||
|
it = groupsLines.erase( it );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int indexOfFirstToDrop = it->indexOf( ':' );
|
||||||
|
if ( indexOfFirstToDrop < 1 )
|
||||||
|
{
|
||||||
|
it = groupsLines.erase( it );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it->truncate( indexOfFirstToDrop );
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return groupsLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ensureGroupsExistInTarget( const QStringList& wantedGroups, const QStringList& availableGroups )
|
||||||
|
{
|
||||||
|
for ( const QString& group : wantedGroups )
|
||||||
|
{
|
||||||
|
if ( !availableGroups.contains( group ) )
|
||||||
|
{
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
CalamaresUtils::System::instance()->targetEnvCall( { "pw", "groupadd", "-n", group } );
|
||||||
|
#else
|
||||||
|
CalamaresUtils::System::instance()->targetEnvCall( { "groupadd", group } );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Calamares::JobResult
|
||||||
|
createUser( const QString& loginName, const QString& fullName, const QString& shell )
|
||||||
|
{
|
||||||
|
QStringList useraddCommand;
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
useraddCommand << "pw"
|
||||||
|
<< "useradd"
|
||||||
|
<< "-n" << loginName << "-m"
|
||||||
|
<< "-c" << fullName;
|
||||||
|
if ( !shell.isEmpty() )
|
||||||
|
{
|
||||||
|
useraddCommand << "-s" << shell;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
useraddCommand << "useradd"
|
||||||
|
<< "-m"
|
||||||
|
<< "-U";
|
||||||
|
if ( !shell.isEmpty() )
|
||||||
|
{
|
||||||
|
useradd << "-s" << shell;
|
||||||
|
}
|
||||||
|
useradd << "-c" << fullName;
|
||||||
|
useradd << loginName;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto commandResult = CalamaresUtils::System::instance()->targetEnvCommand( useraddCommand );
|
||||||
|
if ( commandResult.getExitCode() )
|
||||||
|
{
|
||||||
|
cError() << "useradd failed" << commandResult.getExitCode();
|
||||||
|
return commandResult.explainProcess( useraddCommand, std::chrono::seconds( 10 ) /* bogus timeout */ );
|
||||||
|
}
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Calamares::JobResult
|
||||||
|
setUserGroups( const QString& loginName, const QStringList& groups )
|
||||||
|
{
|
||||||
|
QStringList setgroupsCommand;
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
setgroupsCommand << "pw"
|
||||||
|
<< "usermod"
|
||||||
|
<< "-n" << loginName << "-G" << groups.join( ',' );
|
||||||
|
#else
|
||||||
|
setgroupsCommand << "usermod"
|
||||||
|
<< "-aG" << groups.join( ',' ) << loginName;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto commandResult = CalamaresUtils::System::instance()->targetEnvCommand( setgroupsCommand );
|
||||||
|
if ( commandResult.getExitCode() )
|
||||||
|
{
|
||||||
|
cError() << "usermod failed" << commandResult.getExitCode();
|
||||||
|
return commandResult.explainProcess( setgroupsCommand, std::chrono::seconds( 10 ) /* bogus timeout */ );
|
||||||
|
}
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
CreateUserJob::exec()
|
CreateUserJob::exec()
|
||||||
@ -65,65 +169,37 @@ CreateUserJob::exec()
|
|||||||
{
|
{
|
||||||
cDebug() << "[CREATEUSER]: preparing sudoers";
|
cDebug() << "[CREATEUSER]: preparing sudoers";
|
||||||
|
|
||||||
QFileInfo sudoersFi( destDir.absoluteFilePath( "etc/sudoers.d/10-installer" ) );
|
QString sudoersLine = QString( "%%1 ALL=(ALL) ALL\n" ).arg( gs->value( "sudoersGroup" ).toString() );
|
||||||
|
auto fileResult
|
||||||
|
= CalamaresUtils::System::instance()->createTargetFile( QStringLiteral( "/etc/sudoers.d/10-installer" ),
|
||||||
|
sudoersLine.toUtf8().constData(),
|
||||||
|
CalamaresUtils::System::WriteMode::Overwrite );
|
||||||
|
|
||||||
if ( !sudoersFi.absoluteDir().exists() )
|
if ( fileResult )
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::error( tr( "Sudoers dir is not writable." ) );
|
if ( CalamaresUtils::Permissions::apply( fileResult.path(), 0440 ) )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::error( tr( "Cannot chmod sudoers file." ) );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
QFile sudoersFile( sudoersFi.absoluteFilePath() );
|
else
|
||||||
if ( !sudoersFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
|
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::error( tr( "Cannot create sudoers file for writing." ) );
|
return Calamares::JobResult::error( tr( "Cannot create sudoers file for writing." ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
QString sudoersGroup = gs->value( "sudoersGroup" ).toString();
|
|
||||||
|
|
||||||
QTextStream sudoersOut( &sudoersFile );
|
|
||||||
sudoersOut << QString( "%%1 ALL=(ALL) ALL\n" ).arg( sudoersGroup );
|
|
||||||
|
|
||||||
if ( QProcess::execute( "chmod", { "440", sudoersFi.absoluteFilePath() } ) )
|
|
||||||
return Calamares::JobResult::error( tr( "Cannot chmod sudoers file." ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cDebug() << "[CREATEUSER]: preparing groups";
|
cDebug() << "[CREATEUSER]: preparing groups";
|
||||||
|
|
||||||
QFileInfo groupsFi( destDir.absoluteFilePath( "etc/group" ) );
|
QStringList availableGroups = groupsInTargetSystem( destDir );
|
||||||
QFile groupsFile( groupsFi.absoluteFilePath() );
|
QStringList groupsForThisUser = m_defaultGroups;
|
||||||
if ( !groupsFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
if ( m_autologin && gs->contains( "autologinGroup" ) && !gs->value( "autologinGroup" ).toString().isEmpty() )
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::error( tr( "Cannot open groups file for reading." ) );
|
groupsForThisUser << gs->value( "autologinGroup" ).toString();
|
||||||
}
|
|
||||||
QString groupsData = QString::fromLocal8Bit( groupsFile.readAll() );
|
|
||||||
QStringList groupsLines = groupsData.split( '\n' );
|
|
||||||
for ( QStringList::iterator it = groupsLines.begin(); it != groupsLines.end(); ++it )
|
|
||||||
{
|
|
||||||
int indexOfFirstToDrop = it->indexOf( ':' );
|
|
||||||
it->truncate( indexOfFirstToDrop );
|
|
||||||
}
|
}
|
||||||
|
ensureGroupsExistInTarget( m_defaultGroups, availableGroups );
|
||||||
|
|
||||||
for ( const QString& group : m_defaultGroups )
|
// If we're looking to reuse the contents of an existing /home.
|
||||||
{
|
// This GS setting comes from the **partitioning** module.
|
||||||
if ( !groupsLines.contains( group ) )
|
|
||||||
{
|
|
||||||
CalamaresUtils::System::instance()->targetEnvCall( { "groupadd", group } );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString defaultGroups = m_defaultGroups.join( ',' );
|
|
||||||
if ( m_autologin )
|
|
||||||
{
|
|
||||||
QString autologinGroup;
|
|
||||||
if ( gs->contains( "autologinGroup" ) && !gs->value( "autologinGroup" ).toString().isEmpty() )
|
|
||||||
{
|
|
||||||
autologinGroup = gs->value( "autologinGroup" ).toString();
|
|
||||||
CalamaresUtils::System::instance()->targetEnvCall( { "groupadd", autologinGroup } );
|
|
||||||
defaultGroups.append( QString( ",%1" ).arg( autologinGroup ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're looking to reuse the contents of an existing /home
|
|
||||||
if ( gs->value( "reuseHome" ).toBool() )
|
if ( gs->value( "reuseHome" ).toBool() )
|
||||||
{
|
{
|
||||||
QString shellFriendlyHome = "/home/" + m_userName;
|
QString shellFriendlyHome = "/home/" + m_userName;
|
||||||
@ -133,6 +209,7 @@ CreateUserJob::exec()
|
|||||||
QString backupDirName = "dotfiles_backup_" + QDateTime::currentDateTime().toString( "yyyy-MM-dd_HH-mm-ss" );
|
QString backupDirName = "dotfiles_backup_" + QDateTime::currentDateTime().toString( "yyyy-MM-dd_HH-mm-ss" );
|
||||||
existingHome.mkdir( backupDirName );
|
existingHome.mkdir( backupDirName );
|
||||||
|
|
||||||
|
// We need the extra `sh -c` here to ensure that we can expand the shell globs
|
||||||
CalamaresUtils::System::instance()->targetEnvCall(
|
CalamaresUtils::System::instance()->targetEnvCall(
|
||||||
{ "sh", "-c", "mv -f " + shellFriendlyHome + "/.* " + shellFriendlyHome + "/" + backupDirName } );
|
{ "sh", "-c", "mv -f " + shellFriendlyHome + "/.* " + shellFriendlyHome + "/" + backupDirName } );
|
||||||
}
|
}
|
||||||
@ -140,33 +217,21 @@ CreateUserJob::exec()
|
|||||||
|
|
||||||
cDebug() << "[CREATEUSER]: creating user";
|
cDebug() << "[CREATEUSER]: creating user";
|
||||||
|
|
||||||
QStringList useradd { "useradd", "-m", "-U" };
|
auto useraddResult = createUser( m_userName, m_fullName, gs->value( "userShell" ).toString() );
|
||||||
QString shell = gs->value( "userShell" ).toString();
|
if ( !useraddResult )
|
||||||
if ( !shell.isEmpty() )
|
|
||||||
{
|
{
|
||||||
useradd << "-s" << shell;
|
return useraddResult;
|
||||||
}
|
|
||||||
useradd << "-c" << m_fullName;
|
|
||||||
useradd << m_userName;
|
|
||||||
|
|
||||||
auto commandResult = CalamaresUtils::System::instance()->targetEnvCommand( useradd );
|
|
||||||
if ( commandResult.getExitCode() )
|
|
||||||
{
|
|
||||||
cError() << "useradd failed" << commandResult.getExitCode();
|
|
||||||
return commandResult.explainProcess( useradd, std::chrono::seconds( 10 ) /* bogus timeout */ );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
commandResult
|
auto usergroupsResult = setUserGroups( m_userName, groupsForThisUser );
|
||||||
= CalamaresUtils::System::instance()->targetEnvCommand( { "usermod", "-aG", defaultGroups, m_userName } );
|
if ( !usergroupsResult )
|
||||||
if ( commandResult.getExitCode() )
|
|
||||||
{
|
{
|
||||||
cError() << "usermod failed" << commandResult.getExitCode();
|
return usergroupsResult;
|
||||||
return commandResult.explainProcess( "usermod", std::chrono::seconds( 10 ) /* bogus timeout */ );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString userGroup = QString( "%1:%2" ).arg( m_userName ).arg( m_userName );
|
QString userGroup = QString( "%1:%2" ).arg( m_userName ).arg( m_userName );
|
||||||
QString homeDir = QString( "/home/%1" ).arg( m_userName );
|
QString homeDir = QString( "/home/%1" ).arg( m_userName );
|
||||||
commandResult = CalamaresUtils::System::instance()->targetEnvCommand( { "chown", "-R", userGroup, homeDir } );
|
auto commandResult = CalamaresUtils::System::instance()->targetEnvCommand( { "chown", "-R", userGroup, homeDir } );
|
||||||
if ( commandResult.getExitCode() )
|
if ( commandResult.getExitCode() )
|
||||||
{
|
{
|
||||||
cError() << "chown failed" << commandResult.getExitCode();
|
cError() << "chown failed" << commandResult.getExitCode();
|
||||||
|
Loading…
Reference in New Issue
Block a user