11#include " package_manager.h"
2+ #include " auth_manager.h"
23#include " ../utils/logger.h"
34#include < QStandardPaths>
45#include < QFile>
@@ -40,7 +41,7 @@ void PackageManager::detectHelper() {
4041 return ;
4142 }
4243
43- // Check for paru - deprecate because paru doesn't allow running with pkexec
44+ // Check for paru - deprecated because paru doesn't allow running as root
4445 // QString paruPath = QStandardPaths::findExecutable("paru");
4546 // if (!paruPath.isEmpty()) {
4647 // m_helper = Helper::Paru;
@@ -72,17 +73,14 @@ void PackageManager::installPackage(const QString& packageName, const QString& r
7273 bool isAUR = repoLower == " aur" ;
7374 QString helper = getHelperName ();
7475
75- QString command;
7676 if (isAUR && (m_helper == Helper::Yay)) {
77- // AUR packages - use pkexec to get userpassword before hand
77+ // AUR packages need sudo for yay
7878 // Paru has a problem here, so default to yay
79- command = QString ( " pkexec %1 -S %2 --noconfirm" ). arg (helper, packageName );
79+ executeCommand ( " sudo " , QStringList () << " -S " << helper << " -S " << packageName << " --noconfirm" , true );
8080 } else {
8181 // Official repos and chaotic-aur need root access and use pacman
82- command = QString ( " pkexec pacman -S %1 --noconfirm" ). arg (packageName );
82+ executeCommand ( " sudo " , QStringList () << " -S " << " pacman" << " -S " << packageName << " --noconfirm" , true );
8383 }
84-
85- executeCommand (" sh" , QStringList () << " -c" << command);
8684}
8785
8886void PackageManager::uninstallPackage (const QString& packageName, const QString& repository) {
@@ -92,9 +90,7 @@ void PackageManager::uninstallPackage(const QString& packageName, const QString&
9290 emit operationStarted (QString (" Uninstalling %1..." ).arg (packageName));
9391
9492 // Uninstall always needs root (even for AUR packages, they're in the system db once installed)
95- QString command = QString (" pkexec pacman -Rdd %1 --noconfirm" ).arg (packageName);
96-
97- executeCommand (" sh" , QStringList () << " -c" << command);
93+ executeCommand (" sudo" , QStringList () << " -S" << " pacman" << " -Rdd" << packageName << " --noconfirm" , true );
9894}
9995
10096void PackageManager::updatePackage (const QString& packageName, const QString& repository) {
@@ -108,16 +104,13 @@ void PackageManager::updatePackage(const QString& packageName, const QString& re
108104 bool isAUR = repoLower == " aur" ;
109105 QString helper = getHelperName ();
110106
111- QString command;
112107 if (isAUR && (m_helper == Helper::Yay)) {
113- // AUR packages - run helper as regular user (no pkexec )
114- command = QString ( " %1 -S %2 --noconfirm" ). arg (helper, packageName );
108+ // AUR packages - run helper as regular user (no sudo )
109+ executeCommand (helper, QStringList () << " -S " << packageName << " --noconfirm" );
115110 } else {
116111 // Official repos and chaotic-aur need root access and use pacman
117- command = QString ( " pkexec pacman -S %1 --noconfirm" ). arg (packageName );
112+ executeCommand ( " sudo " , QStringList () << " -S " << " pacman" << " -S " << packageName << " --noconfirm" , true );
118113 }
119-
120- executeCommand (" sh" , QStringList () << " -c" << command);
121114}
122115
123116void PackageManager::updateAllPackages () {
@@ -126,35 +119,38 @@ void PackageManager::updateAllPackages() {
126119 Logger::info (" Updating all packages" );
127120 emit operationStarted (" Updating all packages..." );
128121
129- QString command = QString (" pkexec %1 -Syu --noconfirm" )
130- .arg (getHelperName ());
131-
132- executeCommand (" sh" , QStringList () << " -c" << command);
122+ executeCommand (" sudo" , QStringList () << " -S" << getHelperName () << " -Syu" << " --noconfirm" , true );
133123}
134124
135- void PackageManager::executeCommand (const QString& command, const QStringList& args) {
125+ void PackageManager::executeCommand (const QString& command, const QStringList& args, bool needsAuth ) {
136126 if (m_process->state () != QProcess::NotRunning) {
137127 Logger::warning (" Another operation is already running" );
138128 emit operationError (" Another operation is already in progress" );
139129 return ;
140130 }
141-
131+
142132 // Merge stdout and stderr so we capture all output
143133 m_process->setProcessChannelMode (QProcess::MergedChannels);
144-
134+
145135 Logger::debug (QString (" Executing: %1 %2" ).arg (command, args.join (" " )));
146-
136+
147137 // Emit the actual command being executed to the UI for visibility
148138 QString fullCommand = command + " " + args.join (" " );
149139 emit operationOutput (QString (" >> Executing: %1\n " ).arg (fullCommand));
150-
140+
151141 m_process->start (command, args);
152-
142+
153143 // Check if process started successfully
154144 if (!m_process->waitForStarted (3000 )) {
155145 QString error = QString (" Failed to start process: %1" ).arg (m_process->errorString ());
156146 Logger::error (error);
157147 emit operationError (error);
148+ return ;
149+ }
150+
151+ // Write stored password to sudo's stdin if this is an elevated operation
152+ if (needsAuth) {
153+ AuthManager::instance ().writePasswordToProcess (m_process.get ());
158154 }
159155}
160156
@@ -191,29 +187,35 @@ void PackageManager::cancelRunningOperation() {
191187 if (m_process && m_process->state () != QProcess::NotRunning) {
192188 Logger::warning (" Cancelling running operation..." );
193189 emit operationOutput (" \n >>> Operation cancelled by user <<<\n " );
194-
195- // When using pkexec , we need to kill the actual pacman/yay/paru process
196- // not just the pkexec wrapper. Use pkill to terminate all package manager processes.
190+
191+ // When using sudo , we need to kill the actual pacman/yay/paru process
192+ // not just the sudo wrapper. Use pkill to terminate all package manager processes.
197193 QProcess killProcess;
198- killProcess.start (" pkexec " , QStringList () << " bash" << " -c"
194+ killProcess.start (" sudo " , QStringList () << " -S " << " bash" << " -c"
199195 << " pkill -TERM pacman; pkill -TERM yay; pkill -TERM paru" );
196+ if (killProcess.waitForStarted (3000 )) {
197+ AuthManager::instance ().writePasswordToProcess (&killProcess);
198+ }
200199 killProcess.waitForFinished (2000 );
201-
200+
202201 // Also terminate the QProcess wrapper
203202 m_process->terminate ();
204-
203+
205204 // Wait up to 3 seconds for graceful termination
206205 if (!m_process->waitForFinished (3000 )) {
207206 // Force kill if still running
208207 Logger::warning (" Process did not terminate gracefully, forcing kill..." );
209- killProcess.start (" pkexec " , QStringList () << " bash" << " -c"
208+ killProcess.start (" sudo " , QStringList () << " -S " << " bash" << " -c"
210209 << " pkill -KILL pacman; pkill -KILL yay; pkill -KILL paru" );
210+ if (killProcess.waitForStarted (3000 )) {
211+ AuthManager::instance ().writePasswordToProcess (&killProcess);
212+ }
211213 killProcess.waitForFinished (2000 );
212-
214+
213215 m_process->kill ();
214216 m_process->waitForFinished (1000 );
215217 }
216-
218+
217219 emit operationCompleted (false , " Operation cancelled by user" );
218220 Logger::info (" Operation cancelled successfully" );
219221 } else {
0 commit comments