From df02ed2aa44c7345438a7645bcf84513696b5e3f Mon Sep 17 00:00:00 2001 From: Agnieszka Kostrzewa Date: Mon, 20 Feb 2012 07:56:38 +0100 Subject: [PATCH] Backup dialog. --- backupdlg.ui | 16 +- icons/mount.png | Bin 0 -> 16083 bytes icons/redfirewall2.png | Bin 0 -> 18054 bytes qubesmanager/appmenu_select.py | 19 +-- qubesmanager/backup.py | 271 +++++++++++++++++++++++++++--- qubesmanager/main.py | 25 +-- qubesmanager/multiselectwidget.py | 8 +- qubesmanager/settings.py | 2 +- qubesmanager/thread_monitor.py | 44 +++++ restoredlg.ui | 8 +- 10 files changed, 315 insertions(+), 78 deletions(-) create mode 100644 icons/mount.png create mode 100644 icons/redfirewall2.png create mode 100644 qubesmanager/thread_monitor.py diff --git a/backupdlg.ui b/backupdlg.ui index 04cb139..522ce78 100644 --- a/backupdlg.ui +++ b/backupdlg.ui @@ -19,7 +19,7 @@ QWizard::NoBackButtonOnLastPage|QWizard::NoBackButtonOnStartPage - + @@ -39,7 +39,7 @@ - + @@ -55,7 +55,7 @@ - + 0 @@ -92,10 +92,10 @@ - + - + ... @@ -106,7 +106,7 @@ - + @@ -157,7 +157,7 @@ p, li { white-space: pre-wrap; } - + @@ -176,7 +176,7 @@ p, li { white-space: pre-wrap; } - + 24 diff --git a/icons/mount.png b/icons/mount.png new file mode 100644 index 0000000000000000000000000000000000000000..8c841582386a3ff62179f2fefcede2c7c5aa0955 GIT binary patch literal 16083 zcmV;^J}kkBP)u=FOY;?)mOH-#Pc(J1Sh3OIlRt`vxw{ z`IXB6xWwf$04{O441h~qE(72am&*XS#N{#oE^)aGfJJ6CR$Jnp=ymb`}rpxEQhfWWjNpWexb7doJmqr7l$$(a)$>o8CJoevXFU);x?fHI=3qgKY z09d$W`4|;c&#}$xB#J zZ54DnFTO7b0*pp8PM*%j`Yqe#muOU}gn6wEl`CI)n@`1s@hA|as@A|u1l zw{Kqr2M43Bt`VEI?nHKeq2qeY8XOQ*wnygAopa=TKlizo3l0EZeDQ@Qr=;dSrj=LN zZoK?GUmqU~8$1}jdUQc(XrSVAWo6ae>^C&%@#&|ZA}lNfdVH&RgB-e8+o$&ZHw1!MG8 z!_YY)jw_OGSLJfY(*A}GTNn@M#FT2`{y!kVpSc2G<{C_R55M&_c{wU+bgV{?`6Ac>A1h2F9xR!;66Sez?s)^ zRW|i-*V`xMlh|xF==DuJW8WB~G!UB~m|IuEPZXPdEM%TDAL6v|IYgWC4UyeH?R zo{#oAn{rM8uxQcpP+sg}md-X!UK0P_P6BXj=)79M>u;F30Mh*284BIKDyTru*VDc`5hiRX%DpY}BxHQy$NPcP-?rA`AKE$Vo%I_`mwLhMcbWiIqLvewB+4unaY+y#_UOPvC+{O zK6ntKqr-XlCLZ^EYwo?({XGJKR;%Ui!DbT}`LpuB%FhaRAb7fV+uv7HQ_o3aeS@Oo zueDgUkG=Hl!+B@B4bP^WH2^Gp>z_STD(e!qIaPif}vK+Kh?fsJuAiYxytv%V`K@uyhOJ^yue~HbGM*;Y=IqX@7nVB#DfH? zlG1W~yJmx&cna*@4+Nv|+`M^@)%{lOdbZ^^0l;71S~*^=63EZ@mmiM`kHCeiZ;1!RyB8*IR7!Ci!uHKR*oY*AIz2gXb+%y6abZR$6<2 zkZ+#}5b|w`5{PrqU$O!O0s@2U_t`iS+Otg3cQ_B!)ivNdW(^vfoI?og-OXx^YW8z~ zo}KmEsOs#kmDkohKslg`DzV$?t;UUU_nt&8%0#Ou@NPoB=g<{f+FUu|TcT-4ea z_WCQY%rxNwl%E9v8k^SzM*o35?_b$&l)M4rqGOn!?}M<=V8^(;tCEy}a8;!8T*b|kZo!O}mS)EE#g|&GK}bj_0s;a(ey%;M zP+U@m?|#~7cPS3}kC#pT^fS-Qsy>@a{W)?*0N4vJ$a1zE1JWh{7A{?}g5h(v{Ft}S2mO2XK|*{qPrJJJuC^MxE$eV*Fp!T93k%}gl!R$+ zHY&caeWK|(Kk#!1q*zaA!p@!Baq!>)Zql#4b_#m;?&Ej{dXZIfZi{0R&M^y-WF9+} ziS4`g$uDnaxAQk+gU?@IdF8>@bF6!~wwyy2FIn+CvrUWTjSw3Z%M&`m!PFCV`~fAC zNni*L4&Y|Fyu5<-n4{>_sS`JwPC&E;29->ak|M+%Qhs=NFmK$3h9+L@>6sVEjyQHa zXBykG3Zx*iDij$w2b2WJEn8Mr2EP6FYgAQLV$`Uym@?%?-ZpZpC7mlh2i-fhl>~_9 zmKLnryiHMjBB+p~5^Rsoduq;x^9}%eQipEDk+VzgoQ%%#adxFUQ?2BaN%1W$M&>U| z@csASVCc{x7&ve+cJ125d(NaulRY%L%A?toE0>fX85zPGt-ijAmv70>bB!q4Baogz zK?*1SKz>?MwyQ<*1lsEAD!ld9V&)R+Fm2i`xbC{^Wl@9jb8Q_X$tx_xjy(qyV-jrZ zbFIbpQG^iZ6ab5sF5k%@Ia1n>i;P3Ju3eZy)NnPQr1*k@JnY@O0~02U#ee~W zdHhTkAtxsrD_6dYzx{1l8^gTH#*r(Jgwn=DE*l%0pw}DP1k9PpBmMRE_Ewl=V)!jB z22LUcfv%yJDMnsY--_=`A ztFPdSsH&<%NlA@E8FcefI3}4fwc5s9K|VA8JGhCRGiNSWrn@gznnSr_>2E|t2veRf zH~mzirTnaWc}w>7qam!Ez1zGj>S zQ2=1^TPwd6RKhfA|Nc9svxW?EyifkJq@;@ZLA@-ABAQex!lVLB@?^x2go;<=V zSzjb3cJ*Kd+*SeL_Cg&{4P0sBgsDP1{|IPYT%e=KSU9 zM}Iu409dqS#RPXu#UFt69Vm$^7|* z4)uPqLztMAdxU?-f(5TJci7eKKIwkweb>(`ErPpcJC&KkNaB8F;R=LrEKvRF#it%E zIV%8IxMW2QI}k?OA*=!KyJJSXA0`t`N-~+O@MPi$1oR?5EDp!2+!;Kw_q>}I8fAz@&+?%TP#Qj*1%YN1l8pVee2oT zFLsR&d-t~}Rd=-jmxQBTz_&&LSE?v69 zz4yDj9;;R0kw|{M1?w|guqU?}rz=}gRBeK#jn3xhrN*q3Rzx%@GRJiCyK1v;{`1fO zQU9v|u;9J-{JfiO4yHL|V1JAqIozJb(#RU#H5;cC;s^Qp<@S`VQn6BlkQJaAKT=Vs zYmXofK-QwNveq62h@TUI=3 zp`RUs*L~Y{_ZHL1ymLi<*&BVSufJ5r5wp9qx+C z0E`NfSi-pX6Z4*abk#2gz?*Nr7hzW0s-*p4gHtek=pg=Z1OoEm(l|f$AexTdo)G)a z&#$zfr&9EIC*jjL_<_8^shETodLTs=6o^SN+IB7TZmVau6@9oy9!hiFvCvQc9k0E% zfLWo7_mCux3+Je+PQSrYd(?eeL&i-2TYCYr{9sOvvS?9d? z%;N<=8vuN|meuC?;IP31m>cNlumI#&MKEZ%GR5KvL%VK4i9irD zb>gwEUE{cgpir*7yw=6k%N48gpfJxwQ^`5njtbff{iM&NrXJwQE*dKS+uxQlHxldy zaN4#o&7We5-&bTrdPxiR z4aZ%)zHE6+lYt@qnld!$#I zky>KHQKtAkS$Y)L8u6P8YxarVy)j067-~VG?{u3={lNUWvkrF%0E^yQF^KIsPQHo( zpi5Gs%=|m8faDIONf;!=4+scn;s+Eq>h-N{CPe7_D0@htqa;*fVhm5H5FvD?O55uF zXEOh;rrt9!+`q%QPa}bg7QM!~#FQyF;I`XtS9~{hgUlKWb{86PqRfEJry5aOcNP@y zB194&Nohf3lcM;fMWqsMdtvTlYt9IOg-cgltrFmv_HrcyK&RL^hmt)3!PPyG5C{ki z?E#^_zLEL%DjveQ_B_fqk};ucQZApSj!|BKEDWszQdg&UGqZ99ND6Md_j@8{ZIeGa zaMII{;G>T|U;u8kr+*)m0SqW^v|(#rD^6FLu>Eu+GRs?Vu4Q~TZ;VwR;5@-D7PfiU z3r{`zWxD`){mqpVZEC?W9)0D|A&82IRP=Tc1WqnM+ny`~DXX=$)sX@7Boq%#ln+ zYSb9Vb!!Y(Y|d@Pac1%lJ68=ns9Xl~0Yo*6R?oDu+vGP;0gQ zJgu7Qv;c1{zmYwVV_B5pLxvzMI7Fdv$qIPt{qk)&KOi8qCuA*%AJ9uVEUWbKwAx3P zE^$1?OP{HzsNuuJo_n|FA`{Q#ukGGXspYL(H(}$(^}N?pfy+Y=%|c8}EI+TwEMRkv z0jb3%94|E>t)K}e%eh@_Y(no4yl`D7jO!WfI98=M<6m3zA!KiI9Akuh!~AFFOllhd zOIJ=;34$Yz9MrEb!a~A5l0SJ^C;>vW25QCobexZSx5E#}TF{I5K|w(Ui`R{AAdnP9 z1Triv5TT&~3|uC5ZZoeEV$6YA3Li(9`fEZz$`#Nc4^{shIIxf1R|`+@Or3fY1`Qg_ z&ox>|@vYdNZ$xf&D^q+knvLgf0TH^>X#>MCZ%QZD>jM<;<+J;#(Hr6Kqs4|@X=pAw z=6J8VvU0@IH(uV~1^|>CphwrPh>nQiCf>_S-G<3mw__QU+a#X&fdl|a$ix>FRV&Rj!PC zFs}hwIi-kFH9Lx5N>ri9PyNYpPHkKs+U}f z2r?p-Uc55MXl&)*Po>{_y`ES5N`^xMZGyZ)@&k0^h9dkhq zChq60G^6M&`+Hvo_y@0!!ZX*#Au-&sunKR>of&l~Eht5}y2YUjsVJ4&e%rAuSR2H} zP)#ON(aSIVc|6<9WiP7&0JJcpcTf$@YIQ(sX#XMnue_JjMcWGtotDAfO32TZ_(6LE zO_W6>l1LRvB0ms8AmtL|`2(r96FID}r{qxyLwqeC?4cTes{A2xL`wDX@#UkA^fxjx z3JD3F`HS{lL%#+_s@~t<$V`4S3})7gnk_t+Z>519!9Kvl9>FTuApFKa2xew{_ShIa zIX)IqLC&=lEbNQ7oTx%wNhw0qMn}=9*z=w3Pwl)mqY;|&LlR)D3;+g6)6z1&L6)7a-3{#qP(vo?B+DSrNxc!c^p z*TQZwS+Oa-0<9IL2+~*_JzY|^To=;*rtDUj3Y?2teDvNsH)my?ri33^0h0m%uA!h0 zBUV%qOyX3kQpp4axrskBQPjAFl+@q^0s=#OLItAb<#p^l8`_E%=-M=-Eb)$C68i1P zZNbYMs!`o+Lx{h9BB_hg=_R-UK(q!nW(};rAQ+%qnR!J77EkMpqzLEgW{n05Hl&q8 zs4j)S*2>#ZYHN4pOZ(z`6rq%z*y^~}>Tf@vy?@sZS__Y=ZE6$%pvj*a|M2}UeJO=p2CWH99KkgsDDUZH37o^u z9Si*m>dkm{LoK#uw;(!Lix59Ap3=3+lIvEJRfL$ErFC7lY_I+X4j8Mp&MX+6XTk&iJr&m{nyX`qSH!&O!F%)hs| z0YGjM2n00P!$qn!b0gBy1Xm7l=F>_@dFbF0!Kj9#(6oMkH&3OBzm_w_az06YQ3 z=HWa(X@*ggxf9~>+@wwj@Xg9P0{<9XpP{cd*ES)BBu1j$#J@Wrv6Z;H^zN7P2c4HLRDMFYq$K$20u*cU zb(AQIqlYSoE0ISEZGnLHJIW7;C{jhRJb&=Nqb*GNO^6KEVNhp(cr##%<{56jUJd{S zv6G+Q1}Ss}M~^5U{FO2LG2LZzEZCbr9xR2SC>uU%!HvMx>l;x~RgV0;EcETw6OD}P z(6n^3V1=)rABLn1uzyB{*@tex`!{@xf~Ep&DESWh!xk)T;c0nmz;ZXIpx9?atz4l|w0Q6GdhCCqK76rMvFaH9Eo% zsD7ZXt_fxJCd}WY$H7t)#`X$ET&T{Y(iMJN!R7^p;^mg2J$?|t$mgHO$Kw7gBNcvr zPgWf=(@!BlFepMfvgY;7%vaP@pryGPITVfxP%*!)sTgsiay74A&W6-;C1|(>yK3-|IjZ300}vmSi2>NCQIM9|G?x) z*H3#WA~H&`BwTP{5Ry7|W{vK&24^CQgcou8^qH0J+*i7pGw}m6)6m>+%CR|1k4gPP zSV*hxn6GzHdV7(8tJ$Y$V8-AuJUKoNVX{O{L3Jy3q-MffU#SS=BvW5fQH=bYOvHCe zKz(f;%FBy!^5jvx^wMj55>8xPCmx;bI5)`Fv{>1>0gcf*?u>*lp#oCFJZyYoH>d|-m`T0f3PwdQYGB_Yq;TAj* zMfxiic`7Y{YXM3}Kta+LKltHf3rZR+=)s6yPL&abbw-D>ToXICc9?xfNnuJSe>`_> z91HIp+?kIQu1hU|sU#O#m-PaS=2nzel%c+%4u|*eLQeK++;h(#So;YmDapstqX)5Q z(VH-_P?g3i$S$wnx(&D9IF(=Hll}j~$EtS_6<&|1fIt-HgkkfP!w$>x>DH5|&TtL@ z{!##tP%=8oZV3nw%o_Oz-g5h0xAyGaf2u~SaWETtupV8Lp%%OxVIzs$Er8lcjLw2l=%YtUlh1fr#?l9D@5oiX#ixVU)5&${{fim7C?$r(0^b$?<* zNR1=`qOF%_5VRdVNc><`dNY{5(Kp^tTpJjo!f3m!(S%bB2u(&?8(F-L`Fir(w+sx& zUBe={dy(XHSrZPXo`SZeP7&6TRMl0Xlqq`OjxET|&BWx%H?elnut*{`U(;Y8&~p8BIp)+_x9gr%th7SB0y;8;bbOR`e1k;jPi{IIN4_DB%4M zKY?HsYbjZWGc9=jiRrAPH2)d^a6Q_UA8iK$Li^bsN zvD)_a?q;8kU(q=Le;gTwm>}oR+SD|gu`M+Rt;~E&JVj#bjm-_nE6hb%Q3H{VQ!r5a>r9%oh{56?aK5{qO6WH1uAYu9Fc{PF)B0BB<5aQ~shn0Ean2dFAc zWjI-L0+W)im`1CCa)yK)LnB35)h<)$u0aGvba5`8B^XpjW=#hVgS&g zQ?QQrRs{$I`{I!7elp5iQN;K`M|^!uuooT}5y}0%Box-|I97(TQ>R#?SQR63t)^BM z%a`E5o}D;!a4!ZA9syd9ATRGU8XN0z#~lxF_i+695q2ySFTcEq-4_Ak1lFwi4xfDT z8J}oF&s9-Xg{<6sOddbREp(Lc)AOzTbPe=X&fmN$DJ=MQ`QP98;I{;TBt9~0Kw+aM zDk?Vm=G*SPJ0Y>_ScZOwZPa;rp+}cw7B;FKD{4^DrR%_u1O)j$0l~A<-E#*Y?yJYb z^<{W@dS|XUH8Wad38DgZT=SwkaDu?W56T%oXtH?p`#NTBZyFGWi9LfAVO@GbJ&qqb z0l}bG5Ih=VpA88LP&^^y}%8``0Mk%vZbfkS$9Avu70k_wk2+ zVE&&nfHaSg27_{bD*#9mY_|px_HFgRp~L!4oOI)ZpNAW-hVy`vUiAJgNh$#DuLdb0*f4A&vpMkRA4>W$cwnt|5JQtr;=>k!rJYjHZ`IJR#52|+<&yx63;IG0aWC7(|KIC0`IGwoHF zJ^M+v?}gOV-OTKtz`y?WF`AlMnfc#_)vLe8|Ni#{Pj%C?ee>g5Or10Vp&>zTgFsSE z89Rv%f!LMuDqQ! zgksn$!5%j18(UGEdeYzav7w6meyt#&lll%S{iolSkEJ!0Rx6{ z0OaK{u(Y;d+O*rb!qd|BqPn^gbLakrKVNF97RiaZg!7Pejo@ckt$p2BcQl z@Wi#T%EXQf*^3VHLVO702PzNzfc=XJ^g^E)X8~q$tpU4troqxA&dzm&b*#ZFYs#>F z%X*ZRh&6Z>3Z~Ov13&xfJpfSf@sDM1PBfg1bJ&Pu#=zTUNTA= zad5{z{_7G>lh4d+eKqsvr||tZpK(%`oZN@^_>z)bcB&PlMqSGRaQyfo&ie1ae-^u6 z9qZv6QC3#M;(X#|Dt!Cx7Yr18@F5G`$SrQ!vJpT2_&w&o^eXlpOk>KQ%zzT$@cCqU zs+!E$l9rF$LtDYoEfcfJ)U;*ePakaGvVn$wrJ3JUNkg>&WDShx0sw#*Hu5nAh(wWR z6R(+g-N>s(jl0L+-#pv1RQpZd#pYmoe+gV&>=9B9nz|2_vwwzo7Zv+uzdLkJVai#>N5_2k3RZ@*Fo;uyB9@e6?_@~ zVM7M;yozM@TTC`=IbMp4{aaveb)SM(TV0j&)#o3-UyzqW%BCVv@(JW)i|rsNloWF= zMGI#(k@$fZlYm?AxNmx|z9}~{W%|lb?vjwmvx%<1{M8Wtu~ZI#TW-0BTZA2q6jGV`>#zTv{|3Q_AFkv8pe5!Aw>dNxno~5<5Rex~*p3NJ6`fi8CVxdeQ`Fis6(vT@l1|ds81jVsX z@%aLPB&7UkI}oV5X@*}tYS1;~ue(1eIHZgGL<$>YB4W|ftaJ;WM-#PJctAj4SO{*v zGUALkp-BJQ`N5Tm0T>i7CVJNII)#SP5(VonV9NgHi~n(jlJZHx1qGS>{E;Ikg1I#u zI<%Y5MY#9ghuJxP%%`v6lU9~3dyi*8Klorda&ofp*3x&dXa6Dg{Z_8{_&8_954|#3 zByu1%4W-$~-R|9Dwir(wOWXOw>aVu6G&R-P6;Dd9hiLX;2LkPr1yGoc^9=wJPuWE8 zo2K7>eahgWx9W7>LGqL1V`Jg#708#7QvyLbdiYwZ8gX&qm@(|k0FXqU0UX~g2wlU) z((Lbk+zp$_BxBtI4j)g$>aRZIvyDjkqRBtbdBOPcQ#kTEn2GmiJ$@|*z`})ZBRDu1@4dGS<>jSVy7XP--`DEMFq##{;+CYer`^IUFlZ4;w4{CA0lf& z{=U}!@>olEApt-V>hTgkplwb60YiFCy8fmI!onjIwTblebe&`4-NHta|K<6>8XS$g zu8#agH!-n0b2%(5tZy-6$ELlC(rkTm1NNux$00`8MCJSQzlRU+;Q%6^@6Y(h#*N=| zK)mtBJG`m?@BiLGNLU0qC3Zu%E}fCW*uAfhb0u>cG(DVKg~K~H!sMaask*WvZ{xZj z)*d^0m}d4+FDLYqlF8=__I(0E1Dqzm-Px-bA^=Fp&Pqin^p{AZ*L72G9(Tovk$3v| z`YP-?O=JxT2)C~XD9XlCFQgeG@br{Uzvu=g^$12(fEQ{R=h(MBRhD?6dc8XA+rJN| zjvciFz>k~!y?eKE0Nj1|!$?Z%g0H^%5BK@6zy3A~ii>e7GZS6ABw^^l6a)tNImn&B zP;#QU0jayTLSHXVRxL9X;dJX!)Y+<0W2rJ#8OxfDs#byZ_a?!BM#02-wH~>`LF~5` z@_BxepC>>N+3V1{G#4rWB%y4gya+|h8ajB!?f2f+qi3HfYD%cfq)S3)s01A&Mpk4t zXz*TMDBijw=@)(Rl%Bx|_xD1z-iX6{k0?gnYU--7@4$ZKXJ_)>Ps*p))~#zr{_)x} zX7YoWssAgYW8%=g_W-_%*s#F^`OoS}u7s>sPE{-R@7;~+vLaNQE3n_N4Vkv%Xi(L3 z^i~C-1=-BtZ!z!3avTS(B-!CP>lZozB%y4g#1AMoQ+Mswv&+<*Z@DifrqfXQi8R{S zm4}TMym;6T4^K`;oU9DHqcXL32ts|esBCP-vDD*=5U{ek3aJMVpuD8mp?vc3+qSLc zVe88;zljFD9*2(}MtFEQUve)dI$FW(OBzf#ly(I987HB)G+;~14>)Su2b;>tX(-DW z7E1M&%onm2@MA2giP5+Qz4)rDce!aB^g<2(Y2Jvp86?Uex`cM+_W}UvUZrdzId+QC zw4<(>IAZje3HSO31}bcQNKi0}tZ~@c6oH4YiTT-Ic4MCqK0TW-kpnN7H2&;TTLj#rj@w_1^QA`2%Di*fzx?D>V|R?YvM(ZJ^XoezH}?%i zfVT!^bq3_JR+jf(8kNh=%|%N?JyKEz@et3#*!s@h+YlHUh5>#1qF48>ii#kEMZk&t zQXJS$Gj%D{wBmdHe{odU@6bfgZotUl4CTzmc`>Ea{MXzH*4tUH*BjV%gdnKA>Ji8+ zK^U_NJ>$T)DN$O&0>Q1jfg)+mNLrV=9Isp7XVyRr1wG2|5de}<+E|`V)W&q`6npcG zJMWI~oHSaVO>AVw!W2IO{kw)L3OU-78U4ff+IuCnEhx^)Q@8-K07p-rWT9wRo(HIJ ztVdN%HD6e>U+V&<^JF9kB_q}^mRSKUj8-E`noDq^?gW0!{}Fp@e?VMp83rba16bL4 zz~*g0tDOQ0_4wNS4*m==58yVN=JyN$Nr)3jMJPOM96bEWlnK{fe}70wSU35J)w+22 zc1}Uhc>gnA^tO~RzEDGPO*1N(eU)bc$-Hmdy@xfjkss^cH3KrRjp}4LE zJGU`r-{5rCR3-GEhQFggCH|;*LOd{bG?_6VJ)iabrmL}d*jpG8J)%PoPf^F0IbUMY z(Rt{ckc)1yqH9>cnS}&(_V291N0ybKVvthT&tD7xAfY4?0YC~HDXFBpY5L6T1`Qo? zo6g(YQL9Z^zRKYKi0{$`v7v2~!y6b03}Ga&sJa=o%;d`xL8Np;tAPQ*jL7gXPW+tj zi9@t|_Uu7fbnF=jaWcZ+81TH|)1QAvSFV$nk(13+VWxm(et>pXngZZKLIvp5*e4cG`7F}&CSAPEgDNply-EvS3?2Xr;Il8M!!m_<-Au*lboy#;KG0R)7E5 zHp7GUkE?tTOg~0G_8N9m40ma#qw(#;joioo8j*wHK;;2Ead0}W>SF>eg0^J~O_*ip zG~tkWDehpWg0Y(Z01l_HdLZ~=i4yy9}~-LcKBAt`5Hke_>G&FZh$l@t{eYo}qdIt4e- zdn2x9%#}eiHNywXM|_2pu#}EGPlrST!dJOp;on8ipnoC@6;A=DPl)f^j^HuN_n>uy ztEK0>*oERhDTzct(9)E)8F$=$OV8eYr)o7?$7)PQs~Xi|gOS)J4lyC#2=&!qBy$Bd z((9EyXz>#F?rHRqvi&T(F_uQiTw)J`-6gkjNCYUKK?r%+L3rv z{F$^PwD*?4!^Ow;-GU+A&B)IMPT9)|ESqtsZ8vBk;i^js03`Ih@*)&IrR}QGqe%D$OlTwflGN+_Yumnte8#jgUdAA?if~GdAs`cvT&NA%4vFUvU-d{md^< zkD8B32`+0lJG3D{rPx$XCCX!$q(inCl6 zejy8WJ88`Watk_|(l+hZyKYPwFl2_8&MTlJ7crTPEk_QgZu@EV*V`G(ry*EU0gcJi zw&)uIq0&8pRm^L6$0q?@x&y}wba?;jui&Gxdmokk_e~s2*2xtvc(ep^gCWQ!x5(ck zD{#8*G~UgA63NW=9Z6+Yih)mPVQ%0p(2qi9UaA0)gtCbeKj2|wL{wDN)M+zkbWQGd zjaKXB=jlVF_{@w`sXu=A<)+5^dLmQAs44eGikHTuX}?x`1BR;yVI>{tJA^S&1}#JF zV7xfwMSha}2PafeZVMhPfh0~Pi~q?%AWd+AecIa-dmlp2#99;=vMw+Fpon04593gY z^h+H8lDK9Q)xlw5(PPI>x;i2{Ix#RXIL=}*nOmBh_4)a^*}JxGN;jEWrNT?9$RSfN zug0mhAFI>O!ky|Uo{z_17WeBJGZ^4=C$3Mrp3g_%3uSpwzWnzNJlS^F9xn%gG_ghc zyW;o?s6+Okk-_tHn*Ao%;$B-SHeUvSQ=}i-3Y?|1F}a>es)oA~#uoK>jS zuBTB#9Ji+`Z2R$yWj(&U3;=hbY@#&U$fvYH)B*jalp*zc3!G!^oaw_^ibcs+M>UT2 zNqndd!~@<8LOlinmF$e$JO3G7g1T^ptL*?#SOX7MKynGvH%b6-ozA8JfgJ!_i?`vF z={xu`5T@JfORcByru8elcNqX}3uP0flrl|e)49A)AfS}0RFg+#SZ=YQZZ7`EVvRd| zSP!qG=wQtuLnD5t@U|-{B z@MX|Gwnw~_H3R>!et~x{1E77O_8}KQmVgg1LF{;B?g;=C>NP<23mmTE^*H{n3dNta z?32mN0yHrWa8ukv_$vS37#1}QBceybTcd+U4gj_2k6c}WB$Ds9$<{WIdb>EyP5hfy zbr9(_>F6JN1&%ha=69WC|6xGp|6gW2;IqpB=(vzhyzPHU`O-|=c18OL=BcBxkQCT$ zFbffw60VE84@YbFqS%m$054zk3hjg5At?yeg}GS*seD0l1#vH2OU$qP6h(4{jZLN4WYUS1Zacct@eS={-S~sv(3cE|EW5t z&Q#5mU(GCwl`EVSZ?gYY+x+lI_m}Xu2JTlu^1n9Cl;m8MZK{J&5Wwn+82ni z?ZS(eExcm*l1~Mn6VXn<81W+wYYh%QK*HmGyV=)R!w{ps0)4%w!;6KMIW33r zbLyJ;{cW*mkD-pu2FsH|uZveBw8XSTW?R#gk19;USgGj%7jizRS(P-8B}zJ|}S zqv#0InR;nW2^RgqY+nh;)_{|im3Wq!eo{WYF8Z?Y3t1x6<1k)(CEkaI4>&=?bgc^) z#{fEo0ateS!QhA?Nbx7i^16HkZ$=e7NU;( ze43_o(M}Efy$Q8@EaH*ubt{&t0^wZafJFvsrhJvJIB`T?CrIVpt+KVTcvg@ydn~@U zkx`dbsM`whljRe<%fLVjNYUEBv|hkPIXU$AEL3?EtC^0O>hAahvj&cZ3`kQd8hfMx zXnQFN&jb>6vx+Z)%1%r!6+?PtSr6dfw%wrGpK|-_qMROnv4}X0%?A-)({UHG3e!|R z__+%k2~6?1wo~}Vx{lZT6ZfYIB~t!Hw?M?jC{$xWMJHqtLevA$Q{5k95Q$-A6TnS*5_KsGd4B?eRGlonNG!4!0e}>5`UT&C Z{|BD;QKr$>jbQ))002ovPDHLkV1n5RMR5QC literal 0 HcmV?d00001 diff --git a/icons/redfirewall2.png b/icons/redfirewall2.png new file mode 100644 index 0000000000000000000000000000000000000000..e611d8967f2700a0b1421b4a7d8176cbad1acfeb GIT binary patch literal 18054 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 literal 0 HcmV?d00001 diff --git a/qubesmanager/appmenu_select.py b/qubesmanager/appmenu_select.py index 5544ce9..40ece49 100755 --- a/qubesmanager/appmenu_select.py +++ b/qubesmanager/appmenu_select.py @@ -39,9 +39,10 @@ from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, Pro import subprocess import time -import threading + from operator import itemgetter +from thread_monitor import * from multiselectwidget import * whitelisted_filename = 'whitelisted-appmenus.list' @@ -51,22 +52,6 @@ class AppListWidgetItem(QListWidgetItem): super(AppListWidgetItem, self).__init__(name, parent) self.filename = filename -class ThreadMonitor(QObject): - def __init__(self): - self.success = True - self.error_msg = None - self.event_finished = threading.Event() - - def set_error_msg(self, error_msg): - self.success = False - self.error_msg = error_msg - self.set_finished() - - def is_finished(self): - return self.event_finished.is_set() - - def set_finished(self): - self.event_finished.set() class AppmenuSelectManager: diff --git a/qubesmanager/backup.py b/qubesmanager/backup.py index 8d223f1..5150cc2 100644 --- a/qubesmanager/backup.py +++ b/qubesmanager/backup.py @@ -30,6 +30,7 @@ from qubes.qubes import QubesVmCollection from qubes.qubes import QubesException from qubes.qubes import QubesDaemonPidfile from qubes.qubes import QubesHost +from qubes import qubesutils import qubesmanager.resources_rc @@ -37,9 +38,12 @@ from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, Pro import subprocess import time -import threading +from thread_monitor import * from operator import itemgetter +from datetime import datetime +from string import replace + from ui_backupdlg import * from multiselectwidget import * @@ -47,40 +51,255 @@ from multiselectwidget import * class BackupVMsWindow(Ui_Backup, QWizard): - def __init__(self, parent=None): + __pyqtSignals__ = ("backup_progress(int)",) + + excluded = [] + to_backup = [] + + def __init__(self, app, qvm_collection, blk_manager, parent=None): super(BackupVMsWindow, self).__init__(parent) + self.app = app + self.qvm_collection = qvm_collection + self.blk_manager = blk_manager + + self.backup_dir = None + self.func_output = [] + + for vm in self.qvm_collection.values(): + if vm.qid == 0: + self.vm = vm + break; + + assert self.vm != None + self.setupUi(self) - self.selectVMsWidget = MultiSelectWidget(self) - self.verticalLayout.insertWidget(1, self.selectVMsWidget) + self.dir_line_edit.setReadOnly(True) + + self.select_vms_widget = MultiSelectWidget(self) + self.verticalLayout.insertWidget(1, self.select_vms_widget) - self.selectVMsWidget.available_list.addItem("netVM1") - self.selectVMsWidget.available_list.addItem("appVM1") - self.selectVMsWidget.available_list.addItem("appVM2") - self.selectVMsWidget.available_list.addItem("templateVM1") - self.connect(self, SIGNAL("currentIdChanged(int)"), self.current_page_changed) + self.connect(self.dev_combobox, SIGNAL("activated(int)"), self.dev_combobox_activated) + self.connect(self, SIGNAL("backup_progress(int)"), self.progress_bar.setValue) + self.select_vms_page.isComplete = self.has_selected_vms + self.select_dir_page.isComplete = self.has_selected_dir + #FIXME + #this causes to run isComplete() twice, I don't know why + self.select_vms_page.connect(self.select_vms_widget, SIGNAL("selected_changed()"), SIGNAL("completeChanged()")) - - def reject(self): - self.done(0) + self.__fill_vms_list__() + self.__fill_devs_list__() - def save_and_apply(self): - pass - - @pyqtSlot(name='on_selectPathButton_clicked') - def selectPathButton_clicked(self): - self.path = self.pathLineEdit.text() - newPath = QFileDialog.getExistingDirectory(self, 'Select backup directory.') - if newPath: - self.pathLineEdit.setText(newPath) - self.path = newPath - - def current_page_changed(self, id): - self.button(self.CancelButton).setDisabled(id==3) + def __fill_vms_list__(self): + for vm in self.qvm_collection.values(): + if vm.is_running() and vm.qid != 0: + self.excluded.append(vm.name) + continue + if vm.is_appvm() and vm.internal: + self.excluded.append(vm.name) + continue + + if vm.is_template() and vm.installed_by_rpm: + self.excluded.append(vm.name) + continue + + self.to_backup.append(vm.name) + self.select_vms_widget.available_list.addItem(vm.name) + + def __fill_devs_list__(self): + self.dev_combobox.clear() + self.dev_combobox.addItem("None") + for a in self.blk_manager.attached_devs: + if self.blk_manager.attached_devs[a]['attached_to']['vm'] == self.vm.name : + att = a + " " + unicode(self.blk_manager.attached_devs[a]['size']) + " " + self.blk_manager.attached_devs[a]['desc'] + self.dev_combobox.addItem(att, QVariant(a)) + for a in self.blk_manager.free_devs: + att = a + " " + unicode(self.blk_manager.free_devs[a]['size']) + " " + self.blk_manager.free_devs[a]['desc'] + self.dev_combobox.addItem(att, QVariant(a)) + self.dev_combobox.setCurrentIndex(0) #current selected is null "" + self.prev_dev_idx = 0 + self.dir_line_edit.clear() + self.dir_line_edit.setEnabled(False) + self.select_path_button.setEnabled(False) + + def __check_if_mounted__(self, dev_path): + mounts_file = open("/proc/mounts") + for m in list(mounts_file): + if m.startswith(dev_path): + print m + return m.split(" ")[1] + return None + + def __mount_device__(self, dev_path): + try: + mount_dir_name = "backup" + replace(str(datetime.now()),' ', '-').split(".")[0] + pmount_cmd = ["pmount", dev_path, mount_dir_name] + res = subprocess.check_call(pmount_cmd) + print "pmount device res: ", res + except Exception as ex: + QMessageBox.warning (None, "Error mounting selected device!", "ERROR: {0}".format(ex)) + return None + if res == 0: + self.dev_mount_path = "/media/"+mount_dir_name + return self.dev_mount_path + + def __umount_device__(self, dev_mount_path): + try: + pumount_cmd = ["pumount", dev_mount_path] + res = subprocess.check_call(pumount_cmd) + print "pumount device res: ", res + except Exception as ex: + QMessageBox.warning (None, "Could not unmount backup device!", "ERROR: {0}".format(ex)) + + + + def __enable_dir_line_edit__(self, boolean): + self.dir_line_edit.setEnabled(boolean) + self.select_path_button.setEnabled(boolean) + + + def dev_combobox_activated(self, idx): + print self.dev_combobox.currentText() + if idx == self.prev_dev_idx: #nothing has changed + return + #there was a change + self.prev_dev_idx = idx + + self.dir_line_edit.setText("") + self.backup_dir = None + self.dev_mount_path = None + self.__enable_dir_line_edit__(False) + + if self.dev_combobox.currentText() != "None": #An existing device chosen + dev_name = str(self.dev_combobox.itemData(idx).toString()) + + if dev_name in self.blk_manager.free_devs: + if dev_name.startswith(self.vm.name): # originally attached to dom0 + dev_path = "/dev/"+dev_name.split(":")[1] + print "device from dom0 - no need to attach" + + else: # originally attached to another domain, eg. usbvm + print "device from " + dev_name.split(":")[0] + #attach it to dom0, then treat it as an attached device + self.blk_manager.attach_device(self.vm, dev_name) + + if dev_name in self.blk_manager.attached_devs: #is attached to dom0 + print "device attached as " + self.blk_manager.attached_devs[dev_name]['attached_to']['frontend'] + assert self.blk_manager.attached_devs[dev_name]['attached_to']['vm'] == self.vm.name + + dev_path = "/dev/" + self.blk_manager.attached_devs[dev_name]['attached_to']['frontend'] + + #check if device mounted + self.dev_mount_path = self.__check_if_mounted__(dev_path) + if self.dev_mount_path != None: + self.__enable_dir_line_edit__(True) + else: + self.dev_mount_path = self.__mount_device__(dev_path) + if self.dev_mount_path != None: + self.__enable_dir_line_edit__(True) + + self.select_dir_page.emit(SIGNAL("completeChanged()")) + + + + @pyqtSlot(name='on_select_path_button_clicked') + def select_path_button_clicked(self): + self.backup_dir = self.dir_line_edit.text() + file_dialog = QFileDialog() + file_dialog.setReadOnly(True) + new_path = file_dialog.getExistingDirectory(self, "Select backup directory.", self.dev_mount_path) + if new_path: + self.dir_line_edit.setText(new_path) + self.backup_dir = new_path + self.select_dir_page.emit(SIGNAL("completeChanged()")) + + def validateCurrentPage(self): + if self.currentPage() is self.select_vms_page: + for i in range(self.select_vms_widget.available_list.count()): + vmname = self.select_vms_widget.available_list.item(i).text() + self.excluded.append(vmname) + return True + + def gather_output(self, s): + self.func_output.append(s) + + def update_progress_bar(self, value): + print "progress bar value: ", value + self.emit(SIGNAL("backup_progress(int)"), value) + + + def __do_backup__(self, thread_monitor): + print "doiing backup" + msg = [] + try: + qubesutils.backup_do(str(self.backup_dir), self.files_to_backup, self.update_progress_bar) + #simulate_long_lasting_proces(10, self.update_progress_bar) + except Exception as ex: + print "got exception from backup" + msg.append(str(ex)) + + if len(msg) > 0 : + thread_monitor.set_error_msg('\n'.join(msg)) + + thread_monitor.set_finished() + + + def current_page_changed(self, id): + if self.currentPage() is self.confirm_page: + del self.func_output[:] + self.files_to_backup = qubesutils.backup_prepare(str(self.backup_dir), exclude_list = self.excluded, print_callback = self.gather_output) + for i in self.excluded: + print i + self.textEdit.setReadOnly(True) + self.textEdit.setFontFamily("Monospace") + self.textEdit.setText("\n".join(self.func_output)) + for i in self.func_output: + print i + + for s in self.files_to_backup: + print s + + elif self.currentPage() is self.commit_page: + self.button(self.CancelButton).setDisabled(True) + self.button(self.FinishButton).setDisabled(True) + print "butons disabled" + self.thread_monitor = ThreadMonitor() + thread = threading.Thread (target= self.__do_backup__ , args=(self.thread_monitor,)) + thread.daemon = True + print "will start thread" + thread.start() + + while not self.thread_monitor.is_finished(): + self.app.processEvents() + time.sleep (0.1) + + if not self.thread_monitor.success: + QMessageBox.warning (None, "Backup error!", "ERROR: {1}".format(self.vm.name, self.thread_monitor.error_msg)) + + self.__umount_device__(self.dev_mount_path) + self.button(self.FinishButton).setEnabled(True) + + + def has_selected_vms(self): + print "isComplete called" + return self.select_vms_widget.selected_list.count() > 0 + + def has_selected_dir(self): + return self.backup_dir != None + + +def simulate_long_lasting_proces(period, progress_callback): + for i in range(period): + progress_callback((i*100)/period) + time.sleep(1) + + progress_callback(100) + return 0 + # Bases on the original code by: # Copyright (c) 2002-2007 Pascal Varet @@ -113,7 +332,7 @@ def main(): app = QApplication(sys.argv) app.setOrganizationName("The Qubes Project") app.setOrganizationDomain("http://qubes-os.org") - app.setApplicationName("Qubes Restore VMs") + app.setApplicationName("Qubes Backup VMs") sys.excepthook = handle_exception diff --git a/qubesmanager/main.py b/qubesmanager/main.py index bfbc1e4..9e666d1 100755 --- a/qubesmanager/main.py +++ b/qubesmanager/main.py @@ -42,12 +42,12 @@ from settings import VMSettingsWindow from restore import RestoreVMsWindow from backup import BackupVMsWindow from global_settings import GlobalSettingsWindow +from thread_monitor import * from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent import subprocess import time -import threading from datetime import datetime,timedelta updates_stat_file = 'last_update.stat' @@ -486,23 +486,6 @@ class VmShutdownMonitor(QObject): else: QTimer.singleShot (vm_shutdown_timeout, self.check_if_vm_has_shutdown) -class ThreadMonitor(QObject): - def __init__(self): - self.success = True - self.error_msg = None - self.event_finished = threading.Event() - - def set_error_msg(self, error_msg): - self.success = False - self.error_msg = error_msg - self.set_finished() - - def is_finished(self): - return self.event_finished.is_set() - - def set_finished(self): - self.event_finished.set() - class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): row_height = 30 @@ -1105,7 +1088,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): @pyqtSlot(name='on_action_backup_triggered') def action_backup_triggered(self): - backup_window = BackupVMsWindow() + backup_window = BackupVMsWindow(app, self.qvm_collection, self.blk_manager) backup_window.exec_() @@ -1151,8 +1134,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): action = self.blk_menu.addAction(QIcon(":/remove.png"), str) action.setData(QVariant(d)) - if self.blk_menu.isEmpty() and len(self.blk_manager.free_devs) > 0: + if len(self.blk_manager.free_devs) > 0: for d in self.blk_manager.free_devs: + if d.startswith(vm.name): + continue str = "Attach " + d + " " + unicode(self.blk_manager.free_devs[d]['size']) + " " + self.blk_manager.free_devs[d]['desc'] action = self.blk_menu.addAction(QIcon(":/add.png"), str) action.setData(QVariant(d)) diff --git a/qubesmanager/multiselectwidget.py b/qubesmanager/multiselectwidget.py index fbedf72..a9de974 100644 --- a/qubesmanager/multiselectwidget.py +++ b/qubesmanager/multiselectwidget.py @@ -5,6 +5,8 @@ from ui_multiselectwidget import * class MultiSelectWidget(Ui_MultiSelectWidget, QWidget): + __pyqtSignals__ = ("selected_changed()",) + def __init__(self, parent=None): super(MultiSelectWidget, self).__init__() self.setupUi(self); @@ -23,18 +25,20 @@ class MultiSelectWidget(Ui_MultiSelectWidget, QWidget): item = src.takeItem(row) dst.addItem(item) dst.sortItems() + self.emit(SIGNAL("selected_changed()")) def add_selected(self): self.switch_selected(self.available_list, self.selected_list) def remove_selected(self): - self.switch_selected(self.selected_list, self.available_list) - + self.switch_selected(self.selected_list, self.available_list) + def move_all(self, src, dst): while src.count() > 0: item = src.takeItem(0) dst.addItem(item) dst.sortItems() + self.emit(SIGNAL("selected_changed()")) def add_all(self): self.move_all(self.available_list, self.selected_list) diff --git a/qubesmanager/settings.py b/qubesmanager/settings.py index ef9a1a7..9ca2475 100644 --- a/qubesmanager/settings.py +++ b/qubesmanager/settings.py @@ -145,7 +145,7 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog): thread_monitor.set_finished() return #self.fw_model.apply_rules() - #self.AppListManager.save_appmenu_select_changes() + self.AppListManager.save_appmenu_select_changes() thread_monitor.set_finished() def current_tab_changed(self, idx): diff --git a/qubesmanager/thread_monitor.py b/qubesmanager/thread_monitor.py new file mode 100644 index 0000000..4d5e915 --- /dev/null +++ b/qubesmanager/thread_monitor.py @@ -0,0 +1,44 @@ +#!/usr/bin/python2.6 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2011 Marek Marczykowski +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# + + +from PyQt4.QtCore import * + +import threading + +class ThreadMonitor(QObject): + def __init__(self): + self.success = True + self.error_msg = None + self.event_finished = threading.Event() + + def set_error_msg(self, error_msg): + self.success = False + self.error_msg = error_msg + self.set_finished() + + def is_finished(self): + return self.event_finished.is_set() + + def set_finished(self): + self.event_finished.set() + diff --git a/restoredlg.ui b/restoredlg.ui index 8ff2cee..9c9d244 100644 --- a/restoredlg.ui +++ b/restoredlg.ui @@ -19,7 +19,7 @@ QWizard::NoBackButtonOnLastPage|QWizard::NoBackButtonOnStartPage - + @@ -111,7 +111,7 @@ - + @@ -184,7 +184,7 @@ - + @@ -235,7 +235,7 @@ p, li { white-space: pre-wrap; } - +