Graphical package manager for pacman based on pamac 5.x.x
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

system_daemon.vala 67KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142
  1. /*
  2. * pamac-vala
  3. *
  4. * Copyright (C) 2017-2019 Chris Cromer <cromer@cromnix.org>
  5. * Copyright (C) 2014-2017 Guillaume Benoit <guillaume@manjaro.org>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a get of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. Pamac.SystemDaemon system_daemon;
  21. MainLoop loop;
  22. public delegate void AlpmActionDelegate ();
  23. [Compact]
  24. public class AlpmAction {
  25. public unowned AlpmActionDelegate action_delegate;
  26. public AlpmAction (AlpmActionDelegate action_delegate) {
  27. this.action_delegate = action_delegate;
  28. }
  29. public void run () {
  30. action_delegate ();
  31. }
  32. }
  33. namespace Pamac {
  34. [DBus (name = "org.pamac.system")]
  35. public class SystemDaemon: Object {
  36. private AlpmConfig alpm_config;
  37. private Alpm.Handle? alpm_handle;
  38. private Alpm.Handle? files_handle;
  39. public Cond provider_cond;
  40. public Mutex provider_mutex;
  41. public int? choosen_provider;
  42. private bool refreshed;
  43. private bool force_refresh;
  44. private bool enable_downgrade;
  45. #if DISABLE_AUR
  46. #else
  47. private bool check_aur_updates;
  48. private bool aur_updates_checked;
  49. #endif
  50. private HashTable<string,Variant> new_alpm_conf;
  51. private Alpm.TransFlag flags;
  52. private string[] to_install;
  53. private string[] to_remove;
  54. private string[] to_load;
  55. #if DISABLE_AUR
  56. #else
  57. private string[] to_build;
  58. private UpdateInfos[] to_build_infos;
  59. private GLib.List<string> aur_pkgbases_to_build;
  60. private GenericSet<string?> aur_desc_list;
  61. private GenericSet<string?> already_checked_aur_dep;
  62. #endif
  63. private HashTable<string, string> to_install_as_dep;
  64. #if DISABLE_AUR
  65. #else
  66. private string aurdb_path;
  67. #endif
  68. private string[] temporary_ignorepkgs;
  69. #if DISABLE_AUR
  70. #else
  71. private UpdateInfos[] aur_conflicts_to_remove;
  72. #endif
  73. private ThreadPool<AlpmAction> thread_pool;
  74. private BusName lock_id;
  75. #if DISABLE_AUR
  76. #else
  77. private Json.Array aur_updates_results;
  78. #endif
  79. private GLib.File lockfile;
  80. public ErrorInfos current_error;
  81. public Timer timer;
  82. public Cancellable cancellable;
  83. public Curl.Easy curl;
  84. private bool authorized;
  85. public signal void emit_event (uint primary_event, uint secondary_event, string[] details);
  86. public signal void emit_providers (string depend, string[] providers);
  87. public signal void emit_progress (uint progress, string pkgname, uint percent, uint n_targets, uint current_target);
  88. public signal void emit_download (string filename, uint64 xfered, uint64 total);
  89. public signal void emit_totaldownload (uint64 total);
  90. public signal void emit_log (uint level, string msg);
  91. public signal void set_pkgreason_finished ();
  92. public signal void refresh_finished (bool success);
  93. public signal void get_updates_finished (Updates updates);
  94. public signal void trans_prepare_finished (bool success);
  95. public signal void trans_commit_finished (bool success);
  96. public signal void get_authorization_finished (bool authorized);
  97. #if DISABLE_AUR
  98. public signal void save_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon);
  99. #else
  100. public signal void save_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon,
  101. bool enable_aur, bool search_aur, string aur_build_dir, bool check_aur_updates);
  102. #endif
  103. public signal void write_alpm_config_finished (bool checkspace);
  104. public signal void write_mirrors_config_finished (string choosen_country, string choosen_generation_method);
  105. public signal void generate_mirrors_list_data (string line);
  106. public signal void generate_mirrors_list_finished ();
  107. public SystemDaemon () {
  108. alpm_config = new AlpmConfig ("/etc/pacman.conf");
  109. #if DISABLE_AUR
  110. #else
  111. aur_pkgbases_to_build = new GLib.List<string> ();
  112. aur_desc_list = new GenericSet<string?> (str_hash, str_equal);
  113. already_checked_aur_dep = new GenericSet<string?> (str_hash, str_equal);
  114. #endif
  115. to_install_as_dep = new HashTable<string, string> (str_hash, str_equal);
  116. #if DISABLE_AUR
  117. #else
  118. aurdb_path = "/tmp/pamac-aur";
  119. aur_updates_results = new Json.Array ();
  120. #endif
  121. timer = new Timer ();
  122. lock_id = new BusName ("");
  123. refresh_handle ();
  124. check_old_lock ();
  125. check_extern_lock ();
  126. Timeout.add (500, check_extern_lock);
  127. create_thread_pool ();
  128. cancellable = new Cancellable ();
  129. curl = new Curl.Easy ();
  130. authorized = false;
  131. refreshed = false;
  132. }
  133. public void set_environment_variables (HashTable<string,string> variables) throws DBusError, IOError {
  134. string[] keys = { "HTTP_USER_AGENT",
  135. "http_proxy",
  136. "https_proxy",
  137. "ftp_proxy",
  138. "socks_proxy",
  139. "no_proxy" };
  140. foreach (unowned string key in keys) {
  141. unowned string val;
  142. if (variables.lookup_extended (key, null, out val)) {
  143. Environment.set_variable (key, val, true);
  144. }
  145. }
  146. }
  147. public ErrorInfos get_current_error () throws DBusError, IOError {
  148. return current_error;
  149. }
  150. private void create_thread_pool () {
  151. // create a thread pool which will run alpm action one after one
  152. try {
  153. thread_pool = new ThreadPool<AlpmAction>.with_owned_data (
  154. // call alpm_action.run () on thread start
  155. (alpm_action) => {
  156. alpm_action.run ();
  157. },
  158. // only one thread created so alpm action will run one after one
  159. 1,
  160. // no exclusive thread
  161. false
  162. );
  163. } catch (ThreadError e) {
  164. stderr.printf ("Thread Error %s\n", e.message);
  165. }
  166. }
  167. private void refresh_handle () {
  168. alpm_handle = alpm_config.get_handle ();
  169. if (alpm_handle == null) {
  170. current_error = ErrorInfos () {
  171. message = _("Failed to initialize alpm library")
  172. };
  173. trans_commit_finished (false);
  174. return;
  175. } else {
  176. alpm_handle.eventcb = (Alpm.EventCallBack) cb_event;
  177. alpm_handle.progresscb = (Alpm.ProgressCallBack) cb_progress;
  178. alpm_handle.questioncb = (Alpm.QuestionCallBack) cb_question;
  179. alpm_handle.fetchcb = (Alpm.FetchCallBack) cb_fetch;
  180. alpm_handle.totaldlcb = (Alpm.TotalDownloadCallBack) cb_totaldownload;
  181. alpm_handle.logcb = (Alpm.LogCallBack) cb_log;
  182. lockfile = GLib.File.new_for_path (alpm_handle.lockfile);
  183. var pamac_config = new Pamac.Config ();
  184. if (pamac_config.update_files_db) {
  185. files_handle = alpm_config.get_handle (true);
  186. } else {
  187. files_handle = alpm_config.get_handle (false);
  188. }
  189. files_handle.eventcb = (Alpm.EventCallBack) cb_event;
  190. files_handle.progresscb = (Alpm.ProgressCallBack) cb_progress;
  191. files_handle.questioncb = (Alpm.QuestionCallBack) cb_question;
  192. files_handle.fetchcb = (Alpm.FetchCallBack) cb_fetch;
  193. files_handle.totaldlcb = (Alpm.TotalDownloadCallBack) cb_totaldownload;
  194. files_handle.logcb = (Alpm.LogCallBack) cb_log;
  195. }
  196. }
  197. private void check_old_lock () {
  198. if (lockfile.query_exists ()) {
  199. int exit_status;
  200. string output;
  201. uint64 lockfile_time;
  202. try {
  203. // get lockfile modification time since epoch
  204. Process.spawn_command_line_sync ("stat -c %Y %s".printf (alpm_handle.lockfile),
  205. out output,
  206. null,
  207. out exit_status);
  208. if (exit_status == 0) {
  209. string[] splitted = output.split ("\n");
  210. if (splitted.length == 2) {
  211. if (uint64.try_parse (splitted[0], out lockfile_time)) {
  212. uint64 boot_time;
  213. // get boot time since epoch
  214. Process.spawn_command_line_sync ("cat /proc/stat",
  215. out output,
  216. null,
  217. out exit_status);
  218. if (exit_status == 0) {
  219. splitted = output.split ("\n");
  220. foreach (unowned string line in splitted) {
  221. if ("btime" in line) {
  222. string[] space_splitted = line.split (" ");
  223. if (space_splitted.length == 2) {
  224. if (uint64.try_parse (space_splitted[1], out boot_time)) {
  225. // check if lock file is older than boot time
  226. if (lockfile_time < boot_time) {
  227. // remove the unneeded lock file.
  228. try {
  229. lockfile.delete ();
  230. } catch (Error e) {
  231. stderr.printf ("Error: %s\n", e.message);
  232. }
  233. lock_id = new BusName ("");
  234. }
  235. }
  236. }
  237. }
  238. }
  239. }
  240. }
  241. }
  242. }
  243. } catch (SpawnError e) {
  244. stderr.printf ("Error: %s\n", e.message);
  245. }
  246. }
  247. }
  248. private bool check_extern_lock () {
  249. if (lock_id == "extern") {
  250. if (!lockfile.query_exists ()) {
  251. lock_id = new BusName ("");
  252. refresh_handle ();
  253. }
  254. } else {
  255. if (lockfile.query_exists ()) {
  256. if (lock_id == "") {
  257. // An extern lock appears
  258. lock_id = new BusName ("extern");
  259. }
  260. }
  261. }
  262. return true;
  263. }
  264. public string[] get_mirrors_countries () throws DBusError, IOError {
  265. string[] countries = {};
  266. try {
  267. string countries_str;
  268. int status;
  269. Process.spawn_command_line_sync ("pacman-mirrors -lq",
  270. out countries_str,
  271. null,
  272. out status);
  273. if (status == 0) {
  274. foreach (unowned string country in countries_str.split ("\n")) {
  275. countries += country;
  276. }
  277. }
  278. } catch (SpawnError e) {
  279. stderr.printf ("Error: %s\n", e.message);
  280. }
  281. return countries;
  282. }
  283. public bool get_lock (GLib.BusName sender) throws DBusError, IOError {
  284. if (lock_id == sender) {
  285. return true;
  286. } else if (lock_id == "") {
  287. lock_id = sender;
  288. return true;
  289. }
  290. return false;
  291. }
  292. public bool unlock (GLib.BusName sender) throws DBusError, IOError {
  293. if (lock_id == sender) {
  294. lock_id = new BusName ("");
  295. return true;
  296. }
  297. return false;
  298. }
  299. private async bool check_authorization (GLib.BusName sender) {
  300. if (lock_id != sender) {
  301. return false;
  302. }
  303. if (authorized) {
  304. return true;
  305. }
  306. SourceFunc callback = check_authorization.callback;
  307. try {
  308. Polkit.Authority authority = Polkit.Authority.get_sync ();
  309. Polkit.Subject subject = Polkit.SystemBusName.new (sender);
  310. authority.check_authorization.begin (
  311. subject,
  312. "org.pamac.commit",
  313. null,
  314. Polkit.CheckAuthorizationFlags.ALLOW_USER_INTERACTION,
  315. null,
  316. (obj, res) => {
  317. try {
  318. var result = authority.check_authorization.end (res);
  319. authorized = result.get_is_authorized ();
  320. } catch (GLib.Error e) {
  321. stderr.printf ("%s\n", e.message);
  322. }
  323. Idle.add ((owned) callback);
  324. }
  325. );
  326. yield;
  327. } catch (GLib.Error e) {
  328. stderr.printf ("%s\n", e.message);
  329. }
  330. if (!authorized) {
  331. current_error = ErrorInfos () {
  332. message = _("Authentication failed")
  333. };
  334. }
  335. return authorized;
  336. }
  337. public void start_get_authorization (GLib.BusName sender) throws DBusError, IOError {
  338. check_authorization.begin (sender, (obj, res) => {
  339. bool authorized = check_authorization.end (res);
  340. get_authorization_finished (authorized);
  341. });
  342. }
  343. public void start_save_pamac_config () throws DBusError, IOError {
  344. var pamac_config = new Pamac.Config ();
  345. pamac_config.reload ();
  346. #if DISABLE_AUR
  347. save_pamac_config_finished (pamac_config.recurse, pamac_config.refresh_period, pamac_config.no_update_hide_icon);
  348. #else
  349. save_pamac_config_finished (pamac_config.recurse, pamac_config.refresh_period, pamac_config.no_update_hide_icon,
  350. pamac_config.enable_aur, pamac_config.search_aur, pamac_config.aur_build_dir, pamac_config.check_aur_updates);
  351. #endif
  352. }
  353. private void write_alpm_config () {
  354. alpm_config.write (new_alpm_conf);
  355. alpm_config.reload ();
  356. refresh_handle ();
  357. write_alpm_config_finished ((alpm_handle.checkspace == 1));
  358. }
  359. public void start_write_alpm_config (HashTable<string,Variant> new_alpm_conf_, GLib.BusName sender) throws DBusError, IOError {
  360. check_authorization.begin (sender, (obj, res) => {
  361. bool authorized = check_authorization.end (res);
  362. if (authorized ) {
  363. new_alpm_conf = new_alpm_conf_;
  364. try {
  365. thread_pool.add (new AlpmAction (write_alpm_config));
  366. } catch (ThreadError e) {
  367. stderr.printf ("Thread Error %s\n", e.message);
  368. }
  369. } else {
  370. write_alpm_config_finished ((alpm_handle.checkspace == 1));
  371. }
  372. });
  373. }
  374. private void generate_mirrors_list () {
  375. try {
  376. var process = new Subprocess.newv (
  377. {"pacman-mirrors", "-g"},
  378. SubprocessFlags.STDOUT_PIPE | SubprocessFlags.STDERR_MERGE);
  379. var dis = new DataInputStream (process.get_stdout_pipe ());
  380. string? line;
  381. while ((line = dis.read_line ()) != null) {
  382. generate_mirrors_list_data (line);
  383. }
  384. } catch (Error e) {
  385. stderr.printf ("Error: %s\n", e.message);
  386. }
  387. alpm_config.reload ();
  388. refresh_handle ();
  389. generate_mirrors_list_finished ();
  390. }
  391. public void start_generate_mirrors_list (GLib.BusName sender) throws DBusError, IOError {
  392. check_authorization.begin (sender, (obj, res) => {
  393. bool authorized = check_authorization.end (res);
  394. if (authorized) {
  395. try {
  396. thread_pool.add (new AlpmAction (generate_mirrors_list));
  397. } catch (ThreadError e) {
  398. stderr.printf ("Thread Error %s\n", e.message);
  399. }
  400. }
  401. });
  402. }
  403. public void clean_cache (uint64 keep_nb, bool only_uninstalled, GLib.BusName sender) throws DBusError, IOError {
  404. check_authorization.begin (sender, (obj, res) => {
  405. bool authorized = check_authorization.end (res);
  406. if (authorized) {
  407. string[] commands = {"paccache", "--nocolor", "-rq"};
  408. commands += "-k%llu".printf (keep_nb);
  409. if (only_uninstalled) {
  410. commands += "-u";
  411. }
  412. try {
  413. new Subprocess.newv (
  414. commands,
  415. SubprocessFlags.STDOUT_SILENCE | SubprocessFlags.STDERR_SILENCE);
  416. } catch (Error e) {
  417. stderr.printf ("Error: %s\n", e.message);
  418. }
  419. }
  420. });
  421. }
  422. public void start_write_mirrors_config (HashTable<string,Variant> new_mirrors_conf, GLib.BusName sender) throws DBusError, IOError {
  423. check_authorization.begin (sender, (obj, res) => {
  424. var mirrors_config = new MirrorsConfig ("/etc/pacman-mirrors.conf");
  425. bool authorized = check_authorization.end (res);
  426. if (authorized) {
  427. mirrors_config.write (new_mirrors_conf);
  428. mirrors_config.reload ();
  429. }
  430. write_mirrors_config_finished (mirrors_config.choosen_country, mirrors_config.choosen_generation_method);
  431. });
  432. }
  433. public void start_set_pkgreason (string pkgname, uint reason, GLib.BusName sender) throws DBusError, IOError {
  434. check_authorization.begin (sender, (obj, res) => {
  435. bool authorized = check_authorization.end (res);
  436. if (authorized) {
  437. unowned Alpm.Package? pkg = alpm_handle.localdb.get_pkg (pkgname);
  438. if (pkg != null) {
  439. // lock the database
  440. if (alpm_handle.trans_init (0) == 0) {
  441. pkg.reason = (Alpm.Package.Reason) reason;
  442. alpm_handle.trans_release ();
  443. }
  444. }
  445. }
  446. set_pkgreason_finished ();
  447. });
  448. }
  449. private bool update_dbs (Alpm.Handle handle, int force) {
  450. bool success = false;
  451. unowned Alpm.List<unowned Alpm.DB> syncdbs = handle.syncdbs;
  452. while (syncdbs != null) {
  453. if (cancellable.is_cancelled ()) {
  454. break;
  455. }
  456. unowned Alpm.DB db = syncdbs.data;
  457. if (db.update (force) >= 0) {
  458. // We should always succeed if at least one DB was upgraded - we may possibly
  459. // fail later with unresolved deps, but that should be rare, and would be expected
  460. success = true;
  461. } else {
  462. Alpm.Errno errno = handle.errno ();
  463. current_error.errno = (uint) errno;
  464. if (errno != 0) {
  465. // download error details are set in cb_fetch
  466. if (errno != Alpm.Errno.EXTERNAL_DOWNLOAD) {
  467. current_error.details = { Alpm.strerror (errno) };
  468. }
  469. }
  470. }
  471. syncdbs.next ();
  472. }
  473. return success;
  474. }
  475. private void refresh () {
  476. current_error = ErrorInfos ();
  477. write_log_file ("synchronizing package lists");
  478. cancellable.reset ();
  479. int force = (force_refresh) ? 1 : 0;
  480. // try to copy refresh dbs in tmp
  481. string tmp_dbpath = "/tmp/pamac-checkdbs";
  482. try {
  483. Process.spawn_command_line_sync ("cp -au %s/sync %s".printf (tmp_dbpath, alpm_handle.dbpath));
  484. } catch (SpawnError e) {
  485. stderr.printf ("SpawnError: %s\n", e.message);
  486. }
  487. // a new handle is required to use copied databases
  488. refresh_handle ();
  489. // update ".db"
  490. bool success = update_dbs (alpm_handle, force);
  491. if (cancellable.is_cancelled ()) {
  492. refresh_finished (false);
  493. return;
  494. }
  495. // update ".files", do not need to know if we succeeded
  496. update_dbs (files_handle, force);
  497. if (cancellable.is_cancelled ()) {
  498. refresh_finished (false);
  499. } else if (success) {
  500. refreshed = true;
  501. refresh_finished (true);
  502. } else {
  503. current_error.message = _("Failed to synchronize any databases");
  504. refresh_finished (false);
  505. }
  506. }
  507. public void start_refresh (bool force, GLib.BusName sender) throws DBusError, IOError {
  508. if (lock_id != sender) {
  509. refresh_finished (false);
  510. return;
  511. }
  512. force_refresh = force;
  513. if (force_refresh) {
  514. refreshed = false;
  515. }
  516. if (refreshed) {
  517. refresh_finished (true);
  518. return;
  519. }
  520. try {
  521. thread_pool.add (new AlpmAction (refresh));
  522. } catch (ThreadError e) {
  523. stderr.printf ("Thread Error %s\n", e.message);
  524. }
  525. }
  526. private void add_ignorepkgs () {
  527. foreach (unowned string pkgname in temporary_ignorepkgs) {
  528. alpm_handle.add_ignorepkg (pkgname);
  529. }
  530. }
  531. private void remove_ignorepkgs () {
  532. foreach (unowned string pkgname in temporary_ignorepkgs) {
  533. alpm_handle.remove_ignorepkg (pkgname);
  534. }
  535. temporary_ignorepkgs = {};
  536. }
  537. private AlpmPackage initialise_pkg_struct (Alpm.Package? alpm_pkg) {
  538. if (alpm_pkg != null) {
  539. string repo_name = "";
  540. if (alpm_pkg.origin == Alpm.Package.From.LOCALDB) {
  541. unowned Alpm.Package? sync_pkg = get_syncpkg (alpm_pkg.name);
  542. if (sync_pkg != null) {
  543. repo_name = sync_pkg.db.name;
  544. }
  545. } else if (alpm_pkg.origin == Alpm.Package.From.SYNCDB) {
  546. repo_name = alpm_pkg.db.name;
  547. }
  548. return AlpmPackage () {
  549. name = alpm_pkg.name,
  550. version = alpm_pkg.version,
  551. // desc can be null
  552. desc = alpm_pkg.desc ?? "",
  553. repo = (owned) repo_name,
  554. size = alpm_pkg.isize,
  555. origin = (uint) alpm_pkg.origin
  556. };
  557. } else {
  558. return AlpmPackage () {
  559. name = "",
  560. version = "",
  561. desc = "",
  562. repo = ""
  563. };
  564. }
  565. }
  566. private unowned Alpm.Package? get_syncpkg (string name) {
  567. unowned Alpm.Package? pkg = null;
  568. unowned Alpm.List<unowned Alpm.DB> syncdbs = alpm_handle.syncdbs;
  569. while (syncdbs != null) {
  570. unowned Alpm.DB db = syncdbs.data;
  571. pkg = db.get_pkg (name);
  572. if (pkg != null) {
  573. break;
  574. }
  575. syncdbs.next ();
  576. }
  577. return pkg;
  578. }
  579. #if DISABLE_AUR
  580. #else
  581. private AURPackage initialise_aur_struct (Json.Object json_object) {
  582. string installed_version = "";
  583. unowned Alpm.Package? pkg = alpm_handle.localdb.get_pkg (json_object.get_string_member ("Name"));
  584. if (pkg != null) {
  585. installed_version = pkg.version;
  586. }
  587. return AURPackage () {
  588. name = json_object.get_string_member ("Name"),
  589. version = json_object.get_string_member ("Version"),
  590. installed_version = (owned) installed_version,
  591. // desc can be null
  592. desc = json_object.get_null_member ("Description") ? "" : json_object.get_string_member ("Description"),
  593. popularity = json_object.get_double_member ("Popularity")
  594. };
  595. }
  596. private async void compute_aur_build_list (string[] aur_list) {
  597. try {
  598. Process.spawn_command_line_sync ("mkdir -p %s".printf (aurdb_path));
  599. } catch (SpawnError e) {
  600. stderr.printf ("SpawnError: %s\n", e.message);
  601. }
  602. aur_desc_list.remove_all ();
  603. already_checked_aur_dep.remove_all ();
  604. yield check_aur_dep_list (aur_list);
  605. }
  606. private async void check_aur_dep_list (string[] pkgnames) {
  607. string[] dep_types = {"Depends", "MakeDepends", "CheckDepends"};
  608. string[] dep_to_check = {};
  609. Json.Array results = yield multiinfo (pkgnames);
  610. results.foreach_element ((array, index, node) => {
  611. unowned Json.Object? pkg_info = node.get_object ();
  612. // create fake db desc file
  613. if (pkg_info != null) {
  614. string name = pkg_info.get_string_member ("Name");
  615. string version = pkg_info.get_string_member ("Version");
  616. string pkgdir = "%s-%s".printf (name, version);
  617. string pkgdir_path = "%s/%s".printf (aurdb_path, pkgdir);
  618. aur_desc_list.add (pkgdir);
  619. already_checked_aur_dep.add (name);
  620. try {
  621. var file = GLib.File.new_for_path (pkgdir_path);
  622. bool write_desc_file = false;
  623. if (!file.query_exists ()) {
  624. file.make_directory ();
  625. write_desc_file = true;
  626. }
  627. // compute depends, makedepends and checkdepends in DEPENDS
  628. var depends = new StringBuilder ();
  629. foreach (unowned string dep_type in dep_types) {
  630. unowned Json.Node? dep_node = pkg_info.get_member (dep_type);
  631. if (dep_node != null) {
  632. dep_node.get_array ().foreach_element ((array, index, node) => {
  633. if (write_desc_file) {
  634. depends.append (node.get_string ());
  635. depends.append ("\n");
  636. }
  637. // check deps
  638. unowned string dep_string = node.get_string ();
  639. string dep_name = Alpm.Depend.from_string (dep_string).name;
  640. unowned Alpm.Package? pkg = null;
  641. // search for the name first to avoid provides trouble
  642. pkg = alpm_handle.localdb.get_pkg (dep_name);
  643. if (pkg == null) {
  644. pkg = get_syncpkg (dep_name);
  645. }
  646. if (pkg == null) {
  647. if (!(dep_name in already_checked_aur_dep)) {
  648. dep_to_check += (owned) dep_name;
  649. }
  650. }
  651. });
  652. }
  653. }
  654. if (write_desc_file) {
  655. file = GLib.File.new_for_path ("%s/desc".printf (pkgdir_path));
  656. // creating a DataOutputStream to the file
  657. var dos = new DataOutputStream (file.create (FileCreateFlags.REPLACE_DESTINATION));
  658. // fake filename
  659. dos.put_string ("%FILENAME%\n" + "%s-%s-any.pkg.tar.xz\n\n".printf (name, version));
  660. // name
  661. dos.put_string ("%NAME%\n%s\n\n".printf (name));
  662. // version
  663. dos.put_string ("%VERSION%\n%s\n\n".printf (version));
  664. //base
  665. dos.put_string ("%BASE%\n%s\n\n".printf (pkg_info.get_string_member ("PackageBase")));
  666. // desc can be null
  667. if (!pkg_info.get_null_member ("Description")) {
  668. dos.put_string ("%DESC%\n%s\n\n".printf (pkg_info.get_string_member ("Description")));
  669. }
  670. // version
  671. dos.put_string ("%VERSION%\n%s\n\n".printf (pkg_info.get_string_member ("Version")));
  672. // fake arch
  673. dos.put_string ("%ARCH%\nany\n\n");
  674. // depends
  675. if (depends.len > 0) {
  676. dos.put_string ("%DEPENDS%\n%s\n".printf (depends.str));
  677. }
  678. // conflicts
  679. unowned Json.Node? info_node = pkg_info.get_member ("Conflicts");
  680. if (info_node != null) {
  681. try {
  682. dos.put_string ("%CONFLICTS%\n");
  683. info_node.get_array ().foreach_element ((array, index, _node) => {
  684. try {
  685. dos.put_string ("%s\n".printf (_node.get_string ()));
  686. } catch (GLib.Error e) {
  687. stderr.printf("%s\n", e.message);
  688. }
  689. });
  690. dos.put_string ("\n");
  691. } catch (GLib.Error e) {
  692. stderr.printf("%s\n", e.message);
  693. }
  694. }
  695. // provides
  696. info_node = pkg_info.get_member ("Provides");
  697. if (info_node != null) {
  698. try {
  699. dos.put_string ("%PROVIDES%\n");
  700. info_node.get_array ().foreach_element ((array, index, _node) => {
  701. try {
  702. dos.put_string ("%s\n".printf (_node.get_string ()));
  703. } catch (GLib.Error e) {
  704. stderr.printf("%s\n", e.message);
  705. }
  706. });
  707. dos.put_string ("\n");
  708. } catch (GLib.Error e) {
  709. stderr.printf("%s\n", e.message);
  710. }
  711. }
  712. // replaces
  713. info_node = pkg_info.get_member ("Replaces");
  714. if (info_node != null) {
  715. try {
  716. dos.put_string ("%REPLACES%\n");
  717. info_node.get_array ().foreach_element ((array, index, _node) => {
  718. try {
  719. dos.put_string ("%s\n".printf (_node.get_string ()));
  720. } catch (GLib.Error e) {
  721. stderr.printf("%s\n", e.message);
  722. }
  723. });
  724. dos.put_string ("\n");
  725. } catch (GLib.Error e) {
  726. stderr.printf("%s\n", e.message);
  727. }
  728. }
  729. }
  730. } catch (GLib.Error e) {
  731. stderr.printf("%s\n", e.message);
  732. }
  733. }
  734. });
  735. if (dep_to_check.length > 0) {
  736. yield check_aur_dep_list (dep_to_check);
  737. }
  738. }
  739. #endif
  740. private void get_updates () {
  741. AlpmPackage[] updates_infos = {};
  742. unowned Alpm.Package? pkg = null;
  743. unowned Alpm.Package? candidate = null;
  744. foreach (unowned string name in alpm_config.get_syncfirsts ()) {
  745. pkg = Alpm.find_satisfier (alpm_handle.localdb.pkgcache, name);
  746. if (pkg != null) {
  747. candidate = pkg.sync_newversion (alpm_handle.syncdbs);
  748. if (candidate != null) {
  749. var infos = initialise_pkg_struct (candidate);
  750. infos.installed_version = pkg.version;
  751. updates_infos += (owned) infos;
  752. }
  753. }
  754. }
  755. if (updates_infos.length != 0) {
  756. var updates = Updates () {
  757. is_syncfirst = true,
  758. #if DISABLE_AUR
  759. repos_updates = (owned) updates_infos
  760. #else
  761. repos_updates = (owned) updates_infos,
  762. aur_updates = {}
  763. #endif
  764. };
  765. get_updates_finished (updates);
  766. } else {
  767. #if DISABLE_AUR
  768. #else
  769. string[] local_pkgs = {};
  770. #endif
  771. unowned Alpm.List<unowned Alpm.Package> pkgcache = alpm_handle.localdb.pkgcache;
  772. while (pkgcache != null) {
  773. unowned Alpm.Package installed_pkg = pkgcache.data;
  774. // check if installed_pkg is in IgnorePkg or IgnoreGroup
  775. if (alpm_handle.should_ignore (installed_pkg) == 0) {
  776. candidate = installed_pkg.sync_newversion (alpm_handle.syncdbs);
  777. if (candidate != null) {
  778. var infos = initialise_pkg_struct (candidate);
  779. infos.installed_version = installed_pkg.version;
  780. updates_infos += (owned) infos;
  781. #if DISABLE_AUR
  782. #else
  783. } else {
  784. if (check_aur_updates && (!aur_updates_checked)) {
  785. // check if installed_pkg is a local pkg
  786. unowned Alpm.List<unowned Alpm.DB> syncdbs = alpm_handle.syncdbs;
  787. while (syncdbs != null) {
  788. unowned Alpm.DB db = syncdbs.data;
  789. pkg = Alpm.find_satisfier (db.pkgcache, installed_pkg.name);
  790. if (pkg != null) {
  791. break;
  792. }
  793. syncdbs.next ();
  794. }
  795. if (pkg == null) {
  796. local_pkgs += installed_pkg.name;
  797. }
  798. }
  799. #endif
  800. }
  801. }
  802. pkgcache.next ();
  803. }
  804. #if DISABLE_AUR
  805. #else
  806. if (check_aur_updates) {
  807. // get aur updates
  808. if (!aur_updates_checked) {
  809. multiinfo.begin (local_pkgs, (obj, res) => {
  810. aur_updates_results = multiinfo.end (res);
  811. aur_updates_checked = true;
  812. var updates = Updates () {
  813. is_syncfirst = false,
  814. repos_updates = (owned) updates_infos,
  815. aur_updates = get_aur_updates_infos ()
  816. };
  817. get_updates_finished (updates);
  818. });
  819. } else {
  820. var updates = Updates () {
  821. is_syncfirst = false,
  822. repos_updates = (owned) updates_infos,
  823. aur_updates = get_aur_updates_infos ()
  824. };
  825. get_updates_finished (updates);
  826. }
  827. } else {
  828. #endif
  829. var updates = Updates () {
  830. is_syncfirst = false,
  831. #if DISABLE_AUR
  832. repos_updates = (owned) updates_infos
  833. #else
  834. repos_updates = (owned) updates_infos,
  835. aur_updates = {}
  836. #endif
  837. };
  838. get_updates_finished (updates);
  839. #if DISABLE_AUR
  840. #else
  841. }
  842. #endif
  843. }
  844. }
  845. #if DISABLE_AUR
  846. #else
  847. private AURPackage[] get_aur_updates_infos () {
  848. AURPackage[] aur_updates_infos = {};
  849. aur_updates_results.foreach_element ((array, index, node) => {
  850. unowned Json.Object pkg_info = node.get_object ();
  851. unowned string name = pkg_info.get_string_member ("Name");
  852. unowned string new_version = pkg_info.get_string_member ("Version");
  853. unowned string old_version = alpm_handle.localdb.get_pkg (name).version;
  854. if (Alpm.pkg_vercmp (new_version, old_version) == 1) {
  855. var infos = initialise_aur_struct (pkg_info);
  856. infos.installed_version = old_version;
  857. aur_updates_infos += (owned) infos;
  858. }
  859. });
  860. return aur_updates_infos;
  861. }
  862. #endif
  863. #if DISABLE_AUR
  864. public void start_get_updates () throws DBusError, IOError {
  865. #else
  866. public void start_get_updates (bool check_aur_updates_) throws DBusError, IOError {
  867. check_aur_updates = check_aur_updates_;
  868. #endif
  869. try {
  870. thread_pool.add (new AlpmAction (get_updates));
  871. } catch (ThreadError e) {
  872. stderr.printf ("Thread Error %s\n", e.message);
  873. }
  874. }
  875. private bool trans_init (Alpm.TransFlag flags) {
  876. current_error = ErrorInfos ();
  877. cancellable.reset ();
  878. if (alpm_handle.trans_init (flags) == -1) {
  879. Alpm.Errno errno = alpm_handle.errno ();
  880. current_error.errno = (uint) errno;
  881. current_error.message = _("Failed to init transaction");
  882. if (errno != 0) {
  883. current_error.details = { Alpm.strerror (errno) };
  884. }
  885. return false;
  886. }
  887. return true;
  888. }
  889. private void sysupgrade_prepare () {
  890. current_error = ErrorInfos ();
  891. bool success = trans_init (0);
  892. if (success) {
  893. add_ignorepkgs ();
  894. if (alpm_handle.trans_sysupgrade ((enable_downgrade) ? 1 : 0) == -1) {
  895. Alpm.Errno errno = alpm_handle.errno ();
  896. current_error.errno = (uint) errno;
  897. current_error.message = _("Failed to prepare transaction");
  898. if (errno != 0) {
  899. current_error.details = { Alpm.strerror (errno) };
  900. }
  901. try {
  902. trans_release (lock_id);
  903. } catch (IOError e) {
  904. stderr.printf ("IOError: %s\n", e.message);
  905. } catch (DBusError e) {
  906. stderr.printf ("DBusError: %s\n", e.message);
  907. }
  908. success = false;
  909. } else {
  910. success = trans_prepare_real ();
  911. }
  912. }
  913. trans_prepare_finished (success);
  914. }
  915. public void start_sysupgrade_prepare (bool enable_downgrade_, string[] temporary_ignorepkgs_, GLib.BusName sender) throws DBusError, IOError {
  916. if (lock_id != sender) {
  917. trans_prepare_finished (false);
  918. return;
  919. }
  920. enable_downgrade = enable_downgrade_;
  921. temporary_ignorepkgs = temporary_ignorepkgs_;
  922. try {
  923. thread_pool.add (new AlpmAction (sysupgrade_prepare));
  924. } catch (ThreadError e) {
  925. stderr.printf ("Thread Error %s\n", e.message);
  926. }
  927. }
  928. private bool trans_add_pkg_real (Alpm.Package pkg) {
  929. current_error = ErrorInfos ();
  930. if (alpm_handle.trans_add_pkg (pkg) == -1) {
  931. Alpm.Errno errno = alpm_handle.errno ();
  932. if (errno == Alpm.Errno.TRANS_DUP_TARGET || errno == Alpm.Errno.PKG_IGNORED) {
  933. // just skip duplicate or ignored targets
  934. return true;
  935. } else {
  936. current_error.errno = (uint) errno;
  937. current_error.message = _("Failed to prepare transaction");
  938. if (errno != 0) {
  939. current_error.details = { "%s: %s".printf (pkg.name, Alpm.strerror (errno)) };
  940. }
  941. return false;
  942. }
  943. }
  944. return true;
  945. }
  946. private bool trans_add_pkg (string pkgname) {
  947. current_error = ErrorInfos ();
  948. unowned Alpm.Package? pkg = get_syncpkg (pkgname);
  949. if (pkg == null) {
  950. current_error.message = _("Failed to prepare transaction");
  951. current_error.details = { _("target not found: %s").printf (pkgname) };
  952. return false;
  953. } else {
  954. bool success = trans_add_pkg_real (pkg);
  955. if (success) {
  956. if (("linux31" in pkg.name) || ("linux4" in pkg.name)) {
  957. string[] installed_kernels = {};
  958. string[] installed_modules = {};
  959. unowned Alpm.List<unowned Alpm.Package> pkgcache = alpm_handle.localdb.pkgcache;
  960. while (pkgcache != null) {
  961. unowned Alpm.Package local_pkg = pkgcache.data;
  962. if (("linux31" in local_pkg.name) || ("linux4" in local_pkg.name)) {
  963. string[] local_pkg_splitted = local_pkg.name.split ("-", 2);
  964. if ((local_pkg_splitted[0] in installed_kernels) == false) {
  965. installed_kernels += local_pkg_splitted[0];
  966. }
  967. if (local_pkg_splitted.length == 2) {
  968. if ((local_pkg_splitted[1] in installed_modules) == false) {
  969. installed_modules += local_pkg_splitted[1];
  970. }
  971. }
  972. }
  973. pkgcache.next ();
  974. }
  975. string[] splitted = pkg.name.split ("-", 2);
  976. if (splitted.length == 2) {
  977. // we are adding a module
  978. // add the same module for other installed kernels
  979. foreach (unowned string installed_kernel in installed_kernels) {
  980. string module = installed_kernel + "-" + splitted[1];
  981. unowned Alpm.Package? installed_module_pkg = alpm_handle.localdb.get_pkg (module);
  982. if (installed_module_pkg == null) {
  983. unowned Alpm.Package? module_pkg = get_syncpkg (module);
  984. if (module_pkg != null) {
  985. trans_add_pkg_real (module_pkg);
  986. }
  987. }
  988. }
  989. } else if (splitted.length == 1) {
  990. // we are adding a kernel
  991. // add all installed modules for other kernels
  992. foreach (unowned string installed_module in installed_modules) {
  993. string module = splitted[0] + "-" + installed_module;
  994. unowned Alpm.Package? module_pkg = get_syncpkg (module);
  995. if (module_pkg != null) {
  996. trans_add_pkg_real (module_pkg);
  997. }
  998. }
  999. }
  1000. }
  1001. }
  1002. return success;
  1003. }
  1004. }
  1005. private bool trans_load_pkg (string pkgpath) {
  1006. current_error = ErrorInfos ();
  1007. Alpm.Package* pkg;
  1008. if (alpm_handle.load_tarball (pkgpath, 1, alpm_handle.localfilesiglevel, out pkg) == -1) {
  1009. Alpm.Errno errno = alpm_handle.errno ();
  1010. current_error.errno = (uint) errno;
  1011. current_error.message = _("Failed to prepare transaction");
  1012. if (errno != 0) {
  1013. current_error.details = { "%s: %s".printf (pkgpath, Alpm.strerror (errno)) };
  1014. }
  1015. return false;
  1016. } else if (alpm_handle.trans_add_pkg (pkg) == -1) {
  1017. Alpm.Errno errno = alpm_handle.errno ();
  1018. if (errno == Alpm.Errno.TRANS_DUP_TARGET || errno == Alpm.Errno.PKG_IGNORED) {
  1019. // just skip duplicate or ignored targets
  1020. return true;
  1021. } else {
  1022. current_error.errno = (uint) errno;
  1023. current_error.message = _("Failed to prepare transaction");
  1024. if (errno != 0) {
  1025. current_error.details = { "%s: %s".printf (pkg->name, Alpm.strerror (errno)) };
  1026. }
  1027. // free the package because it will not be used
  1028. delete pkg;
  1029. return false;
  1030. }
  1031. }
  1032. return true;
  1033. }
  1034. private bool trans_remove_pkg (string pkgname) {
  1035. current_error = ErrorInfos ();
  1036. unowned Alpm.Package? pkg = alpm_handle.localdb.get_pkg (pkgname);
  1037. if (pkg == null) {
  1038. current_error.message = _("Failed to prepare transaction");
  1039. current_error.details = { _("target not found: %s").printf (pkgname) };
  1040. return false;
  1041. } else if (alpm_handle.trans_remove_pkg (pkg) == -1) {
  1042. Alpm.Errno errno = alpm_handle.errno ();
  1043. if (errno == Alpm.Errno.TRANS_DUP_TARGET) {
  1044. // just skip duplicate targets
  1045. return true;
  1046. } else {
  1047. current_error.errno = (uint) errno;
  1048. current_error.message = _("Failed to prepare transaction");
  1049. if (errno != 0) {
  1050. current_error.details = { "%s: %s".printf (pkg.name, Alpm.strerror (errno)) };
  1051. }
  1052. return false;
  1053. }
  1054. }
  1055. return true;
  1056. }
  1057. private bool trans_prepare_real () {
  1058. bool success = true;
  1059. current_error = ErrorInfos ();
  1060. string[] details = {};
  1061. Alpm.List err_data;
  1062. if (alpm_handle.trans_prepare (out err_data) == -1) {
  1063. Alpm.Errno errno = alpm_handle.errno ();
  1064. current_error.errno = (uint) errno;
  1065. current_error.message = _("Failed to prepare transaction");
  1066. switch (errno) {
  1067. case 0:
  1068. break;
  1069. case Alpm.Errno.PKG_INVALID_ARCH:
  1070. details += Alpm.strerror (errno) + ":";
  1071. unowned Alpm.List<string*> list = err_data;
  1072. while (list != null) {
  1073. string* pkgname = list.data;
  1074. details += _("package %s does not have a valid architecture").printf (pkgname);
  1075. delete pkgname;
  1076. list.next ();
  1077. }
  1078. break;
  1079. case Alpm.Errno.UNSATISFIED_DEPS:
  1080. details += Alpm.strerror (errno) + ":";
  1081. unowned Alpm.List<Alpm.DepMissing*> list = err_data;
  1082. while (list != null) {
  1083. Alpm.DepMissing* miss = list.data;
  1084. string depstring = miss->depend.compute_string ();
  1085. unowned Alpm.List<unowned Alpm.Package> trans_add = alpm_handle.trans_to_add ();
  1086. unowned Alpm.Package pkg;
  1087. string detail;
  1088. if (miss->causingpkg == null) {
  1089. /* package being installed/upgraded has unresolved dependency */
  1090. detail = _("unable to satisfy dependency '%s' required by %s").printf (depstring, miss->target);
  1091. } else if ((pkg = Alpm.pkg_find (trans_add, miss->causingpkg)) != null) {
  1092. /* upgrading a package breaks a local dependency */
  1093. detail = _("installing %s (%s) breaks dependency '%s' required by %s").printf (miss->causingpkg, pkg.version, depstring, miss->target);
  1094. } else {
  1095. /* removing a package breaks a local dependency */
  1096. detail = _("removing %s breaks dependency '%s' required by %s").printf (miss->causingpkg, depstring, miss->target);
  1097. }
  1098. if (!(detail in details)) {
  1099. details += detail;
  1100. }
  1101. delete miss;
  1102. list.next ();
  1103. }
  1104. break;
  1105. case Alpm.Errno.CONFLICTING_DEPS:
  1106. details += Alpm.strerror (errno) + ":";
  1107. unowned Alpm.List<Alpm.Conflict*> list = err_data;
  1108. while (list != null) {
  1109. Alpm.Conflict* conflict = list.data;
  1110. string conflict_detail = _("%s and %s are in conflict").printf (conflict->package1, conflict->package2);
  1111. // only print reason if it contains new information
  1112. if (conflict->reason.mod != Alpm.Depend.Mode.ANY) {
  1113. conflict_detail += " (%s)".printf (conflict->reason.compute_string ());
  1114. }
  1115. details += (owned) conflict_detail;
  1116. delete conflict;
  1117. list.next ();
  1118. }
  1119. break;
  1120. default:
  1121. details += Alpm.strerror (errno);
  1122. break;
  1123. }
  1124. current_error.details = (owned) details;
  1125. try {
  1126. trans_release (lock_id);
  1127. } catch (IOError e) {
  1128. stderr.printf ("IOError: %s\n", e.message);
  1129. } catch (DBusError e) {
  1130. stderr.printf ("DBusError: %s\n", e.message);
  1131. }
  1132. success = false;
  1133. } else {
  1134. // Search for holdpkg in target list
  1135. bool found_locked_pkg = false;
  1136. unowned Alpm.List<unowned Alpm.Package> to_remove = alpm_handle.trans_to_remove ();
  1137. while (to_remove != null) {
  1138. unowned Alpm.Package pkg = to_remove.data;
  1139. if (alpm_config.get_holdpkgs ().find_custom (pkg.name, strcmp) != null) {
  1140. details += _("%s needs to be removed but it is a locked package").printf (pkg.name);
  1141. found_locked_pkg = true;
  1142. break;
  1143. }
  1144. to_remove.next ();
  1145. }
  1146. if (found_locked_pkg) {
  1147. current_error.message = _("Failed to prepare transaction");
  1148. current_error.details = (owned) details;
  1149. try {
  1150. trans_release (lock_id);
  1151. } catch (IOError e) {
  1152. stderr.printf ("IOError: %s\n", e.message);
  1153. } catch (DBusError e) {
  1154. stderr.printf ("DBusError: %s\n", e.message);
  1155. }
  1156. success = false;
  1157. }
  1158. }
  1159. return success;
  1160. }
  1161. private void trans_prepare () {
  1162. bool success = trans_init (flags);
  1163. if (success) {
  1164. foreach (unowned string name in to_install) {
  1165. success = trans_add_pkg (name);
  1166. if (!success) {
  1167. break;
  1168. }
  1169. }
  1170. if (success) {
  1171. foreach (unowned string name in to_remove) {
  1172. success = trans_remove_pkg (name);
  1173. if (!success) {
  1174. break;
  1175. }
  1176. }
  1177. }
  1178. if (success) {
  1179. foreach (unowned string path in to_load) {
  1180. success = trans_load_pkg (path);
  1181. if (!success) {
  1182. break;
  1183. }
  1184. }
  1185. }
  1186. if (success) {
  1187. success = trans_prepare_real ();
  1188. } else {
  1189. try {
  1190. trans_release (lock_id);
  1191. } catch (IOError e) {
  1192. stderr.printf ("IOError: %s\n", e.message);
  1193. } catch (DBusError e) {
  1194. stderr.printf ("DBusError: %s\n", e.message);
  1195. }
  1196. }
  1197. }
  1198. trans_prepare_finished (success);
  1199. }
  1200. #if DISABLE_AUR
  1201. #else
  1202. private void build_prepare () {
  1203. // create a fake aur db
  1204. try {
  1205. var list = new StringBuilder ();
  1206. foreach (unowned string name_version in aur_desc_list) {
  1207. list.append (name_version);
  1208. list.append (" ");
  1209. }
  1210. Process.spawn_command_line_sync ("rm -f %ssync/aur.db".printf (alpm_handle.dbpath));
  1211. Process.spawn_command_line_sync ("bsdtar -cf %ssync/aur.db -C %s %s".printf (alpm_handle.dbpath, aurdb_path, list.str));
  1212. } catch (SpawnError e) {
  1213. stderr.printf ("SpawnError: %s\n", e.message);
  1214. }
  1215. // get an handle without emit signal callbacks AND fake aur db
  1216. alpm_handle = alpm_config.get_handle ();
  1217. if (alpm_handle == null) {
  1218. current_error = ErrorInfos () {
  1219. message = _("Failed to initialize alpm library")
  1220. };
  1221. trans_commit_finished (false);
  1222. } else {
  1223. alpm_handle.questioncb = (Alpm.QuestionCallBack) cb_question;
  1224. lockfile = GLib.File.new_for_path (alpm_handle.lockfile);
  1225. // fake aur db
  1226. alpm_handle.register_syncdb ("aur", 0);
  1227. // add to_build in to_install for the fake trans prpeapre
  1228. foreach (unowned string name in to_build) {
  1229. to_install += name;
  1230. // check if we need to remove debug package to avoid dep problem
  1231. string debug_pkg_name = "%s-debug".printf (name);
  1232. if (alpm_handle.localdb.get_pkg (debug_pkg_name) != null) {
  1233. to_remove += debug_pkg_name;
  1234. }
  1235. }
  1236. // check base-devel group needed to build pkgs
  1237. var backup_to_remove = new GenericSet<string?> (str_hash, str_equal);
  1238. foreach (unowned string name in to_remove) {
  1239. backup_to_remove.add (name);
  1240. }
  1241. unowned Alpm.List<unowned Alpm.DB> syncdbs = alpm_handle.syncdbs;
  1242. while (syncdbs != null) {
  1243. unowned Alpm.DB db = syncdbs.data;
  1244. unowned Alpm.Group? grp = db.get_group ("base-devel");
  1245. if (grp != null) {
  1246. unowned Alpm.List<unowned Alpm.Package> packages = grp.packages;
  1247. while (packages != null) {
  1248. unowned Alpm.Package pkg = packages.data;
  1249. if (Alpm.find_satisfier (alpm_handle.localdb.pkgcache, pkg.name) == null) {
  1250. to_install += pkg.name;
  1251. } else {
  1252. // remove the needed pkg from to_remove
  1253. backup_to_remove.remove (pkg.name);
  1254. }
  1255. packages.next ();
  1256. }
  1257. }
  1258. syncdbs.next ();
  1259. }
  1260. // check git needed to build pkgs
  1261. if (Alpm.find_satisfier (alpm_handle.localdb.pkgcache, "git") == null) {
  1262. to_install += "git";
  1263. } else {
  1264. // remove the needed pkg from to_remove
  1265. backup_to_remove.remove ("git");
  1266. }
  1267. to_remove = {};
  1268. foreach (unowned string name in backup_to_remove) {
  1269. to_remove += name;
  1270. }
  1271. // fake trans prepare
  1272. current_error = ErrorInfos ();
  1273. bool success = true;
  1274. if (alpm_handle.trans_init (flags | Alpm.TransFlag.NOLOCK) == -1) {
  1275. Alpm.Errno errno = alpm_handle.errno ();
  1276. current_error.errno = (uint) errno;
  1277. current_error.message = _("Failed to init transaction");
  1278. if (errno != 0) {
  1279. current_error.details = { Alpm.strerror (errno) };
  1280. }
  1281. success = false;
  1282. }
  1283. if (success) {
  1284. foreach (unowned string name in to_install) {
  1285. success = trans_add_pkg (name);
  1286. if (!success) {
  1287. break;
  1288. }
  1289. }
  1290. if (success) {
  1291. foreach (unowned string name in to_remove) {
  1292. success = trans_remove_pkg (name);
  1293. if (!success) {
  1294. break;
  1295. }
  1296. }
  1297. }
  1298. if (success) {
  1299. foreach (unowned string path in to_load) {
  1300. success = trans_load_pkg (path);
  1301. if (!success) {
  1302. break;
  1303. }
  1304. }
  1305. }
  1306. if (success) {
  1307. success = trans_prepare_real ();
  1308. if (success) {
  1309. // check trans preparation result
  1310. string[] real_to_install = {};
  1311. unowned Alpm.List<unowned Alpm.Package> pkgs_to_add = alpm_handle.trans_to_add ();
  1312. while (pkgs_to_add != null) {
  1313. unowned Alpm.Package trans_pkg = pkgs_to_add.data;
  1314. unowned Alpm.DB? db = trans_pkg.db;
  1315. if (db != null) {
  1316. if (db.name == "aur") {
  1317. // it is a aur pkg to build
  1318. aur_pkgbases_to_build.append (trans_pkg.pkgbase);
  1319. var infos = UpdateInfos () {
  1320. name = trans_pkg.name,
  1321. old_version = "",
  1322. new_version = trans_pkg.version,
  1323. repo = "",
  1324. download_size = 0
  1325. };
  1326. to_build_infos += (owned) infos;
  1327. if (!(trans_pkg.name in to_build)) {
  1328. to_install_as_dep.insert (trans_pkg.name, trans_pkg.name);
  1329. }
  1330. } else {
  1331. // it is a pkg to install
  1332. real_to_install += trans_pkg.name;
  1333. if (!(trans_pkg.name in to_install)) {
  1334. to_install_as_dep.insert (trans_pkg.name, trans_pkg.name);
  1335. }
  1336. }
  1337. }
  1338. pkgs_to_add.next ();
  1339. }
  1340. aur_conflicts_to_remove = {};
  1341. unowned Alpm.List<unowned Alpm.Package> pkgs_to_remove = alpm_handle.trans_to_remove ();
  1342. while (pkgs_to_remove != null) {
  1343. unowned Alpm.Package trans_pkg = pkgs_to_remove.data;
  1344. // it is a pkg to remove
  1345. if (!(trans_pkg.name in to_remove)) {
  1346. var infos = UpdateInfos () {
  1347. name = trans_pkg.name,
  1348. old_version = trans_pkg.version,
  1349. new_version = "",
  1350. repo = "",
  1351. download_size = 0
  1352. };
  1353. aur_conflicts_to_remove += (owned) infos;
  1354. }
  1355. pkgs_to_remove.next ();
  1356. }
  1357. try {
  1358. trans_release (lock_id);
  1359. } catch (IOError e) {
  1360. stderr.printf ("IOError: %s\n", e.message);
  1361. } catch (DBusError e) {
  1362. stderr.printf ("DBusError: %s\n", e.message);
  1363. }
  1364. try {
  1365. Process.spawn_command_line_sync ("rm -f %ssync/aur.db".printf (alpm_handle.dbpath));
  1366. } catch (SpawnError e) {
  1367. stderr.printf ("SpawnError: %s\n", e.message);
  1368. }
  1369. // get standard handle
  1370. refresh_handle ();
  1371. // launch standard prepare
  1372. to_install = real_to_install;
  1373. trans_prepare ();
  1374. }
  1375. } else {
  1376. try {
  1377. trans_release (lock_id);
  1378. } catch (IOError e) {
  1379. stderr.printf ("IOError: %s\n", e.message);
  1380. } catch (DBusError e) {
  1381. stderr.printf ("DBusError: %s\n", e.message);
  1382. }
  1383. }
  1384. }
  1385. if (!success) {
  1386. // get standard handle
  1387. refresh_handle ();
  1388. trans_prepare_finished (false);
  1389. }
  1390. }
  1391. }
  1392. #endif
  1393. #if DISABLE_AUR
  1394. public void start_trans_prepare (Alpm.TransFlag flags_,
  1395. string[] to_install_,
  1396. string[] to_remove_,
  1397. string[] to_load_,
  1398. GLib.BusName sender) throws DBusError, IOError {
  1399. #else
  1400. public void start_trans_prepare (Alpm.TransFlag flags_,
  1401. string[] to_install_,
  1402. string[] to_remove_,
  1403. string[] to_load_,
  1404. string[] to_build_,
  1405. GLib.BusName sender) throws DBusError, IOError {
  1406. #endif
  1407. if (lock_id != sender) {
  1408. trans_prepare_finished (false);
  1409. return;
  1410. }
  1411. flags = flags_;
  1412. to_install = to_install_;
  1413. to_remove = to_remove_;
  1414. to_load = to_load_;
  1415. #if DISABLE_AUR
  1416. #else
  1417. to_build = to_build_;
  1418. to_build_infos = {};
  1419. aur_pkgbases_to_build = new GLib.List<string> ();
  1420. if (to_build.length != 0) {
  1421. compute_aur_build_list.begin (to_build, (obj, res) => {
  1422. try {
  1423. thread_pool.add (new AlpmAction (build_prepare));
  1424. } catch (ThreadError e) {
  1425. stderr.printf ("Thread Error %s\n", e.message);
  1426. }
  1427. });
  1428. } else {
  1429. #endif
  1430. try {
  1431. thread_pool.add (new AlpmAction (trans_prepare));
  1432. } catch (ThreadError e) {
  1433. stderr.printf ("Thread Error %s\n", e.message);
  1434. }
  1435. #if DISABLE_AUR
  1436. #else
  1437. }
  1438. #endif
  1439. }
  1440. public void choose_provider (int provider) throws DBusError, IOError {
  1441. provider_mutex.lock ();
  1442. choosen_provider = provider;
  1443. provider_cond.signal ();
  1444. provider_mutex.unlock ();
  1445. }
  1446. public TransactionSummary get_transaction_summary () throws DBusError, IOError {
  1447. UpdateInfos[] to_install = {};
  1448. UpdateInfos[] to_upgrade = {};
  1449. UpdateInfos[] to_downgrade = {};
  1450. UpdateInfos[] to_reinstall = {};
  1451. UpdateInfos[] to_remove = {};
  1452. unowned Alpm.List<unowned Alpm.Package> pkgs_to_add = alpm_handle.trans_to_add ();
  1453. while (pkgs_to_add != null) {
  1454. unowned Alpm.Package trans_pkg = pkgs_to_add.data;
  1455. unowned Alpm.Package? local_pkg = alpm_handle.localdb.get_pkg (trans_pkg.name);
  1456. var infos = UpdateInfos () {
  1457. name = trans_pkg.name,
  1458. old_version = local_pkg != null ? local_pkg.version : "",
  1459. new_version = trans_pkg.version,
  1460. // if pkg was load from a file, pkg.db is null
  1461. repo =trans_pkg.db != null ? trans_pkg.db.name : "",
  1462. download_size = trans_pkg.download_size
  1463. };
  1464. if (local_pkg == null) {
  1465. to_install += (owned) infos;
  1466. } else {
  1467. int cmp = Alpm.pkg_vercmp (trans_pkg.version, local_pkg.version);
  1468. if (cmp == 1) {
  1469. to_upgrade += (owned) infos;
  1470. } else if (cmp == 0) {
  1471. to_reinstall += (owned) infos;
  1472. } else {
  1473. to_downgrade += (owned) infos;
  1474. }
  1475. }
  1476. pkgs_to_add.next ();
  1477. }
  1478. unowned Alpm.List<unowned Alpm.Package> pkgs_to_remove = alpm_handle.trans_to_remove ();
  1479. while (pkgs_to_remove != null) {
  1480. unowned Alpm.Package trans_pkg = pkgs_to_remove.data;
  1481. var infos = UpdateInfos () {
  1482. name = trans_pkg.name,
  1483. old_version = trans_pkg.version,
  1484. new_version = "",
  1485. repo = trans_pkg.db.name
  1486. };
  1487. to_remove += (owned) infos;
  1488. pkgs_to_remove.next ();
  1489. }
  1490. #if DISABLE_AUR
  1491. #else
  1492. UpdateInfos[] conflicts_to_remove = {};
  1493. foreach (unowned UpdateInfos infos in aur_conflicts_to_remove){
  1494. conflicts_to_remove += infos;
  1495. }
  1496. aur_conflicts_to_remove = {};
  1497. string[] pkgbases_to_build = {};
  1498. foreach (unowned string name in aur_pkgbases_to_build) {
  1499. pkgbases_to_build += name;
  1500. }
  1501. #endif
  1502. var summary = TransactionSummary () {
  1503. to_install = (owned) to_install,
  1504. to_upgrade = (owned) to_upgrade,
  1505. to_downgrade = (owned) to_downgrade,
  1506. to_reinstall = (owned) to_reinstall,
  1507. #if DISABLE_AUR
  1508. to_remove = (owned) to_remove
  1509. #else
  1510. to_remove = (owned) to_remove,
  1511. to_build = to_build_infos,
  1512. aur_conflicts_to_remove = conflicts_to_remove,
  1513. aur_pkgbases_to_build = pkgbases_to_build
  1514. #endif
  1515. };
  1516. return summary;
  1517. }
  1518. private void trans_commit () {
  1519. current_error = ErrorInfos ();
  1520. bool success = true;
  1521. Alpm.List err_data;
  1522. if (alpm_handle.trans_commit (out err_data) == -1) {
  1523. Alpm.Errno errno = alpm_handle.errno ();
  1524. current_error.errno = (uint) errno;
  1525. // cancel the download return an EXTERNAL_DOWNLOAD error
  1526. if (errno == Alpm.Errno.EXTERNAL_DOWNLOAD && cancellable.is_cancelled ()) {
  1527. try {
  1528. trans_release (lock_id);
  1529. } catch (IOError e) {
  1530. stderr.printf ("IOError: %s\n", e.message);
  1531. } catch (DBusError e) {
  1532. stderr.printf ("DBusError: %s\n", e.message);
  1533. }
  1534. trans_commit_finished (false);
  1535. return;
  1536. }
  1537. current_error.message = _("Failed to commit transaction");
  1538. switch (errno) {
  1539. case 0:
  1540. break;
  1541. case Alpm.Errno.FILE_CONFLICTS:
  1542. string[] details = {};
  1543. details += Alpm.strerror (errno) + ":";
  1544. //TransFlag flags = alpm_handle.trans_get_flags ();
  1545. //if ((flags & TransFlag.FORCE) != 0) {
  1546. //details += _("unable to %s directory-file conflicts").printf ("--force");
  1547. //}
  1548. unowned Alpm.List<Alpm.FileConflict*> list = err_data;
  1549. while (list != null) {
  1550. Alpm.FileConflict* conflict = list.data;
  1551. switch (conflict->type) {
  1552. case Alpm.FileConflict.Type.TARGET:
  1553. details += _("%s exists in both %s and %s").printf (conflict->file, conflict->target, conflict->ctarget);
  1554. break;
  1555. case Alpm.FileConflict.Type.FILESYSTEM:
  1556. details += _("%s: %s already exists in filesystem").printf (conflict->target, conflict->file);
  1557. break;
  1558. }
  1559. delete conflict;
  1560. list.next ();
  1561. }
  1562. current_error.details = (owned) details;
  1563. break;
  1564. case Alpm.Errno.PKG_INVALID:
  1565. case Alpm.Errno.PKG_INVALID_CHECKSUM:
  1566. case Alpm.Errno.PKG_INVALID_SIG:
  1567. case Alpm.Errno.DLT_INVALID:
  1568. string[] details = {};
  1569. details += Alpm.strerror (errno) + ":";
  1570. unowned Alpm.List<string*> list = err_data;
  1571. while (list != null) {
  1572. string* filename = list.data;
  1573. details += _("%s is invalid or corrupted").printf (filename);
  1574. delete filename;
  1575. list.next ();
  1576. }
  1577. current_error.details = (owned) details;
  1578. break;
  1579. case Alpm.Errno.EXTERNAL_DOWNLOAD:
  1580. // details are set in cb_fetch
  1581. break;
  1582. default:
  1583. current_error.details = {Alpm.strerror (errno)};
  1584. break;
  1585. }
  1586. success = false;
  1587. }
  1588. try {
  1589. trans_release (lock_id);
  1590. } catch (IOError e) {
  1591. stderr.printf ("IOError: %s\n", e.message);
  1592. } catch (DBusError e) {
  1593. stderr.printf ("DBusError: %s\n", e.message);
  1594. }
  1595. to_install_as_dep.foreach_remove ((pkgname, val) => {
  1596. unowned Alpm.Package? pkg = alpm_handle.localdb.get_pkg (pkgname);
  1597. if (pkg != null) {
  1598. pkg.reason = Alpm.Package.Reason.DEPEND;
  1599. return true; // remove current pkgname
  1600. }
  1601. return false;
  1602. });
  1603. trans_commit_finished (success);
  1604. }
  1605. public void start_trans_commit (GLib.BusName sender) throws DBusError, IOError {
  1606. check_authorization.begin (sender, (obj, res) => {
  1607. bool authorized = check_authorization.end (res);
  1608. if (authorized) {
  1609. try {
  1610. thread_pool.add (new AlpmAction (trans_commit));
  1611. } catch (ThreadError e) {
  1612. stderr.printf ("Thread Error %s\n", e.message);
  1613. }
  1614. } else {
  1615. try {
  1616. trans_release (lock_id);
  1617. } catch (IOError e) {
  1618. stderr.printf ("IOError: %s\n", e.message);
  1619. } catch (DBusError e) {
  1620. stderr.printf ("DBusError: %s\n", e.message);
  1621. }
  1622. trans_commit_finished (false);
  1623. }
  1624. });
  1625. }
  1626. public void trans_release (GLib.BusName sender) throws DBusError, IOError {
  1627. if (lock_id != sender) {
  1628. return;
  1629. }
  1630. alpm_handle.trans_release ();
  1631. remove_ignorepkgs ();
  1632. }
  1633. public void trans_cancel (GLib.BusName sender) throws DBusError, IOError {
  1634. if (lock_id != sender) {
  1635. return;
  1636. }
  1637. if (alpm_handle.trans_interrupt () == 0) {
  1638. // a transaction is being interrupted
  1639. // it will end the normal way
  1640. return;
  1641. }
  1642. cancellable.cancel ();
  1643. }
  1644. [DBus (no_reply = true)]
  1645. public void quit () throws DBusError, IOError {
  1646. // wait for all tasks to be processed
  1647. ThreadPool.free ((owned) thread_pool, false, true);
  1648. loop.quit ();
  1649. }
  1650. // End of Daemon Object
  1651. }
  1652. }
  1653. private void write_log_file (string event) {
  1654. var now = new DateTime.now_local ();
  1655. string log = "%s [PAMAC] %s\n".printf (now.format ("[%Y-%m-%d %H:%M]"), event);
  1656. var file = GLib.File.new_for_path ("/var/log/pacman.log");
  1657. try {
  1658. // creating a DataOutputStream to the file
  1659. var dos = new DataOutputStream (file.append_to (FileCreateFlags.NONE));
  1660. // writing a short string to the stream
  1661. dos.put_string (log);
  1662. } catch (GLib.Error e) {
  1663. stderr.printf ("%s\n", e.message);
  1664. }
  1665. }
  1666. private void cb_event (Alpm.Event.Data data) {
  1667. string[] details = {};
  1668. uint secondary_type = 0;
  1669. switch (data.type) {
  1670. case Alpm.Event.Type.HOOK_START:
  1671. switch (data.hook_when) {
  1672. case Alpm.HookWhen.PRE_TRANSACTION:
  1673. secondary_type = (uint) Alpm.HookWhen.PRE_TRANSACTION;
  1674. break;
  1675. case Alpm.HookWhen.POST_TRANSACTION:
  1676. secondary_type = (uint) Alpm.HookWhen.POST_TRANSACTION;
  1677. break;
  1678. default:
  1679. break;
  1680. }
  1681. break;
  1682. case Alpm.Event.Type.HOOK_RUN_START:
  1683. details += data.hook_run_name;
  1684. details += data.hook_run_desc ?? "";
  1685. details += data.hook_run_position.to_string ();
  1686. details += data.hook_run_total.to_string ();
  1687. break;
  1688. case Alpm.Event.Type.PACKAGE_OPERATION_START:
  1689. switch (data.package_operation_operation) {
  1690. case Alpm.Package.Operation.REMOVE:
  1691. details += data.package_operation_oldpkg.name;
  1692. details += data.package_operation_oldpkg.version;
  1693. secondary_type = (uint) Alpm.Package.Operation.REMOVE;
  1694. break;
  1695. case Alpm.Package.Operation.INSTALL:
  1696. details += data.package_operation_newpkg.name;
  1697. details += data.package_operation_newpkg.version;
  1698. secondary_type = (uint) Alpm.Package.Operation.INSTALL;
  1699. break;
  1700. case Alpm.Package.Operation.REINSTALL:
  1701. details += data.package_operation_newpkg.name;
  1702. details += data.package_operation_newpkg.version;
  1703. secondary_type = (uint) Alpm.Package.Operation.REINSTALL;
  1704. break;
  1705. case Alpm.Package.Operation.UPGRADE:
  1706. details += data.package_operation_oldpkg.name;
  1707. details += data.package_operation_oldpkg.version;
  1708. details += data.package_operation_newpkg.version;
  1709. secondary_type = (uint) Alpm.Package.Operation.UPGRADE;
  1710. break;
  1711. case Alpm.Package.Operation.DOWNGRADE:
  1712. details += data.package_operation_oldpkg.name;
  1713. details += data.package_operation_oldpkg.version;
  1714. details += data.package_operation_newpkg.version;
  1715. secondary_type = (uint) Alpm.Package.Operation.DOWNGRADE;
  1716. break;
  1717. default:
  1718. break;
  1719. }
  1720. break;
  1721. case Alpm.Event.Type.DELTA_PATCH_START:
  1722. details += data.delta_patch_delta.to;
  1723. details += data.delta_patch_delta.delta;
  1724. break;
  1725. case Alpm.Event.Type.SCRIPTLET_INFO:
  1726. details += data.scriptlet_info_line;
  1727. break;
  1728. case Alpm.Event.Type.PKGDOWNLOAD_START:
  1729. // do not emit event when download is cancelled
  1730. if (system_daemon.cancellable.is_cancelled ()) {
  1731. return;
  1732. }
  1733. details += data.pkgdownload_file;
  1734. break;
  1735. case Alpm.Event.Type.OPTDEP_REMOVAL:
  1736. details += data.optdep_removal_pkg.name;
  1737. details += data.optdep_removal_optdep.compute_string ();
  1738. break;
  1739. case Alpm.Event.Type.DATABASE_MISSING:
  1740. details += data.database_missing_dbname;
  1741. break;
  1742. case Alpm.Event.Type.PACNEW_CREATED:
  1743. details += data.pacnew_created_file;
  1744. break;
  1745. case Alpm.Event.Type.PACSAVE_CREATED:
  1746. details += data.pacsave_created_file;
  1747. break;
  1748. default:
  1749. break;
  1750. }
  1751. system_daemon.emit_event ((uint) data.type, secondary_type, details);
  1752. }
  1753. private void cb_question (Alpm.Question.Data data) {
  1754. switch (data.type) {
  1755. case Alpm.Question.Type.INSTALL_IGNOREPKG:
  1756. // Do not install package in IgnorePkg/IgnoreGroup
  1757. data.install_ignorepkg_install = 0;
  1758. break;
  1759. case Alpm.Question.Type.REPLACE_PKG:
  1760. // Auto-remove conflicts in case of replaces
  1761. data.replace_replace = 1;
  1762. break;
  1763. case Alpm.Question.Type.CONFLICT_PKG:
  1764. // Auto-remove conflicts
  1765. data.conflict_remove = 1;
  1766. break;
  1767. case Alpm.Question.Type.REMOVE_PKGS:
  1768. // Return an error if there are top-level packages which have unresolvable dependencies
  1769. data.remove_pkgs_skip = 0;
  1770. break;
  1771. case Alpm.Question.Type.SELECT_PROVIDER:
  1772. string depend_str = data.select_provider_depend.compute_string ();
  1773. string[] providers_str = {};
  1774. unowned Alpm.List<unowned Alpm.Package> list = data.select_provider_providers;
  1775. while (list != null) {
  1776. unowned Alpm.Package pkg = list.data;
  1777. providers_str += pkg.name;
  1778. list.next ();
  1779. }
  1780. system_daemon.provider_cond = Cond ();
  1781. system_daemon.provider_mutex = Mutex ();
  1782. system_daemon.choosen_provider = null;
  1783. system_daemon.emit_providers (depend_str, providers_str);
  1784. system_daemon.provider_mutex.lock ();
  1785. while (system_daemon.choosen_provider == null) {
  1786. system_daemon.provider_cond.wait (system_daemon.provider_mutex);
  1787. }
  1788. data.select_provider_use_index = system_daemon.choosen_provider;
  1789. system_daemon.provider_mutex.unlock ();
  1790. break;
  1791. case Alpm.Question.Type.CORRUPTED_PKG:
  1792. // Auto-remove corrupted pkgs in cache
  1793. data.corrupted_remove = 1;
  1794. break;
  1795. case Alpm.Question.Type.IMPORT_KEY:
  1796. if (data.import_key_key.revoked == 1) {
  1797. // Do not get revoked key
  1798. data.import_key_import = 0;
  1799. } else {
  1800. // Auto get not revoked key
  1801. data.import_key_import = 1;
  1802. }
  1803. break;
  1804. default:
  1805. data.any_answer = 0;
  1806. break;
  1807. }
  1808. }
  1809. private void cb_progress (Alpm.Progress progress, string pkgname, int percent, uint n_targets, uint current_target) {
  1810. if (percent == 0) {
  1811. system_daemon.emit_progress ((uint) progress, pkgname, (uint) percent, n_targets, current_target);
  1812. system_daemon.timer.start ();
  1813. } else if (percent == 100) {
  1814. system_daemon.emit_progress ((uint) progress, pkgname, (uint) percent, n_targets, current_target);
  1815. system_daemon.timer.stop ();
  1816. }else if (system_daemon.timer.elapsed () < 0.5) {
  1817. return;
  1818. } else {
  1819. system_daemon.emit_progress ((uint) progress, pkgname, (uint) percent, n_targets, current_target);
  1820. system_daemon.timer.start ();
  1821. }
  1822. }
  1823. private uint64 prevprogress;
  1824. private int cb_download (void* data, uint64 dltotal, uint64 dlnow, uint64 ultotal, uint64 ulnow) {
  1825. if (unlikely (system_daemon.cancellable.is_cancelled ())) {
  1826. return 1;
  1827. }
  1828. string filename = (string) data;
  1829. if (unlikely (dlnow == 0 || dltotal == 0 || prevprogress == dltotal)) {
  1830. return 0;
  1831. } else if (unlikely (prevprogress == 0)) {
  1832. system_daemon.emit_download (filename, 0, dltotal);
  1833. system_daemon.emit_download (filename, dlnow, dltotal);
  1834. system_daemon.timer.start ();
  1835. } else if (unlikely (dlnow == dltotal)) {
  1836. system_daemon.emit_download (filename, dlnow, dltotal);
  1837. system_daemon.timer.stop ();
  1838. } else if (likely (system_daemon.timer.elapsed () < 0.5)) {
  1839. return 0;
  1840. } else {
  1841. system_daemon.emit_download (filename, dlnow, dltotal);
  1842. system_daemon.timer.start ();
  1843. }
  1844. prevprogress = dlnow;
  1845. return 0;
  1846. }
  1847. private int cb_fetch (string fileurl, string localpath, int force) {
  1848. if (system_daemon.cancellable.is_cancelled ()) {
  1849. return -1;
  1850. }
  1851. char error_buffer[Curl.ERROR_SIZE];
  1852. var url = GLib.File.new_for_uri (fileurl);
  1853. var destfile = GLib.File.new_for_path (localpath + url.get_basename ());
  1854. var tempfile = GLib.File.new_for_path (destfile.get_path () + ".part");
  1855. system_daemon.curl.reset ();
  1856. system_daemon.curl.setopt (Curl.Option.FAILONERROR, 1L);
  1857. system_daemon.curl.setopt (Curl.Option.CONNECTTIMEOUT, 30L);
  1858. system_daemon.curl.setopt (Curl.Option.FILETIME, 1L);
  1859. system_daemon.curl.setopt (Curl.Option.FOLLOWLOCATION, 1L);
  1860. system_daemon.curl.setopt (Curl.Option.XFERINFOFUNCTION, cb_download);
  1861. system_daemon.curl.setopt (Curl.Option.LOW_SPEED_LIMIT, 1L);
  1862. system_daemon.curl.setopt (Curl.Option.LOW_SPEED_TIME, 30L);
  1863. system_daemon.curl.setopt (Curl.Option.NETRC, Curl.NetRCOption.OPTIONAL);
  1864. system_daemon.curl.setopt (Curl.Option.HTTPAUTH, Curl.CURLAUTH_ANY);
  1865. system_daemon.curl.setopt (Curl.Option.URL, fileurl);
  1866. system_daemon.curl.setopt (Curl.Option.ERRORBUFFER, error_buffer);
  1867. system_daemon.curl.setopt (Curl.Option.NOPROGRESS, 0L);
  1868. system_daemon.curl.setopt (Curl.Option.XFERINFODATA, (void*) url.get_basename ());
  1869. bool remove_partial_download = true;
  1870. if (fileurl.contains (".pkg.tar.") && !fileurl.has_suffix (".sig")) {
  1871. remove_partial_download = false;
  1872. }
  1873. string open_mode = "wb";
  1874. prevprogress = 0;
  1875. try {
  1876. if (force == 0) {
  1877. if (destfile.query_exists ()) {
  1878. // start from scratch only download if our local is out of date.
  1879. system_daemon.curl.setopt (Curl.Option.TIMECONDITION, Curl.TimeCond.IFMODSINCE);
  1880. FileInfo info = destfile.query_info ("time::modified", 0);
  1881. TimeVal time = info.get_modification_time ();
  1882. system_daemon.curl.setopt (Curl.Option.TIMEVALUE, time.tv_sec);
  1883. } else if (tempfile.query_exists ()) {
  1884. // a previous partial download exists, resume from end of file.
  1885. FileInfo info = tempfile.query_info ("standard::size", 0);
  1886. int64 size = info.get_size ();
  1887. system_daemon.curl.setopt (Curl.Option.RESUME_FROM_LARGE, size);
  1888. open_mode = "ab";
  1889. }
  1890. } else {
  1891. if (tempfile.query_exists ()) {
  1892. tempfile.delete ();
  1893. }
  1894. }
  1895. } catch (GLib.Error e) {
  1896. stderr.printf ("Error: %s\n", e.message);
  1897. }
  1898. Posix.FILE localf = Posix.FILE.open (tempfile.get_path (), open_mode);
  1899. if (localf == null) {
  1900. stderr.printf ("could not open file %s\n", tempfile.get_path ());
  1901. return -1;
  1902. }
  1903. system_daemon.curl.setopt (Curl.Option.WRITEDATA, localf);
  1904. // perform transfer
  1905. Curl.Code err = system_daemon.curl.perform ();
  1906. // disconnect relationships from the curl handle for things that might go out
  1907. // of scope, but could still be touched on connection teardown. This really
  1908. // only applies to FTP transfers.
  1909. system_daemon.curl.setopt (Curl.Option.NOPROGRESS, 1L);
  1910. system_daemon.curl.setopt (Curl.Option.ERRORBUFFER, null);
  1911. int ret;
  1912. // was it a success?
  1913. switch (err) {
  1914. case Curl.Code.OK:
  1915. long timecond, remote_time = -1;
  1916. double remote_size, bytes_dl;
  1917. unowned string effective_url;
  1918. // retrieve info about the state of the transfer
  1919. system_daemon.curl.getinfo (Curl.Info.FILETIME, out remote_time);
  1920. system_daemon.curl.getinfo (Curl.Info.CONTENT_LENGTH_DOWNLOAD, out remote_size);
  1921. system_daemon.curl.getinfo (Curl.Info.SIZE_DOWNLOAD, out bytes_dl);
  1922. system_daemon.curl.getinfo (Curl.Info.CONDITION_UNMET, out timecond);
  1923. system_daemon.curl.getinfo (Curl.Info.EFFECTIVE_URL, out effective_url);
  1924. if (timecond == 1 && bytes_dl == 0) {
  1925. // time condition was met and we didn't download anything. we need to
  1926. // clean up the 0 byte .part file that's left behind.
  1927. try {
  1928. if (tempfile.query_exists ()) {
  1929. tempfile.delete ();
  1930. }
  1931. } catch (GLib.Error e) {
  1932. stderr.printf ("Error: %s\n", e.message);
  1933. }
  1934. ret = 1;
  1935. }
  1936. // remote_size isn't necessarily the full size of the file, just what the
  1937. // server reported as remaining to download. compare it to what curl reported
  1938. // as actually being transferred during curl_easy_perform ()
  1939. else if (remote_size != -1 && bytes_dl != -1 && bytes_dl != remote_size) {
  1940. string error = _("%s appears to be truncated: %jd/%jd bytes\n").printf (
  1941. fileurl, bytes_dl, remote_size);
  1942. system_daemon.emit_log ((uint) Alpm.LogLevel.ERROR, error);
  1943. system_daemon.current_error.details = {error};
  1944. if (remove_partial_download) {
  1945. try {
  1946. if (tempfile.query_exists ()) {
  1947. tempfile.delete ();
  1948. }
  1949. } catch (GLib.Error e) {
  1950. stderr.printf ("Error: %s\n", e.message);
  1951. }
  1952. }
  1953. ret = -1;
  1954. } else {
  1955. try {
  1956. tempfile.move (destfile, FileCopyFlags.OVERWRITE);
  1957. } catch (GLib.Error e) {
  1958. stderr.printf ("Error: %s\n", e.message);
  1959. }
  1960. ret = 0;
  1961. }
  1962. break;
  1963. case Curl.Code.ABORTED_BY_CALLBACK:
  1964. if (remove_partial_download) {
  1965. try {
  1966. if (tempfile.query_exists ()) {
  1967. tempfile.delete ();
  1968. }
  1969. } catch (GLib.Error e) {
  1970. stderr.printf ("Error: %s\n", e.message);
  1971. }
  1972. }
  1973. ret = -1;
  1974. break;
  1975. default:
  1976. // other cases are errors
  1977. try {
  1978. if (tempfile.query_exists ()) {
  1979. if (remove_partial_download) {
  1980. tempfile.delete ();
  1981. } else {
  1982. // delete zero length downloads
  1983. FileInfo info = tempfile.query_info ("standard::size", 0);
  1984. int64 size = info.get_size ();
  1985. if (size == 0) {
  1986. tempfile.delete ();
  1987. }
  1988. }
  1989. }
  1990. } catch (GLib.Error e) {
  1991. stderr.printf ("Error: %s\n", e.message);
  1992. }
  1993. // do not report error for missing sig
  1994. if (!fileurl.has_suffix (".sig")) {
  1995. string hostname = url.get_uri ().split("/")[2];
  1996. string error = _("failed retrieving file '%s' from %s : %s\n").printf (
  1997. url.get_basename (), hostname, (string) error_buffer);
  1998. system_daemon.emit_log ((uint) Alpm.LogLevel.ERROR, error);
  1999. system_daemon.current_error.details = {error};
  2000. }
  2001. ret = -1;
  2002. break;
  2003. }
  2004. return ret;
  2005. }
  2006. private void cb_totaldownload (uint64 total) {
  2007. system_daemon.emit_totaldownload (total);
  2008. }
  2009. private void cb_log (Alpm.LogLevel level, string fmt, va_list args) {
  2010. // do not log errors when download is cancelled
  2011. if (system_daemon.cancellable.is_cancelled ()) {
  2012. return;
  2013. }
  2014. Alpm.LogLevel logmask = Alpm.LogLevel.ERROR | Alpm.LogLevel.WARNING;
  2015. if ((level & logmask) == 0) {
  2016. return;
  2017. }
  2018. string? log = null;
  2019. log = fmt.vprintf (args);
  2020. if (log != null) {
  2021. system_daemon.emit_log ((uint) level, log);
  2022. }
  2023. }
  2024. void on_bus_acquired (DBusConnection conn) {
  2025. system_daemon = new Pamac.SystemDaemon ();
  2026. try {
  2027. conn.register_object ("/org/pamac/system", system_daemon);
  2028. }
  2029. catch (IOError e) {
  2030. stderr.printf ("Could not register service\n");
  2031. loop.quit ();
  2032. }
  2033. }
  2034. void main () {
  2035. // i18n
  2036. Intl.bindtextdomain(Constants.GETTEXT_PACKAGE, Path.build_filename(Constants.DATADIR,"locale"));
  2037. Intl.setlocale (LocaleCategory.ALL, "");
  2038. Intl.textdomain(Constants.GETTEXT_PACKAGE);
  2039. Intl.bind_textdomain_codeset(Constants.GETTEXT_PACKAGE, "utf-8" );
  2040. Bus.own_name (BusType.SYSTEM,
  2041. "org.pamac.system",
  2042. BusNameOwnerFlags.NONE,
  2043. on_bus_acquired,
  2044. null,
  2045. () => {
  2046. stderr.printf ("Could not acquire name\n");
  2047. loop.quit ();
  2048. });
  2049. Curl.global_init (Curl.GLOBAL_SSL);
  2050. loop = new MainLoop ();
  2051. loop.run ();
  2052. Curl.global_cleanup ();
  2053. }