Merge branch 'calamares' of https://github.com/calamares/calamares into development
This commit is contained in:
commit
9d8e9a6c7d
16
CHANGES
16
CHANGES
@ -7,25 +7,35 @@ contributors are listed. Note that Calamares does not have a historical
|
|||||||
changelog -- this log starts with version 3.2.0. The release notes on the
|
changelog -- this log starts with version 3.2.0. The release notes on the
|
||||||
website will have to do for older versions.
|
website will have to do for older versions.
|
||||||
|
|
||||||
# 3.2.33 (unreleased) #
|
# 3.2.33 (2020-11-03) #
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
This release contains contributions from (alphabetically by first name):
|
||||||
- Anke Boersma
|
- Anke Boersma
|
||||||
- Andrius Štikonas
|
- Andrius Štikonas
|
||||||
- Artem Grinev
|
- Artem Grinev
|
||||||
- Gaël PORTAY
|
- Gaël PORTAY
|
||||||
|
- Matti Hyttinen
|
||||||
- TTran Me
|
- TTran Me
|
||||||
|
|
||||||
## Core ##
|
## Core ##
|
||||||
- Calamares now sets the C++ standard for compilation to C++17; this
|
- Calamares now sets the C++ standard for compilation to C++17; this
|
||||||
is for better compatibility and fewer warnings when building with
|
is for better compatibility and fewer warnings when building with
|
||||||
modern KDE Frameworks and KPMcore 4.2.0.
|
modern KDE Frameworks and KPMcore 4.2.0.
|
||||||
- Vietnamese translations have been added. Welcome!
|
- Vietnamese translations have been added. Welcome! (Thanks TTran)
|
||||||
|
|
||||||
## Modules ##
|
## Modules ##
|
||||||
|
- The *initcpiocfg* module should support plymouth with encryption
|
||||||
|
now. (Thanks Matti)
|
||||||
- The *keyboard* and *keyboardq* modules now share backend code
|
- The *keyboard* and *keyboardq* modules now share backend code
|
||||||
and handle non-ASCII layouts better (for setting passwords
|
and handle non-ASCII layouts better (for setting passwords
|
||||||
and usernames).
|
and usernames). (Thanks Artem)
|
||||||
|
- Various cleanups and documentation improvements in the *partition*
|
||||||
|
module, and configurable GPT name for swap. (Thanks Gaël)
|
||||||
|
- The *users* module now has a more detailed way to specify
|
||||||
|
user groups -- which may be system groups rather than user-GIDs.
|
||||||
|
A new option in each group can require that the group already
|
||||||
|
exists in the target system, allowing for better consistency checks
|
||||||
|
with the squashfs. #1523
|
||||||
|
|
||||||
|
|
||||||
# 3.2.32.1 (2020-10-17) #
|
# 3.2.32.1 (2020-10-17) #
|
||||||
|
@ -44,7 +44,7 @@ project( CALAMARES
|
|||||||
VERSION 3.2.33
|
VERSION 3.2.33
|
||||||
LANGUAGES C CXX )
|
LANGUAGES C CXX )
|
||||||
|
|
||||||
set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development
|
set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during development
|
||||||
|
|
||||||
### OPTIONS
|
### OPTIONS
|
||||||
#
|
#
|
||||||
|
@ -42,6 +42,8 @@ function( calamares_add_test )
|
|||||||
Qt5::Test
|
Qt5::Test
|
||||||
)
|
)
|
||||||
calamares_automoc( ${TEST_NAME} )
|
calamares_automoc( ${TEST_NAME} )
|
||||||
|
# We specifically pass in the source directory of the test-being-
|
||||||
|
# compiled, so that it can find test-files in that source dir.
|
||||||
target_compile_definitions( ${TEST_NAME} PRIVATE -DBUILD_AS_TEST="${CMAKE_CURRENT_SOURCE_DIR}" ${TEST_DEFINITIONS} )
|
target_compile_definitions( ${TEST_NAME} PRIVATE -DBUILD_AS_TEST="${CMAKE_CURRENT_SOURCE_DIR}" ${TEST_DEFINITIONS} )
|
||||||
if( TEST_GUI )
|
if( TEST_GUI )
|
||||||
target_link_libraries( ${TEST_NAME} calamaresui Qt5::Gui )
|
target_link_libraries( ${TEST_NAME} calamaresui Qt5::Gui )
|
||||||
|
@ -40,7 +40,7 @@ git clone https://github.com/calamares/calamares.git
|
|||||||
```
|
```
|
||||||
|
|
||||||
Calamares is a KDE-Frameworks and Qt-based, C++17, CMake-built application.
|
Calamares is a KDE-Frameworks and Qt-based, C++17, CMake-built application.
|
||||||
The dependencies are explainged in [CONTRIBUTING.md](CONTRIBUTING.md).
|
The dependencies are explained in [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||||
|
|
||||||
## Contributing to Calamares
|
## Contributing to Calamares
|
||||||
|
|
||||||
|
@ -619,17 +619,17 @@ Bu proqramdan çıxılacaq və bütün dəyişikliklər itiriləcəkdir.</transl
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1448"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1448"/>
|
||||||
<source>This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/></source>
|
<source>This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/></source>
|
||||||
<translation type="unfinished"/>
|
<translation>Bu yaddaş qurğusunda artıq əməliyyat sistemi var, lakin, bölmə cədvəli <strong>%1</strong>, lazım olan <strong>%2</strong> ilə fərqlidir.<br/></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1471"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1471"/>
|
||||||
<source>This storage device has one of its partitions <strong>mounted</strong>.</source>
|
<source>This storage device has one of its partitions <strong>mounted</strong>.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Bu yaddaş qurğusunda bölmələrdən biri <strong>quraşdırılmışdır</strong>.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1476"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1476"/>
|
||||||
<source>This storage device is a part of an <strong>inactive RAID</strong> device.</source>
|
<source>This storage device is a part of an <strong>inactive RAID</strong> device.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Bu yaddaş qurğusu <strong>qeyri-aktiv RAİD</strong> qurğusunun bir hissəsidir.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1603"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1603"/>
|
||||||
@ -2869,7 +2869,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="83"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="83"/>
|
||||||
<source>Directory not found</source>
|
<source>Directory not found</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Qovluq tapılmadı</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="84"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="84"/>
|
||||||
|
@ -619,17 +619,17 @@ Bu proqramdan çıxılacaq və bütün dəyişikliklər itiriləcəkdir.</transl
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1448"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1448"/>
|
||||||
<source>This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/></source>
|
<source>This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/></source>
|
||||||
<translation type="unfinished"/>
|
<translation>Bu yaddaş qurğusunda artıq əməliyyat sistemi var, lakin, bölmə cədvəli <strong>%1</strong>, lazım olan <strong>%2</strong> ilə fərqlidir.<br/></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1471"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1471"/>
|
||||||
<source>This storage device has one of its partitions <strong>mounted</strong>.</source>
|
<source>This storage device has one of its partitions <strong>mounted</strong>.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Bu yaddaş qurğusunda bölmələrdən biri <strong>quraşdırılmışdır</strong>.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1476"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1476"/>
|
||||||
<source>This storage device is a part of an <strong>inactive RAID</strong> device.</source>
|
<source>This storage device is a part of an <strong>inactive RAID</strong> device.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Bu yaddaş qurğusu <strong>qeyri-aktiv RAİD</strong> qurğusunun bir hissəsidir.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1603"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1603"/>
|
||||||
@ -2869,7 +2869,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="83"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="83"/>
|
||||||
<source>Directory not found</source>
|
<source>Directory not found</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Qovluq tapılmadı</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="84"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="84"/>
|
||||||
|
@ -437,7 +437,7 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamares/PythonHelper.cpp" line="288"/>
|
<location filename="../src/libcalamares/PythonHelper.cpp" line="288"/>
|
||||||
<source>Unknown exception type</source>
|
<source>Unknown exception type</source>
|
||||||
<translation>טיפוס חריגה אינו מוכר</translation>
|
<translation>סוג חריגה לא מוכר</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamares/PythonHelper.cpp" line="306"/>
|
<location filename="../src/libcalamares/PythonHelper.cpp" line="306"/>
|
||||||
|
@ -1620,7 +1620,7 @@ Telepítés nem folytatható. <a href="#details">Részletek...</a></
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/license/LicensePage.ui" line="26"/>
|
<location filename="../src/modules/license/LicensePage.ui" line="26"/>
|
||||||
<source><h1>License Agreement</h1></source>
|
<source><h1>License Agreement</h1></source>
|
||||||
<translation type="unfinished"/>
|
<translation><h1>Licenszszerződés</h1></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/license/LicensePage.cpp" line="136"/>
|
<location filename="../src/modules/license/LicensePage.cpp" line="136"/>
|
||||||
|
@ -304,12 +304,12 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="208"/>
|
<location filename="../src/libcalamaresui/ViewManager.cpp" line="208"/>
|
||||||
<source>Calamares Initialization Failed</source>
|
<source>Calamares Initialization Failed</source>
|
||||||
<translation>Calamares 초기화 실패</translation>
|
<translation>깔라마레스 초기화 실패</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="209"/>
|
<location filename="../src/libcalamaresui/ViewManager.cpp" line="209"/>
|
||||||
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
|
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
|
||||||
<translation>%1 가 설치될 수 없습니다. Calamares가 모든 구성된 모듈을 불러올 수 없었습니다. 이것은 Calamares가 분포에 의해 사용되는 방식에서 비롯된 문제입니다.</translation>
|
<translation>%1 가 설치될 수 없습니다. 깔라마레스가 모든 구성된 모듈을 불러올 수 없었습니다. 이것은 깔라마레스가 배포판에서 사용되는 방식에서 발생한 문제입니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="215"/>
|
<location filename="../src/libcalamaresui/ViewManager.cpp" line="215"/>
|
||||||
@ -617,17 +617,17 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1448"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1448"/>
|
||||||
<source>This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/></source>
|
<source>This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/></source>
|
||||||
<translation type="unfinished"/>
|
<translation>이 스토리지 장치에는 이미 운영 체제가 설치되어 있으나 <strong>%1</strong> 파티션 테이블이 필요로 하는 <strong>%2</strong>와 다릅니다.<br/></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1471"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1471"/>
|
||||||
<source>This storage device has one of its partitions <strong>mounted</strong>.</source>
|
<source>This storage device has one of its partitions <strong>mounted</strong>.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>이 스토리지 장치는 하나 이상의 <strong>마운트된</strong> 파티션을 갖고 있습니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1476"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1476"/>
|
||||||
<source>This storage device is a part of an <strong>inactive RAID</strong> device.</source>
|
<source>This storage device is a part of an <strong>inactive RAID</strong> device.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>이 스토리지 장치는 <strong>비활성화된 RAID</strong> 장치의 일부입니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1603"/>
|
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1603"/>
|
||||||
@ -730,7 +730,7 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/locale/Config.cpp" line="334"/>
|
<location filename="../src/modules/locale/Config.cpp" line="334"/>
|
||||||
<source>Set timezone to %1/%2.</source>
|
<source>Set timezone to %1/%2.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>표준시간대를 %1/%2로 설정합니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/locale/Config.cpp" line="372"/>
|
<location filename="../src/modules/locale/Config.cpp" line="372"/>
|
||||||
@ -790,22 +790,22 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/Config.cpp" line="244"/>
|
<location filename="../src/modules/welcome/Config.cpp" line="244"/>
|
||||||
<source><h1>Welcome to the Calamares setup program for %1</h1></source>
|
<source><h1>Welcome to the Calamares setup program for %1</h1></source>
|
||||||
<translation type="unfinished"/>
|
<translation><h1> 깔라마레스 설치 프로그램 %1에 오신 것을 환영합니다</h1></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/Config.cpp" line="245"/>
|
<location filename="../src/modules/welcome/Config.cpp" line="245"/>
|
||||||
<source><h1>Welcome to %1 setup</h1></source>
|
<source><h1>Welcome to %1 setup</h1></source>
|
||||||
<translation type="unfinished"/>
|
<translation><h1>%1 설치에 오신 것을 환영합니다</h1></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/Config.cpp" line="250"/>
|
<location filename="../src/modules/welcome/Config.cpp" line="250"/>
|
||||||
<source><h1>Welcome to the Calamares installer for %1</h1></source>
|
<source><h1>Welcome to the Calamares installer for %1</h1></source>
|
||||||
<translation type="unfinished"/>
|
<translation><h1>깔라마레스 인스톨러 %1에 오신 것을 환영합니다</h1></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/Config.cpp" line="251"/>
|
<location filename="../src/modules/welcome/Config.cpp" line="251"/>
|
||||||
<source><h1>Welcome to the %1 installer</h1></source>
|
<source><h1>Welcome to the %1 installer</h1></source>
|
||||||
<translation type="unfinished"/>
|
<translation><h1>%1 인스톨러에 오신 것을 환영합니다</h1></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/users/Config.cpp" line="164"/>
|
<location filename="../src/modules/users/Config.cpp" line="164"/>
|
||||||
@ -815,7 +815,7 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/users/Config.cpp" line="170"/>
|
<location filename="../src/modules/users/Config.cpp" line="170"/>
|
||||||
<source>'%1' is not allowed as username.</source>
|
<source>'%1' is not allowed as username.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>'%1'은 사용자 이름으로 허용되지 않습니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/users/Config.cpp" line="177"/>
|
<location filename="../src/modules/users/Config.cpp" line="177"/>
|
||||||
@ -840,7 +840,7 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/users/Config.cpp" line="237"/>
|
<location filename="../src/modules/users/Config.cpp" line="237"/>
|
||||||
<source>'%1' is not allowed as hostname.</source>
|
<source>'%1' is not allowed as hostname.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>'%1'은 호스트 이름으로 허용되지 않습니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/users/Config.cpp" line="243"/>
|
<location filename="../src/modules/users/Config.cpp" line="243"/>
|
||||||
@ -1813,7 +1813,7 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/localeq/Map.qml" line="243"/>
|
<location filename="../src/modules/localeq/Map.qml" line="243"/>
|
||||||
<source>Timezone: %1</source>
|
<source>Timezone: %1</source>
|
||||||
<translation type="unfinished"/>
|
<translation>표준시간대: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/localeq/Map.qml" line="264"/>
|
<location filename="../src/modules/localeq/Map.qml" line="264"/>
|
||||||
@ -1945,7 +1945,7 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/oemid/OEMPage.ui" line="52"/>
|
<location filename="../src/modules/oemid/OEMPage.ui" line="52"/>
|
||||||
<source><html><head/><body><h1>OEM Configuration</h1><p>Calamares will use OEM settings while configuring the target system.</p></body></html></source>
|
<source><html><head/><body><h1>OEM Configuration</h1><p>Calamares will use OEM settings while configuring the target system.</p></body></html></source>
|
||||||
<translation><html><head/><body><h1>OEM 구성</h1> <p>Calamares는 대상 시스템을 구성하는 동안 OEM 설정을 사용합니다.</p></body></html></translation>
|
<translation><html><head/><body><h1>OEM 구성</h1> <p>깔라마레스는 대상 시스템을 구성하는 동안 OEM 설정을 사용합니다.</p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -1973,22 +1973,22 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<location filename="../src/modules/localeq/Offline.qml" line="169"/>
|
<location filename="../src/modules/localeq/Offline.qml" line="169"/>
|
||||||
<location filename="../src/modules/localeq/Offline.qml" line="213"/>
|
<location filename="../src/modules/localeq/Offline.qml" line="213"/>
|
||||||
<source>Timezone: %1</source>
|
<source>Timezone: %1</source>
|
||||||
<translation type="unfinished"/>
|
<translation>표준시간대: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/localeq/Offline.qml" line="111"/>
|
<location filename="../src/modules/localeq/Offline.qml" line="111"/>
|
||||||
<source>Select your preferred Zone within your Region.</source>
|
<source>Select your preferred Zone within your Region.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>선호하는 표준시간대와 지역을 선택하세요.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/localeq/Offline.qml" line="182"/>
|
<location filename="../src/modules/localeq/Offline.qml" line="182"/>
|
||||||
<source>Zones</source>
|
<source>Zones</source>
|
||||||
<translation type="unfinished"/>
|
<translation>표준시간대</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/localeq/Offline.qml" line="229"/>
|
<location filename="../src/modules/localeq/Offline.qml" line="229"/>
|
||||||
<source>You can fine-tune Language and Locale settings below.</source>
|
<source>You can fine-tune Language and Locale settings below.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>아래에서 언어 및 로케일을 상세하게 설정할 수 있습니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -2864,7 +2864,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="83"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="83"/>
|
||||||
<source>Directory not found</source>
|
<source>Directory not found</source>
|
||||||
<translation type="unfinished"/>
|
<translation>디렉터리를 찾을 수 없습니다</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="84"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="84"/>
|
||||||
@ -3044,7 +3044,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/fsresizer/ResizeFSJob.cpp" line="176"/>
|
<location filename="../src/modules/fsresizer/ResizeFSJob.cpp" line="176"/>
|
||||||
<source>Calamares cannot start KPMCore for the file-system resize job.</source>
|
<source>Calamares cannot start KPMCore for the file-system resize job.</source>
|
||||||
<translation>Calamares는 파일 시스템 크기 조정 작업을 위해 KPMCore를 시작할 수 없습니다.</translation>
|
<translation>깔라마레스는 파일 시스템 크기 조정 작업을 위해 KPMCore를 시작할 수 없습니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/fsresizer/ResizeFSJob.cpp" line="184"/>
|
<location filename="../src/modules/fsresizer/ResizeFSJob.cpp" line="184"/>
|
||||||
@ -3482,18 +3482,18 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="122"/>
|
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="122"/>
|
||||||
<source>KDE user feedback</source>
|
<source>KDE user feedback</source>
|
||||||
<translation type="unfinished"/>
|
<translation>KDE 사용자 의견</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="128"/>
|
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="128"/>
|
||||||
<source>Configuring KDE user feedback.</source>
|
<source>Configuring KDE user feedback.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>KDE 사용자 의견을 설정하는 중입니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="150"/>
|
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="150"/>
|
||||||
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="156"/>
|
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="156"/>
|
||||||
<source>Error in KDE user feedback configuration.</source>
|
<source>Error in KDE user feedback configuration.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>KDE 사용자 의견 설정 중에 오류가 발생했습니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="151"/>
|
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="151"/>
|
||||||
@ -3744,7 +3744,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="216"/>
|
<location filename="../src/modules/welcome/WelcomePage.cpp" line="216"/>
|
||||||
<source><h1>Welcome to the Calamares setup program for %1.</h1></source>
|
<source><h1>Welcome to the Calamares setup program for %1.</h1></source>
|
||||||
<translation><h1>%1에 대한 Calamares 설정 프로그램에 오신 것을 환영합니다.</h1></translation>
|
<translation><h1>%1에 대한 깔라마레스 설정 프로그램에 오신 것을 환영합니다.</h1></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="217"/>
|
<location filename="../src/modules/welcome/WelcomePage.cpp" line="217"/>
|
||||||
@ -3754,7 +3754,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="222"/>
|
<location filename="../src/modules/welcome/WelcomePage.cpp" line="222"/>
|
||||||
<source><h1>Welcome to the Calamares installer for %1.</h1></source>
|
<source><h1>Welcome to the Calamares installer for %1.</h1></source>
|
||||||
<translation><h1>%1을 위한 Calamares 설치 관리자에 오신 것을 환영합니다.</h1></translation>
|
<translation><h1>%1을 위한 깔라마레스 설치 관리자에 오신 것을 환영합니다.</h1></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="223"/>
|
<location filename="../src/modules/welcome/WelcomePage.cpp" line="223"/>
|
||||||
@ -3877,7 +3877,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/keyboardq/keyboardq.qml" line="276"/>
|
<location filename="../src/modules/keyboardq/keyboardq.qml" line="276"/>
|
||||||
<source>Keyboard Variant</source>
|
<source>Keyboard Variant</source>
|
||||||
<translation type="unfinished"/>
|
<translation>키보드 유형</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/keyboardq/keyboardq.qml" line="386"/>
|
<location filename="../src/modules/keyboardq/keyboardq.qml" line="386"/>
|
||||||
@ -3890,7 +3890,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/localeq/localeq.qml" line="81"/>
|
<location filename="../src/modules/localeq/localeq.qml" line="81"/>
|
||||||
<source>Change</source>
|
<source>Change</source>
|
||||||
<translation type="unfinished"/>
|
<translation>변경</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -3941,7 +3941,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="36"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="36"/>
|
||||||
<source>Pick your user name and credentials to login and perform admin tasks</source>
|
<source>Pick your user name and credentials to login and perform admin tasks</source>
|
||||||
<translation type="unfinished"/>
|
<translation>로그인 및 관리자 작업을 수행하려면 사용자 이름과 자격 증명을 선택하세요</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="52"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="52"/>
|
||||||
@ -3961,7 +3961,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="87"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="87"/>
|
||||||
<source>Login Name</source>
|
<source>Login Name</source>
|
||||||
<translation type="unfinished"/>
|
<translation>로그인 이름</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="103"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="103"/>
|
||||||
@ -4006,7 +4006,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="216"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="216"/>
|
||||||
<source>Validate passwords quality</source>
|
<source>Validate passwords quality</source>
|
||||||
<translation type="unfinished"/>
|
<translation>패스워드 품질 검증</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="226"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="226"/>
|
||||||
@ -4016,12 +4016,12 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="234"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="234"/>
|
||||||
<source>Log in automatically without asking for the password</source>
|
<source>Log in automatically without asking for the password</source>
|
||||||
<translation type="unfinished"/>
|
<translation>패스워드를 묻지 않고 자동으로 로그인합니다</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="243"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="243"/>
|
||||||
<source>Reuse user password as root password</source>
|
<source>Reuse user password as root password</source>
|
||||||
<translation type="unfinished"/>
|
<translation>사용자 패스워드를 루트 패스워드로 재사용합니다</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="253"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="253"/>
|
||||||
@ -4031,22 +4031,22 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="268"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="268"/>
|
||||||
<source>Choose a root password to keep your account safe.</source>
|
<source>Choose a root password to keep your account safe.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>당신의 계정을 안전하게 보호하기 위해서 루트 패스워드를 선택하세요.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="279"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="279"/>
|
||||||
<source>Root Password</source>
|
<source>Root Password</source>
|
||||||
<translation type="unfinished"/>
|
<translation>루트 패스워드</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="298"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="298"/>
|
||||||
<source>Repeat Root Password</source>
|
<source>Repeat Root Password</source>
|
||||||
<translation type="unfinished"/>
|
<translation>루트 패스워드 확인</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="318"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="318"/>
|
||||||
<source>Enter the same password twice, so that it can be checked for typing errors.</source>
|
<source>Enter the same password twice, so that it can be checked for typing errors.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>입력 오류를 확인하기 위해서 동일한 패스워드를 두번 입력해주세요.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -4060,7 +4060,7 @@ Output:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcomeq/welcomeq.qml" line="66"/>
|
<location filename="../src/modules/welcomeq/welcomeq.qml" line="66"/>
|
||||||
<source>About</source>
|
<source>About</source>
|
||||||
<translation>Calamares에 대하여</translation>
|
<translation>깔라마레스에 대하여</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcomeq/welcomeq.qml" line="80"/>
|
<location filename="../src/modules/welcomeq/welcomeq.qml" line="80"/>
|
||||||
|
@ -2870,7 +2870,7 @@ Išvestis:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="83"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="83"/>
|
||||||
<source>Directory not found</source>
|
<source>Directory not found</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Katalogas nerastas</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="84"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="84"/>
|
||||||
@ -3885,7 +3885,7 @@ Išvestis:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/keyboardq/keyboardq.qml" line="276"/>
|
<location filename="../src/modules/keyboardq/keyboardq.qml" line="276"/>
|
||||||
<source>Keyboard Variant</source>
|
<source>Keyboard Variant</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Klaviatūros variantas</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/keyboardq/keyboardq.qml" line="386"/>
|
<location filename="../src/modules/keyboardq/keyboardq.qml" line="386"/>
|
||||||
@ -3989,7 +3989,7 @@ Išvestis:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="87"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="87"/>
|
||||||
<source>Login Name</source>
|
<source>Login Name</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Prisijungimo vardas</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="103"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="103"/>
|
||||||
@ -4009,7 +4009,7 @@ Išvestis:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="140"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="140"/>
|
||||||
<source>This name will be used if you make the computer visible to others on a network.</source>
|
<source>This name will be used if you make the computer visible to others on a network.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Šis vardas bus naudojamas, jeigu padarysite savo kompiuterį matomą kitiems naudotojams tinkle.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="155"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="155"/>
|
||||||
@ -4074,7 +4074,7 @@ Išvestis:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="318"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="318"/>
|
||||||
<source>Enter the same password twice, so that it can be checked for typing errors.</source>
|
<source>Enter the same password twice, so that it can be checked for typing errors.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Norint įsitikinti, kad rašydami slaptažodį nesuklydote, įrašykite tą patį slaptažodį du kartus.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -206,6 +206,8 @@ msgid ""
|
|||||||
"The displaymanagers list is empty or undefined in both globalstorage and "
|
"The displaymanagers list is empty or undefined in both globalstorage and "
|
||||||
"displaymanager.conf."
|
"displaymanager.conf."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Ekran menecerləri siyahısı həm qlobal yaddaşda, həm də displaymanager.conf-"
|
||||||
|
"da boşdur və ya təyin olunmamışdır."
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:977
|
#: src/modules/displaymanager/main.py:977
|
||||||
msgid "Display manager configuration was incomplete"
|
msgid "Display manager configuration was incomplete"
|
||||||
|
@ -206,6 +206,8 @@ msgid ""
|
|||||||
"The displaymanagers list is empty or undefined in both globalstorage and "
|
"The displaymanagers list is empty or undefined in both globalstorage and "
|
||||||
"displaymanager.conf."
|
"displaymanager.conf."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Ekran menecerləri siyahısı həm qlobal yaddaşda, həm də displaymanager.conf-"
|
||||||
|
"da boşdur və ya təyin olunmamışdır."
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:977
|
#: src/modules/displaymanager/main.py:977
|
||||||
msgid "Display manager configuration was incomplete"
|
msgid "Display manager configuration was incomplete"
|
||||||
@ -318,11 +320,11 @@ msgstr "Aparat saatını ayarlamaq."
|
|||||||
|
|
||||||
#: src/modules/mkinitfs/main.py:27
|
#: src/modules/mkinitfs/main.py:27
|
||||||
msgid "Creating initramfs with mkinitfs."
|
msgid "Creating initramfs with mkinitfs."
|
||||||
msgstr "mkinitfs ilə initramfs yaradılır."
|
msgstr "mkinitfs ilə initramfs yaradılır"
|
||||||
|
|
||||||
#: src/modules/mkinitfs/main.py:49
|
#: src/modules/mkinitfs/main.py:49
|
||||||
msgid "Failed to run mkinitfs on the target"
|
msgid "Failed to run mkinitfs on the target"
|
||||||
msgstr "Hədəfdə dracut başladılmadı"
|
msgstr "Hədəfdə mkinitfs başlatmaq baş tutmadı"
|
||||||
|
|
||||||
#: src/modules/mkinitfs/main.py:50 src/modules/dracut/main.py:50
|
#: src/modules/mkinitfs/main.py:50 src/modules/dracut/main.py:50
|
||||||
msgid "The exit code was {}"
|
msgid "The exit code was {}"
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# 김지현 <potatogim@potatogim.net>, 2018
|
# Ji-Hyeon Gim <potatogim@potatogim.net>, 2018
|
||||||
# JungHee Lee <daemul72@gmail.com>, 2020
|
# JungHee Lee <daemul72@gmail.com>, 2020
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
|
2617
lang/tz_vi.ts
Normal file
2617
lang/tz_vi.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -249,6 +249,7 @@ JobQueue::~JobQueue()
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete m_storage;
|
delete m_storage;
|
||||||
|
s_instance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -161,7 +161,10 @@ def modify_mkinitcpio_conf(partitions, root_mount_point):
|
|||||||
hooks.append("usr")
|
hooks.append("usr")
|
||||||
|
|
||||||
if encrypt_hook:
|
if encrypt_hook:
|
||||||
hooks.append("encrypt")
|
if detect_plymouth():
|
||||||
|
hooks.append("plymouth-encrypt")
|
||||||
|
else:
|
||||||
|
hooks.append("encrypt")
|
||||||
if not unencrypted_separate_boot and \
|
if not unencrypted_separate_boot and \
|
||||||
os.path.isfile(
|
os.path.isfile(
|
||||||
os.path.join(root_mount_point, "crypto_keyfile.bin")
|
os.path.join(root_mount_point, "crypto_keyfile.bin")
|
||||||
|
@ -179,6 +179,8 @@ SetKeyboardLayoutJob::findLegacyKeymap() const
|
|||||||
bool
|
bool
|
||||||
SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const QString& convertedKeymapPath ) const
|
SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const QString& convertedKeymapPath ) const
|
||||||
{
|
{
|
||||||
|
cDebug() << "Writing vconsole data to" << vconsoleConfPath;
|
||||||
|
|
||||||
QString keymap = findConvertedKeymap( convertedKeymapPath );
|
QString keymap = findConvertedKeymap( convertedKeymapPath );
|
||||||
if ( keymap.isEmpty() )
|
if ( keymap.isEmpty() )
|
||||||
{
|
{
|
||||||
@ -205,15 +207,20 @@ SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const
|
|||||||
file.close();
|
file.close();
|
||||||
if ( stream.status() != QTextStream::Ok )
|
if ( stream.status() != QTextStream::Ok )
|
||||||
{
|
{
|
||||||
|
cError() << "Could not read lines from" << file.fileName();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out the existing lines and replace the KEYMAP= line
|
// Write out the existing lines and replace the KEYMAP= line
|
||||||
file.open( QIODevice::WriteOnly | QIODevice::Text );
|
if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
|
||||||
|
{
|
||||||
|
cError() << "Could not open" << file.fileName() << "for writing.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
QTextStream stream( &file );
|
QTextStream stream( &file );
|
||||||
bool found = false;
|
bool found = false;
|
||||||
foreach ( const QString& existingLine, existingLines )
|
for ( const QString& existingLine : qAsConst( existingLines ) )
|
||||||
{
|
{
|
||||||
if ( existingLine.trimmed().startsWith( "KEYMAP=" ) )
|
if ( existingLine.trimmed().startsWith( "KEYMAP=" ) )
|
||||||
{
|
{
|
||||||
@ -233,7 +240,7 @@ SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const
|
|||||||
stream.flush();
|
stream.flush();
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
cDebug() << "Written KEYMAP=" << keymap << "to vconsole.conf";
|
cDebug() << Logger::SubEntry << "Written KEYMAP=" << keymap << "to vconsole.conf" << stream.status();
|
||||||
|
|
||||||
return ( stream.status() == QTextStream::Ok );
|
return ( stream.status() == QTextStream::Ok );
|
||||||
}
|
}
|
||||||
@ -242,8 +249,14 @@ SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const
|
|||||||
bool
|
bool
|
||||||
SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const
|
SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const
|
||||||
{
|
{
|
||||||
|
cDebug() << "Writing X11 configuration to" << keyboardConfPath;
|
||||||
|
|
||||||
QFile file( keyboardConfPath );
|
QFile file( keyboardConfPath );
|
||||||
file.open( QIODevice::WriteOnly | QIODevice::Text );
|
if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
|
||||||
|
{
|
||||||
|
cError() << "Could not open" << file.fileName() << "for writing.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
QTextStream stream( &file );
|
QTextStream stream( &file );
|
||||||
|
|
||||||
stream << "# Read and parsed by systemd-localed. It's probably wise not to edit this file\n"
|
stream << "# Read and parsed by systemd-localed. It's probably wise not to edit this file\n"
|
||||||
@ -287,8 +300,8 @@ SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const
|
|||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
cDebug() << "Written XkbLayout" << m_layout << "; XkbModel" << m_model << "; XkbVariant" << m_variant
|
cDebug() << Logger::SubEntry << "Written XkbLayout" << m_layout << "; XkbModel" << m_model << "; XkbVariant"
|
||||||
<< "to X.org file" << keyboardConfPath;
|
<< m_variant << "to X.org file" << keyboardConfPath << stream.status();
|
||||||
|
|
||||||
return ( stream.status() == QTextStream::Ok );
|
return ( stream.status() == QTextStream::Ok );
|
||||||
}
|
}
|
||||||
@ -297,8 +310,14 @@ SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const
|
|||||||
bool
|
bool
|
||||||
SetKeyboardLayoutJob::writeDefaultKeyboardData( const QString& defaultKeyboardPath ) const
|
SetKeyboardLayoutJob::writeDefaultKeyboardData( const QString& defaultKeyboardPath ) const
|
||||||
{
|
{
|
||||||
|
cDebug() << "Writing default keyboard data to" << defaultKeyboardPath;
|
||||||
|
|
||||||
QFile file( defaultKeyboardPath );
|
QFile file( defaultKeyboardPath );
|
||||||
file.open( QIODevice::WriteOnly | QIODevice::Text );
|
if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
|
||||||
|
{
|
||||||
|
cError() << "Could not open" << defaultKeyboardPath << "for writing";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
QTextStream stream( &file );
|
QTextStream stream( &file );
|
||||||
|
|
||||||
stream << "# KEYBOARD CONFIGURATION FILE\n\n"
|
stream << "# KEYBOARD CONFIGURATION FILE\n\n"
|
||||||
@ -313,8 +332,8 @@ SetKeyboardLayoutJob::writeDefaultKeyboardData( const QString& defaultKeyboardPa
|
|||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
cDebug() << "Written XKBMODEL" << m_model << "; XKBLAYOUT" << m_layout << "; XKBVARIANT" << m_variant
|
cDebug() << Logger::SubEntry << "Written XKBMODEL" << m_model << "; XKBLAYOUT" << m_layout << "; XKBVARIANT"
|
||||||
<< "to /etc/default/keyboard file" << defaultKeyboardPath;
|
<< m_variant << "to /etc/default/keyboard file" << defaultKeyboardPath << stream.status();
|
||||||
|
|
||||||
return ( stream.status() == QTextStream::Ok );
|
return ( stream.status() == QTextStream::Ok );
|
||||||
}
|
}
|
||||||
@ -329,60 +348,72 @@ SetKeyboardLayoutJob::exec()
|
|||||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
QDir destDir( gs->value( "rootMountPoint" ).toString() );
|
QDir destDir( gs->value( "rootMountPoint" ).toString() );
|
||||||
|
|
||||||
// Get the path to the destination's /etc/vconsole.conf
|
|
||||||
QString vconsoleConfPath = destDir.absoluteFilePath( "etc/vconsole.conf" );
|
|
||||||
|
|
||||||
// Get the path to the destination's /etc/X11/xorg.conf.d/00-keyboard.conf
|
|
||||||
QString xorgConfDPath;
|
|
||||||
QString keyboardConfPath;
|
|
||||||
if ( QDir::isAbsolutePath( m_xOrgConfFileName ) )
|
|
||||||
{
|
{
|
||||||
keyboardConfPath = m_xOrgConfFileName;
|
// Get the path to the destination's /etc/vconsole.conf
|
||||||
while ( keyboardConfPath.startsWith( '/' ) )
|
QString vconsoleConfPath = destDir.absoluteFilePath( "etc/vconsole.conf" );
|
||||||
|
|
||||||
|
// Get the path to the destination's path to the converted key mappings
|
||||||
|
QString convertedKeymapPath = m_convertedKeymapPath;
|
||||||
|
if ( !convertedKeymapPath.isEmpty() )
|
||||||
{
|
{
|
||||||
keyboardConfPath.remove( 0, 1 );
|
while ( convertedKeymapPath.startsWith( '/' ) )
|
||||||
|
{
|
||||||
|
convertedKeymapPath.remove( 0, 1 );
|
||||||
|
}
|
||||||
|
convertedKeymapPath = destDir.absoluteFilePath( convertedKeymapPath );
|
||||||
}
|
}
|
||||||
keyboardConfPath = destDir.absoluteFilePath( keyboardConfPath );
|
|
||||||
xorgConfDPath = QFileInfo( keyboardConfPath ).path();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xorgConfDPath = destDir.absoluteFilePath( "etc/X11/xorg.conf.d" );
|
|
||||||
keyboardConfPath = QDir( xorgConfDPath ).absoluteFilePath( m_xOrgConfFileName );
|
|
||||||
}
|
|
||||||
destDir.mkpath( xorgConfDPath );
|
|
||||||
|
|
||||||
QString defaultKeyboardPath;
|
if ( !writeVConsoleData( vconsoleConfPath, convertedKeymapPath ) )
|
||||||
if ( QDir( destDir.absoluteFilePath( "etc/default" ) ).exists() )
|
|
||||||
{
|
|
||||||
defaultKeyboardPath = destDir.absoluteFilePath( "etc/default/keyboard" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the path to the destination's path to the converted key mappings
|
|
||||||
QString convertedKeymapPath = m_convertedKeymapPath;
|
|
||||||
if ( !convertedKeymapPath.isEmpty() )
|
|
||||||
{
|
|
||||||
while ( convertedKeymapPath.startsWith( '/' ) )
|
|
||||||
{
|
{
|
||||||
convertedKeymapPath.remove( 0, 1 );
|
return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for the virtual console." ),
|
||||||
|
tr( "Failed to write to %1" ).arg( vconsoleConfPath ) );
|
||||||
}
|
}
|
||||||
convertedKeymapPath = destDir.absoluteFilePath( convertedKeymapPath );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !writeVConsoleData( vconsoleConfPath, convertedKeymapPath ) )
|
|
||||||
return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for the virtual console." ),
|
|
||||||
tr( "Failed to write to %1" ).arg( vconsoleConfPath ) );
|
|
||||||
|
|
||||||
if ( !writeX11Data( keyboardConfPath ) )
|
|
||||||
return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for X11." ),
|
|
||||||
tr( "Failed to write to %1" ).arg( keyboardConfPath ) );
|
|
||||||
|
|
||||||
if ( !defaultKeyboardPath.isEmpty() && m_writeEtcDefaultKeyboard )
|
|
||||||
{
|
{
|
||||||
if ( !writeDefaultKeyboardData( defaultKeyboardPath ) )
|
// Get the path to the destination's /etc/X11/xorg.conf.d/00-keyboard.conf
|
||||||
return Calamares::JobResult::error(
|
QString xorgConfDPath;
|
||||||
tr( "Failed to write keyboard configuration to existing /etc/default directory." ),
|
QString keyboardConfPath;
|
||||||
tr( "Failed to write to %1" ).arg( keyboardConfPath ) );
|
if ( QDir::isAbsolutePath( m_xOrgConfFileName ) )
|
||||||
|
{
|
||||||
|
keyboardConfPath = m_xOrgConfFileName;
|
||||||
|
while ( keyboardConfPath.startsWith( '/' ) )
|
||||||
|
{
|
||||||
|
keyboardConfPath.remove( 0, 1 );
|
||||||
|
}
|
||||||
|
keyboardConfPath = destDir.absoluteFilePath( keyboardConfPath );
|
||||||
|
xorgConfDPath = QFileInfo( keyboardConfPath ).path();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xorgConfDPath = destDir.absoluteFilePath( "etc/X11/xorg.conf.d" );
|
||||||
|
keyboardConfPath = QDir( xorgConfDPath ).absoluteFilePath( m_xOrgConfFileName );
|
||||||
|
}
|
||||||
|
destDir.mkpath( xorgConfDPath );
|
||||||
|
|
||||||
|
if ( !writeX11Data( keyboardConfPath ) )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for X11." ),
|
||||||
|
tr( "Failed to write to %1" ).arg( keyboardConfPath ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QString defaultKeyboardPath;
|
||||||
|
if ( QDir( destDir.absoluteFilePath( "etc/default" ) ).exists() )
|
||||||
|
{
|
||||||
|
defaultKeyboardPath = destDir.absoluteFilePath( "etc/default/keyboard" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !defaultKeyboardPath.isEmpty() && m_writeEtcDefaultKeyboard )
|
||||||
|
{
|
||||||
|
if ( !writeDefaultKeyboardData( defaultKeyboardPath ) )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::error(
|
||||||
|
tr( "Failed to write keyboard configuration to existing /etc/default directory." ),
|
||||||
|
tr( "Failed to write to %1" ).arg( defaultKeyboardPath ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Calamares::JobResult::ok();
|
return Calamares::JobResult::ok();
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
# SPDX-FileCopyrightText: 2017 Alf Gaida <agaida@siduction.org>
|
# SPDX-FileCopyrightText: 2017 Alf Gaida <agaida@siduction.org>
|
||||||
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
# SPDX-FileCopyrightText: 2019 Kevin Kofler <kevin.kofler@chello.at>
|
# SPDX-FileCopyrightText: 2019 Kevin Kofler <kevin.kofler@chello.at>
|
||||||
|
# SPDX-FileCopyrightText: 2019-2020 Collabora Ltd
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
#
|
#
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
# Calamares is Free Software: see the License-Identifier above.
|
||||||
@ -38,6 +39,9 @@ def mount_partition(root_mount_point, partition, partitions):
|
|||||||
# Create mount point with `+` rather than `os.path.join()` because
|
# Create mount point with `+` rather than `os.path.join()` because
|
||||||
# `partition["mountPoint"]` starts with a '/'.
|
# `partition["mountPoint"]` starts with a '/'.
|
||||||
raw_mount_point = partition["mountPoint"]
|
raw_mount_point = partition["mountPoint"]
|
||||||
|
if not raw_mount_point:
|
||||||
|
return
|
||||||
|
|
||||||
mount_point = root_mount_point + raw_mount_point
|
mount_point = root_mount_point + raw_mount_point
|
||||||
|
|
||||||
# Ensure that the created directory has the correct SELinux context on
|
# Ensure that the created directory has the correct SELinux context on
|
||||||
@ -52,26 +56,22 @@ def mount_partition(root_mount_point, partition, partitions):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
fstype = partition.get("fs", "").lower()
|
fstype = partition.get("fs", "").lower()
|
||||||
|
if not fstype or fstype == "unformatted":
|
||||||
|
return
|
||||||
|
|
||||||
if fstype == "fat16" or fstype == "fat32":
|
if fstype == "fat16" or fstype == "fat32":
|
||||||
fstype = "vfat"
|
fstype = "vfat"
|
||||||
|
|
||||||
if "luksMapperName" in partition:
|
device = partition["device"]
|
||||||
libcalamares.utils.debug(
|
|
||||||
"about to mount {!s}".format(partition["luksMapperName"]))
|
|
||||||
libcalamares.utils.mount(
|
|
||||||
"/dev/mapper/{!s}".format(partition["luksMapperName"]),
|
|
||||||
mount_point,
|
|
||||||
fstype,
|
|
||||||
partition.get("options", ""),
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
if "luksMapperName" in partition:
|
||||||
libcalamares.utils.mount(partition["device"],
|
device = os.path.join("/dev/mapper", partition["luksMapperName"])
|
||||||
mount_point,
|
|
||||||
fstype,
|
if libcalamares.utils.mount(device,
|
||||||
partition.get("options", ""),
|
mount_point,
|
||||||
)
|
fstype,
|
||||||
|
partition.get("options", "")) != 0:
|
||||||
|
libcalamares.utils.warning("Cannot mount {}".format(device))
|
||||||
|
|
||||||
# If the root partition is btrfs, we create a subvolume "@"
|
# If the root partition is btrfs, we create a subvolume "@"
|
||||||
# for the root mount point.
|
# for the root mount point.
|
||||||
@ -96,37 +96,23 @@ def mount_partition(root_mount_point, partition, partitions):
|
|||||||
|
|
||||||
subprocess.check_call(["umount", "-v", root_mount_point])
|
subprocess.check_call(["umount", "-v", root_mount_point])
|
||||||
|
|
||||||
|
device = partition["device"]
|
||||||
|
|
||||||
if "luksMapperName" in partition:
|
if "luksMapperName" in partition:
|
||||||
libcalamares.utils.mount(
|
device = os.path.join("/dev/mapper", partition["luksMapperName"])
|
||||||
"/dev/mapper/{!s}".format(partition["luksMapperName"]),
|
|
||||||
mount_point,
|
if libcalamares.utils.mount(device,
|
||||||
fstype,
|
mount_point,
|
||||||
",".join(
|
fstype,
|
||||||
["subvol=@", partition.get("options", "")]),
|
",".join(["subvol=@", partition.get("options", "")])) != 0:
|
||||||
)
|
libcalamares.utils.warning("Cannot mount {}".format(device))
|
||||||
if not has_home_mount_point:
|
|
||||||
libcalamares.utils.mount(
|
if not has_home_mount_point:
|
||||||
"/dev/mapper/{!s}".format(partition["luksMapperName"]),
|
if libcalamares.utils.mount(device,
|
||||||
root_mount_point + "/home",
|
root_mount_point + "/home",
|
||||||
fstype,
|
fstype,
|
||||||
",".join(
|
",".join(["subvol=@home", partition.get("options", "")])) != 0:
|
||||||
["subvol=@home", partition.get("options", "")]),
|
libcalamares.utils.warning("Cannot mount {}".format(device))
|
||||||
)
|
|
||||||
else:
|
|
||||||
libcalamares.utils.mount(
|
|
||||||
partition["device"],
|
|
||||||
mount_point,
|
|
||||||
fstype,
|
|
||||||
",".join(["subvol=@", partition.get("options", "")]),
|
|
||||||
)
|
|
||||||
if not has_home_mount_point:
|
|
||||||
libcalamares.utils.mount(
|
|
||||||
partition["device"],
|
|
||||||
root_mount_point + "/home",
|
|
||||||
fstype,
|
|
||||||
",".join(
|
|
||||||
["subvol=@home", partition.get("options", "")]),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
|
@ -439,11 +439,14 @@ isEfiSystem()
|
|||||||
bool
|
bool
|
||||||
isEfiBootable( const Partition* candidate )
|
isEfiBootable( const Partition* candidate )
|
||||||
{
|
{
|
||||||
cDebug() << "Check EFI bootable" << convenienceName( candidate ) << candidate->devicePath();
|
const auto flags = PartitionInfo::flags( candidate );
|
||||||
cDebug() << Logger::SubEntry << "flags" << candidate->activeFlags();
|
|
||||||
|
|
||||||
auto flags = PartitionInfo::flags( candidate );
|
|
||||||
|
|
||||||
|
// TODO: with KPMCore 4, this comment is wrong: the flags
|
||||||
|
// are remapped, and the ESP flag is the same as Boot.
|
||||||
|
#if defined( WITH_KPMCORE4API )
|
||||||
|
static_assert( KPM_PARTITION_FLAG_ESP == KPM_PARTITION_FLAG( Boot ), "KPMCore API enum changed" );
|
||||||
|
return flags.testFlag( KPM_PARTITION_FLAG_ESP );
|
||||||
|
#else
|
||||||
/* If bit 17 is set, old-style Esp flag, it's OK */
|
/* If bit 17 is set, old-style Esp flag, it's OK */
|
||||||
if ( flags.testFlag( KPM_PARTITION_FLAG_ESP ) )
|
if ( flags.testFlag( KPM_PARTITION_FLAG_ESP ) )
|
||||||
{
|
{
|
||||||
@ -455,19 +458,28 @@ isEfiBootable( const Partition* candidate )
|
|||||||
while ( root && !root->isRoot() )
|
while ( root && !root->isRoot() )
|
||||||
{
|
{
|
||||||
root = root->parent();
|
root = root->parent();
|
||||||
cDebug() << Logger::SubEntry << "moved towards root" << Logger::Pointer( root );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strange case: no root found, no partition table node?
|
// Strange case: no root found, no partition table node?
|
||||||
if ( !root )
|
if ( !root )
|
||||||
{
|
{
|
||||||
|
cWarning() << "No root of partition table found.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PartitionTable* table = dynamic_cast< const PartitionTable* >( root );
|
const PartitionTable* table = dynamic_cast< const PartitionTable* >( root );
|
||||||
cDebug() << Logger::SubEntry << "partition table" << Logger::Pointer( table ) << "type"
|
if ( !table )
|
||||||
<< ( table ? table->type() : PartitionTable::TableType::unknownTableType );
|
{
|
||||||
return table && ( table->type() == PartitionTable::TableType::gpt ) && flags.testFlag( KPM_PARTITION_FLAG( Boot ) );
|
cWarning() << "Root of partition table is not a PartitionTable object";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( table->type() == PartitionTable::TableType::gpt )
|
||||||
|
{
|
||||||
|
const auto bootFlag = KPM_PARTITION_FLAG( Boot );
|
||||||
|
return flags.testFlag( bootFlag );
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
|
@ -97,21 +97,6 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO
|
|||||||
// empty and a EFI boot partition, while BIOS starts at
|
// empty and a EFI boot partition, while BIOS starts at
|
||||||
// the 1MiB boundary (usually sector 2048).
|
// the 1MiB boundary (usually sector 2048).
|
||||||
int empty_space_sizeB = isEfi ? 2_MiB : 1_MiB;
|
int empty_space_sizeB = isEfi ? 2_MiB : 1_MiB;
|
||||||
int uefisys_part_sizeB = 0_MiB;
|
|
||||||
|
|
||||||
if ( isEfi )
|
|
||||||
{
|
|
||||||
if ( gs->contains( "efiSystemPartitionSize" ) )
|
|
||||||
{
|
|
||||||
CalamaresUtils::Partition::PartitionSize part_size
|
|
||||||
= CalamaresUtils::Partition::PartitionSize( gs->value( "efiSystemPartitionSize" ).toString() );
|
|
||||||
uefisys_part_sizeB = part_size.toBytes( dev->capacity() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uefisys_part_sizeB = 300_MiB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since sectors count from 0, if the space is 2048 sectors in size,
|
// Since sectors count from 0, if the space is 2048 sectors in size,
|
||||||
// the first free sector has number 2048 (and there are 2048 sectors
|
// the first free sector has number 2048 (and there are 2048 sectors
|
||||||
@ -128,6 +113,14 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO
|
|||||||
|
|
||||||
if ( isEfi )
|
if ( isEfi )
|
||||||
{
|
{
|
||||||
|
int uefisys_part_sizeB = 300_MiB;
|
||||||
|
if ( gs->contains( "efiSystemPartitionSize" ) )
|
||||||
|
{
|
||||||
|
CalamaresUtils::Partition::PartitionSize part_size
|
||||||
|
= CalamaresUtils::Partition::PartitionSize( gs->value( "efiSystemPartitionSize" ).toString() );
|
||||||
|
uefisys_part_sizeB = part_size.toBytes( dev->capacity() );
|
||||||
|
}
|
||||||
|
|
||||||
qint64 efiSectorCount = CalamaresUtils::bytesToSectors( uefisys_part_sizeB, dev->logicalSize() );
|
qint64 efiSectorCount = CalamaresUtils::bytesToSectors( uefisys_part_sizeB, dev->logicalSize() );
|
||||||
Q_ASSERT( efiSectorCount > 0 );
|
Q_ASSERT( efiSectorCount > 0 );
|
||||||
|
|
||||||
@ -203,6 +196,10 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO
|
|||||||
KPM_PARTITION_FLAG( None ) );
|
KPM_PARTITION_FLAG( None ) );
|
||||||
}
|
}
|
||||||
PartitionInfo::setFormat( swapPartition, true );
|
PartitionInfo::setFormat( swapPartition, true );
|
||||||
|
if ( gs->contains( "swapPartitionName" ))
|
||||||
|
{
|
||||||
|
swapPartition->setLabel( gs->value( "swapPartitionName" ).toString() );
|
||||||
|
}
|
||||||
core->createPartition( dev, swapPartition );
|
core->createPartition( dev, swapPartition );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -716,6 +716,8 @@ PartitionCoreModule::updateIsDirty()
|
|||||||
void
|
void
|
||||||
PartitionCoreModule::scanForEfiSystemPartitions()
|
PartitionCoreModule::scanForEfiSystemPartitions()
|
||||||
{
|
{
|
||||||
|
const bool wasEmpty = m_efiSystemPartitions.isEmpty();
|
||||||
|
|
||||||
m_efiSystemPartitions.clear();
|
m_efiSystemPartitions.clear();
|
||||||
|
|
||||||
QList< Device* > devices;
|
QList< Device* > devices;
|
||||||
@ -732,6 +734,11 @@ PartitionCoreModule::scanForEfiSystemPartitions()
|
|||||||
{
|
{
|
||||||
cWarning() << "system is EFI but no EFI system partitions found.";
|
cWarning() << "system is EFI but no EFI system partitions found.";
|
||||||
}
|
}
|
||||||
|
else if ( wasEmpty )
|
||||||
|
{
|
||||||
|
// But it isn't empty anymore, so whatever problem has been solved
|
||||||
|
cDebug() << "system is EFI and new EFI system partition has been found.";
|
||||||
|
}
|
||||||
|
|
||||||
m_efiSystemPartitions = efiSystemPartitions;
|
m_efiSystemPartitions = efiSystemPartitions;
|
||||||
}
|
}
|
||||||
@ -861,9 +868,9 @@ PartitionCoreModule::setBootLoaderInstallPath( const QString& path )
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PartitionCoreModule::initLayout( const QVariantList& config )
|
PartitionCoreModule::initLayout( FileSystem::Type defaultFsType, const QVariantList& config )
|
||||||
{
|
{
|
||||||
m_partLayout.init( config );
|
m_partLayout.init( defaultFsType, config );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -875,7 +882,8 @@ PartitionCoreModule::layoutApply( Device* dev,
|
|||||||
const PartitionRole& role )
|
const PartitionRole& role )
|
||||||
{
|
{
|
||||||
bool isEfi = PartUtils::isEfiSystem();
|
bool isEfi = PartUtils::isEfiSystem();
|
||||||
QList< Partition* > partList = m_partLayout.createPartitions( dev, firstSector, lastSector, luksPassphrase, parent, role );
|
QList< Partition* > partList
|
||||||
|
= m_partLayout.createPartitions( dev, firstSector, lastSector, luksPassphrase, parent, role );
|
||||||
|
|
||||||
// Partition::mountPoint() tells us where it is mounted **now**, while
|
// Partition::mountPoint() tells us where it is mounted **now**, while
|
||||||
// PartitionInfo::mountPoint() says where it will be mounted in the target system.
|
// PartitionInfo::mountPoint() says where it will be mounted in the target system.
|
||||||
|
@ -156,7 +156,11 @@ public:
|
|||||||
/// @brief Set the path where the bootloader will be installed
|
/// @brief Set the path where the bootloader will be installed
|
||||||
void setBootLoaderInstallPath( const QString& path );
|
void setBootLoaderInstallPath( const QString& path );
|
||||||
|
|
||||||
void initLayout( const QVariantList& config = QVariantList() );
|
/** @brief Initialize the default layout that will be applied
|
||||||
|
*
|
||||||
|
* See PartitionLayout::init()
|
||||||
|
*/
|
||||||
|
void initLayout( FileSystem::Type defaultFsType, const QVariantList& config = QVariantList() );
|
||||||
|
|
||||||
void layoutApply( Device* dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase );
|
void layoutApply( Device* dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase );
|
||||||
void layoutApply( Device* dev,
|
void layoutApply( Device* dev,
|
||||||
|
@ -52,7 +52,15 @@ PartitionTable::Flags
|
|||||||
flags( const Partition* partition )
|
flags( const Partition* partition )
|
||||||
{
|
{
|
||||||
auto v = partition->property( FLAGS_PROPERTY );
|
auto v = partition->property( FLAGS_PROPERTY );
|
||||||
if ( v.type() == QVariant::Int )
|
if ( !v.isValid() )
|
||||||
|
{
|
||||||
|
return partition->activeFlags();
|
||||||
|
}
|
||||||
|
// The underlying type of PartitionTable::Flags can be int or uint
|
||||||
|
// (see qflags.h) and so setting those flags can create a QVariant
|
||||||
|
// of those types; we don't just want to check QVariant::canConvert()
|
||||||
|
// here because that will also accept QByteArray and some other things.
|
||||||
|
if ( v.type() == QVariant::Int || v.type() == QVariant::UInt )
|
||||||
{
|
{
|
||||||
return static_cast< PartitionTable::Flags >( v.toInt() );
|
return static_cast< PartitionTable::Flags >( v.toInt() );
|
||||||
}
|
}
|
||||||
|
@ -27,32 +27,10 @@
|
|||||||
#include <kpmcore/core/partition.h>
|
#include <kpmcore/core/partition.h>
|
||||||
#include <kpmcore/fs/filesystem.h>
|
#include <kpmcore/fs/filesystem.h>
|
||||||
|
|
||||||
static FileSystem::Type
|
PartitionLayout::PartitionLayout() {}
|
||||||
getDefaultFileSystemType()
|
|
||||||
{
|
|
||||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
|
||||||
FileSystem::Type defaultFS = FileSystem::Ext4;
|
|
||||||
|
|
||||||
if ( gs->contains( "defaultFileSystemType" ) )
|
|
||||||
{
|
|
||||||
PartUtils::findFS( gs->value( "defaultFileSystemType" ).toString(), &defaultFS );
|
|
||||||
if ( defaultFS == FileSystem::Unknown )
|
|
||||||
{
|
|
||||||
defaultFS = FileSystem::Ext4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultFS;
|
|
||||||
}
|
|
||||||
|
|
||||||
PartitionLayout::PartitionLayout()
|
|
||||||
: m_defaultFsType( getDefaultFileSystemType() )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PartitionLayout::PartitionLayout( const PartitionLayout& layout )
|
PartitionLayout::PartitionLayout( const PartitionLayout& layout )
|
||||||
: m_defaultFsType( layout.m_defaultFsType )
|
: m_partLayout( layout.m_partLayout )
|
||||||
, m_partLayout( layout.m_partLayout )
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,9 +41,14 @@ PartitionLayout::PartitionEntry::PartitionEntry()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PartitionLayout::PartitionEntry::PartitionEntry( const QString& mountPoint, const QString& size, const QString& minSize, const QString& maxSize )
|
PartitionLayout::PartitionEntry::PartitionEntry( FileSystem::Type fs,
|
||||||
|
const QString& mountPoint,
|
||||||
|
const QString& size,
|
||||||
|
const QString& minSize,
|
||||||
|
const QString& maxSize )
|
||||||
: partAttributes( 0 )
|
: partAttributes( 0 )
|
||||||
, partMountPoint( mountPoint )
|
, partMountPoint( mountPoint )
|
||||||
|
, partFileSystem( fs )
|
||||||
, partSize( size )
|
, partSize( size )
|
||||||
, partMinSize( minSize )
|
, partMinSize( minSize )
|
||||||
, partMaxSize( maxSize )
|
, partMaxSize( maxSize )
|
||||||
@ -95,20 +78,6 @@ PartitionLayout::PartitionEntry::PartitionEntry( const QString& label,
|
|||||||
PartUtils::findFS( fs, &partFileSystem );
|
PartUtils::findFS( fs, &partFileSystem );
|
||||||
}
|
}
|
||||||
|
|
||||||
PartitionLayout::PartitionEntry::PartitionEntry( const PartitionEntry& e )
|
|
||||||
: partLabel( e.partLabel )
|
|
||||||
, partUUID( e.partUUID )
|
|
||||||
, partType( e.partType )
|
|
||||||
, partAttributes( e.partAttributes )
|
|
||||||
, partMountPoint( e.partMountPoint )
|
|
||||||
, partFileSystem( e.partFileSystem )
|
|
||||||
, partFeatures( e.partFeatures )
|
|
||||||
, partSize( e.partSize )
|
|
||||||
, partMinSize( e.partMinSize )
|
|
||||||
, partMaxSize( e.partMaxSize )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PartitionLayout::addEntry( const PartitionEntry& entry )
|
PartitionLayout::addEntry( const PartitionEntry& entry )
|
||||||
@ -124,7 +93,7 @@ PartitionLayout::addEntry( const PartitionEntry& entry )
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PartitionLayout::init( const QVariantList& config )
|
PartitionLayout::init( FileSystem::Type defaultFsType, const QVariantList& config )
|
||||||
{
|
{
|
||||||
bool ok;
|
bool ok;
|
||||||
|
|
||||||
@ -134,8 +103,7 @@ PartitionLayout::init( const QVariantList& config )
|
|||||||
{
|
{
|
||||||
QVariantMap pentry = r.toMap();
|
QVariantMap pentry = r.toMap();
|
||||||
|
|
||||||
if ( !pentry.contains( "name" ) || !pentry.contains( "mountPoint" ) || !pentry.contains( "filesystem" )
|
if ( !pentry.contains( "name" ) || !pentry.contains( "size" ) )
|
||||||
|| !pentry.contains( "size" ) )
|
|
||||||
{
|
{
|
||||||
cError() << "Partition layout entry #" << config.indexOf( r )
|
cError() << "Partition layout entry #" << config.indexOf( r )
|
||||||
<< "lacks mandatory attributes, switching to default layout.";
|
<< "lacks mandatory attributes, switching to default layout.";
|
||||||
@ -148,7 +116,7 @@ PartitionLayout::init( const QVariantList& config )
|
|||||||
CalamaresUtils::getString( pentry, "type" ),
|
CalamaresUtils::getString( pentry, "type" ),
|
||||||
CalamaresUtils::getUnsignedInteger( pentry, "attributes", 0 ),
|
CalamaresUtils::getUnsignedInteger( pentry, "attributes", 0 ),
|
||||||
CalamaresUtils::getString( pentry, "mountPoint" ),
|
CalamaresUtils::getString( pentry, "mountPoint" ),
|
||||||
CalamaresUtils::getString( pentry, "filesystem" ),
|
CalamaresUtils::getString( pentry, "filesystem", "unformatted" ),
|
||||||
CalamaresUtils::getSubMap( pentry, "features", ok ),
|
CalamaresUtils::getSubMap( pentry, "features", ok ),
|
||||||
CalamaresUtils::getString( pentry, "size", QStringLiteral( "0" ) ),
|
CalamaresUtils::getString( pentry, "size", QStringLiteral( "0" ) ),
|
||||||
CalamaresUtils::getString( pentry, "minSize", QStringLiteral( "0" ) ),
|
CalamaresUtils::getString( pentry, "minSize", QStringLiteral( "0" ) ),
|
||||||
@ -162,7 +130,7 @@ PartitionLayout::init( const QVariantList& config )
|
|||||||
|
|
||||||
if ( !m_partLayout.count() )
|
if ( !m_partLayout.count() )
|
||||||
{
|
{
|
||||||
addEntry( { QString( "/" ), QString( "100%" ) } );
|
addEntry( { defaultFsType, QString( "/" ), QString( "100%" ) } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,8 +196,8 @@ PartitionLayout::createPartitions( Device* dev,
|
|||||||
{
|
{
|
||||||
if ( entry.partSize.unit() == CalamaresUtils::Partition::SizeUnit::Percent )
|
if ( entry.partSize.unit() == CalamaresUtils::Partition::SizeUnit::Percent )
|
||||||
{
|
{
|
||||||
qint64 sectors = entry.partSize.toSectors( availableSectors + partSectorsMap.value( &entry ),
|
qint64 sectors
|
||||||
dev->logicalSize() );
|
= entry.partSize.toSectors( availableSectors + partSectorsMap.value( &entry ), dev->logicalSize() );
|
||||||
if ( entry.partMinSize.isValid() )
|
if ( entry.partMinSize.isValid() )
|
||||||
{
|
{
|
||||||
sectors = std::max( sectors, entry.partMinSize.toSectors( totalSectors, dev->logicalSize() ) );
|
sectors = std::max( sectors, entry.partMinSize.toSectors( totalSectors, dev->logicalSize() ) );
|
||||||
@ -258,13 +226,24 @@ PartitionLayout::createPartitions( Device* dev,
|
|||||||
Partition* part = nullptr;
|
Partition* part = nullptr;
|
||||||
if ( luksPassphrase.isEmpty() )
|
if ( luksPassphrase.isEmpty() )
|
||||||
{
|
{
|
||||||
part = KPMHelpers::createNewPartition(
|
part = KPMHelpers::createNewPartition( parent,
|
||||||
parent, *dev, role, entry.partFileSystem, currentSector, currentSector + sectors - 1, KPM_PARTITION_FLAG( None ) );
|
*dev,
|
||||||
|
role,
|
||||||
|
entry.partFileSystem,
|
||||||
|
currentSector,
|
||||||
|
currentSector + sectors - 1,
|
||||||
|
KPM_PARTITION_FLAG( None ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
part = KPMHelpers::createNewEncryptedPartition(
|
part = KPMHelpers::createNewEncryptedPartition( parent,
|
||||||
parent, *dev, role, entry.partFileSystem, currentSector, currentSector + sectors - 1, luksPassphrase, KPM_PARTITION_FLAG( None ) );
|
*dev,
|
||||||
|
role,
|
||||||
|
entry.partFileSystem,
|
||||||
|
currentSector,
|
||||||
|
currentSector + sectors - 1,
|
||||||
|
luksPassphrase,
|
||||||
|
KPM_PARTITION_FLAG( None ) );
|
||||||
}
|
}
|
||||||
PartitionInfo::setFormat( part, true );
|
PartitionInfo::setFormat( part, true );
|
||||||
PartitionInfo::setMountPoint( part, entry.partMountPoint );
|
PartitionInfo::setMountPoint( part, entry.partMountPoint );
|
||||||
|
@ -34,7 +34,7 @@ public:
|
|||||||
QString partLabel;
|
QString partLabel;
|
||||||
QString partUUID;
|
QString partUUID;
|
||||||
QString partType;
|
QString partType;
|
||||||
quint64 partAttributes;
|
quint64 partAttributes = 0;
|
||||||
QString partMountPoint;
|
QString partMountPoint;
|
||||||
FileSystem::Type partFileSystem = FileSystem::Unknown;
|
FileSystem::Type partFileSystem = FileSystem::Unknown;
|
||||||
QVariantMap partFeatures;
|
QVariantMap partFeatures;
|
||||||
@ -44,8 +44,13 @@ public:
|
|||||||
|
|
||||||
/// @brief All-zeroes PartitionEntry
|
/// @brief All-zeroes PartitionEntry
|
||||||
PartitionEntry();
|
PartitionEntry();
|
||||||
/// @brief Parse @p mountPoint, @p size, @p minSize and @p maxSize to their respective member variables
|
/** @brief Parse @p mountPoint, @p size, @p minSize and @p maxSize to their respective member variables
|
||||||
PartitionEntry( const QString& mountPoint,
|
*
|
||||||
|
* Sets a specific FS type (not parsed from string like the other
|
||||||
|
* constructor).
|
||||||
|
*/
|
||||||
|
PartitionEntry( FileSystem::Type fs,
|
||||||
|
const QString& mountPoint,
|
||||||
const QString& size,
|
const QString& size,
|
||||||
const QString& minSize = QString(),
|
const QString& minSize = QString(),
|
||||||
const QString& maxSize = QString() );
|
const QString& maxSize = QString() );
|
||||||
@ -61,7 +66,7 @@ public:
|
|||||||
const QString& minSize = QString(),
|
const QString& minSize = QString(),
|
||||||
const QString& maxSize = QString() );
|
const QString& maxSize = QString() );
|
||||||
/// @brief Copy PartitionEntry
|
/// @brief Copy PartitionEntry
|
||||||
PartitionEntry( const PartitionEntry& e );
|
PartitionEntry( const PartitionEntry& e ) = default;
|
||||||
|
|
||||||
bool isValid() const
|
bool isValid() const
|
||||||
{
|
{
|
||||||
@ -78,7 +83,13 @@ public:
|
|||||||
PartitionLayout( const PartitionLayout& layout );
|
PartitionLayout( const PartitionLayout& layout );
|
||||||
~PartitionLayout();
|
~PartitionLayout();
|
||||||
|
|
||||||
void init( const QVariantList& config );
|
/** @brief create the configuration from @p config
|
||||||
|
*
|
||||||
|
* @p config is a list of partition entries (in QVariant form,
|
||||||
|
* read from YAML). If no entries are given, then a single
|
||||||
|
* partition is created with the given @p defaultFsType
|
||||||
|
*/
|
||||||
|
void init( FileSystem::Type defaultFsType, const QVariantList& config );
|
||||||
bool addEntry( const PartitionEntry& entry );
|
bool addEntry( const PartitionEntry& entry );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,7 +104,6 @@ public:
|
|||||||
const PartitionRole& role );
|
const PartitionRole& role );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileSystem::Type m_defaultFsType;
|
|
||||||
QList< PartitionEntry > m_partLayout;
|
QList< PartitionEntry > m_partLayout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,8 +136,8 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core )
|
|||||||
bool partResizedMoved = newFirstSector != m_partition->firstSector() || newLastSector != m_partition->lastSector();
|
bool partResizedMoved = newFirstSector != m_partition->firstSector() || newLastSector != m_partition->lastSector();
|
||||||
|
|
||||||
cDebug() << "old boundaries:" << m_partition->firstSector() << m_partition->lastSector() << m_partition->length();
|
cDebug() << "old boundaries:" << m_partition->firstSector() << m_partition->lastSector() << m_partition->length();
|
||||||
cDebug() << "new boundaries:" << newFirstSector << newLastSector;
|
cDebug() << Logger::SubEntry << "new boundaries:" << newFirstSector << newLastSector;
|
||||||
cDebug() << "dirty status:" << m_partitionSizeController->isDirty();
|
cDebug() << Logger::SubEntry << "dirty status:" << m_partitionSizeController->isDirty();
|
||||||
|
|
||||||
FileSystem::Type fsType = FileSystem::Unknown;
|
FileSystem::Type fsType = FileSystem::Unknown;
|
||||||
if ( m_ui->formatRadioButton->isChecked() )
|
if ( m_ui->formatRadioButton->isChecked() )
|
||||||
@ -147,6 +147,9 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core )
|
|||||||
: FileSystem::typeForName( m_ui->fileSystemComboBox->currentText() );
|
: FileSystem::typeForName( m_ui->fileSystemComboBox->currentText() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto resultFlags = newFlags();
|
||||||
|
const auto currentFlags = PartitionInfo::flags( m_partition );
|
||||||
|
|
||||||
if ( partResizedMoved )
|
if ( partResizedMoved )
|
||||||
{
|
{
|
||||||
if ( m_ui->formatRadioButton->isChecked() )
|
if ( m_ui->formatRadioButton->isChecked() )
|
||||||
@ -157,20 +160,20 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core )
|
|||||||
fsType,
|
fsType,
|
||||||
newFirstSector,
|
newFirstSector,
|
||||||
newLastSector,
|
newLastSector,
|
||||||
newFlags() );
|
resultFlags );
|
||||||
PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) );
|
PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) );
|
||||||
PartitionInfo::setFormat( newPartition, true );
|
PartitionInfo::setFormat( newPartition, true );
|
||||||
|
|
||||||
core->deletePartition( m_device, m_partition );
|
core->deletePartition( m_device, m_partition );
|
||||||
core->createPartition( m_device, newPartition );
|
core->createPartition( m_device, newPartition );
|
||||||
core->setPartitionFlags( m_device, newPartition, newFlags() );
|
core->setPartitionFlags( m_device, newPartition, resultFlags );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
core->resizePartition( m_device, m_partition, newFirstSector, newLastSector );
|
core->resizePartition( m_device, m_partition, newFirstSector, newLastSector );
|
||||||
if ( m_partition->activeFlags() != newFlags() )
|
if ( currentFlags != resultFlags )
|
||||||
{
|
{
|
||||||
core->setPartitionFlags( m_device, m_partition, newFlags() );
|
core->setPartitionFlags( m_device, m_partition, resultFlags );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,9 +186,9 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core )
|
|||||||
if ( m_partition->fileSystem().type() == fsType )
|
if ( m_partition->fileSystem().type() == fsType )
|
||||||
{
|
{
|
||||||
core->formatPartition( m_device, m_partition );
|
core->formatPartition( m_device, m_partition );
|
||||||
if ( m_partition->activeFlags() != newFlags() )
|
if ( currentFlags != resultFlags )
|
||||||
{
|
{
|
||||||
core->setPartitionFlags( m_device, m_partition, newFlags() );
|
core->setPartitionFlags( m_device, m_partition, resultFlags );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // otherwise, we delete and recreate the partition with new fs type
|
else // otherwise, we delete and recreate the partition with new fs type
|
||||||
@ -196,22 +199,22 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core )
|
|||||||
fsType,
|
fsType,
|
||||||
m_partition->firstSector(),
|
m_partition->firstSector(),
|
||||||
m_partition->lastSector(),
|
m_partition->lastSector(),
|
||||||
newFlags() );
|
resultFlags );
|
||||||
PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) );
|
PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) );
|
||||||
PartitionInfo::setFormat( newPartition, true );
|
PartitionInfo::setFormat( newPartition, true );
|
||||||
|
|
||||||
core->deletePartition( m_device, m_partition );
|
core->deletePartition( m_device, m_partition );
|
||||||
core->createPartition( m_device, newPartition );
|
core->createPartition( m_device, newPartition );
|
||||||
core->setPartitionFlags( m_device, newPartition, newFlags() );
|
core->setPartitionFlags( m_device, newPartition, resultFlags );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
core->refreshPartition( m_device, m_partition );
|
if ( currentFlags != resultFlags )
|
||||||
if ( m_partition->activeFlags() != newFlags() )
|
|
||||||
{
|
{
|
||||||
core->setPartitionFlags( m_device, m_partition, newFlags() );
|
core->setPartitionFlags( m_device, m_partition, resultFlags );
|
||||||
}
|
}
|
||||||
|
core->refreshPartition( m_device, m_partition );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -543,6 +543,12 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
|||||||
gs->insert( "efiSystemPartitionName", CalamaresUtils::getString( configurationMap, "efiSystemPartitionName" ) );
|
gs->insert( "efiSystemPartitionName", CalamaresUtils::getString( configurationMap, "efiSystemPartitionName" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read and parse key swapPartitionName
|
||||||
|
if ( configurationMap.contains( "swapPartitionName" ) )
|
||||||
|
{
|
||||||
|
gs->insert( "swapPartitionName", CalamaresUtils::getString( configurationMap, "swapPartitionName" ) );
|
||||||
|
}
|
||||||
|
|
||||||
// OTHER SETTINGS
|
// OTHER SETTINGS
|
||||||
//
|
//
|
||||||
gs->insert( "drawNestedPartitions", CalamaresUtils::getBool( configurationMap, "drawNestedPartitions", false ) );
|
gs->insert( "drawNestedPartitions", CalamaresUtils::getBool( configurationMap, "drawNestedPartitions", false ) );
|
||||||
@ -596,7 +602,8 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
|||||||
QFuture< void > future = QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule );
|
QFuture< void > future = QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule );
|
||||||
m_future->setFuture( future );
|
m_future->setFuture( future );
|
||||||
|
|
||||||
m_core->initLayout( configurationMap.value( "partitionLayout" ).toList() );
|
m_core->initLayout( fsType == FileSystem::Unknown ? FileSystem::Ext4 : fsType,
|
||||||
|
configurationMap.value( "partitionLayout" ).toList() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ mapForPartition( Partition* partition, const QString& uuid )
|
|||||||
using TR = Logger::DebugRow< const char* const, const QString& >;
|
using TR = Logger::DebugRow< const char* const, const QString& >;
|
||||||
deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode()
|
deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode()
|
||||||
<< TR( "partlabel", map[ "partlabel" ].toString() ) << TR( "partuuid", map[ "partuuid" ].toString() )
|
<< TR( "partlabel", map[ "partlabel" ].toString() ) << TR( "partuuid", map[ "partuuid" ].toString() )
|
||||||
<< TR( "parttype", map[ "partype" ].toString() ) << TR( "partattrs", map[ "partattrs" ].toString() )
|
<< TR( "parttype", map[ "parttype" ].toString() ) << TR( "partattrs", map[ "partattrs" ].toString() )
|
||||||
<< TR( "mountPoint:", PartitionInfo::mountPoint( partition ) ) << TR( "fs:", map[ "fs" ].toString() )
|
<< TR( "mountPoint:", PartitionInfo::mountPoint( partition ) ) << TR( "fs:", map[ "fs" ].toString() )
|
||||||
<< TR( "fsName", map[ "fsName" ].toString() ) << TR( "uuid", uuid )
|
<< TR( "fsName", map[ "fsName" ].toString() ) << TR( "uuid", uuid )
|
||||||
<< TR( "claimed", map[ "claimed" ].toString() );
|
<< TR( "claimed", map[ "claimed" ].toString() );
|
||||||
@ -153,7 +153,7 @@ FillGlobalStorageJob::prettyDescription() const
|
|||||||
QString path = partitionMap.value( "device" ).toString();
|
QString path = partitionMap.value( "device" ).toString();
|
||||||
QString mountPoint = partitionMap.value( "mountPoint" ).toString();
|
QString mountPoint = partitionMap.value( "mountPoint" ).toString();
|
||||||
QString fsType = partitionMap.value( "fs" ).toString();
|
QString fsType = partitionMap.value( "fs" ).toString();
|
||||||
if ( mountPoint.isEmpty() || fsType.isEmpty() )
|
if ( mountPoint.isEmpty() || fsType.isEmpty() || fsType == QString( "unformatted" ) )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@ efiSystemPartition: "/boot/efi"
|
|||||||
# If nothing is specified, the default size of 300MiB will be used.
|
# If nothing is specified, the default size of 300MiB will be used.
|
||||||
# efiSystemPartitionSize: 300M
|
# efiSystemPartitionSize: 300M
|
||||||
|
|
||||||
# This optional setting specifies the name of the EFI system partition.
|
# This optional setting specifies the name of the EFI system partition (see
|
||||||
|
# PARTLABEL; gpt only; requires KPMCore >= 4.2.0).
|
||||||
# If nothing is specified, the partition name is left unset.
|
# If nothing is specified, the partition name is left unset.
|
||||||
# efiSystemPartitionName: EFI
|
# efiSystemPartitionName: EFI
|
||||||
|
|
||||||
@ -48,6 +49,11 @@ userSwapChoices:
|
|||||||
# - reuse # Re-use existing swap, but don't create any (unsupported right now)
|
# - reuse # Re-use existing swap, but don't create any (unsupported right now)
|
||||||
- file # To swap file instead of partition
|
- file # To swap file instead of partition
|
||||||
|
|
||||||
|
# This optional setting specifies the name of the swap partition (see
|
||||||
|
# PARTLABEL; gpt only; requires KPMCore >= 4.2.0).
|
||||||
|
# If nothing is specified, the partition name is left unset.
|
||||||
|
# swapPartitionName: swap
|
||||||
|
|
||||||
# LEGACY SETTINGS (these will generate a warning)
|
# LEGACY SETTINGS (these will generate a warning)
|
||||||
# ensureSuspendToDisk: true
|
# ensureSuspendToDisk: true
|
||||||
# neverCreateSwap: false
|
# neverCreateSwap: false
|
||||||
@ -201,8 +207,8 @@ defaultFileSystemType: "ext4"
|
|||||||
# - uuid: partition uuid (optional parameter; gpt only; requires KPMCore >= 4.2.0)
|
# - uuid: partition uuid (optional parameter; gpt only; requires KPMCore >= 4.2.0)
|
||||||
# - type: partition type (optional parameter; gpt only; requires KPMCore >= 4.2.0)
|
# - type: partition type (optional parameter; gpt only; requires KPMCore >= 4.2.0)
|
||||||
# - attributes: partition attributes (optional parameter; gpt only; requires KPMCore >= 4.2.0)
|
# - attributes: partition attributes (optional parameter; gpt only; requires KPMCore >= 4.2.0)
|
||||||
# - filesystem: filesystem type
|
# - filesystem: filesystem type (optional parameter; fs not created if "unformatted" or unset)
|
||||||
# - mountPoint: partition mount point
|
# - mountPoint: partition mount point (optional parameter; not mounted if unset)
|
||||||
# - size: partition size in bytes (append 'K', 'M' or 'G' for KiB, MiB or GiB)
|
# - size: partition size in bytes (append 'K', 'M' or 'G' for KiB, MiB or GiB)
|
||||||
# or
|
# or
|
||||||
# % of the available drive space if a '%' is appended to the value
|
# % of the available drive space if a '%' is appended to the value
|
||||||
|
@ -25,6 +25,7 @@ class SmartStatus;
|
|||||||
QTEST_GUILESS_MAIN( CreateLayoutsTests )
|
QTEST_GUILESS_MAIN( CreateLayoutsTests )
|
||||||
|
|
||||||
static CalamaresUtils::Partition::KPMManager* kpmcore = nullptr;
|
static CalamaresUtils::Partition::KPMManager* kpmcore = nullptr;
|
||||||
|
static Calamares::JobQueue* jobqueue = nullptr;
|
||||||
|
|
||||||
using CalamaresUtils::operator""_MiB;
|
using CalamaresUtils::operator""_MiB;
|
||||||
using CalamaresUtils::operator""_GiB;
|
using CalamaresUtils::operator""_GiB;
|
||||||
@ -39,7 +40,7 @@ CreateLayoutsTests::CreateLayoutsTests()
|
|||||||
void
|
void
|
||||||
CreateLayoutsTests::init()
|
CreateLayoutsTests::init()
|
||||||
{
|
{
|
||||||
std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) );
|
jobqueue = new Calamares::JobQueue( nullptr );
|
||||||
kpmcore = new CalamaresUtils::Partition::KPMManager();
|
kpmcore = new CalamaresUtils::Partition::KPMManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ void
|
|||||||
CreateLayoutsTests::cleanup()
|
CreateLayoutsTests::cleanup()
|
||||||
{
|
{
|
||||||
delete kpmcore;
|
delete kpmcore;
|
||||||
|
delete jobqueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -57,7 +59,7 @@ CreateLayoutsTests::testFixedSizePartition()
|
|||||||
PartitionRole role( PartitionRole::Role::Any );
|
PartitionRole role( PartitionRole::Role::Any );
|
||||||
QList< Partition* > partitions;
|
QList< Partition* > partitions;
|
||||||
|
|
||||||
if ( !layout.addEntry( { QString( "/" ), QString( "5MiB" ) } ) )
|
if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/" ), QString( "5MiB" ) } ) )
|
||||||
{
|
{
|
||||||
QFAIL( qPrintable( "Unable to create / partition" ) );
|
QFAIL( qPrintable( "Unable to create / partition" ) );
|
||||||
}
|
}
|
||||||
@ -77,7 +79,7 @@ CreateLayoutsTests::testPercentSizePartition()
|
|||||||
PartitionRole role( PartitionRole::Role::Any );
|
PartitionRole role( PartitionRole::Role::Any );
|
||||||
QList< Partition* > partitions;
|
QList< Partition* > partitions;
|
||||||
|
|
||||||
if ( !layout.addEntry( { QString( "/" ), QString( "50%" ) } ) )
|
if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/" ), QString( "50%" ) } ) )
|
||||||
{
|
{
|
||||||
QFAIL( qPrintable( "Unable to create / partition" ) );
|
QFAIL( qPrintable( "Unable to create / partition" ) );
|
||||||
}
|
}
|
||||||
@ -97,17 +99,17 @@ CreateLayoutsTests::testMixedSizePartition()
|
|||||||
PartitionRole role( PartitionRole::Role::Any );
|
PartitionRole role( PartitionRole::Role::Any );
|
||||||
QList< Partition* > partitions;
|
QList< Partition* > partitions;
|
||||||
|
|
||||||
if ( !layout.addEntry( { QString( "/" ), QString( "5MiB" ) } ) )
|
if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/" ), QString( "5MiB" ) } ) )
|
||||||
{
|
{
|
||||||
QFAIL( qPrintable( "Unable to create / partition" ) );
|
QFAIL( qPrintable( "Unable to create / partition" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !layout.addEntry( { QString( "/home" ), QString( "50%" ) } ) )
|
if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/home" ), QString( "50%" ) } ) )
|
||||||
{
|
{
|
||||||
QFAIL( qPrintable( "Unable to create /home partition" ) );
|
QFAIL( qPrintable( "Unable to create /home partition" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !layout.addEntry( { QString( "/bkup" ), QString( "50%" ) } ) )
|
if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/bkup" ), QString( "50%" ) } ) )
|
||||||
{
|
{
|
||||||
QFAIL( qPrintable( "Unable to create /bkup partition" ) );
|
QFAIL( qPrintable( "Unable to create /bkup partition" ) );
|
||||||
}
|
}
|
||||||
@ -122,7 +124,7 @@ CreateLayoutsTests::testMixedSizePartition()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_KPMCORE4API
|
#ifdef WITH_KPMCORE4API
|
||||||
// TODO: Get a clean way to instanciate a test Device from KPMCore
|
// TODO: Get a clean way to instantiate a test Device from KPMCore
|
||||||
class DevicePrivate
|
class DevicePrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -39,10 +39,11 @@ def list_mounts(root_mount_point):
|
|||||||
"""
|
"""
|
||||||
lst = []
|
lst = []
|
||||||
|
|
||||||
|
root_mount_point = os.path.normpath(root_mount_point)
|
||||||
for line in open("/etc/mtab").readlines():
|
for line in open("/etc/mtab").readlines():
|
||||||
device, mount_point, _ = line.split(" ", 2)
|
device, mount_point, _ = line.split(" ", 2)
|
||||||
|
|
||||||
if mount_point.startswith(root_mount_point):
|
if os.path.commonprefix([root_mount_point, mount_point]) == root_mount_point:
|
||||||
lst.append((device, mount_point))
|
lst.append((device, mount_point))
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
|
@ -23,33 +23,45 @@ endif()
|
|||||||
|
|
||||||
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
|
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
|
||||||
|
|
||||||
set( JOB_SRC
|
set( _users_src
|
||||||
|
# Jobs
|
||||||
CreateUserJob.cpp
|
CreateUserJob.cpp
|
||||||
|
MiscJobs.cpp
|
||||||
SetPasswordJob.cpp
|
SetPasswordJob.cpp
|
||||||
SetHostNameJob.cpp
|
SetHostNameJob.cpp
|
||||||
)
|
# Configuration
|
||||||
set( CONFIG_SRC
|
|
||||||
CheckPWQuality.cpp
|
CheckPWQuality.cpp
|
||||||
Config.cpp
|
Config.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
calamares_add_library(
|
||||||
|
users_internal
|
||||||
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
|
TARGET_TYPE STATIC
|
||||||
|
NO_INSTALL
|
||||||
|
NO_VERSION
|
||||||
|
SOURCES
|
||||||
|
${_users_src}
|
||||||
|
LINK_LIBRARIES
|
||||||
|
Qt5::DBus
|
||||||
|
${CRYPT_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
calamares_add_plugin( users
|
calamares_add_plugin( users
|
||||||
TYPE viewmodule
|
TYPE viewmodule
|
||||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
SOURCES
|
SOURCES
|
||||||
UsersViewStep.cpp
|
UsersViewStep.cpp
|
||||||
UsersPage.cpp
|
UsersPage.cpp
|
||||||
${JOB_SRC}
|
|
||||||
${CONFIG_SRC}
|
|
||||||
UI
|
UI
|
||||||
page_usersetup.ui
|
page_usersetup.ui
|
||||||
RESOURCES
|
RESOURCES
|
||||||
users.qrc
|
users.qrc
|
||||||
LINK_PRIVATE_LIBRARIES
|
LINK_PRIVATE_LIBRARIES
|
||||||
|
users_internal
|
||||||
calamaresui
|
calamaresui
|
||||||
${CRYPT_LIBRARIES}
|
${CRYPT_LIBRARIES}
|
||||||
${USER_EXTRA_LIB}
|
${USER_EXTRA_LIB}
|
||||||
Qt5::DBus
|
|
||||||
SHARED_LIB
|
SHARED_LIB
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,10 +75,14 @@ calamares_add_test(
|
|||||||
)
|
)
|
||||||
|
|
||||||
calamares_add_test(
|
calamares_add_test(
|
||||||
userscreatetest
|
usersgroupstest
|
||||||
SOURCES
|
SOURCES
|
||||||
TestCreateUserJob.cpp
|
TestGroupInformation.cpp
|
||||||
CreateUserJob.cpp
|
${_users_src} # Build again with test-visibility
|
||||||
|
LIBRARIES
|
||||||
|
Qt5::DBus # HostName job can use DBus to systemd
|
||||||
|
${CRYPT_LIBRARIES} # SetPassword job uses crypt()
|
||||||
|
${USER_EXTRA_LIB}
|
||||||
)
|
)
|
||||||
|
|
||||||
calamares_add_test(
|
calamares_add_test(
|
||||||
@ -82,8 +98,7 @@ calamares_add_test(
|
|||||||
userstest
|
userstest
|
||||||
SOURCES
|
SOURCES
|
||||||
Tests.cpp
|
Tests.cpp
|
||||||
${JOB_SRC}
|
${_users_src} # Build again with test-visibility
|
||||||
${CONFIG_SRC}
|
|
||||||
LIBRARIES
|
LIBRARIES
|
||||||
Qt5::DBus # HostName job can use DBus to systemd
|
Qt5::DBus # HostName job can use DBus to systemd
|
||||||
${CRYPT_LIBRARIES} # SetPassword job uses crypt()
|
${CRYPT_LIBRARIES} # SetPassword job uses crypt()
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "CreateUserJob.h"
|
#include "CreateUserJob.h"
|
||||||
|
#include "MiscJobs.h"
|
||||||
#include "SetHostNameJob.h"
|
#include "SetHostNameJob.h"
|
||||||
#include "SetPasswordJob.h"
|
#include "SetPasswordJob.h"
|
||||||
|
|
||||||
@ -34,6 +35,11 @@ static void
|
|||||||
updateGSAutoLogin( bool doAutoLogin, const QString& login )
|
updateGSAutoLogin( bool doAutoLogin, const QString& login )
|
||||||
{
|
{
|
||||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
if ( !gs )
|
||||||
|
{
|
||||||
|
cWarning() << "No Global Storage available";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( doAutoLogin && !login.isEmpty() )
|
if ( doAutoLogin && !login.isEmpty() )
|
||||||
{
|
{
|
||||||
@ -95,11 +101,16 @@ Config::setUserShell( const QString& shell )
|
|||||||
cWarning() << "User shell" << shell << "is not an absolute path.";
|
cWarning() << "User shell" << shell << "is not an absolute path.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The shell is put into GS because the CreateUser job expects it there
|
if ( shell != m_userShell )
|
||||||
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
|
||||||
if ( gs )
|
|
||||||
{
|
{
|
||||||
gs->insert( "userShell", shell );
|
m_userShell = shell;
|
||||||
|
emit userShellChanged( shell );
|
||||||
|
// The shell is put into GS as well.
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
if ( gs )
|
||||||
|
{
|
||||||
|
gs->insert( "userShell", shell );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,15 +128,41 @@ insertInGlobalStorage( const QString& key, const QString& group )
|
|||||||
void
|
void
|
||||||
Config::setAutologinGroup( const QString& group )
|
Config::setAutologinGroup( const QString& group )
|
||||||
{
|
{
|
||||||
insertInGlobalStorage( QStringLiteral( "autologinGroup" ), group );
|
if ( group != m_autologinGroup )
|
||||||
emit autologinGroupChanged( group );
|
{
|
||||||
|
m_autologinGroup = group;
|
||||||
|
insertInGlobalStorage( QStringLiteral( "autologinGroup" ), group );
|
||||||
|
emit autologinGroupChanged( group );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList
|
||||||
|
Config::groupsForThisUser() const
|
||||||
|
{
|
||||||
|
QStringList l;
|
||||||
|
l.reserve( defaultGroups().size() + 1 );
|
||||||
|
|
||||||
|
for ( const auto& g : defaultGroups() )
|
||||||
|
{
|
||||||
|
l << g.name();
|
||||||
|
}
|
||||||
|
if ( doAutoLogin() && !autologinGroup().isEmpty() )
|
||||||
|
{
|
||||||
|
l << autologinGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Config::setSudoersGroup( const QString& group )
|
Config::setSudoersGroup( const QString& group )
|
||||||
{
|
{
|
||||||
insertInGlobalStorage( QStringLiteral( "sudoersGroup" ), group );
|
if ( group != m_sudoersGroup )
|
||||||
emit sudoersGroupChanged( group );
|
{
|
||||||
|
m_sudoersGroup = group;
|
||||||
|
insertInGlobalStorage( QStringLiteral( "sudoersGroup" ), group );
|
||||||
|
emit sudoersGroupChanged( group );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -134,10 +171,9 @@ Config::setLoginName( const QString& login )
|
|||||||
{
|
{
|
||||||
if ( login != m_loginName )
|
if ( login != m_loginName )
|
||||||
{
|
{
|
||||||
updateGSAutoLogin( doAutoLogin(), login );
|
|
||||||
|
|
||||||
m_customLoginName = !login.isEmpty();
|
m_customLoginName = !login.isEmpty();
|
||||||
m_loginName = login;
|
m_loginName = login;
|
||||||
|
updateGSAutoLogin( doAutoLogin(), login );
|
||||||
emit loginNameChanged( login );
|
emit loginNameChanged( login );
|
||||||
emit loginNameStatusChanged( loginNameStatus() );
|
emit loginNameStatusChanged( loginNameStatus() );
|
||||||
}
|
}
|
||||||
@ -189,6 +225,8 @@ Config::setHostName( const QString& host )
|
|||||||
{
|
{
|
||||||
if ( host != m_hostName )
|
if ( host != m_hostName )
|
||||||
{
|
{
|
||||||
|
m_customHostName = !host.isEmpty();
|
||||||
|
m_hostName = host;
|
||||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
if ( host.isEmpty() )
|
if ( host.isEmpty() )
|
||||||
{
|
{
|
||||||
@ -198,9 +236,6 @@ Config::setHostName( const QString& host )
|
|||||||
{
|
{
|
||||||
gs->insert( "hostname", host );
|
gs->insert( "hostname", host );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_customHostName = !host.isEmpty();
|
|
||||||
m_hostName = host;
|
|
||||||
emit hostNameChanged( host );
|
emit hostNameChanged( host );
|
||||||
emit hostNameStatusChanged( hostNameStatus() );
|
emit hostNameStatusChanged( hostNameStatus() );
|
||||||
}
|
}
|
||||||
@ -369,8 +404,8 @@ Config::setAutoLogin( bool b )
|
|||||||
{
|
{
|
||||||
if ( b != m_doAutoLogin )
|
if ( b != m_doAutoLogin )
|
||||||
{
|
{
|
||||||
updateGSAutoLogin( b, loginName() );
|
|
||||||
m_doAutoLogin = b;
|
m_doAutoLogin = b;
|
||||||
|
updateGSAutoLogin( b, loginName() );
|
||||||
emit autoLoginChanged( b );
|
emit autoLoginChanged( b );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -590,16 +625,59 @@ Config::checkReady()
|
|||||||
|
|
||||||
|
|
||||||
STATICTEST void
|
STATICTEST void
|
||||||
setConfigurationDefaultGroups( const QVariantMap& map, QStringList& defaultGroups )
|
setConfigurationDefaultGroups( const QVariantMap& map, QList< GroupDescription >& defaultGroups )
|
||||||
{
|
{
|
||||||
// '#' is not a valid group name; use that to distinguish an empty-list
|
defaultGroups.clear();
|
||||||
// in the configuration (which is a legitimate, if unusual, choice)
|
|
||||||
// from a bad or missing configuration value.
|
const QString key( "defaultGroups" );
|
||||||
defaultGroups = CalamaresUtils::getStringList( map, QStringLiteral( "defaultGroups" ), QStringList { "#" } );
|
auto groupsFromConfig = map.value( key ).toList();
|
||||||
if ( defaultGroups.contains( QStringLiteral( "#" ) ) )
|
if ( groupsFromConfig.isEmpty() )
|
||||||
{
|
{
|
||||||
cWarning() << "Using fallback groups. Please check *defaultGroups* in users.conf";
|
if ( map.contains( key ) && map.value( key ).isValid() && map.value( key ).canConvert( QVariant::List ) )
|
||||||
defaultGroups = QStringList { "lp", "video", "network", "storage", "wheel", "audio" };
|
{
|
||||||
|
// Explicitly set, but empty: this is valid, but unusual.
|
||||||
|
cDebug() << key << "has explicit empty value.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// By default give the user a handful of "traditional" groups, if
|
||||||
|
// none are specified at all. These are system (GID < 1000) groups.
|
||||||
|
cWarning() << "Using fallback groups. Please check *defaultGroups* value in users.conf";
|
||||||
|
for ( const auto& s : { "lp", "video", "network", "storage", "wheel", "audio" } )
|
||||||
|
{
|
||||||
|
defaultGroups.append(
|
||||||
|
GroupDescription( s, GroupDescription::CreateIfNeeded {}, GroupDescription::SystemGroup {} ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( const auto& v : groupsFromConfig )
|
||||||
|
{
|
||||||
|
if ( v.type() == QVariant::String )
|
||||||
|
{
|
||||||
|
defaultGroups.append( GroupDescription( v.toString() ) );
|
||||||
|
}
|
||||||
|
else if ( v.type() == QVariant::Map )
|
||||||
|
{
|
||||||
|
const auto innermap = v.toMap();
|
||||||
|
QString name = CalamaresUtils::getString( innermap, "name" );
|
||||||
|
if ( !name.isEmpty() )
|
||||||
|
{
|
||||||
|
defaultGroups.append( GroupDescription( name,
|
||||||
|
CalamaresUtils::getBool( innermap, "must_exist", false ),
|
||||||
|
CalamaresUtils::getBool( innermap, "system", false ) ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "Ignoring *defaultGroups* entry without a name" << v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "Unknown *defaultGroups* entry" << v;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,8 +815,16 @@ Config::createJobs() const
|
|||||||
|
|
||||||
Calamares::Job* j;
|
Calamares::Job* j;
|
||||||
|
|
||||||
j = new CreateUserJob(
|
if ( m_sudoersGroup.isEmpty() )
|
||||||
loginName(), fullName().isEmpty() ? loginName() : fullName(), doAutoLogin(), defaultGroups() );
|
{
|
||||||
|
j = new SetupSudoJob( m_sudoersGroup );
|
||||||
|
jobs.append( Calamares::job_ptr( j ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
j = new SetupGroupsJob( this );
|
||||||
|
jobs.append( Calamares::job_ptr( j ) );
|
||||||
|
|
||||||
|
j = new CreateUserJob( this );
|
||||||
jobs.append( Calamares::job_ptr( j ) );
|
jobs.append( Calamares::job_ptr( j ) );
|
||||||
|
|
||||||
j = new SetPasswordJob( loginName(), userPassword() );
|
j = new SetPasswordJob( loginName(), userPassword() );
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "Job.h"
|
#include "Job.h"
|
||||||
#include "utils/NamedEnum.h"
|
#include "utils/NamedEnum.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVariantMap>
|
#include <QVariantMap>
|
||||||
|
|
||||||
@ -30,7 +31,61 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( HostNameActions )
|
|||||||
|
|
||||||
const NamedEnumTable< HostNameAction >& hostNameActionNames();
|
const NamedEnumTable< HostNameAction >& hostNameActionNames();
|
||||||
|
|
||||||
class Config : public QObject
|
/** @brief Settings for a single group
|
||||||
|
*
|
||||||
|
* The list of defaultgroups from the configuration can be
|
||||||
|
* set up in a fine-grained way, with both user- and system-
|
||||||
|
* level groups; this class stores a configuration for each.
|
||||||
|
*/
|
||||||
|
class GroupDescription
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// TODO: still too-weakly typed, add a macro to define strongly-typed bools
|
||||||
|
class MustExist : public std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
class CreateIfNeeded : public std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
class SystemGroup : public std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
class UserGroup : public std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
///@brief An invalid, empty group
|
||||||
|
GroupDescription() {}
|
||||||
|
|
||||||
|
///@brief A group with full details
|
||||||
|
GroupDescription( const QString& name, bool mustExistAlready = CreateIfNeeded {}, bool isSystem = UserGroup {} )
|
||||||
|
: m_name( name )
|
||||||
|
, m_isValid( !name.isEmpty() )
|
||||||
|
, m_mustAlreadyExist( mustExistAlready )
|
||||||
|
, m_isSystem( isSystem )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const { return m_isValid; }
|
||||||
|
bool isSystemGroup() const { return m_isSystem; }
|
||||||
|
bool mustAlreadyExist() const { return m_mustAlreadyExist; }
|
||||||
|
QString name() const { return m_name; }
|
||||||
|
|
||||||
|
///@brief Equality of groups depends only on name and kind
|
||||||
|
bool operator==( const GroupDescription& rhs ) const
|
||||||
|
{
|
||||||
|
return rhs.name() == name() && rhs.isSystemGroup() == isSystemGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
bool m_isValid = false;
|
||||||
|
bool m_mustAlreadyExist = false;
|
||||||
|
bool m_isSystem = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PLUGINDLLEXPORT Config : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -158,7 +213,12 @@ public:
|
|||||||
/// Current setting for "require strong password"?
|
/// Current setting for "require strong password"?
|
||||||
bool requireStrongPasswords() const { return m_requireStrongPasswords; }
|
bool requireStrongPasswords() const { return m_requireStrongPasswords; }
|
||||||
|
|
||||||
const QStringList& defaultGroups() const { return m_defaultGroups; }
|
const QList< GroupDescription >& defaultGroups() const { return m_defaultGroups; }
|
||||||
|
/** @brief the names of all the groups for the current user
|
||||||
|
*
|
||||||
|
* Takes into account defaultGroups and autologin behavior.
|
||||||
|
*/
|
||||||
|
QStringList groupsForThisUser() const;
|
||||||
|
|
||||||
// The user enters a password (and again in a separate UI element)
|
// The user enters a password (and again in a separate UI element)
|
||||||
QString userPassword() const { return m_userPassword; }
|
QString userPassword() const { return m_userPassword; }
|
||||||
@ -242,7 +302,7 @@ private:
|
|||||||
PasswordStatus passwordStatus( const QString&, const QString& ) const;
|
PasswordStatus passwordStatus( const QString&, const QString& ) const;
|
||||||
void checkReady();
|
void checkReady();
|
||||||
|
|
||||||
QStringList m_defaultGroups;
|
QList< GroupDescription > m_defaultGroups;
|
||||||
QString m_userShell;
|
QString m_userShell;
|
||||||
QString m_autologinGroup;
|
QString m_autologinGroup;
|
||||||
QString m_sudoersGroup;
|
QString m_sudoersGroup;
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include "CreateUserJob.h"
|
#include "CreateUserJob.h"
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
#include "GlobalStorage.h"
|
#include "GlobalStorage.h"
|
||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
@ -21,15 +23,9 @@
|
|||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
|
||||||
|
|
||||||
CreateUserJob::CreateUserJob( const QString& userName,
|
CreateUserJob::CreateUserJob( const Config* config )
|
||||||
const QString& fullName,
|
|
||||||
bool autologin,
|
|
||||||
const QStringList& defaultGroups )
|
|
||||||
: Calamares::Job()
|
: Calamares::Job()
|
||||||
, m_userName( userName )
|
, m_config( config )
|
||||||
, m_fullName( fullName )
|
|
||||||
, m_autologin( autologin )
|
|
||||||
, m_defaultGroups( defaultGroups )
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,68 +33,21 @@ CreateUserJob::CreateUserJob( const QString& userName,
|
|||||||
QString
|
QString
|
||||||
CreateUserJob::prettyName() const
|
CreateUserJob::prettyName() const
|
||||||
{
|
{
|
||||||
return tr( "Create user %1" ).arg( m_userName );
|
return tr( "Create user %1" ).arg( m_config->loginName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString
|
QString
|
||||||
CreateUserJob::prettyDescription() const
|
CreateUserJob::prettyDescription() const
|
||||||
{
|
{
|
||||||
return tr( "Create user <strong>%1</strong>." ).arg( m_userName );
|
return tr( "Create user <strong>%1</strong>." ).arg( m_config->loginName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString
|
QString
|
||||||
CreateUserJob::prettyStatusMessage() const
|
CreateUserJob::prettyStatusMessage() const
|
||||||
{
|
{
|
||||||
return tr( "Creating user %1." ).arg( m_userName );
|
return m_status.isEmpty() ? tr( "Creating user %1." ).arg( m_config->loginName() ) : m_status;
|
||||||
}
|
|
||||||
|
|
||||||
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
|
static Calamares::JobResult
|
||||||
@ -161,47 +110,22 @@ setUserGroups( const QString& loginName, const QStringList& groups )
|
|||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
CreateUserJob::exec()
|
CreateUserJob::exec()
|
||||||
{
|
{
|
||||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
QDir destDir;
|
||||||
QDir destDir( gs->value( "rootMountPoint" ).toString() );
|
bool reuseHome = false;
|
||||||
|
|
||||||
if ( gs->contains( "sudoersGroup" ) && !gs->value( "sudoersGroup" ).toString().isEmpty() )
|
|
||||||
{
|
{
|
||||||
cDebug() << "[CREATEUSER]: preparing sudoers";
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
destDir = QDir( gs->value( "rootMountPoint" ).toString() );
|
||||||
QString sudoersLine = QString( "%%1 ALL=(ALL) ALL\n" ).arg( gs->value( "sudoersGroup" ).toString() );
|
reuseHome = gs->value( "reuseHome" ).toBool();
|
||||||
auto fileResult
|
|
||||||
= CalamaresUtils::System::instance()->createTargetFile( QStringLiteral( "/etc/sudoers.d/10-installer" ),
|
|
||||||
sudoersLine.toUtf8().constData(),
|
|
||||||
CalamaresUtils::System::WriteMode::Overwrite );
|
|
||||||
|
|
||||||
if ( fileResult )
|
|
||||||
{
|
|
||||||
if ( !CalamaresUtils::Permissions::apply( fileResult.path(), 0440 ) )
|
|
||||||
{
|
|
||||||
return Calamares::JobResult::error( tr( "Cannot chmod sudoers file." ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Calamares::JobResult::error( tr( "Cannot create sudoers file for writing." ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cDebug() << "[CREATEUSER]: preparing groups";
|
|
||||||
|
|
||||||
QStringList availableGroups = groupsInTargetSystem( destDir );
|
|
||||||
QStringList groupsForThisUser = m_defaultGroups;
|
|
||||||
if ( m_autologin && gs->contains( "autologinGroup" ) && !gs->value( "autologinGroup" ).toString().isEmpty() )
|
|
||||||
{
|
|
||||||
groupsForThisUser << gs->value( "autologinGroup" ).toString();
|
|
||||||
}
|
|
||||||
ensureGroupsExistInTarget( groupsForThisUser, availableGroups );
|
|
||||||
|
|
||||||
// If we're looking to reuse the contents of an existing /home.
|
// If we're looking to reuse the contents of an existing /home.
|
||||||
// This GS setting comes from the **partitioning** module.
|
// This GS setting comes from the **partitioning** module.
|
||||||
if ( gs->value( "reuseHome" ).toBool() )
|
if ( reuseHome )
|
||||||
{
|
{
|
||||||
QString shellFriendlyHome = "/home/" + m_userName;
|
m_status = tr( "Preserving home directory" );
|
||||||
|
emit progress( 0.2 );
|
||||||
|
QString shellFriendlyHome = "/home/" + m_config->loginName();
|
||||||
QDir existingHome( destDir.absolutePath() + shellFriendlyHome );
|
QDir existingHome( destDir.absolutePath() + shellFriendlyHome );
|
||||||
if ( existingHome.exists() )
|
if ( existingHome.exists() )
|
||||||
{
|
{
|
||||||
@ -216,20 +140,26 @@ CreateUserJob::exec()
|
|||||||
|
|
||||||
cDebug() << "[CREATEUSER]: creating user";
|
cDebug() << "[CREATEUSER]: creating user";
|
||||||
|
|
||||||
auto useraddResult = createUser( m_userName, m_fullName, gs->value( "userShell" ).toString() );
|
m_status = tr( "Creating user %1" ).arg( m_config->loginName() );
|
||||||
|
emit progress( 0.5 );
|
||||||
|
auto useraddResult = createUser( m_config->loginName(), m_config->fullName(), m_config->userShell() );
|
||||||
if ( !useraddResult )
|
if ( !useraddResult )
|
||||||
{
|
{
|
||||||
return useraddResult;
|
return useraddResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto usergroupsResult = setUserGroups( m_userName, groupsForThisUser );
|
m_status = tr( "Configuring user %1" ).arg( m_config->loginName() );
|
||||||
|
emit progress( 0.8 );
|
||||||
|
auto usergroupsResult = setUserGroups( m_config->loginName(), m_config->groupsForThisUser() );
|
||||||
if ( !usergroupsResult )
|
if ( !usergroupsResult )
|
||||||
{
|
{
|
||||||
return usergroupsResult;
|
return usergroupsResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString userGroup = QString( "%1:%2" ).arg( m_userName ).arg( m_userName );
|
m_status = tr( "Setting file permissions" );
|
||||||
QString homeDir = QString( "/home/%1" ).arg( m_userName );
|
emit progress( 0.9 );
|
||||||
|
QString userGroup = QString( "%1:%2" ).arg( m_config->loginName() ).arg( m_config->loginName() );
|
||||||
|
QString homeDir = QString( "/home/%1" ).arg( m_config->loginName() );
|
||||||
auto 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() )
|
||||||
{
|
{
|
||||||
|
@ -12,23 +12,21 @@
|
|||||||
|
|
||||||
#include "Job.h"
|
#include "Job.h"
|
||||||
|
|
||||||
#include <QStringList>
|
class Config;
|
||||||
|
|
||||||
class CreateUserJob : public Calamares::Job
|
class CreateUserJob : public Calamares::Job
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
CreateUserJob( const QString& userName, const QString& fullName, bool autologin, const QStringList& defaultGroups );
|
CreateUserJob( const Config* config );
|
||||||
QString prettyName() const override;
|
QString prettyName() const override;
|
||||||
QString prettyDescription() const override;
|
QString prettyDescription() const override;
|
||||||
QString prettyStatusMessage() const override;
|
QString prettyStatusMessage() const override;
|
||||||
Calamares::JobResult exec() override;
|
Calamares::JobResult exec() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_userName;
|
const Config* m_config;
|
||||||
QString m_fullName;
|
QString m_status;
|
||||||
bool m_autologin;
|
|
||||||
QStringList m_defaultGroups;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CREATEUSERJOB_H */
|
#endif /* CREATEUSERJOB_H */
|
||||||
|
194
src/modules/users/MiscJobs.cpp
Normal file
194
src/modules/users/MiscJobs.cpp
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MiscJobs.h"
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Permissions.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
SetupSudoJob::SetupSudoJob( const QString& group )
|
||||||
|
: m_sudoGroup( group )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
SetupSudoJob::prettyName() const
|
||||||
|
{
|
||||||
|
return tr( "Configure <pre>sudo</pre> users." );
|
||||||
|
}
|
||||||
|
|
||||||
|
Calamares::JobResult
|
||||||
|
SetupSudoJob::exec()
|
||||||
|
{
|
||||||
|
if ( m_sudoGroup.isEmpty() )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString sudoersLine = QString( "%%1 ALL=(ALL) ALL\n" ).arg( m_sudoGroup );
|
||||||
|
auto fileResult
|
||||||
|
= CalamaresUtils::System::instance()->createTargetFile( QStringLiteral( "/etc/sudoers.d/10-installer" ),
|
||||||
|
sudoersLine.toUtf8().constData(),
|
||||||
|
CalamaresUtils::System::WriteMode::Overwrite );
|
||||||
|
|
||||||
|
if ( fileResult )
|
||||||
|
{
|
||||||
|
if ( !CalamaresUtils::Permissions::apply( fileResult.path(), 0440 ) )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::error( tr( "Cannot chmod sudoers file." ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::error( tr( "Cannot create sudoers file for writing." ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
STATICTEST QStringList
|
||||||
|
groupsInTargetSystem()
|
||||||
|
{
|
||||||
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
if ( !gs )
|
||||||
|
{
|
||||||
|
return QStringList();
|
||||||
|
}
|
||||||
|
QDir targetRoot( gs->value( "rootMountPoint" ).toString() );
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Create groups in target system as needed
|
||||||
|
*
|
||||||
|
* Given a list of groups that already exist, @p availableGroups,
|
||||||
|
* go through the @p wantedGroups and create each of them. Groups that
|
||||||
|
* fail, or which should have already been there, are added to
|
||||||
|
* @p missingGroups by name.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ensureGroupsExistInTarget( const QList< GroupDescription >& wantedGroups,
|
||||||
|
const QStringList& availableGroups,
|
||||||
|
QStringList& missingGroups )
|
||||||
|
{
|
||||||
|
int failureCount = 0;
|
||||||
|
|
||||||
|
for ( const auto& group : wantedGroups )
|
||||||
|
{
|
||||||
|
if ( group.isValid() && !availableGroups.contains( group.name() ) )
|
||||||
|
{
|
||||||
|
if ( group.mustAlreadyExist() )
|
||||||
|
{
|
||||||
|
// Should have been there already: don't create it
|
||||||
|
missingGroups.append( group.name() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList cmd;
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
if ( group.isSystemGroup() )
|
||||||
|
{
|
||||||
|
cWarning() << "Ignoring must-be-a-system group for" << group.name() << "on FreeBSD";
|
||||||
|
}
|
||||||
|
cmd = QStringList { "pw", "groupadd", "-n", group.name() };
|
||||||
|
#else
|
||||||
|
cmd << QStringLiteral( "groupadd" );
|
||||||
|
if ( group.isSystemGroup() )
|
||||||
|
{
|
||||||
|
cmd << "--system";
|
||||||
|
}
|
||||||
|
cmd << group.name();
|
||||||
|
#endif
|
||||||
|
if ( CalamaresUtils::System::instance()->targetEnvCall( cmd ) )
|
||||||
|
{
|
||||||
|
failureCount++;
|
||||||
|
missingGroups.append( group.name() + QChar( '*' ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !missingGroups.isEmpty() )
|
||||||
|
{
|
||||||
|
cWarning() << "Missing groups in target system (* for groupadd failure):" << Logger::DebugList( missingGroups );
|
||||||
|
}
|
||||||
|
return failureCount == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupGroupsJob::SetupGroupsJob( const Config* config )
|
||||||
|
: m_config( config )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
SetupGroupsJob::prettyName() const
|
||||||
|
{
|
||||||
|
return tr( "Preparing groups." );
|
||||||
|
}
|
||||||
|
|
||||||
|
Calamares::JobResult
|
||||||
|
SetupGroupsJob::exec()
|
||||||
|
{
|
||||||
|
const auto& defaultGroups = m_config->defaultGroups();
|
||||||
|
QStringList availableGroups = groupsInTargetSystem();
|
||||||
|
QStringList missingGroups;
|
||||||
|
|
||||||
|
if ( !ensureGroupsExistInTarget( defaultGroups, availableGroups, missingGroups ) )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::error( tr( "Could not create groups in target system" ) );
|
||||||
|
}
|
||||||
|
if ( !missingGroups.isEmpty() )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::error(
|
||||||
|
tr( "Could not create groups in target system" ),
|
||||||
|
tr( "These groups are missing in the target system: %1" ).arg( missingGroups.join( ',' ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_config->doAutoLogin() && !m_config->autologinGroup().isEmpty() )
|
||||||
|
{
|
||||||
|
const QString autologinGroup = m_config->autologinGroup();
|
||||||
|
(void)ensureGroupsExistInTarget(
|
||||||
|
QList< GroupDescription >() << GroupDescription( autologinGroup ), availableGroups, missingGroups );
|
||||||
|
}
|
||||||
|
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
49
src/modules/users/MiscJobs.h
Normal file
49
src/modules/users/MiscJobs.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**@file Various small jobs
|
||||||
|
*
|
||||||
|
* This file collects miscellaneous jobs that need to be run to prepare
|
||||||
|
* the system for the user-creation job.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USERS_MISCJOBS_H
|
||||||
|
#define USERS_MISCJOBS_H
|
||||||
|
|
||||||
|
#include "Job.h"
|
||||||
|
|
||||||
|
class Config;
|
||||||
|
|
||||||
|
class SetupSudoJob : public Calamares::Job
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SetupSudoJob( const QString& group );
|
||||||
|
QString prettyName() const override;
|
||||||
|
Calamares::JobResult exec() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString m_sudoGroup;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetupGroupsJob : public Calamares::Job
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SetupGroupsJob( const Config* config );
|
||||||
|
QString prettyName() const override;
|
||||||
|
Calamares::JobResult exec() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Config* m_config;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,72 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*
|
|
||||||
* Calamares is Free Software: see the License-Identifier above.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "CreateUserJob.h"
|
|
||||||
|
|
||||||
#include "utils/Logger.h"
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QtTest/QtTest>
|
|
||||||
|
|
||||||
// Implementation details
|
|
||||||
extern QStringList groupsInTargetSystem( const QDir& targetRoot ); // CreateUserJob
|
|
||||||
|
|
||||||
class CreateUserTests : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
CreateUserTests();
|
|
||||||
~CreateUserTests() override {}
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void initTestCase();
|
|
||||||
|
|
||||||
void testReadGroup();
|
|
||||||
};
|
|
||||||
|
|
||||||
CreateUserTests::CreateUserTests() {}
|
|
||||||
|
|
||||||
void
|
|
||||||
CreateUserTests::initTestCase()
|
|
||||||
{
|
|
||||||
Logger::setupLogLevel( Logger::LOGDEBUG );
|
|
||||||
cDebug() << "Users test started.";
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CreateUserTests::testReadGroup()
|
|
||||||
{
|
|
||||||
QDir root( "/" );
|
|
||||||
QVERIFY( root.exists() );
|
|
||||||
|
|
||||||
// Get the groups in the host system
|
|
||||||
QStringList groups = groupsInTargetSystem( root );
|
|
||||||
QVERIFY( groups.count() > 2 );
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
QVERIFY( groups.contains( QStringLiteral( "wheel" ) ) );
|
|
||||||
#else
|
|
||||||
QVERIFY( groups.contains( QStringLiteral( "root" ) ) );
|
|
||||||
#endif
|
|
||||||
// openSUSE doesn't have "sys"
|
|
||||||
// QVERIFY( groups.contains( QStringLiteral( "sys" ) ) );
|
|
||||||
QVERIFY( groups.contains( QStringLiteral( "nogroup" ) ) );
|
|
||||||
QVERIFY( groups.contains( QStringLiteral( "tty" ) ) );
|
|
||||||
|
|
||||||
for ( const QString& s : groups )
|
|
||||||
{
|
|
||||||
QVERIFY( !s.isEmpty() );
|
|
||||||
QVERIFY( !s.contains( '#' ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN( CreateUserTests )
|
|
||||||
|
|
||||||
#include "utils/moc-warnings.h"
|
|
||||||
|
|
||||||
#include "TestCreateUserJob.moc"
|
|
106
src/modules/users/TestGroupInformation.cpp
Normal file
106
src/modules/users/TestGroupInformation.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "CreateUserJob.h"
|
||||||
|
#include "MiscJobs.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Yaml.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
|
// Implementation details
|
||||||
|
extern QStringList groupsInTargetSystem(); // CreateUserJob
|
||||||
|
|
||||||
|
class GroupTests : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
GroupTests();
|
||||||
|
~GroupTests() override {}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void initTestCase();
|
||||||
|
|
||||||
|
void testReadGroup();
|
||||||
|
void testCreateGroup();
|
||||||
|
};
|
||||||
|
|
||||||
|
GroupTests::GroupTests() {}
|
||||||
|
|
||||||
|
void
|
||||||
|
GroupTests::initTestCase()
|
||||||
|
{
|
||||||
|
Logger::setupLogLevel( Logger::LOGDEBUG );
|
||||||
|
cDebug() << "Users test started.";
|
||||||
|
if ( !Calamares::JobQueue::instance() )
|
||||||
|
{
|
||||||
|
(void)new Calamares::JobQueue();
|
||||||
|
}
|
||||||
|
Calamares::JobQueue::instance()->globalStorage()->insert( "rootMountPoint", "/" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GroupTests::testReadGroup()
|
||||||
|
{
|
||||||
|
// Get the groups in the host system
|
||||||
|
QStringList groups = groupsInTargetSystem();
|
||||||
|
QVERIFY( groups.count() > 2 );
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
QVERIFY( groups.contains( QStringLiteral( "wheel" ) ) );
|
||||||
|
#else
|
||||||
|
QVERIFY( groups.contains( QStringLiteral( "root" ) ) );
|
||||||
|
#endif
|
||||||
|
// openSUSE doesn't have "sys"
|
||||||
|
// QVERIFY( groups.contains( QStringLiteral( "sys" ) ) );
|
||||||
|
QVERIFY( groups.contains( QStringLiteral( "nogroup" ) ) );
|
||||||
|
QVERIFY( groups.contains( QStringLiteral( "tty" ) ) );
|
||||||
|
|
||||||
|
for ( const QString& s : groups )
|
||||||
|
{
|
||||||
|
QVERIFY( !s.isEmpty() );
|
||||||
|
QVERIFY( !s.contains( '#' ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupTests::testCreateGroup()
|
||||||
|
{
|
||||||
|
// BUILD_AS_TEST is the source-directory path
|
||||||
|
QFile fi( QString( "%1/tests/5-issue-1523.conf" ).arg( BUILD_AS_TEST ) );
|
||||||
|
QVERIFY( fi.exists() );
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
const auto map = CalamaresUtils::loadYaml( fi, &ok );
|
||||||
|
QVERIFY( ok );
|
||||||
|
QVERIFY( map.count() > 0 ); // Just that it loaded, one key *defaultGroups*
|
||||||
|
|
||||||
|
Config c;
|
||||||
|
c.setConfigurationMap( map );
|
||||||
|
|
||||||
|
QCOMPARE( c.defaultGroups().count(), 4 );
|
||||||
|
QVERIFY( c.defaultGroups().contains( QStringLiteral( "adm" ) ) );
|
||||||
|
QVERIFY( c.defaultGroups().contains( QStringLiteral( "bar" ) ) );
|
||||||
|
|
||||||
|
Calamares::JobQueue::instance()->globalStorage()->insert( "rootMountPoint", "/" );
|
||||||
|
|
||||||
|
SetupGroupsJob j(&c);
|
||||||
|
QVERIFY( !j.exec() ); // running as regular user this should fail
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN( GroupTests )
|
||||||
|
|
||||||
|
#include "utils/moc-warnings.h"
|
||||||
|
|
||||||
|
#include "TestGroupInformation.moc"
|
@ -16,7 +16,7 @@
|
|||||||
#include <QtTest/QtTest>
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
// Implementation details
|
// Implementation details
|
||||||
extern void setConfigurationDefaultGroups( const QVariantMap& map, QStringList& defaultGroups );
|
extern void setConfigurationDefaultGroups( const QVariantMap& map, QList< GroupDescription >& defaultGroups );
|
||||||
extern HostNameActions getHostNameActions( const QVariantMap& configurationMap );
|
extern HostNameActions getHostNameActions( const QVariantMap& configurationMap );
|
||||||
extern bool addPasswordCheck( const QString& key, const QVariant& value, PasswordCheckList& passwordChecks );
|
extern bool addPasswordCheck( const QString& key, const QVariant& value, PasswordCheckList& passwordChecks );
|
||||||
|
|
||||||
@ -33,6 +33,9 @@ public:
|
|||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
|
|
||||||
|
// Derpy test for getting and setting regular values
|
||||||
|
void testGetSet();
|
||||||
|
|
||||||
void testDefaultGroups();
|
void testDefaultGroups();
|
||||||
void testDefaultGroupsYAML_data();
|
void testDefaultGroupsYAML_data();
|
||||||
void testDefaultGroupsYAML();
|
void testDefaultGroupsYAML();
|
||||||
@ -50,35 +53,97 @@ UserTests::initTestCase()
|
|||||||
{
|
{
|
||||||
Logger::setupLogLevel( Logger::LOGDEBUG );
|
Logger::setupLogLevel( Logger::LOGDEBUG );
|
||||||
cDebug() << "Users test started.";
|
cDebug() << "Users test started.";
|
||||||
|
|
||||||
|
if ( !Calamares::JobQueue::instance() )
|
||||||
|
{
|
||||||
|
(void)new Calamares::JobQueue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserTests::testGetSet()
|
||||||
|
{
|
||||||
|
Config c;
|
||||||
|
|
||||||
|
{
|
||||||
|
const QString sh( "/bin/sh" );
|
||||||
|
QCOMPARE( c.userShell(), QString() );
|
||||||
|
c.setUserShell( sh );
|
||||||
|
QCOMPARE( c.userShell(), sh );
|
||||||
|
c.setUserShell( sh + sh );
|
||||||
|
QCOMPARE( c.userShell(), sh + sh );
|
||||||
|
|
||||||
|
const QString badsh( "bash" ); // Not absolute, that's bad
|
||||||
|
c.setUserShell( badsh ); // .. so unchanged
|
||||||
|
QCOMPARE( c.userShell(), sh + sh ); // what was set previously
|
||||||
|
|
||||||
|
// Explicit set to empty is ok
|
||||||
|
c.setUserShell( QString() );
|
||||||
|
QCOMPARE( c.userShell(), QString() );
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const QString al( "autolg" );
|
||||||
|
QCOMPARE( c.autologinGroup(), QString() );
|
||||||
|
c.setAutologinGroup( al );
|
||||||
|
QCOMPARE( c.autologinGroup(), al );
|
||||||
|
QVERIFY( !c.doAutoLogin() );
|
||||||
|
c.setAutoLogin( true );
|
||||||
|
QVERIFY( c.doAutoLogin() );
|
||||||
|
QCOMPARE( c.autologinGroup(), al );
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const QString su( "sudogrp" );
|
||||||
|
QCOMPARE( c.sudoersGroup(), QString() );
|
||||||
|
c.setSudoersGroup( su );
|
||||||
|
QCOMPARE( c.sudoersGroup(), su );
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const QString ful( "Jan-Jaap Karel Kees" );
|
||||||
|
const QString lg( "jjkk" );
|
||||||
|
QCOMPARE( c.fullName(), QString() );
|
||||||
|
QCOMPARE( c.loginName(), QString() );
|
||||||
|
QVERIFY( c.loginNameStatus().isEmpty() ); // empty login name is ok
|
||||||
|
c.setLoginName( lg );
|
||||||
|
c.setFullName( ful );
|
||||||
|
QVERIFY( c.loginNameStatus().isEmpty() ); // now it's still ok
|
||||||
|
QCOMPARE( c.loginName(), lg );
|
||||||
|
QCOMPARE( c.fullName(), ful );
|
||||||
|
c.setLoginName( "root" );
|
||||||
|
QVERIFY( !c.loginNameStatus().isEmpty() ); // can't be root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
UserTests::testDefaultGroups()
|
UserTests::testDefaultGroups()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
QStringList groups;
|
QList< GroupDescription > groups;
|
||||||
QVariantMap hweelGroup;
|
QVariantMap hweelGroup;
|
||||||
QVERIFY( groups.isEmpty() );
|
QVERIFY( groups.isEmpty() );
|
||||||
hweelGroup.insert( "defaultGroups", QStringList { "hweel" } );
|
hweelGroup.insert( "defaultGroups", QStringList { "hweel" } );
|
||||||
setConfigurationDefaultGroups( hweelGroup, groups );
|
setConfigurationDefaultGroups( hweelGroup, groups );
|
||||||
QCOMPARE( groups.count(), 1 );
|
QCOMPARE( groups.count(), 1 );
|
||||||
QVERIFY( groups.contains( "hweel" ) );
|
QVERIFY( groups.contains( GroupDescription( "hweel" ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
QStringList desired { "wheel", "root", "operator" };
|
QStringList desired { "wheel", "root", "operator" };
|
||||||
QStringList groups;
|
QList< GroupDescription > groups;
|
||||||
QVariantMap threeGroup;
|
QVariantMap threeGroup;
|
||||||
QVERIFY( groups.isEmpty() );
|
QVERIFY( groups.isEmpty() );
|
||||||
threeGroup.insert( "defaultGroups", desired );
|
threeGroup.insert( "defaultGroups", desired );
|
||||||
setConfigurationDefaultGroups( threeGroup, groups );
|
setConfigurationDefaultGroups( threeGroup, groups );
|
||||||
QCOMPARE( groups.count(), 3 );
|
QCOMPARE( groups.count(), 3 );
|
||||||
QVERIFY( !groups.contains( "hweel" ) );
|
QVERIFY( !groups.contains( GroupDescription( "hweel" ) ) );
|
||||||
QCOMPARE( groups, desired );
|
for ( const auto& s : desired )
|
||||||
|
{
|
||||||
|
QVERIFY( groups.contains( GroupDescription( s ) ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
QStringList groups;
|
QList< GroupDescription > groups;
|
||||||
QVariantMap explicitEmpty;
|
QVariantMap explicitEmpty;
|
||||||
QVERIFY( groups.isEmpty() );
|
QVERIFY( groups.isEmpty() );
|
||||||
explicitEmpty.insert( "defaultGroups", QStringList() );
|
explicitEmpty.insert( "defaultGroups", QStringList() );
|
||||||
@ -87,22 +152,22 @@ UserTests::testDefaultGroups()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
QStringList groups;
|
QList< GroupDescription > groups;
|
||||||
QVariantMap missing;
|
QVariantMap missing;
|
||||||
QVERIFY( groups.isEmpty() );
|
QVERIFY( groups.isEmpty() );
|
||||||
setConfigurationDefaultGroups( missing, groups );
|
setConfigurationDefaultGroups( missing, groups );
|
||||||
QCOMPARE( groups.count(), 6 ); // because of fallback!
|
QCOMPARE( groups.count(), 6 ); // because of fallback!
|
||||||
QVERIFY( groups.contains( "lp" ) );
|
QVERIFY( groups.contains( GroupDescription( "lp", false, GroupDescription::SystemGroup {} ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
QStringList groups;
|
QList< GroupDescription > groups;
|
||||||
QVariantMap typeMismatch;
|
QVariantMap typeMismatch;
|
||||||
QVERIFY( groups.isEmpty() );
|
QVERIFY( groups.isEmpty() );
|
||||||
typeMismatch.insert( "defaultGroups", 1 );
|
typeMismatch.insert( "defaultGroups", 1 );
|
||||||
setConfigurationDefaultGroups( typeMismatch, groups );
|
setConfigurationDefaultGroups( typeMismatch, groups );
|
||||||
QCOMPARE( groups.count(), 6 ); // because of fallback!
|
QCOMPARE( groups.count(), 6 ); // because of fallback!
|
||||||
QVERIFY( groups.contains( "lp" ) );
|
QVERIFY( groups.contains( GroupDescription( "lp", false, GroupDescription::SystemGroup {} ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +181,7 @@ UserTests::testDefaultGroupsYAML_data()
|
|||||||
QTest::newRow( "users.conf" ) << "users.conf" << 7 << "video";
|
QTest::newRow( "users.conf" ) << "users.conf" << 7 << "video";
|
||||||
QTest::newRow( "dashed list" ) << "tests/4-audio.conf" << 4 << "audio";
|
QTest::newRow( "dashed list" ) << "tests/4-audio.conf" << 4 << "audio";
|
||||||
QTest::newRow( "blocked list" ) << "tests/3-wing.conf" << 3 << "wing";
|
QTest::newRow( "blocked list" ) << "tests/3-wing.conf" << 3 << "wing";
|
||||||
|
QTest::newRow( "issue 1523" ) << "tests/5-issue-1523.conf" << 4 << "foobar";
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -130,6 +196,7 @@ UserTests::testDefaultGroupsYAML()
|
|||||||
QFETCH( int, count );
|
QFETCH( int, count );
|
||||||
QFETCH( QString, group );
|
QFETCH( QString, group );
|
||||||
|
|
||||||
|
// BUILD_AS_TEST is the source-directory path
|
||||||
QFile fi( QString( "%1/%2" ).arg( BUILD_AS_TEST, filename ) );
|
QFile fi( QString( "%1/%2" ).arg( BUILD_AS_TEST, filename ) );
|
||||||
QVERIFY( fi.exists() );
|
QVERIFY( fi.exists() );
|
||||||
|
|
||||||
|
14
src/modules/users/tests/5-issue-1523.conf
Normal file
14
src/modules/users/tests/5-issue-1523.conf
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# SPDX-FileCopyrightText: no
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
#
|
||||||
|
---
|
||||||
|
defaultGroups:
|
||||||
|
- adm
|
||||||
|
- name: foo
|
||||||
|
must_exist: false
|
||||||
|
system: true
|
||||||
|
- name: bar
|
||||||
|
must_exist: true
|
||||||
|
- name: foobar
|
||||||
|
must_exist: false
|
||||||
|
system: false
|
@ -3,26 +3,42 @@
|
|||||||
#
|
#
|
||||||
# Configuration for the one-user-system user module.
|
# Configuration for the one-user-system user module.
|
||||||
#
|
#
|
||||||
# Besides these settings, the user module also places the following
|
# Besides these settings, the users module also places the following
|
||||||
# keys into the globalconfig area, based on user input in the view step.
|
# keys into the Global Storage area, based on user input in the view step.
|
||||||
#
|
#
|
||||||
# - hostname
|
# - hostname
|
||||||
# - username
|
# - username
|
||||||
# - password (obscured)
|
# - password (obscured)
|
||||||
# - autologinUser (if enabled, set to username)
|
# - autologinUser (if enabled, set to username)
|
||||||
#
|
#
|
||||||
# These globalconfig keys are set when the jobs for this module
|
# These Global Storage keys are set when the configuration for this module
|
||||||
# are created.
|
# is read and when they are modified in the UI.
|
||||||
---
|
---
|
||||||
# Used as default groups for the created user.
|
# Used as default groups for the created user.
|
||||||
# Adjust to your Distribution defaults.
|
# Adjust to your Distribution defaults.
|
||||||
|
#
|
||||||
|
# Each entry in the *defaultGroups* list is either:
|
||||||
|
# - a string, naming a group; this is a **non**-system group
|
||||||
|
# which does not need to exist in the target system; if it
|
||||||
|
# does not exist, it will be created.
|
||||||
|
# - an entry with subkeys *name*, *must_exist* and *system*;
|
||||||
|
# if the group *must_exist* and does not, an error is thrown
|
||||||
|
# and the installation fails.
|
||||||
|
#
|
||||||
|
# The group is created if it does not exist, and it is
|
||||||
|
# created as a system group (GID < 1000) or user group
|
||||||
|
# (GID >= 1000) depending on the value of *system*.
|
||||||
defaultGroups:
|
defaultGroups:
|
||||||
- users
|
- name: users
|
||||||
|
must_exist: true
|
||||||
|
system: true
|
||||||
- lp
|
- lp
|
||||||
- video
|
- video
|
||||||
- network
|
- network
|
||||||
- storage
|
- storage
|
||||||
- wheel
|
- name: wheel
|
||||||
|
must_exist: false
|
||||||
|
system: true
|
||||||
- audio
|
- audio
|
||||||
|
|
||||||
# Some Distributions require a 'autologin' group for the user.
|
# Some Distributions require a 'autologin' group for the user.
|
||||||
|
@ -11,7 +11,16 @@ properties:
|
|||||||
# Group settings
|
# Group settings
|
||||||
defaultGroups:
|
defaultGroups:
|
||||||
type: array
|
type: array
|
||||||
items: { type: string }
|
items:
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
name: { type: string }
|
||||||
|
must_exist: { type: boolean, default: false }
|
||||||
|
system: { type: boolean, default: false }
|
||||||
|
additionalProperties: false
|
||||||
|
required: [ name ]
|
||||||
autologinGroup: { type: string }
|
autologinGroup: { type: string }
|
||||||
sudoersGroup: { type: string }
|
sudoersGroup: { type: string }
|
||||||
# Skip login (depends on displaymanager support)
|
# Skip login (depends on displaymanager support)
|
||||||
|
@ -13,9 +13,8 @@ find_package( Crypt REQUIRED )
|
|||||||
|
|
||||||
# Add optional libraries here
|
# Add optional libraries here
|
||||||
set( USER_EXTRA_LIB )
|
set( USER_EXTRA_LIB )
|
||||||
set( _users ${CMAKE_CURRENT_SOURCE_DIR}/../users )
|
|
||||||
|
|
||||||
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ${CMAKE_CURRENT_SOURCE_DIR}/../../libcalamares ${_users} )
|
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../users )
|
||||||
|
|
||||||
find_package( LibPWQuality )
|
find_package( LibPWQuality )
|
||||||
set_package_properties(
|
set_package_properties(
|
||||||
@ -33,15 +32,11 @@ calamares_add_plugin( usersq
|
|||||||
TYPE viewmodule
|
TYPE viewmodule
|
||||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
SOURCES
|
SOURCES
|
||||||
${_users}/Config.cpp
|
|
||||||
${_users}/CreateUserJob.cpp
|
|
||||||
${_users}/SetPasswordJob.cpp
|
|
||||||
UsersQmlViewStep.cpp
|
UsersQmlViewStep.cpp
|
||||||
${_users}/SetHostNameJob.cpp
|
|
||||||
${_users}/CheckPWQuality.cpp
|
|
||||||
RESOURCES
|
RESOURCES
|
||||||
usersq.qrc
|
usersq.qrc
|
||||||
LINK_PRIVATE_LIBRARIES
|
LINK_PRIVATE_LIBRARIES
|
||||||
|
users_internal
|
||||||
calamaresui
|
calamaresui
|
||||||
${CRYPT_LIBRARIES}
|
${CRYPT_LIBRARIES}
|
||||||
${USER_EXTRA_LIB}
|
${USER_EXTRA_LIB}
|
||||||
|
Loading…
Reference in New Issue
Block a user