@@ -132,6 +132,7 @@ free_storage_patch_cb(struct rb_node *node)
132132 patch = rb_entry (node , struct kpatch_storage_patch , node );
133133 kpatch_close_file (& patch -> kpfile );
134134
135+ free (patch -> desc );
135136 free (patch );
136137}
137138
@@ -368,6 +369,63 @@ storage_have_patch(kpatch_storage_t *storage, const char *buildid,
368369 return PATCH_FOUND ;
369370}
370371
372+ static char *
373+ storage_get_description (kpatch_storage_t * storage ,
374+ struct kpatch_storage_patch * patch )
375+ {
376+ char * desc = NULL ;
377+ char path [PATH_MAX ];
378+ int fd , rv , alloc = 0 , sz = 0 ;
379+
380+ if (!storage -> is_patch_dir )
381+ return NULL ;
382+
383+ if (patch -> desc )
384+ return patch -> desc ;
385+
386+ sprintf (path , "%s/%d/description" , patch -> buildid , patch -> patchlevel );
387+ fd = openat (storage -> patch_fd , path , O_RDONLY );
388+ if (fd == -1 )
389+ return NULL ;
390+
391+ while (1 ) {
392+ if (sz + 1024 >= alloc ) {
393+ char * olddesc = desc ;
394+ alloc += PAGE_SIZE ;
395+
396+ desc = malloc (alloc );
397+
398+ if (olddesc != NULL ) {
399+ memcpy (desc , olddesc , sz );
400+ free (olddesc );
401+ }
402+
403+ olddesc = desc ;
404+ }
405+
406+ rv = read (fd , desc + sz , alloc - sz );
407+ if (rv == -1 && errno == EINTR )
408+ continue ;
409+
410+ if (rv == -1 )
411+ goto err_free ;
412+
413+ if (rv == 0 )
414+ break ;
415+
416+ sz += rv ;
417+ }
418+
419+ patch -> desc = desc ;
420+
421+ return desc ;
422+
423+ err_free :
424+ free (desc );
425+ close (fd );
426+ return NULL ;
427+ }
428+
371429static int
372430storage_lookup_patches (kpatch_storage_t * storage , kpatch_process_t * proc )
373431{
@@ -1353,6 +1411,7 @@ int usage_info(const char *err)
13531411 fprintf (stderr , "usage: libcare-ctl info [options] [-b BUILDID] [-p PID] [-s STORAGE] [-r REGEXP]\n" );
13541412 fprintf (stderr , "\nOptions:\n" );
13551413 fprintf (stderr , " -h - this message\n" );
1414+ fprintf (stderr , " -n - don't print patch descriptions\n" );
13561415 fprintf (stderr , " -b <BUILDID> - output all processes having object with specified BuildID loaded\n" );
13571416 fprintf (stderr , " -p <PID> - target process, 'all' or omitted for all the system processes\n" );
13581417 fprintf (stderr , " -s <STORAGE> - only show BuildIDs of object having patches in STORAGE, default %s\n" ,
@@ -1365,8 +1424,23 @@ struct info_data {
13651424 const char * buildid ;
13661425 kpatch_storage_t * storage ;
13671426 regex_t * name_re ;
1427+ int print_description ;
1428+ int may_update , vulnerable ;
13681429};
13691430
1431+ const char * RED = "\x1B[31m" ;
1432+ const char * GREEN = "\x1B[32m" ;
1433+ const char * YELLOW = "\x1B[33m" ;
1434+ const char * RESET = "\x1B[0m" ;
1435+
1436+ static void
1437+ init_colors (void )
1438+ {
1439+ if (!isatty (fileno (stdout ))) {
1440+ RED = GREEN = YELLOW = RESET = "" ;
1441+ }
1442+ }
1443+
13701444static int
13711445object_info (struct info_data * data , struct object_file * o ,
13721446 int * pid_printed )
@@ -1422,11 +1496,52 @@ object_info(struct info_data *data, struct object_file *o,
14221496 if (storage_patch_found (patch ) && patch -> patchlevel ) {
14231497 printf (" latest=%d" , patch -> patchlevel );
14241498 }
1425- if (patch && (o -> applied_patch == NULL || patch -> patchlevel > o -> kpfile .patch -> user_level )) {
1426- printf ("\nbetter patch available, do `libcare-client /run/libcare.sock update`" );
1499+
1500+ /* empty patch patchlevel=0 with description of bugs in the version */
1501+ if (patch && patch -> patchlevel == 0 && o -> applied_patch == NULL ) {
1502+ printf (" %sVULNERABLE%s\n" , RED , RESET );
1503+
1504+ if (data -> print_description ) {
1505+ char * desc ;
1506+
1507+ desc = storage_get_description (data -> storage , patch );
1508+ printf ("\n%sVULNERABLE VERSION:\n" , RED );
1509+
1510+ printf ("%s%s" , desc , RESET );
1511+ }
1512+
1513+ data -> vulnerable ++ ;
14271514 }
1515+
14281516 printf ("\n" );
14291517
1518+ /* Old or no patch applied but we have one in storage */
1519+ if (patch && patch -> patchlevel != 0 &&
1520+ (o -> applied_patch == NULL || patch -> patchlevel > o -> kpfile .patch -> user_level )) {
1521+ if (data -> print_description ) {
1522+ char * desc ;
1523+
1524+ printf ("\n%snew patch description:\n" , YELLOW );
1525+
1526+ desc = storage_get_description (data -> storage , patch );
1527+ printf ("%s%s" , desc , RESET );
1528+ }
1529+
1530+ data -> may_update ++ ;
1531+ return 0 ;
1532+ }
1533+
1534+ /* patch applied and is latest version. show descripition for it */
1535+ if (patch && o -> applied_patch != NULL && data -> print_description ) {
1536+ char * desc ;
1537+
1538+ printf ("\n%slatest patch applied\n" , GREEN );
1539+
1540+ desc = storage_get_description (data -> storage , patch );
1541+ printf ("%s%s" , desc , RESET );
1542+ return 0 ;
1543+ }
1544+
14301545 return 0 ;
14311546}
14321547
@@ -1455,6 +1570,8 @@ process_info(int pid, void *_data)
14551570 if (object_info (data , o , & pid_printed ))
14561571 break ;
14571572
1573+ if (pid_printed && data -> print_description )
1574+ printf ("========================================\n" );
14581575out :
14591576 kpatch_process_free (proc );
14601577
@@ -1465,14 +1582,21 @@ static int
14651582processes_info (int pid ,
14661583 const char * buildid ,
14671584 const char * storagepath ,
1468- const char * regexp )
1585+ const char * regexp ,
1586+ int print_description )
14691587{
14701588 int ret = -1 ;
14711589 struct info_data data = { 0 , };
14721590 kpatch_storage_t storage ;
14731591 regex_t regex ;
14741592
1593+ init_colors ();
1594+
14751595 data .buildid = buildid ;
1596+ data .print_description = print_description ;
1597+ data .may_update = 0 ;
1598+ data .vulnerable = 0 ;
1599+
14761600 if (regexp != NULL ) {
14771601 ret = regcomp (& regex , regexp , REG_EXTENDED );
14781602 if (ret != 0 ) {
@@ -1491,6 +1615,17 @@ processes_info(int pid,
14911615
14921616 ret = processes_do (pid , process_info , & data );
14931617
1618+ if (data .vulnerable ) {
1619+ printf ("%s%d object(s) are vulnerable%s\n" , RED , data .vulnerable , RESET );
1620+ }
1621+
1622+ if (data .may_update ) {
1623+ printf ("%s%d object(s) may be updated to the latest patch%s\n" ,
1624+ YELLOW , data .may_update , RESET );
1625+ printf ("\n%sRun: libcare-client /run/libcare.sock update%s\n" ,
1626+ RED , RESET );
1627+ }
1628+
14941629out_err :
14951630 if (data .storage != NULL ) {
14961631 storage_free (data .storage );
@@ -1504,12 +1639,12 @@ processes_info(int pid,
15041639
15051640int cmd_info_user (int argc , char * argv [])
15061641{
1507- int opt , pid = -1 , verbose = 0 ;
1642+ int opt , pid = -1 , verbose = 0 , print_description = 1 ;
15081643 const char * buildid = NULL ;
15091644 const char * storagepath = storage_dir ;
15101645 const char * regexp = NULL ;
15111646
1512- while ((opt = getopt (argc , argv , "hb:p:s:r:v " )) != EOF ) {
1647+ while ((opt = getopt (argc , argv , "hb:p:s:r:vn " )) != EOF ) {
15131648 switch (opt ) {
15141649 case 'b' :
15151650 buildid = optarg ;
@@ -1524,6 +1659,9 @@ int cmd_info_user(int argc, char *argv[])
15241659 !strcmp (storagepath , "/dev/null" ))
15251660 storagepath = NULL ;
15261661 break ;
1662+ case 'n' :
1663+ print_description = 0 ;
1664+ break ;
15271665 case 'r' :
15281666 regexp = optarg ;
15291667 break ;
@@ -1546,7 +1684,8 @@ int cmd_info_user(int argc, char *argv[])
15461684 }
15471685
15481686
1549- return processes_info (pid , buildid , storagepath , regexp );
1687+ return processes_info (pid , buildid , storagepath , regexp ,
1688+ print_description );
15501689}
15511690
15521691
0 commit comments