1212#endif
1313
1414static int r2pm_install (RList * targets , bool uninstall , bool clean , bool force , bool global );
15+ static bool r2pm_bindir_in_path = false;
1516
1617static const char * helpmsg =
1718 "Usage: r2pm [-flags] [pkgs...]\n"
@@ -203,6 +204,139 @@ static char *r2pm_dbdir(void) {
203204 return res ;
204205}
205206
207+ static bool path_has_dir (const char * path , const char * dir ) {
208+ char * ptr , * path_copy , * entry ;
209+ if (R_STR_ISEMPTY (path ) || R_STR_ISEMPTY (dir )) {
210+ return false;
211+ }
212+ path_copy = strdup (path );
213+ if (!path_copy ) {
214+ return false;
215+ }
216+ entry = path_copy ;
217+ do {
218+ ptr = strchr (entry , R_SYS_ENVSEP [0 ]);
219+ if (ptr ) {
220+ * ptr = '\0' ;
221+ }
222+ if (!strcmp (entry , dir )) {
223+ free (path_copy );
224+ return true;
225+ }
226+ if (ptr ) {
227+ entry = ptr + 1 ;
228+ }
229+ } while (ptr );
230+ free (path_copy );
231+ return false;
232+ }
233+
234+ static const char * r2pm_shellrc_name (void ) {
235+ char * shell = r_sys_getenv ("SHELL" );
236+ const char * res = ".profile" ;
237+ if (R_STR_ISNOTEMPTY (shell )) {
238+ const char * shell_name = r_str_lchr (shell , '/' );
239+ shell_name = shell_name ? shell_name + 1 : shell ;
240+ if (!strcmp (shell_name , "bash" )) {
241+ res = ".bashrc" ;
242+ } else if (!strcmp (shell_name , "zsh" )) {
243+ res = ".zshrc" ;
244+ }
245+ }
246+ free (shell );
247+ return res ;
248+ }
249+
250+ static void r2pm_suggest_bindir_in_shellrc (void ) {
251+ char * bindir = r_sys_getenv ("R2PM_BINDIR" );
252+ const char * shellrc ;
253+ if (R_STR_ISEMPTY (bindir )) {
254+ free (bindir );
255+ return ;
256+ }
257+ shellrc = r2pm_shellrc_name ();
258+ R_LOG_INFO ("Your shell PATH does not include %s" , bindir );
259+ R_LOG_INFO ("Add it to ~/%s with:" , shellrc );
260+ R_LOG_INFO (" printf '\\nexport PATH=\"$PATH:%s\"\\n' >> ~/%s" , bindir , shellrc );
261+ free (bindir );
262+ }
263+
264+ static bool list_has_string (RList * list , const char * name ) {
265+ RListIter * iter ;
266+ const char * entry ;
267+ if (!list || !name ) {
268+ return false;
269+ }
270+ r_list_foreach (list , iter , entry ) {
271+ if (!strcmp (entry , name )) {
272+ return true;
273+ }
274+ }
275+ return false;
276+ }
277+
278+ static RList * r2pm_bindir_snapshot (void ) {
279+ char * bindir = r_sys_getenv ("R2PM_BINDIR" );
280+ if (R_STR_ISEMPTY (bindir )) {
281+ free (bindir );
282+ return NULL ;
283+ }
284+ RList * files = r_sys_dir (bindir );
285+ free (bindir );
286+ return files ;
287+ }
288+
289+ static RList * r2pm_bindir_new_files (RList * before , RList * after ) {
290+ RListIter * iter ;
291+ const char * file ;
292+ RList * res = r_list_newf (free );
293+ if (!res || !after ) {
294+ r_list_free (res );
295+ return NULL ;
296+ }
297+ r_list_foreach (after , iter , file ) {
298+ if (* file == '.' ) {
299+ continue ;
300+ }
301+ if (!list_has_string (before , file )) {
302+ r_list_append (res , strdup (file ));
303+ }
304+ }
305+ return res ;
306+ }
307+
308+ static void r2pm_report_new_bindir_files (const char * pkg , RList * new_files ) {
309+ RListIter * iter ;
310+ const char * file ;
311+ char * bindir = r_sys_getenv ("R2PM_BINDIR" );
312+ RStrBuf * sb ;
313+ char * files ;
314+ if (R_STR_ISEMPTY (bindir ) || !new_files || r_list_empty (new_files )) {
315+ free (bindir );
316+ return ;
317+ }
318+ sb = r_strbuf_new ("" );
319+ if (!sb ) {
320+ free (bindir );
321+ return ;
322+ }
323+ r_list_foreach (new_files , iter , file ) {
324+ if (!r_strbuf_length (sb )) {
325+ r_strbuf_appendf (sb , "%s" , file );
326+ } else {
327+ r_strbuf_appendf (sb , ", %s" , file );
328+ }
329+ }
330+ files = r_strbuf_drain (sb );
331+ R_LOG_INFO ("New files in %s after installing %s: %s" , bindir , pkg , files );
332+ R_LOG_INFO ("Run them from your shell with 'r2pm -r <programname>'" );
333+ if (!r2pm_bindir_in_path ) {
334+ r2pm_suggest_bindir_in_shellrc ();
335+ }
336+ free (files );
337+ free (bindir );
338+ }
339+
206340static char * r2pm_pkgdir (void ) {
207341 return r_xdg_datadir ("r2pm/pkg" );
208342}
@@ -562,6 +696,9 @@ static void r2pm_setenv(R2Pm *r2pm) {
562696 free (pkgcfg );
563697
564698 char * r2pm_bindir = r_str_newf ("%s/bin" , r2_prefix );
699+ char * path = r_sys_getenv ("PATH" );
700+ r2pm_bindir_in_path = path_has_dir (path , r2pm_bindir );
701+ free (path );
565702 r_sys_mkdirp (r2pm_bindir );
566703 r_sys_setenv ("R2PM_BINDIR" , r2pm_bindir );
567704 r_sys_setenv_sep ("PATH" , r2pm_bindir , false);
@@ -940,6 +1077,7 @@ static int r2pm_install_pkg(const char *pkg, bool clean, bool global) {
9401077 }
9411078 char * srcdir = r2pm_gitdir ();
9421079 R_LOG_DEBUG ("Entering %s" , srcdir );
1080+ RList * bindir_before = r2pm_bindir_snapshot ();
9431081 char * qjs_script = r2pm_get (pkg , "\nR2PM_INSTALL_QJS() {\n" , TT_CODEBLOCK );
9441082 if (qjs_script ) {
9451083 int res = 0 ;
@@ -950,6 +1088,9 @@ static int r2pm_install_pkg(const char *pkg, bool clean, bool global) {
9501088 int child = fork ();
9511089 if (child == -1 ) {
9521090 R_LOG_ERROR ("Cannot find radare2 in PATH" );
1091+ free (qjs_script );
1092+ r_list_free (bindir_before );
1093+ free (srcdir );
9531094 return -1 ;
9541095 }
9551096 if (child ) {
@@ -963,15 +1104,24 @@ static int r2pm_install_pkg(const char *pkg, bool clean, bool global) {
9631104 R_LOG_WARN ("r2pm.qjs support is experimental" );
9641105 res = 1 ;
9651106#endif
1107+ if (res == 0 ) {
1108+ RList * bindir_after = r2pm_bindir_snapshot ();
1109+ RList * new_files = r2pm_bindir_new_files (bindir_before , bindir_after );
1110+ r2pm_report_new_bindir_files (pkg , new_files );
1111+ r_list_free (new_files );
1112+ r_list_free (bindir_after );
1113+ }
9661114 // run script!
9671115 free (qjs_script );
1116+ r_list_free (bindir_before );
9681117 free (srcdir );
9691118 return res ;
9701119 }
9711120#if R2__WINDOWS__
9721121 char * script = r2pm_get (pkg , "\nR2PM_INSTALL_WINDOWS() {\n" , TT_CODEBLOCK );
9731122 if (!script ) {
9741123 R_LOG_ERROR ("This package does not have R2PM_INSTALL_WINDOWS instructions" );
1124+ r_list_free (bindir_before );
9751125 return 1 ;
9761126 }
9771127 script = r_str_replace_all (script , "\r\n" , " & " );
@@ -985,10 +1135,20 @@ static int r2pm_install_pkg(const char *pkg, bool clean, bool global) {
9851135 }
9861136 int res = r_sandbox_system (s , 1 );
9871137 free (s );
1138+ if (res == 0 ) {
1139+ r2pm_register (pkg , global );
1140+ RList * bindir_after = r2pm_bindir_snapshot ();
1141+ RList * new_files = r2pm_bindir_new_files (bindir_before , bindir_after );
1142+ r2pm_report_new_bindir_files (pkg , new_files );
1143+ r_list_free (new_files );
1144+ r_list_free (bindir_after );
1145+ }
1146+ r_list_free (bindir_before );
9881147#else
9891148 char * script = r2pm_get (pkg , "\nR2PM_INSTALL() {\n" , TT_CODEBLOCK );
9901149 if (!script ) {
9911150 R_LOG_ERROR ("Cannot find '%s' package or missing R2PM_INSTALL block" , pkg );
1151+ r_list_free (bindir_before );
9921152 free (srcdir );
9931153 return 1 ;
9941154 }
@@ -1004,6 +1164,7 @@ static int r2pm_install_pkg(const char *pkg, bool clean, bool global) {
10041164 if (have_builddir && !r_file_is_directory (pkgdir )) {
10051165 R_LOG_ERROR ("Cannot find directory: %s" , pkgdir );
10061166 free (pkgdir );
1167+ r_list_free (bindir_before );
10071168 return 1 ;
10081169 }
10091170 char * s = have_builddir
@@ -1015,7 +1176,13 @@ static int r2pm_install_pkg(const char *pkg, bool clean, bool global) {
10151176 free (s );
10161177 if (res == 0 ) {
10171178 r2pm_register (pkg , global );
1179+ RList * bindir_after = r2pm_bindir_snapshot ();
1180+ RList * new_files = r2pm_bindir_new_files (bindir_before , bindir_after );
1181+ r2pm_report_new_bindir_files (pkg , new_files );
1182+ r_list_free (new_files );
1183+ r_list_free (bindir_after );
10181184 }
1185+ r_list_free (bindir_before );
10191186#endif
10201187 free (script );
10211188 free (srcdir );
0 commit comments