diff --git a/CHANGES b/CHANGES index 73c99cf9b..98db4d483 100644 --- a/CHANGES +++ b/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 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): - Anke Boersma - Andrius Štikonas - Artem Grinev - Gaël PORTAY + - Matti Hyttinen - TTran Me ## Core ## - Calamares now sets the C++ standard for compilation to C++17; this is for better compatibility and fewer warnings when building with modern KDE Frameworks and KPMcore 4.2.0. - - Vietnamese translations have been added. Welcome! + - Vietnamese translations have been added. Welcome! (Thanks TTran) ## Modules ## + - The *initcpiocfg* module should support plymouth with encryption + now. (Thanks Matti) - The *keyboard* and *keyboardq* modules now share backend code 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) # diff --git a/CMakeLists.txt b/CMakeLists.txt index b20ce50d9..d8744afb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ project( CALAMARES VERSION 3.2.33 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 # diff --git a/CMakeModules/CalamaresAddTest.cmake b/CMakeModules/CalamaresAddTest.cmake index 56a45d7dc..228d7cbc0 100644 --- a/CMakeModules/CalamaresAddTest.cmake +++ b/CMakeModules/CalamaresAddTest.cmake @@ -42,6 +42,8 @@ function( calamares_add_test ) Qt5::Test ) 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} ) if( TEST_GUI ) target_link_libraries( ${TEST_NAME} calamaresui Qt5::Gui ) diff --git a/README.md b/README.md index a2cb426b7..d3db39089 100644 --- a/README.md +++ b/README.md @@ -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. -The dependencies are explainged in [CONTRIBUTING.md](CONTRIBUTING.md). +The dependencies are explained in [CONTRIBUTING.md](CONTRIBUTING.md). ## Contributing to Calamares diff --git a/lang/calamares_az.ts b/lang/calamares_az.ts index e73b01885..cad678b40 100644 --- a/lang/calamares_az.ts +++ b/lang/calamares_az.ts @@ -619,17 +619,17 @@ Bu proqramdan çıxılacaq və bütün dəyişikliklər itiriləcəkdir. 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/> - + 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/> This storage device has one of its partitions <strong>mounted</strong>. - + Bu yaddaş qurğusunda bölmələrdən biri <strong>quraşdırılmışdır</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + Bu yaddaş qurğusu <strong>qeyri-aktiv RAİD</strong> qurğusunun bir hissəsidir. @@ -2869,7 +2869,7 @@ Output: Directory not found - + Qovluq tapılmadı diff --git a/lang/calamares_az_AZ.ts b/lang/calamares_az_AZ.ts index 51ef10496..161a04990 100644 --- a/lang/calamares_az_AZ.ts +++ b/lang/calamares_az_AZ.ts @@ -619,17 +619,17 @@ Bu proqramdan çıxılacaq və bütün dəyişikliklər itiriləcəkdir. 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/> - + 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/> This storage device has one of its partitions <strong>mounted</strong>. - + Bu yaddaş qurğusunda bölmələrdən biri <strong>quraşdırılmışdır</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + Bu yaddaş qurğusu <strong>qeyri-aktiv RAİD</strong> qurğusunun bir hissəsidir. @@ -2869,7 +2869,7 @@ Output: Directory not found - + Qovluq tapılmadı diff --git a/lang/calamares_he.ts b/lang/calamares_he.ts index e87f6bb19..5ed81a899 100644 --- a/lang/calamares_he.ts +++ b/lang/calamares_he.ts @@ -437,7 +437,7 @@ The installer will quit and all changes will be lost. Unknown exception type - טיפוס חריגה אינו מוכר + סוג חריגה לא מוכר diff --git a/lang/calamares_hu.ts b/lang/calamares_hu.ts index f7651406c..e0ca6cd41 100644 --- a/lang/calamares_hu.ts +++ b/lang/calamares_hu.ts @@ -1620,7 +1620,7 @@ Telepítés nem folytatható. <a href="#details">Részletek...</a> <h1>License Agreement</h1> - + <h1>Licenszszerződés</h1> diff --git a/lang/calamares_ko.ts b/lang/calamares_ko.ts index 481637f00..3a5820569 100644 --- a/lang/calamares_ko.ts +++ b/lang/calamares_ko.ts @@ -304,12 +304,12 @@ Calamares Initialization Failed - Calamares 초기화 실패 + 깔라마레스 초기화 실패 %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. - %1 가 설치될 수 없습니다. Calamares가 모든 구성된 모듈을 불러올 수 없었습니다. 이것은 Calamares가 분포에 의해 사용되는 방식에서 비롯된 문제입니다. + %1 가 설치될 수 없습니다. 깔라마레스가 모든 구성된 모듈을 불러올 수 없었습니다. 이것은 깔라마레스가 배포판에서 사용되는 방식에서 발생한 문제입니다. @@ -617,17 +617,17 @@ The installer will quit and all changes will be lost. 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/> - + 이 스토리지 장치에는 이미 운영 체제가 설치되어 있으나 <strong>%1</strong> 파티션 테이블이 필요로 하는 <strong>%2</strong>와 다릅니다.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + 이 스토리지 장치는 하나 이상의 <strong>마운트된</strong> 파티션을 갖고 있습니다. This storage device is a part of an <strong>inactive RAID</strong> device. - + 이 스토리지 장치는 <strong>비활성화된 RAID</strong> 장치의 일부입니다. @@ -730,7 +730,7 @@ The installer will quit and all changes will be lost. Set timezone to %1/%2. - + 표준시간대를 %1/%2로 설정합니다. @@ -790,22 +790,22 @@ The installer will quit and all changes will be lost. <h1>Welcome to the Calamares setup program for %1</h1> - + <h1> 깔라마레스 설치 프로그램 %1에 오신 것을 환영합니다</h1> <h1>Welcome to %1 setup</h1> - + <h1>%1 설치에 오신 것을 환영합니다</h1> <h1>Welcome to the Calamares installer for %1</h1> - + <h1>깔라마레스 인스톨러 %1에 오신 것을 환영합니다</h1> <h1>Welcome to the %1 installer</h1> - + <h1>%1 인스톨러에 오신 것을 환영합니다</h1> @@ -815,7 +815,7 @@ The installer will quit and all changes will be lost. '%1' is not allowed as username. - + '%1'은 사용자 이름으로 허용되지 않습니다. @@ -840,7 +840,7 @@ The installer will quit and all changes will be lost. '%1' is not allowed as hostname. - + '%1'은 호스트 이름으로 허용되지 않습니다. @@ -1813,7 +1813,7 @@ The installer will quit and all changes will be lost. Timezone: %1 - + 표준시간대: %1 @@ -1945,7 +1945,7 @@ The installer will quit and all changes will be lost. <html><head/><body><h1>OEM Configuration</h1><p>Calamares will use OEM settings while configuring the target system.</p></body></html> - <html><head/><body><h1>OEM 구성</h1> <p>Calamares는 대상 시스템을 구성하는 동안 OEM 설정을 사용합니다.</p></body></html> + <html><head/><body><h1>OEM 구성</h1> <p>깔라마레스는 대상 시스템을 구성하는 동안 OEM 설정을 사용합니다.</p></body></html> @@ -1973,22 +1973,22 @@ The installer will quit and all changes will be lost. Timezone: %1 - + 표준시간대: %1 Select your preferred Zone within your Region. - + 선호하는 표준시간대와 지역을 선택하세요. Zones - + 표준시간대 You can fine-tune Language and Locale settings below. - + 아래에서 언어 및 로케일을 상세하게 설정할 수 있습니다. @@ -2864,7 +2864,7 @@ Output: Directory not found - + 디렉터리를 찾을 수 없습니다 @@ -3044,7 +3044,7 @@ Output: Calamares cannot start KPMCore for the file-system resize job. - Calamares는 파일 시스템 크기 조정 작업을 위해 KPMCore를 시작할 수 없습니다. + 깔라마레스는 파일 시스템 크기 조정 작업을 위해 KPMCore를 시작할 수 없습니다. @@ -3482,18 +3482,18 @@ Output: KDE user feedback - + KDE 사용자 의견 Configuring KDE user feedback. - + KDE 사용자 의견을 설정하는 중입니다. Error in KDE user feedback configuration. - + KDE 사용자 의견 설정 중에 오류가 발생했습니다. @@ -3744,7 +3744,7 @@ Output: <h1>Welcome to the Calamares setup program for %1.</h1> - <h1>%1에 대한 Calamares 설정 프로그램에 오신 것을 환영합니다.</h1> + <h1>%1에 대한 깔라마레스 설정 프로그램에 오신 것을 환영합니다.</h1> @@ -3754,7 +3754,7 @@ Output: <h1>Welcome to the Calamares installer for %1.</h1> - <h1>%1을 위한 Calamares 설치 관리자에 오신 것을 환영합니다.</h1> + <h1>%1을 위한 깔라마레스 설치 관리자에 오신 것을 환영합니다.</h1> @@ -3877,7 +3877,7 @@ Output: Keyboard Variant - + 키보드 유형 @@ -3890,7 +3890,7 @@ Output: Change - + 변경 @@ -3941,7 +3941,7 @@ Output: Pick your user name and credentials to login and perform admin tasks - + 로그인 및 관리자 작업을 수행하려면 사용자 이름과 자격 증명을 선택하세요 @@ -3961,7 +3961,7 @@ Output: Login Name - + 로그인 이름 @@ -4006,7 +4006,7 @@ Output: Validate passwords quality - + 패스워드 품질 검증 @@ -4016,12 +4016,12 @@ Output: Log in automatically without asking for the password - + 패스워드를 묻지 않고 자동으로 로그인합니다 Reuse user password as root password - + 사용자 패스워드를 루트 패스워드로 재사용합니다 @@ -4031,22 +4031,22 @@ Output: Choose a root password to keep your account safe. - + 당신의 계정을 안전하게 보호하기 위해서 루트 패스워드를 선택하세요. Root Password - + 루트 패스워드 Repeat Root Password - + 루트 패스워드 확인 Enter the same password twice, so that it can be checked for typing errors. - + 입력 오류를 확인하기 위해서 동일한 패스워드를 두번 입력해주세요. @@ -4060,7 +4060,7 @@ Output: About - Calamares에 대하여 + 깔라마레스에 대하여 diff --git a/lang/calamares_lt.ts b/lang/calamares_lt.ts index 676603ca3..0adb509ac 100644 --- a/lang/calamares_lt.ts +++ b/lang/calamares_lt.ts @@ -2870,7 +2870,7 @@ Išvestis: Directory not found - + Katalogas nerastas @@ -3885,7 +3885,7 @@ Išvestis: Keyboard Variant - + Klaviatūros variantas @@ -3989,7 +3989,7 @@ Išvestis: Login Name - + Prisijungimo vardas @@ -4009,7 +4009,7 @@ Išvestis: This name will be used if you make the computer visible to others on a network. - + Šis vardas bus naudojamas, jeigu padarysite savo kompiuterį matomą kitiems naudotojams tinkle. @@ -4074,7 +4074,7 @@ Išvestis: Enter the same password twice, so that it can be checked for typing errors. - + Norint įsitikinti, kad rašydami slaptažodį nesuklydote, įrašykite tą patį slaptažodį du kartus. diff --git a/lang/python/az/LC_MESSAGES/python.po b/lang/python/az/LC_MESSAGES/python.po index 516429c2d..8637bfe7e 100644 --- a/lang/python/az/LC_MESSAGES/python.po +++ b/lang/python/az/LC_MESSAGES/python.po @@ -206,6 +206,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." 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 msgid "Display manager configuration was incomplete" diff --git a/lang/python/az_AZ/LC_MESSAGES/python.po b/lang/python/az_AZ/LC_MESSAGES/python.po index 5fdf99797..4fb1f949b 100644 --- a/lang/python/az_AZ/LC_MESSAGES/python.po +++ b/lang/python/az_AZ/LC_MESSAGES/python.po @@ -206,6 +206,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." 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 msgid "Display manager configuration was incomplete" @@ -318,11 +320,11 @@ msgstr "Aparat saatını ayarlamaq." #: src/modules/mkinitfs/main.py:27 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 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 msgid "The exit code was {}" diff --git a/lang/python/ko/LC_MESSAGES/python.po b/lang/python/ko/LC_MESSAGES/python.po index 7108fb0e0..8b8a891e8 100644 --- a/lang/python/ko/LC_MESSAGES/python.po +++ b/lang/python/ko/LC_MESSAGES/python.po @@ -4,7 +4,7 @@ # FIRST AUTHOR , YEAR. # # Translators: -# 김지현 , 2018 +# Ji-Hyeon Gim , 2018 # JungHee Lee , 2020 # #, fuzzy diff --git a/lang/tz_vi.ts b/lang/tz_vi.ts new file mode 100644 index 000000000..b7149efa9 --- /dev/null +++ b/lang/tz_vi.ts @@ -0,0 +1,2617 @@ + + + + + QObject + + + Africa + tz_regions + Châu phi + + + + America + tz_regions + Châu Mỹ + + + + Antarctica + tz_regions + Nam Cực + + + + Arctic + tz_regions + Bắc cực + + + + Asia + tz_regions + Châu Á + + + + Atlantic + tz_regions + Đại Tây Dương + + + + Australia + tz_regions + Châu Úc + + + + Europe + tz_regions + Châu Âu + + + + Indian + tz_regions + Ấn Độ + + + + Pacific + tz_regions + Thái Bình Dương + + + + Abidjan + tz_names + Abidjan + + + + Accra + tz_names + Accra + + + + Adak + tz_names + Adak + + + + Addis Ababa + tz_names + A-đi A-ba-ba + + + + Adelaide + tz_names + Adelaide + + + + Aden + tz_names + Aden + + + + Algiers + tz_names + Algiers + + + + Almaty + tz_names + Almaty + + + + Amman + tz_names + Amman + + + + Amsterdam + tz_names + Am-xtéc-đam + + + + Anadyr + tz_names + Anadyr + + + + Anchorage + tz_names + Anchorage + + + + Andorra + tz_names + Andorra + + + + Anguilla + tz_names + An-gui-la + + + + Antananarivo + tz_names + An-ta-na-na-ri-vô + + + + Antigua + tz_names + Antigua + + + + Apia + tz_names + A-pi-a + + + + Aqtau + tz_names + Aqtau + + + + Aqtobe + tz_names + Aqtobe + + + + Araguaina + tz_names + Araguaina + + + + Argentina/Buenos Aires + tz_names + Ác-hen-ti-na/Buenos Aires + + + + Argentina/Catamarca + tz_names + Ác-hen-ti-na/Catamarca + + + + Argentina/Cordoba + tz_names + Ác-hen-ti-na/Cordoba + + + + Argentina/Jujuy + tz_names + Ác-hen-ti-na/Jujuy + + + + Argentina/La Rioja + tz_names + Ác-hen-ti-na/La Rioja + + + + Argentina/Mendoza + tz_names + Ác-hen-ti-na/Mendoza + + + + Argentina/Rio Gallegos + tz_names + Ác-hen-ti-na/Rio Gallegos + + + + Argentina/Salta + tz_names + Ác-hen-ti-na/Salta + + + + Argentina/San Juan + tz_names + Ác-hen-ti-na/San Juan + + + + Argentina/San Luis + tz_names + Ác-hen-ti-na/San Luis + + + + Argentina/Tucuman + tz_names + Ác-hen-ti-na/Tucuman + + + + Argentina/Ushuaia + tz_names + Ác-hen-ti-na/Ushuaia + + + + Aruba + tz_names + A-ru-ba + + + + Ashgabat + tz_names + A-sơ-kha0bast + + + + Asmara + tz_names + Át-ma-ra + + + + Astrakhan + tz_names + Astrakhan + + + + Asuncion + tz_names + A-sun-sân + + + + Athens + tz_names + A-ten + + + + Atikokan + tz_names + Atikokan + + + + Atyrau + tz_names + Atyrau + + + + Auckland + tz_names + Auckland + + + + Azores + tz_names + Azores + + + + Baghdad + tz_names + Bát-đa + + + + Bahia + tz_names + Bahia + + + + Bahia Banderas + tz_names + Bahia Banderas + + + + Bahrain + tz_names + Ba-ranh + + + + Baku + tz_names + Ba-cu + + + + Bamako + tz_names + Bamako + + + + Bangkok + tz_names + Băng Cốc + + + + Bangui + tz_names + Ban-gui + + + + Banjul + tz_names + Ban-giun + + + + Barbados + tz_names + Bác-ba-đốt + + + + Barnaul + tz_names + Barnaul + + + + Beirut + tz_names + Bê-rút + + + + Belem + tz_names + Belem + + + + Belgrade + tz_names + Bê-ô-grát + + + + Belize + tz_names + Bê-li-xê + + + + Berlin + tz_names + Béc Lin + + + + Bermuda + tz_names + Béc-mu-đa + + + + Bishkek + tz_names + Bi-skec + + + + Bissau + tz_names + Bit-xao + + + + Blanc-Sablon + tz_names + Blanc-Sablon + + + + Blantyre + tz_names + Blantyre + + + + Boa Vista + tz_names + Boa Vista + + + + Bogota + tz_names + Bô-gô-ta + + + + Boise + tz_names + Boise + + + + Bougainville + tz_names + Bougainville + + + + Bratislava + tz_names + Bra-tít-xla-va + + + + Brazzaville + tz_names + Brazzaville + + + + Brisbane + tz_names + Brisbane + + + + Broken Hill + tz_names + Đồi Broken + + + + Brunei + tz_names + Bru-nây + + + + Brussels + tz_names + Brúc-xen + + + + Bucharest + tz_names + Bu-ca-rét + + + + Budapest + tz_names + Bu-đa-pét + + + + Bujumbura + tz_names + Bu-gium-bu-ra + + + + Busingen + tz_names + Busingen + + + + Cairo + tz_names + Cai Rô + + + + Cambridge Bay + tz_names + Vịnh Cambridge + + + + Campo Grande + tz_names + Campo Grande + + + + Canary + tz_names + Canary + + + + Cancun + tz_names + Cancun + + + + Cape Verde + tz_names + Cáp-ve + + + + Caracas + tz_names + Ca-ra-cát + + + + Casablanca + tz_names + Casablanca + + + + Casey + tz_names + Casey + + + + Cayenne + tz_names + Cayenne + + + + Cayman + tz_names + Quần đảo Cay-man + + + + Ceuta + tz_names + Ceuta + + + + Chagos + tz_names + Chagos + + + + Chatham + tz_names + Chatham + + + + Chicago + tz_names + Chi Ca Gô + + + + Chihuahua + tz_names + Chihuahua + + + + Chisinau + tz_names + Ki-si-nhốp + + + + Chita + tz_names + Chita + + + + Choibalsan + tz_names + Choibalsan + + + + Christmas + tz_names + Christmas + + + + Chuuk + tz_names + Chuuk + + + + Cocos + tz_names + Cocos + + + + Colombo + tz_names + Cô Lôm Bô + + + + Comoro + tz_names + (Liên bang) Cô-mo + + + + Conakry + tz_names + Cô-na-cri + + + + Copenhagen + tz_names + Cô-pen-ha-gen + + + + Costa Rica + tz_names + Cốt-xta-ri-ca + + + + Creston + tz_names + Creston + + + + Cuiaba + tz_names + Cuiaba + + + + Curacao + tz_names + Cu-ra-xao + + + + Currie + tz_names + Currie + + + + Dakar + tz_names + Dakar + + + + Damascus + tz_names + Đa-mát + + + + Danmarkshavn + tz_names + Danmarkshavn + + + + Dar es Salaam + tz_names + Dar es Salaam + + + + Darwin + tz_names + Darwin + + + + Davis + tz_names + Davis + + + + Dawson + tz_names + Dawson + + + + Dawson Creek + tz_names + Dawson Creek + + + + Denver + tz_names + Denver + + + + Detroit + tz_names + Detroit + + + + Dhaka + tz_names + Đắc-ca + + + + Dili + tz_names + Đi-li + + + + Djibouti + tz_names + Cộng hòa Gi-bu-ti + + + + Dominica + tz_names + Đô-mi-ni-ca-na + + + + Douala + tz_names + Douala + + + + Dubai + tz_names + Đu Bai + + + + Dublin + tz_names + Đu-blin + + + + DumontDUrville + tz_names + DumontDUrville + + + + Dushanbe + tz_names + Đu-san-be + + + + Easter + tz_names + Đảo Phục Sinh + + + + Edmonton + tz_names + Edmonton + + + + Efate + tz_names + Efate + + + + Eirunepe + tz_names + Eirunepe + + + + El Aaiun + tz_names + El Aaiun + + + + El Salvador + tz_names + En Xan-va-đo + + + + Enderbury + tz_names + Đảo Enderbury + + + + Eucla + tz_names + Eucla + + + + Fakaofo + tz_names + Fakaofo + + + + Famagusta + tz_names + Famagusta + + + + Faroe + tz_names + Quần đảo Fa-rô + + + + Fiji + tz_names + Phi-gi + + + + Fort Nelson + tz_names + Fort Nelson + + + + Fortaleza + tz_names + Fortaleza + + + + Freetown + tz_names + Phritao + + + + Funafuti + tz_names + Funafuti + + + + Gaborone + tz_names + Ga-bô-rô-nê + + + + Galapagos + tz_names + Quần đảo Galapagos + + + + Gambier + tz_names + Gambier + + + + Gaza + tz_names + Dải Gaza + + + + Gibraltar + tz_names + Gibraltar + + + + Glace Bay + tz_names + Vịnh Glace + + + + Godthab + tz_names + Nu-úc + + + + Goose Bay + tz_names + Vịnh Goose + + + + Grand Turk + tz_names + Đảo Grand Turk + + + + Grenada + tz_names + Grê-na-đa + + + + Guadalcanal + tz_names + Guadalcanal + + + + Guadeloupe + tz_names + Goa-đê-lốp + + + + Guam + tz_names + Guam + + + + Guatemala + tz_names + Goa-tê-ma-la + + + + Guayaquil + tz_names + Guayaquil + + + + Guernsey + tz_names + Guernsey + + + + Guyana + tz_names + Guy-a-na + + + + Halifax + tz_names + Halifa + + + + Harare + tz_names + Ha-ra-rê + + + + Havana + tz_names + Ha Va Na + + + + Hebron + tz_names + Hebron + + + + Helsinki + tz_names + Hen-sin-ki + + + + Hermosillo + tz_names + Hermosillo + + + + Ho Chi Minh + tz_names + Hồ Chí Minh + + + + Hobart + tz_names + Hobart + + + + Hong Kong + tz_names + Hồng Công + + + + Honolulu + tz_names + Honolulu + + + + Hovd + tz_names + Khovd + + + + Indiana/Indianapolis + tz_names + Indiana/Indianapolis + + + + Indiana/Knox + tz_names + Indiana/Knox + + + + Indiana/Marengo + tz_names + Indiana/Marengo + + + + Indiana/Petersburg + tz_names + Indiana/Petersburg + + + + Indiana/Tell City + tz_names + Indiana/Tell City + + + + Indiana/Vevay + tz_names + Indiana/Vevay + + + + Indiana/Vincennes + tz_names + Indiana/Vincennes + + + + Indiana/Winamac + tz_names + Indiana/Winamac + + + + Inuvik + tz_names + Inuvik + + + + Iqaluit + tz_names + Iqaluit + + + + Irkutsk + tz_names + Irkutsk + + + + Isle of Man + tz_names + Đảo Man + + + + Istanbul + tz_names + Istanbul + + + + Jakarta + tz_names + Gia Các Ta + + + + Jamaica + tz_names + Gia-mai-ca + + + + Jayapura + tz_names + Jayapura + + + + Jersey + tz_names + Jersey + + + + Jerusalem + tz_names + Giê-ru-xa-lem + + + + Johannesburg + tz_names + Johannesburg + + + + Juba + tz_names + Juba + + + + Juneau + tz_names + Juneau + + + + Kabul + tz_names + Ka-bun + + + + Kaliningrad + tz_names + Kaliningrad + + + + Kamchatka + tz_names + Bán đảo Kamchatka + + + + Kampala + tz_names + Campala + + + + Karachi + tz_names + Karachi + + + + Kathmandu + tz_names + Cát-man-đu + + + + Kentucky/Louisville + tz_names + Ken túc ky/Louisville + + + + Kentucky/Monticello + tz_names + Ken túc ky/Monticello + + + + Kerguelen + tz_names + Đảo Kerguelen + + + + Khandyga + tz_names + Khandyga + + + + Khartoum + tz_names + Khác-tum + + + + Kiev + tz_names + Kyiv + + + + Kigali + tz_names + Ki-ga-li + + + + Kinshasa + tz_names + Kin-xa-sa + + + + Kiritimati + tz_names + Kiritimati + + + + Kirov + tz_names + Kirov + + + + Kolkata + tz_names + Kolkata + + + + Kosrae + tz_names + Kosrae + + + + Kralendijk + tz_names + Kralendijk + + + + Krasnoyarsk + tz_names + Krasnoyarsk + + + + Kuala Lumpur + tz_names + Kuala Lam Pơ + + + + Kuching + tz_names + Kuching + + + + Kuwait + tz_names + Kuwait + + + + Kwajalein + tz_names + Kwajalein + + + + La Paz + tz_names + La Pa-xơ + + + + Lagos + tz_names + Lagos + + + + Libreville + tz_names + Li-brơ-vin + + + + Lima + tz_names + Lima + + + + Lindeman + tz_names + Hồ Lindeman + + + + Lisbon + tz_names + Lít Bon + + + + Ljubljana + tz_names + Liu-bli-an-na + + + + Lome + tz_names + Lô-mê + + + + London + tz_names + Luân Đôn + + + + Longyearbyen + tz_names + Longyearbyen + + + + Lord Howe + tz_names + Đảo Lord Howe + + + + Los Angeles + tz_names + Lốt Ăng Giơ Lét + + + + Lower Princes + tz_names + Lower Princes + + + + Luanda + tz_names + Lu-an-đa + + + + Lubumbashi + tz_names + Lubumbashi + + + + Lusaka + tz_names + Lu-xa-ca + + + + Luxembourg + tz_names + Lúc-xăm-bua + + + + Macau + tz_names + Ma Cao + + + + Maceio + tz_names + Maceio + + + + Macquarie + tz_names + Macquarie + + + + Madeira + tz_names + Madeira + + + + Madrid + tz_names + Ma Rích + + + + Magadan + tz_names + Magadan + + + + Mahe + tz_names + Mahe + + + + Majuro + tz_names + Majuro + + + + Makassar + tz_names + Makassar + + + + Malabo + tz_names + Malabo + + + + Maldives + tz_names + Man-đi-vơ + + + + Malta + tz_names + Man-Man-tata + + + + Managua + tz_names + Ma-na-goa + + + + Manaus + tz_names + Manaus + + + + Manila + tz_names + Manila + + + + Maputo + tz_names + Maputo + + + + Mariehamn + tz_names + Mariehamn + + + + Marigot + tz_names + Marigot + + + + Marquesas + tz_names + Quần đảo Marquesas + + + + Martinique + tz_names + Martinique + + + + Maseru + tz_names + Ma-xê-ru + + + + Matamoros + tz_names + Matamoros + + + + Mauritius + tz_names + Mô-ri-xơ + + + + Mawson + tz_names + Mawson + + + + Mayotte + tz_names + Mayotte + + + + Mazatlan + tz_names + Mazatlan + + + + Mbabane + tz_names + Mbabane + + + + McMurdo + tz_names + McMurdo + + + + Melbourne + tz_names + Melbourne + + + + Menominee + tz_names + Menominee + + + + Merida + tz_names + Merida + + + + Metlakatla + tz_names + Metlakatla + + + + Mexico City + tz_names + Thành phố Mê Xi Cô + + + + Midway + tz_names + Midway + + + + Minsk + tz_names + Min-xcơ + + + + Miquelon + tz_names + Mi-kê-lân + + + + Mogadishu + tz_names + Mô-ga-đi-su + + + + Monaco + tz_names + Mô-na-cô + + + + Moncton + tz_names + Moncton + + + + Monrovia + tz_names + Monrovia + + + + Monterrey + tz_names + Monterrey + + + + Montevideo + tz_names + Mông-tơ-vi-di-ô + + + + Montserrat + tz_names + Montserrat + + + + Moscow + tz_names + Mát Cơ Va + + + + Muscat + tz_names + Mu Cát + + + + Nairobi + tz_names + Nai-rô-bi + + + + Nassau + tz_names + Nát-xô + + + + Nauru + tz_names + Na-u-ru + + + + Ndjamena + tz_names + Gia-mê-na + + + + New York + tz_names + Nữu Ước + + + + Niamey + tz_names + Ni-a-mây + + + + Nicosia + tz_names + Ni-cô-xi-a + + + + Nipigon + tz_names + Nipigon + + + + Niue + tz_names + Ni-u-ê + + + + Nome + tz_names + Nome + + + + Norfolk + tz_names + Norfolk + + + + Noronha + tz_names + Noronha + + + + North Dakota/Beulah + tz_names + Bắc Dakota/Beulah + + + + North Dakota/Center + tz_names + Bắc Dakota/Center + + + + North Dakota/New Salem + tz_names + Bắc Dakota/New Salem + + + + Nouakchott + tz_names + Nu-ác-sốt + + + + Noumea + tz_names + No-mi + + + + Novokuznetsk + tz_names + Novokuznetsk + + + + Novosibirsk + tz_names + Novosibirsk + + + + Ojinaga + tz_names + Ojinaga + + + + Omsk + tz_names + Omsk + + + + Oral + tz_names + Oral + + + + Oslo + tz_names + Ốt-xlô + + + + Ouagadougou + tz_names + U-a-ga-đu-gu + + + + Pago Pago + tz_names + Pago Pago + + + + Palau + tz_names + Pa-lau + + + + Palmer + tz_names + Palmer + + + + Panama + tz_names + Pa-na-ma + + + + Pangnirtung + tz_names + Pangnirtung + + + + Paramaribo + tz_names + Pa-ra-ma-ri-bô + + + + Paris + tz_names + Pa Ri + + + + Perth + tz_names + Perth + + + + Phnom Penh + tz_names + Phnôm Pênh + + + + Phoenix + tz_names + Phoenix + + + + Pitcairn + tz_names + Quần đảo Pít-cơn + + + + Podgorica + tz_names + Pốt-gô-ri-xa + + + + Pohnpei + tz_names + Pohnpei + + + + Pontianak + tz_names + Pontianak + + + + Port Moresby + tz_names + Cảng Moresby + + + + Port of Spain + tz_names + Cảng Tây Ban Nha + + + + Port-au-Prince + tz_names + Cảng au Prince + + + + Porto Velho + tz_names + Cảng Velho + + + + Porto-Novo + tz_names + Cảng-Novo + + + + Prague + tz_names + Praha + + + + Puerto Rico + tz_names + Cảng Rico + + + + Punta Arenas + tz_names + Đấu trường Punta + + + + Pyongyang + tz_names + Bình Nhưỡng + + + + Qatar + tz_names + Ca-ta + + + + Qostanay + tz_names + Kostanay + + + + Qyzylorda + tz_names + Kyzylorda + + + + Rainy River + tz_names + Rainy River + + + + Rankin Inlet + tz_names + Rankin Inlet + + + + Rarotonga + tz_names + Rarotonga + + + + Recife + tz_names + Recife + + + + Regina + tz_names + Regina + + + + Resolute + tz_names + Resolute + + + + Reunion + tz_names + Rê-u-niên + + + + Reykjavik + tz_names + Rây-ki-a-vích + + + + Riga + tz_names + Ri-ga + + + + Rio Branco + tz_names + Rio Branco + + + + Riyadh + tz_names + Ri-át + + + + Rome + tz_names + Rô Ma + + + + Rothera + tz_names + Rothera + + + + Saipan + tz_names + Saipan + + + + Sakhalin + tz_names + Sakhalin + + + + Samara + tz_names + Samara + + + + Samarkand + tz_names + Samarkand + + + + San Marino + tz_names + San Marino + + + + Santarem + tz_names + Santarem + + + + Santiago + tz_names + Santiago + + + + Santo Domingo + tz_names + Xan-tô Đô-min-gô + + + + Sao Paulo + tz_names + Sao Paolo + + + + Sao Tome + tz_names + Sao Tô-mê + + + + Sarajevo + tz_names + Xa-ra-ê-vô + + + + Saratov + tz_names + Saratov + + + + Scoresbysund + tz_names + Scoresby Sund + + + + Seoul + tz_names + Xê un + + + + Shanghai + tz_names + Thượng Hải + + + + Simferopol + tz_names + Simferopol + + + + Singapore + tz_names + Singapo + + + + Sitka + tz_names + Sitka + + + + Skopje + tz_names + Xcốp-pi-ê + + + + Sofia + tz_names + Sofia + + + + South Georgia + tz_names + Nam Georgia + + + + Srednekolymsk + tz_names + Srednekolymsk + + + + St Barthelemy + tz_names + St Barthelemy + + + + St Helena + tz_names + St Helena + + + + St Johns + tz_names + St Johns + + + + St Kitts + tz_names + St Kitts + + + + St Lucia + tz_names + St Lucia + + + + St Thomas + tz_names + St Thomas + + + + St Vincent + tz_names + St Vincent + + + + Stanley + tz_names + Stanley + + + + Stockholm + tz_names + Xtốc-khôm + + + + Swift Current + tz_names + Swift Current + + + + Sydney + tz_names + Xít ni + + + + Syowa + tz_names + Syowa + + + + Tahiti + tz_names + Tahiti + + + + Taipei + tz_names + Đài Bắc + + + + Tallinn + tz_names + Ta-lin + + + + Tarawa + tz_names + Tarawa + + + + Tashkent + tz_names + Ta-sơ-ken + + + + Tbilisi + tz_names + Tbi-li-xi + + + + Tegucigalpa + tz_names + Te-gu-xi-gan-pa + + + + Tehran + tz_names + Tê-hê-ran + + + + Thimphu + tz_names + Thim-bu + + + + Thule + tz_names + Thule + + + + Thunder Bay + tz_names + Vịnh Thunder + + + + Tijuana + tz_names + Tijuana + + + + Tirane + tz_names + Ti-ra-na + + + + Tokyo + tz_names + Tô Ky Ôs + + + + Tomsk + tz_names + Tomsk + + + + Tongatapu + tz_names + Tongatapu + + + + Toronto + tz_names + Tô Rôn Tô + + + + Tortola + tz_names + Tortola + + + + Tripoli + tz_names + Tri Pô Li + + + + Troll + tz_names + Troll + + + + Tunis + tz_names + Tuy-nít + + + + Ulaanbaatar + tz_names + Ulan Bato + + + + Ulyanovsk + tz_names + Ulyanovsk + + + + Urumqi + tz_names + Urumqi + + + + Ust-Nera + tz_names + Ust-Nera + + + + Uzhgorod + tz_names + Uzhgorod + + + + Vaduz + tz_names + Vaduz + + + + Vancouver + tz_names + Van Cô Vơ + + + + Vatican + tz_names + Va Ti Can + + + + Vienna + tz_names + Viên + + + + Vientiane + tz_names + Viêng Chăn + + + + Vilnius + tz_names + Vin-ni-út + + + + Vladivostok + tz_names + Vladivostok + + + + Volgograd + tz_names + Volgograd + + + + Vostok + tz_names + Vostok + + + + Wake + tz_names + Wake + + + + Wallis + tz_names + Wa Li + + + + Warsaw + tz_names + Vác-sa-va + + + + Whitehorse + tz_names + Whitehorse + + + + Windhoek + tz_names + Windhoek + + + + Winnipeg + tz_names + Winnipeg + + + + Yakutat + tz_names + Yakutat + + + + Yakutsk + tz_names + Yakutsk + + + + Yangon + tz_names + Ragoon + + + + Yekaterinburg + tz_names + Yekaterinburg + + + + Yellowknife + tz_names + Yellowknife + + + + Yerevan + tz_names + Ê-rê-van + + + + Zagreb + tz_names + Da-gờ-rép + + + + Zaporozhye + tz_names + Zaporizhia + + + + Zurich + tz_names + Zurich + + + diff --git a/src/libcalamares/JobQueue.cpp b/src/libcalamares/JobQueue.cpp index 1637f0719..b66be7ebe 100644 --- a/src/libcalamares/JobQueue.cpp +++ b/src/libcalamares/JobQueue.cpp @@ -249,6 +249,7 @@ JobQueue::~JobQueue() } delete m_storage; + s_instance = nullptr; } diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index 7a94a8acc..c3bc0b95a 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -161,7 +161,10 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): hooks.append("usr") if encrypt_hook: - hooks.append("encrypt") + if detect_plymouth(): + hooks.append("plymouth-encrypt") + else: + hooks.append("encrypt") if not unencrypted_separate_boot and \ os.path.isfile( os.path.join(root_mount_point, "crypto_keyfile.bin") diff --git a/src/modules/keyboard/SetKeyboardLayoutJob.cpp b/src/modules/keyboard/SetKeyboardLayoutJob.cpp index 419d6f3fc..c80d84e7d 100644 --- a/src/modules/keyboard/SetKeyboardLayoutJob.cpp +++ b/src/modules/keyboard/SetKeyboardLayoutJob.cpp @@ -179,6 +179,8 @@ SetKeyboardLayoutJob::findLegacyKeymap() const bool SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const QString& convertedKeymapPath ) const { + cDebug() << "Writing vconsole data to" << vconsoleConfPath; + QString keymap = findConvertedKeymap( convertedKeymapPath ); if ( keymap.isEmpty() ) { @@ -205,15 +207,20 @@ SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const file.close(); if ( stream.status() != QTextStream::Ok ) { + cError() << "Could not read lines from" << file.fileName(); return false; } } // 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 ); bool found = false; - foreach ( const QString& existingLine, existingLines ) + for ( const QString& existingLine : qAsConst( existingLines ) ) { if ( existingLine.trimmed().startsWith( "KEYMAP=" ) ) { @@ -233,7 +240,7 @@ SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const stream.flush(); 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 ); } @@ -242,8 +249,14 @@ SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const bool SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const { + cDebug() << "Writing X11 configuration to" << 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 ); 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(); - cDebug() << "Written XkbLayout" << m_layout << "; XkbModel" << m_model << "; XkbVariant" << m_variant - << "to X.org file" << keyboardConfPath; + cDebug() << Logger::SubEntry << "Written XkbLayout" << m_layout << "; XkbModel" << m_model << "; XkbVariant" + << m_variant << "to X.org file" << keyboardConfPath << stream.status(); return ( stream.status() == QTextStream::Ok ); } @@ -297,8 +310,14 @@ SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const bool SetKeyboardLayoutJob::writeDefaultKeyboardData( const QString& defaultKeyboardPath ) const { + cDebug() << "Writing default keyboard data to" << 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 ); stream << "# KEYBOARD CONFIGURATION FILE\n\n" @@ -313,8 +332,8 @@ SetKeyboardLayoutJob::writeDefaultKeyboardData( const QString& defaultKeyboardPa file.close(); - cDebug() << "Written XKBMODEL" << m_model << "; XKBLAYOUT" << m_layout << "; XKBVARIANT" << m_variant - << "to /etc/default/keyboard file" << defaultKeyboardPath; + cDebug() << Logger::SubEntry << "Written XKBMODEL" << m_model << "; XKBLAYOUT" << m_layout << "; XKBVARIANT" + << m_variant << "to /etc/default/keyboard file" << defaultKeyboardPath << stream.status(); return ( stream.status() == QTextStream::Ok ); } @@ -329,60 +348,72 @@ SetKeyboardLayoutJob::exec() Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); 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; - while ( keyboardConfPath.startsWith( '/' ) ) + // Get the path to the destination's /etc/vconsole.conf + 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 ( 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( '/' ) ) + if ( !writeVConsoleData( vconsoleConfPath, convertedKeymapPath ) ) { - 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 ) ) - return Calamares::JobResult::error( - tr( "Failed to write keyboard configuration to existing /etc/default directory." ), - tr( "Failed to write to %1" ).arg( keyboardConfPath ) ); + // 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; + 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(); diff --git a/src/modules/mount/main.py b/src/modules/mount/main.py index 01c0650bf..71599a6de 100644 --- a/src/modules/mount/main.py +++ b/src/modules/mount/main.py @@ -7,6 +7,7 @@ # SPDX-FileCopyrightText: 2017 Alf Gaida # SPDX-FileCopyrightText: 2019 Adriaan de Groot # SPDX-FileCopyrightText: 2019 Kevin Kofler +# SPDX-FileCopyrightText: 2019-2020 Collabora Ltd # SPDX-License-Identifier: GPL-3.0-or-later # # 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 # `partition["mountPoint"]` starts with a '/'. raw_mount_point = partition["mountPoint"] + if not raw_mount_point: + return + mount_point = root_mount_point + raw_mount_point # Ensure that the created directory has the correct SELinux context on @@ -52,26 +56,22 @@ def mount_partition(root_mount_point, partition, partitions): raise fstype = partition.get("fs", "").lower() + if not fstype or fstype == "unformatted": + return if fstype == "fat16" or fstype == "fat32": fstype = "vfat" - if "luksMapperName" in partition: - 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", ""), - ) + device = partition["device"] - else: - libcalamares.utils.mount(partition["device"], - mount_point, - fstype, - partition.get("options", ""), - ) + if "luksMapperName" in partition: + device = os.path.join("/dev/mapper", partition["luksMapperName"]) + + if libcalamares.utils.mount(device, + mount_point, + fstype, + partition.get("options", "")) != 0: + libcalamares.utils.warning("Cannot mount {}".format(device)) # If the root partition is btrfs, we create a subvolume "@" # 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]) + device = partition["device"] + if "luksMapperName" in partition: - libcalamares.utils.mount( - "/dev/mapper/{!s}".format(partition["luksMapperName"]), - mount_point, - fstype, - ",".join( - ["subvol=@", partition.get("options", "")]), - ) - if not has_home_mount_point: - libcalamares.utils.mount( - "/dev/mapper/{!s}".format(partition["luksMapperName"]), - root_mount_point + "/home", - fstype, - ",".join( - ["subvol=@home", partition.get("options", "")]), - ) - 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", "")]), - ) + device = os.path.join("/dev/mapper", partition["luksMapperName"]) + + if libcalamares.utils.mount(device, + mount_point, + fstype, + ",".join(["subvol=@", partition.get("options", "")])) != 0: + libcalamares.utils.warning("Cannot mount {}".format(device)) + + if not has_home_mount_point: + if libcalamares.utils.mount(device, + root_mount_point + "/home", + fstype, + ",".join(["subvol=@home", partition.get("options", "")])) != 0: + libcalamares.utils.warning("Cannot mount {}".format(device)) def run(): diff --git a/src/modules/partition/core/PartUtils.cpp b/src/modules/partition/core/PartUtils.cpp index 07ab5acc1..92bcbace0 100644 --- a/src/modules/partition/core/PartUtils.cpp +++ b/src/modules/partition/core/PartUtils.cpp @@ -439,11 +439,14 @@ isEfiSystem() bool isEfiBootable( const Partition* candidate ) { - cDebug() << "Check EFI bootable" << convenienceName( candidate ) << candidate->devicePath(); - cDebug() << Logger::SubEntry << "flags" << candidate->activeFlags(); - - auto flags = PartitionInfo::flags( candidate ); + const 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 ( flags.testFlag( KPM_PARTITION_FLAG_ESP ) ) { @@ -455,19 +458,28 @@ isEfiBootable( const Partition* candidate ) while ( root && !root->isRoot() ) { root = root->parent(); - cDebug() << Logger::SubEntry << "moved towards root" << Logger::Pointer( root ); } // Strange case: no root found, no partition table node? if ( !root ) { + cWarning() << "No root of partition table found."; return false; } const PartitionTable* table = dynamic_cast< const PartitionTable* >( root ); - cDebug() << Logger::SubEntry << "partition table" << Logger::Pointer( table ) << "type" - << ( table ? table->type() : PartitionTable::TableType::unknownTableType ); - return table && ( table->type() == PartitionTable::TableType::gpt ) && flags.testFlag( KPM_PARTITION_FLAG( Boot ) ); + if ( !table ) + { + 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 diff --git a/src/modules/partition/core/PartitionActions.cpp b/src/modules/partition/core/PartitionActions.cpp index a78e8ff53..5d92d9b92 100644 --- a/src/modules/partition/core/PartitionActions.cpp +++ b/src/modules/partition/core/PartitionActions.cpp @@ -97,21 +97,6 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO // empty and a EFI boot partition, while BIOS starts at // the 1MiB boundary (usually sector 2048). 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, // 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 ) { + 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() ); Q_ASSERT( efiSectorCount > 0 ); @@ -203,6 +196,10 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO KPM_PARTITION_FLAG( None ) ); } PartitionInfo::setFormat( swapPartition, true ); + if ( gs->contains( "swapPartitionName" )) + { + swapPartition->setLabel( gs->value( "swapPartitionName" ).toString() ); + } core->createPartition( dev, swapPartition ); } diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp index 706f99017..254d007c1 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -716,6 +716,8 @@ PartitionCoreModule::updateIsDirty() void PartitionCoreModule::scanForEfiSystemPartitions() { + const bool wasEmpty = m_efiSystemPartitions.isEmpty(); + m_efiSystemPartitions.clear(); QList< Device* > devices; @@ -732,6 +734,11 @@ PartitionCoreModule::scanForEfiSystemPartitions() { 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; } @@ -861,9 +868,9 @@ PartitionCoreModule::setBootLoaderInstallPath( const QString& path ) } void -PartitionCoreModule::initLayout( const QVariantList& config ) +PartitionCoreModule::initLayout( FileSystem::Type defaultFsType, const QVariantList& config ) { - m_partLayout.init( config ); + m_partLayout.init( defaultFsType, config ); } void @@ -875,7 +882,8 @@ PartitionCoreModule::layoutApply( Device* dev, const PartitionRole& role ) { 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 // PartitionInfo::mountPoint() says where it will be mounted in the target system. diff --git a/src/modules/partition/core/PartitionCoreModule.h b/src/modules/partition/core/PartitionCoreModule.h index 46feb5f94..46604b97c 100644 --- a/src/modules/partition/core/PartitionCoreModule.h +++ b/src/modules/partition/core/PartitionCoreModule.h @@ -156,7 +156,11 @@ public: /// @brief Set the path where the bootloader will be installed 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, diff --git a/src/modules/partition/core/PartitionInfo.cpp b/src/modules/partition/core/PartitionInfo.cpp index 87aa03b66..c4d239db8 100644 --- a/src/modules/partition/core/PartitionInfo.cpp +++ b/src/modules/partition/core/PartitionInfo.cpp @@ -52,7 +52,15 @@ PartitionTable::Flags flags( const Partition* partition ) { 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() ); } diff --git a/src/modules/partition/core/PartitionLayout.cpp b/src/modules/partition/core/PartitionLayout.cpp index 15b18da93..d6f817af7 100644 --- a/src/modules/partition/core/PartitionLayout.cpp +++ b/src/modules/partition/core/PartitionLayout.cpp @@ -27,32 +27,10 @@ #include #include -static FileSystem::Type -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() {} 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 ) , partMountPoint( mountPoint ) + , partFileSystem( fs ) , partSize( size ) , partMinSize( minSize ) , partMaxSize( maxSize ) @@ -95,20 +78,6 @@ PartitionLayout::PartitionEntry::PartitionEntry( const QString& label, 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 PartitionLayout::addEntry( const PartitionEntry& entry ) @@ -124,7 +93,7 @@ PartitionLayout::addEntry( const PartitionEntry& entry ) } void -PartitionLayout::init( const QVariantList& config ) +PartitionLayout::init( FileSystem::Type defaultFsType, const QVariantList& config ) { bool ok; @@ -134,8 +103,7 @@ PartitionLayout::init( const QVariantList& config ) { QVariantMap pentry = r.toMap(); - if ( !pentry.contains( "name" ) || !pentry.contains( "mountPoint" ) || !pentry.contains( "filesystem" ) - || !pentry.contains( "size" ) ) + if ( !pentry.contains( "name" ) || !pentry.contains( "size" ) ) { cError() << "Partition layout entry #" << config.indexOf( r ) << "lacks mandatory attributes, switching to default layout."; @@ -148,7 +116,7 @@ PartitionLayout::init( const QVariantList& config ) CalamaresUtils::getString( pentry, "type" ), CalamaresUtils::getUnsignedInteger( pentry, "attributes", 0 ), CalamaresUtils::getString( pentry, "mountPoint" ), - CalamaresUtils::getString( pentry, "filesystem" ), + CalamaresUtils::getString( pentry, "filesystem", "unformatted" ), CalamaresUtils::getSubMap( pentry, "features", ok ), CalamaresUtils::getString( pentry, "size", QStringLiteral( "0" ) ), CalamaresUtils::getString( pentry, "minSize", QStringLiteral( "0" ) ), @@ -162,7 +130,7 @@ PartitionLayout::init( const QVariantList& config ) 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 ) { - qint64 sectors = entry.partSize.toSectors( availableSectors + partSectorsMap.value( &entry ), - dev->logicalSize() ); + qint64 sectors + = entry.partSize.toSectors( availableSectors + partSectorsMap.value( &entry ), dev->logicalSize() ); if ( entry.partMinSize.isValid() ) { sectors = std::max( sectors, entry.partMinSize.toSectors( totalSectors, dev->logicalSize() ) ); @@ -258,13 +226,24 @@ PartitionLayout::createPartitions( Device* dev, Partition* part = nullptr; if ( luksPassphrase.isEmpty() ) { - part = KPMHelpers::createNewPartition( - parent, *dev, role, entry.partFileSystem, currentSector, currentSector + sectors - 1, KPM_PARTITION_FLAG( None ) ); + part = KPMHelpers::createNewPartition( parent, + *dev, + role, + entry.partFileSystem, + currentSector, + currentSector + sectors - 1, + KPM_PARTITION_FLAG( None ) ); } else { - part = KPMHelpers::createNewEncryptedPartition( - parent, *dev, role, entry.partFileSystem, currentSector, currentSector + sectors - 1, luksPassphrase, KPM_PARTITION_FLAG( None ) ); + part = KPMHelpers::createNewEncryptedPartition( parent, + *dev, + role, + entry.partFileSystem, + currentSector, + currentSector + sectors - 1, + luksPassphrase, + KPM_PARTITION_FLAG( None ) ); } PartitionInfo::setFormat( part, true ); PartitionInfo::setMountPoint( part, entry.partMountPoint ); diff --git a/src/modules/partition/core/PartitionLayout.h b/src/modules/partition/core/PartitionLayout.h index 9720ab765..6e0c73f8f 100644 --- a/src/modules/partition/core/PartitionLayout.h +++ b/src/modules/partition/core/PartitionLayout.h @@ -34,7 +34,7 @@ public: QString partLabel; QString partUUID; QString partType; - quint64 partAttributes; + quint64 partAttributes = 0; QString partMountPoint; FileSystem::Type partFileSystem = FileSystem::Unknown; QVariantMap partFeatures; @@ -44,8 +44,13 @@ public: /// @brief All-zeroes PartitionEntry PartitionEntry(); - /// @brief Parse @p mountPoint, @p size, @p minSize and @p maxSize to their respective member variables - PartitionEntry( const QString& mountPoint, + /** @brief Parse @p mountPoint, @p size, @p minSize and @p maxSize to their respective member variables + * + * 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& minSize = QString(), const QString& maxSize = QString() ); @@ -61,7 +66,7 @@ public: const QString& minSize = QString(), const QString& maxSize = QString() ); /// @brief Copy PartitionEntry - PartitionEntry( const PartitionEntry& e ); + PartitionEntry( const PartitionEntry& e ) = default; bool isValid() const { @@ -78,7 +83,13 @@ public: PartitionLayout( const PartitionLayout& layout ); ~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 ); /** @@ -93,7 +104,6 @@ public: const PartitionRole& role ); private: - FileSystem::Type m_defaultFsType; QList< PartitionEntry > m_partLayout; }; diff --git a/src/modules/partition/gui/EditExistingPartitionDialog.cpp b/src/modules/partition/gui/EditExistingPartitionDialog.cpp index 1e66c539c..3de6e0c4c 100644 --- a/src/modules/partition/gui/EditExistingPartitionDialog.cpp +++ b/src/modules/partition/gui/EditExistingPartitionDialog.cpp @@ -136,8 +136,8 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) bool partResizedMoved = newFirstSector != m_partition->firstSector() || newLastSector != m_partition->lastSector(); cDebug() << "old boundaries:" << m_partition->firstSector() << m_partition->lastSector() << m_partition->length(); - cDebug() << "new boundaries:" << newFirstSector << newLastSector; - cDebug() << "dirty status:" << m_partitionSizeController->isDirty(); + cDebug() << Logger::SubEntry << "new boundaries:" << newFirstSector << newLastSector; + cDebug() << Logger::SubEntry << "dirty status:" << m_partitionSizeController->isDirty(); FileSystem::Type fsType = FileSystem::Unknown; if ( m_ui->formatRadioButton->isChecked() ) @@ -147,6 +147,9 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) : FileSystem::typeForName( m_ui->fileSystemComboBox->currentText() ); } + const auto resultFlags = newFlags(); + const auto currentFlags = PartitionInfo::flags( m_partition ); + if ( partResizedMoved ) { if ( m_ui->formatRadioButton->isChecked() ) @@ -157,20 +160,20 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) fsType, newFirstSector, newLastSector, - newFlags() ); + resultFlags ); PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) ); PartitionInfo::setFormat( newPartition, true ); core->deletePartition( m_device, m_partition ); core->createPartition( m_device, newPartition ); - core->setPartitionFlags( m_device, newPartition, newFlags() ); + core->setPartitionFlags( m_device, newPartition, resultFlags ); } else { 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 ) { 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 @@ -196,22 +199,22 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) fsType, m_partition->firstSector(), m_partition->lastSector(), - newFlags() ); + resultFlags ); PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) ); PartitionInfo::setFormat( newPartition, true ); core->deletePartition( m_device, m_partition ); core->createPartition( m_device, newPartition ); - core->setPartitionFlags( m_device, newPartition, newFlags() ); + core->setPartitionFlags( m_device, newPartition, resultFlags ); } } else { - core->refreshPartition( 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 ); } + core->refreshPartition( m_device, m_partition ); } } } diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index 0431e1107..561fdaba7 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -543,6 +543,12 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap ) 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 // 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 ); m_future->setFuture( future ); - m_core->initLayout( configurationMap.value( "partitionLayout" ).toList() ); + m_core->initLayout( fsType == FileSystem::Unknown ? FileSystem::Ext4 : fsType, + configurationMap.value( "partitionLayout" ).toList() ); } diff --git a/src/modules/partition/jobs/FillGlobalStorageJob.cpp b/src/modules/partition/jobs/FillGlobalStorageJob.cpp index 8e7958e83..5384cf243 100644 --- a/src/modules/partition/jobs/FillGlobalStorageJob.cpp +++ b/src/modules/partition/jobs/FillGlobalStorageJob.cpp @@ -105,7 +105,7 @@ mapForPartition( Partition* partition, const QString& uuid ) using TR = Logger::DebugRow< const char* const, const QString& >; deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode() << 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( "fsName", map[ "fsName" ].toString() ) << TR( "uuid", uuid ) << TR( "claimed", map[ "claimed" ].toString() ); @@ -153,7 +153,7 @@ FillGlobalStorageJob::prettyDescription() const QString path = partitionMap.value( "device" ).toString(); QString mountPoint = partitionMap.value( "mountPoint" ).toString(); QString fsType = partitionMap.value( "fs" ).toString(); - if ( mountPoint.isEmpty() || fsType.isEmpty() ) + if ( mountPoint.isEmpty() || fsType.isEmpty() || fsType == QString( "unformatted" ) ) { continue; } diff --git a/src/modules/partition/partition.conf b/src/modules/partition/partition.conf index 0f8764bfd..e5de69659 100644 --- a/src/modules/partition/partition.conf +++ b/src/modules/partition/partition.conf @@ -12,7 +12,8 @@ efiSystemPartition: "/boot/efi" # If nothing is specified, the default size of 300MiB will be used. # 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. # efiSystemPartitionName: EFI @@ -48,6 +49,11 @@ userSwapChoices: # - reuse # Re-use existing swap, but don't create any (unsupported right now) - 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) # ensureSuspendToDisk: true # neverCreateSwap: false @@ -201,8 +207,8 @@ defaultFileSystemType: "ext4" # - uuid: partition uuid (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) -# - filesystem: filesystem type -# - mountPoint: partition mount point +# - filesystem: filesystem type (optional parameter; fs not created if "unformatted" or unset) +# - 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) # or # % of the available drive space if a '%' is appended to the value diff --git a/src/modules/partition/tests/CreateLayoutsTests.cpp b/src/modules/partition/tests/CreateLayoutsTests.cpp index fb991fc82..04a06b2b3 100644 --- a/src/modules/partition/tests/CreateLayoutsTests.cpp +++ b/src/modules/partition/tests/CreateLayoutsTests.cpp @@ -25,6 +25,7 @@ class SmartStatus; QTEST_GUILESS_MAIN( CreateLayoutsTests ) static CalamaresUtils::Partition::KPMManager* kpmcore = nullptr; +static Calamares::JobQueue* jobqueue = nullptr; using CalamaresUtils::operator""_MiB; using CalamaresUtils::operator""_GiB; @@ -39,7 +40,7 @@ CreateLayoutsTests::CreateLayoutsTests() void CreateLayoutsTests::init() { - std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) ); + jobqueue = new Calamares::JobQueue( nullptr ); kpmcore = new CalamaresUtils::Partition::KPMManager(); } @@ -47,6 +48,7 @@ void CreateLayoutsTests::cleanup() { delete kpmcore; + delete jobqueue; } void @@ -57,7 +59,7 @@ CreateLayoutsTests::testFixedSizePartition() PartitionRole role( PartitionRole::Role::Any ); QList< Partition* > partitions; - if ( !layout.addEntry( { QString( "/" ), QString( "5MiB" ) } ) ) + if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/" ), QString( "5MiB" ) } ) ) { QFAIL( qPrintable( "Unable to create / partition" ) ); } @@ -77,7 +79,7 @@ CreateLayoutsTests::testPercentSizePartition() PartitionRole role( PartitionRole::Role::Any ); QList< Partition* > partitions; - if ( !layout.addEntry( { QString( "/" ), QString( "50%" ) } ) ) + if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/" ), QString( "50%" ) } ) ) { QFAIL( qPrintable( "Unable to create / partition" ) ); } @@ -97,17 +99,17 @@ CreateLayoutsTests::testMixedSizePartition() PartitionRole role( PartitionRole::Role::Any ); QList< Partition* > partitions; - if ( !layout.addEntry( { QString( "/" ), QString( "5MiB" ) } ) ) + if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/" ), QString( "5MiB" ) } ) ) { 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" ) ); } - if ( !layout.addEntry( { QString( "/bkup" ), QString( "50%" ) } ) ) + if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/bkup" ), QString( "50%" ) } ) ) { QFAIL( qPrintable( "Unable to create /bkup partition" ) ); } @@ -122,7 +124,7 @@ CreateLayoutsTests::testMixedSizePartition() } #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 { public: diff --git a/src/modules/umount/main.py b/src/modules/umount/main.py index 86ab1599a..0035a6b0f 100644 --- a/src/modules/umount/main.py +++ b/src/modules/umount/main.py @@ -39,10 +39,11 @@ def list_mounts(root_mount_point): """ lst = [] + root_mount_point = os.path.normpath(root_mount_point) for line in open("/etc/mtab").readlines(): 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)) return lst diff --git a/src/modules/users/CMakeLists.txt b/src/modules/users/CMakeLists.txt index fdae38440..92a9e03e7 100644 --- a/src/modules/users/CMakeLists.txt +++ b/src/modules/users/CMakeLists.txt @@ -23,33 +23,45 @@ endif() include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ) -set( JOB_SRC +set( _users_src + # Jobs CreateUserJob.cpp + MiscJobs.cpp SetPasswordJob.cpp SetHostNameJob.cpp -) -set( CONFIG_SRC + # Configuration CheckPWQuality.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 TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO SOURCES UsersViewStep.cpp UsersPage.cpp - ${JOB_SRC} - ${CONFIG_SRC} UI page_usersetup.ui RESOURCES users.qrc LINK_PRIVATE_LIBRARIES + users_internal calamaresui ${CRYPT_LIBRARIES} ${USER_EXTRA_LIB} - Qt5::DBus SHARED_LIB ) @@ -63,10 +75,14 @@ calamares_add_test( ) calamares_add_test( - userscreatetest + usersgroupstest SOURCES - TestCreateUserJob.cpp - CreateUserJob.cpp + TestGroupInformation.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( @@ -82,8 +98,7 @@ calamares_add_test( userstest SOURCES Tests.cpp - ${JOB_SRC} - ${CONFIG_SRC} + ${_users_src} # Build again with test-visibility LIBRARIES Qt5::DBus # HostName job can use DBus to systemd ${CRYPT_LIBRARIES} # SetPassword job uses crypt() diff --git a/src/modules/users/Config.cpp b/src/modules/users/Config.cpp index f8904b9d4..0e70cc215 100644 --- a/src/modules/users/Config.cpp +++ b/src/modules/users/Config.cpp @@ -10,6 +10,7 @@ #include "Config.h" #include "CreateUserJob.h" +#include "MiscJobs.h" #include "SetHostNameJob.h" #include "SetPasswordJob.h" @@ -34,6 +35,11 @@ static void updateGSAutoLogin( bool doAutoLogin, const QString& login ) { Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); + if ( !gs ) + { + cWarning() << "No Global Storage available"; + return; + } if ( doAutoLogin && !login.isEmpty() ) { @@ -95,11 +101,16 @@ Config::setUserShell( const QString& shell ) cWarning() << "User shell" << shell << "is not an absolute path."; return; } - // The shell is put into GS because the CreateUser job expects it there - auto* gs = Calamares::JobQueue::instance()->globalStorage(); - if ( gs ) + if ( shell != m_userShell ) { - 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 Config::setAutologinGroup( const QString& group ) { - insertInGlobalStorage( QStringLiteral( "autologinGroup" ), group ); - emit autologinGroupChanged( group ); + if ( group != m_autologinGroup ) + { + 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 Config::setSudoersGroup( const QString& group ) { - insertInGlobalStorage( QStringLiteral( "sudoersGroup" ), group ); - emit sudoersGroupChanged( group ); + if ( group != m_sudoersGroup ) + { + m_sudoersGroup = group; + insertInGlobalStorage( QStringLiteral( "sudoersGroup" ), group ); + emit sudoersGroupChanged( group ); + } } @@ -134,10 +171,9 @@ Config::setLoginName( const QString& login ) { if ( login != m_loginName ) { - updateGSAutoLogin( doAutoLogin(), login ); - m_customLoginName = !login.isEmpty(); m_loginName = login; + updateGSAutoLogin( doAutoLogin(), login ); emit loginNameChanged( login ); emit loginNameStatusChanged( loginNameStatus() ); } @@ -189,6 +225,8 @@ Config::setHostName( const QString& host ) { if ( host != m_hostName ) { + m_customHostName = !host.isEmpty(); + m_hostName = host; Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); if ( host.isEmpty() ) { @@ -198,9 +236,6 @@ Config::setHostName( const QString& host ) { gs->insert( "hostname", host ); } - - m_customHostName = !host.isEmpty(); - m_hostName = host; emit hostNameChanged( host ); emit hostNameStatusChanged( hostNameStatus() ); } @@ -369,8 +404,8 @@ Config::setAutoLogin( bool b ) { if ( b != m_doAutoLogin ) { - updateGSAutoLogin( b, loginName() ); m_doAutoLogin = b; + updateGSAutoLogin( b, loginName() ); emit autoLoginChanged( b ); } } @@ -590,16 +625,59 @@ Config::checkReady() 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 - // in the configuration (which is a legitimate, if unusual, choice) - // from a bad or missing configuration value. - defaultGroups = CalamaresUtils::getStringList( map, QStringLiteral( "defaultGroups" ), QStringList { "#" } ); - if ( defaultGroups.contains( QStringLiteral( "#" ) ) ) + defaultGroups.clear(); + + const QString key( "defaultGroups" ); + auto groupsFromConfig = map.value( key ).toList(); + if ( groupsFromConfig.isEmpty() ) { - cWarning() << "Using fallback groups. Please check *defaultGroups* in users.conf"; - defaultGroups = QStringList { "lp", "video", "network", "storage", "wheel", "audio" }; + if ( map.contains( key ) && map.value( key ).isValid() && map.value( key ).canConvert( QVariant::List ) ) + { + // 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; - j = new CreateUserJob( - loginName(), fullName().isEmpty() ? loginName() : fullName(), doAutoLogin(), defaultGroups() ); + if ( m_sudoersGroup.isEmpty() ) + { + 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 ) ); j = new SetPasswordJob( loginName(), userPassword() ); diff --git a/src/modules/users/Config.h b/src/modules/users/Config.h index e4057941c..d4bfee4a4 100644 --- a/src/modules/users/Config.h +++ b/src/modules/users/Config.h @@ -15,6 +15,7 @@ #include "Job.h" #include "utils/NamedEnum.h" +#include #include #include @@ -30,7 +31,61 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( HostNameActions ) 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 @@ -158,7 +213,12 @@ public: /// Current setting for "require strong password"? 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) QString userPassword() const { return m_userPassword; } @@ -242,7 +302,7 @@ private: PasswordStatus passwordStatus( const QString&, const QString& ) const; void checkReady(); - QStringList m_defaultGroups; + QList< GroupDescription > m_defaultGroups; QString m_userShell; QString m_autologinGroup; QString m_sudoersGroup; diff --git a/src/modules/users/CreateUserJob.cpp b/src/modules/users/CreateUserJob.cpp index 24b0f36d1..e08108a46 100644 --- a/src/modules/users/CreateUserJob.cpp +++ b/src/modules/users/CreateUserJob.cpp @@ -7,6 +7,8 @@ #include "CreateUserJob.h" +#include "Config.h" + #include "GlobalStorage.h" #include "JobQueue.h" #include "utils/CalamaresUtilsSystem.h" @@ -21,15 +23,9 @@ #include -CreateUserJob::CreateUserJob( const QString& userName, - const QString& fullName, - bool autologin, - const QStringList& defaultGroups ) +CreateUserJob::CreateUserJob( const Config* config ) : Calamares::Job() - , m_userName( userName ) - , m_fullName( fullName ) - , m_autologin( autologin ) - , m_defaultGroups( defaultGroups ) + , m_config( config ) { } @@ -37,68 +33,21 @@ CreateUserJob::CreateUserJob( const QString& userName, QString CreateUserJob::prettyName() const { - return tr( "Create user %1" ).arg( m_userName ); + return tr( "Create user %1" ).arg( m_config->loginName() ); } QString CreateUserJob::prettyDescription() const { - return tr( "Create user %1." ).arg( m_userName ); + return tr( "Create user %1." ).arg( m_config->loginName() ); } QString CreateUserJob::prettyStatusMessage() const { - return tr( "Creating user %1." ).arg( m_userName ); -} - -STATICTEST QStringList -groupsInTargetSystem( const QDir& targetRoot ) -{ - QFileInfo groupsFi( targetRoot.absoluteFilePath( "etc/group" ) ); - QFile groupsFile( groupsFi.absoluteFilePath() ); - if ( !groupsFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) - { - return QStringList(); - } - QString groupsData = QString::fromLocal8Bit( groupsFile.readAll() ); - QStringList groupsLines = groupsData.split( '\n' ); - QStringList::iterator it = groupsLines.begin(); - while ( it != groupsLines.end() ) - { - if ( it->startsWith( '#' ) ) - { - it = groupsLines.erase( it ); - continue; - } - int indexOfFirstToDrop = it->indexOf( ':' ); - if ( indexOfFirstToDrop < 1 ) - { - it = groupsLines.erase( it ); - continue; - } - it->truncate( indexOfFirstToDrop ); - ++it; - } - return groupsLines; -} - -static void -ensureGroupsExistInTarget( const QStringList& wantedGroups, const QStringList& availableGroups ) -{ - for ( const QString& group : wantedGroups ) - { - if ( !availableGroups.contains( group ) ) - { -#ifdef __FreeBSD__ - CalamaresUtils::System::instance()->targetEnvCall( { "pw", "groupadd", "-n", group } ); -#else - CalamaresUtils::System::instance()->targetEnvCall( { "groupadd", group } ); -#endif - } - } + return m_status.isEmpty() ? tr( "Creating user %1." ).arg( m_config->loginName() ) : m_status; } static Calamares::JobResult @@ -161,47 +110,22 @@ setUserGroups( const QString& loginName, const QStringList& groups ) Calamares::JobResult CreateUserJob::exec() { - Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); - QDir destDir( gs->value( "rootMountPoint" ).toString() ); + QDir destDir; + bool reuseHome = false; - if ( gs->contains( "sudoersGroup" ) && !gs->value( "sudoersGroup" ).toString().isEmpty() ) { - cDebug() << "[CREATEUSER]: preparing sudoers"; - - QString sudoersLine = QString( "%%1 ALL=(ALL) ALL\n" ).arg( gs->value( "sudoersGroup" ).toString() ); - auto fileResult - = CalamaresUtils::System::instance()->createTargetFile( QStringLiteral( "/etc/sudoers.d/10-installer" ), - sudoersLine.toUtf8().constData(), - CalamaresUtils::System::WriteMode::Overwrite ); - - if ( 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." ) ); - } + Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); + destDir = QDir( gs->value( "rootMountPoint" ).toString() ); + reuseHome = gs->value( "reuseHome" ).toBool(); } - 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. // 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 ); if ( existingHome.exists() ) { @@ -216,20 +140,26 @@ CreateUserJob::exec() 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 ) { 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 ) { return usergroupsResult; } - QString userGroup = QString( "%1:%2" ).arg( m_userName ).arg( m_userName ); - QString homeDir = QString( "/home/%1" ).arg( m_userName ); + m_status = tr( "Setting file permissions" ); + 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 } ); if ( commandResult.getExitCode() ) { diff --git a/src/modules/users/CreateUserJob.h b/src/modules/users/CreateUserJob.h index 0a46198b9..28a48c886 100644 --- a/src/modules/users/CreateUserJob.h +++ b/src/modules/users/CreateUserJob.h @@ -12,23 +12,21 @@ #include "Job.h" -#include +class Config; class CreateUserJob : public Calamares::Job { Q_OBJECT public: - CreateUserJob( const QString& userName, const QString& fullName, bool autologin, const QStringList& defaultGroups ); + CreateUserJob( const Config* config ); QString prettyName() const override; QString prettyDescription() const override; QString prettyStatusMessage() const override; Calamares::JobResult exec() override; private: - QString m_userName; - QString m_fullName; - bool m_autologin; - QStringList m_defaultGroups; + const Config* m_config; + QString m_status; }; #endif /* CREATEUSERJOB_H */ diff --git a/src/modules/users/MiscJobs.cpp b/src/modules/users/MiscJobs.cpp new file mode 100644 index 000000000..a62ada6d7 --- /dev/null +++ b/src/modules/users/MiscJobs.cpp @@ -0,0 +1,194 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * 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 +#include +#include + +SetupSudoJob::SetupSudoJob( const QString& group ) + : m_sudoGroup( group ) +{ +} + +QString +SetupSudoJob::prettyName() const +{ + return tr( "Configure
sudo
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(); +} diff --git a/src/modules/users/MiscJobs.h b/src/modules/users/MiscJobs.h new file mode 100644 index 000000000..fe4ff87c0 --- /dev/null +++ b/src/modules/users/MiscJobs.h @@ -0,0 +1,49 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * 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 diff --git a/src/modules/users/TestCreateUserJob.cpp b/src/modules/users/TestCreateUserJob.cpp deleted file mode 100644 index fc2d74dcd..000000000 --- a/src/modules/users/TestCreateUserJob.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* === This file is part of Calamares - === - * - * SPDX-FileCopyrightText: 2020 Adriaan de Groot - * 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 -#include - -// 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" diff --git a/src/modules/users/TestGroupInformation.cpp b/src/modules/users/TestGroupInformation.cpp new file mode 100644 index 000000000..dd4bfe78f --- /dev/null +++ b/src/modules/users/TestGroupInformation.cpp @@ -0,0 +1,106 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * 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 +#include + +// 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" diff --git a/src/modules/users/Tests.cpp b/src/modules/users/Tests.cpp index 9ed7718c7..b687a6434 100644 --- a/src/modules/users/Tests.cpp +++ b/src/modules/users/Tests.cpp @@ -16,7 +16,7 @@ #include // 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 bool addPasswordCheck( const QString& key, const QVariant& value, PasswordCheckList& passwordChecks ); @@ -33,6 +33,9 @@ public: private Q_SLOTS: void initTestCase(); + // Derpy test for getting and setting regular values + void testGetSet(); + void testDefaultGroups(); void testDefaultGroupsYAML_data(); void testDefaultGroupsYAML(); @@ -50,35 +53,97 @@ UserTests::initTestCase() { Logger::setupLogLevel( Logger::LOGDEBUG ); 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 UserTests::testDefaultGroups() { { - QStringList groups; + QList< GroupDescription > groups; QVariantMap hweelGroup; QVERIFY( groups.isEmpty() ); hweelGroup.insert( "defaultGroups", QStringList { "hweel" } ); setConfigurationDefaultGroups( hweelGroup, groups ); QCOMPARE( groups.count(), 1 ); - QVERIFY( groups.contains( "hweel" ) ); + QVERIFY( groups.contains( GroupDescription( "hweel" ) ) ); } { QStringList desired { "wheel", "root", "operator" }; - QStringList groups; + QList< GroupDescription > groups; QVariantMap threeGroup; QVERIFY( groups.isEmpty() ); threeGroup.insert( "defaultGroups", desired ); setConfigurationDefaultGroups( threeGroup, groups ); QCOMPARE( groups.count(), 3 ); - QVERIFY( !groups.contains( "hweel" ) ); - QCOMPARE( groups, desired ); + QVERIFY( !groups.contains( GroupDescription( "hweel" ) ) ); + for ( const auto& s : desired ) + { + QVERIFY( groups.contains( GroupDescription( s ) ) ); + } } { - QStringList groups; + QList< GroupDescription > groups; QVariantMap explicitEmpty; QVERIFY( groups.isEmpty() ); explicitEmpty.insert( "defaultGroups", QStringList() ); @@ -87,22 +152,22 @@ UserTests::testDefaultGroups() } { - QStringList groups; + QList< GroupDescription > groups; QVariantMap missing; QVERIFY( groups.isEmpty() ); setConfigurationDefaultGroups( missing, groups ); 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; QVERIFY( groups.isEmpty() ); typeMismatch.insert( "defaultGroups", 1 ); setConfigurationDefaultGroups( typeMismatch, groups ); 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( "dashed list" ) << "tests/4-audio.conf" << 4 << "audio"; QTest::newRow( "blocked list" ) << "tests/3-wing.conf" << 3 << "wing"; + QTest::newRow( "issue 1523" ) << "tests/5-issue-1523.conf" << 4 << "foobar"; } void @@ -130,6 +196,7 @@ UserTests::testDefaultGroupsYAML() QFETCH( int, count ); QFETCH( QString, group ); + // BUILD_AS_TEST is the source-directory path QFile fi( QString( "%1/%2" ).arg( BUILD_AS_TEST, filename ) ); QVERIFY( fi.exists() ); diff --git a/src/modules/users/tests/5-issue-1523.conf b/src/modules/users/tests/5-issue-1523.conf new file mode 100644 index 000000000..a0c5e49ba --- /dev/null +++ b/src/modules/users/tests/5-issue-1523.conf @@ -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 diff --git a/src/modules/users/users.conf b/src/modules/users/users.conf index ee1ccbf1c..2e09ae123 100644 --- a/src/modules/users/users.conf +++ b/src/modules/users/users.conf @@ -3,26 +3,42 @@ # # Configuration for the one-user-system user module. # -# Besides these settings, the user module also places the following -# keys into the globalconfig area, based on user input in the view step. +# Besides these settings, the users module also places the following +# keys into the Global Storage area, based on user input in the view step. # # - hostname # - username # - password (obscured) # - autologinUser (if enabled, set to username) # -# These globalconfig keys are set when the jobs for this module -# are created. +# These Global Storage keys are set when the configuration for this module +# is read and when they are modified in the UI. --- # Used as default groups for the created user. # 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: - - users + - name: users + must_exist: true + system: true - lp - video - network - storage - - wheel + - name: wheel + must_exist: false + system: true - audio # Some Distributions require a 'autologin' group for the user. diff --git a/src/modules/users/users.schema.yaml b/src/modules/users/users.schema.yaml index 310df350f..81088032c 100644 --- a/src/modules/users/users.schema.yaml +++ b/src/modules/users/users.schema.yaml @@ -11,7 +11,16 @@ properties: # Group settings defaultGroups: 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 } sudoersGroup: { type: string } # Skip login (depends on displaymanager support) diff --git a/src/modules/usersq/CMakeLists.txt b/src/modules/usersq/CMakeLists.txt index 26c270bfb..7e3fffb8d 100644 --- a/src/modules/usersq/CMakeLists.txt +++ b/src/modules/usersq/CMakeLists.txt @@ -13,9 +13,8 @@ find_package( Crypt REQUIRED ) # Add optional libraries here 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 ) set_package_properties( @@ -33,15 +32,11 @@ calamares_add_plugin( usersq TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO SOURCES - ${_users}/Config.cpp - ${_users}/CreateUserJob.cpp - ${_users}/SetPasswordJob.cpp UsersQmlViewStep.cpp - ${_users}/SetHostNameJob.cpp - ${_users}/CheckPWQuality.cpp RESOURCES usersq.qrc LINK_PRIVATE_LIBRARIES + users_internal calamaresui ${CRYPT_LIBRARIES} ${USER_EXTRA_LIB}