@@ -210,6 +210,7 @@ struct lsns {
210210 unsigned int raw : 1 ,
211211 json : 1 ,
212212 tree : 2 ,
213+ persist : 1 ,
213214 no_trunc : 1 ,
214215 no_headings : 1 ,
215216 no_wrap : 1 ;
@@ -722,7 +723,7 @@ static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, in
722723 if (clone_type < 0 )
723724 return NULL ;
724725 lsns_type = clone_type_to_lsns_type (clone_type );
725- if (lsns_type < 0 )
726+ if (lsns_type < 0 || ls -> fltr_types [ lsns_type ] == 0 )
726727 return NULL ;
727728
728729 fd_owner = ioctl (fd , NS_GET_USERNS );
@@ -858,6 +859,42 @@ static void read_related_namespaces(struct lsns *ls)
858859 }
859860}
860861
862+ static int read_persistent_namespaces (struct lsns * ls )
863+ {
864+ struct libmnt_iter * itr = mnt_new_iter (MNT_ITER_FORWARD );
865+ struct libmnt_fs * fs = NULL ;
866+
867+ while (mnt_table_next_fs (ls -> tab , itr , & fs ) == 0 ) {
868+ const char * root ;
869+ char * p , * end = NULL ;
870+ ino_t ino ;
871+ int fd ;
872+
873+ if (!mnt_fs_match_fstype (fs , "nsfs" ))
874+ continue ;
875+ root = mnt_fs_get_root (fs );
876+ if (!root || !(p = strchr (root , '[' )))
877+ continue ;
878+
879+ errno = 0 ;
880+ ino = strtoumax (++ p , & end , 10 );
881+ if (!end || * end != ']' || errno != 0 )
882+ continue ;
883+ if (get_namespace (ls , ino ))
884+ continue ;
885+
886+ fd = open (mnt_fs_get_target (fs ), O_RDONLY );
887+ if (fd < 0 )
888+ continue ;
889+
890+ add_namespace_for_nsfd (ls , fd , ino );
891+ close (fd );
892+ }
893+
894+ mnt_free_iter (itr );
895+ return 0 ;
896+ }
897+
861898#endif /* USE_NS_GET_API */
862899
863900static int read_namespaces (struct lsns * ls )
@@ -885,6 +922,8 @@ static int read_namespaces(struct lsns *ls)
885922 }
886923
887924#ifdef USE_NS_GET_API
925+ read_persistent_namespaces (ls );
926+
888927 if (ls -> tree == LSNS_TREE_OWNER || ls -> tree == LSNS_TREE_PARENT )
889928 read_related_namespaces (ls );
890929#endif
@@ -1150,6 +1189,8 @@ static int show_namespaces(struct lsns *ls)
11501189
11511190 if (ls -> fltr_pid != 0 && !namespace_has_process (ns , ls -> fltr_pid ))
11521191 continue ;
1192+ if (ls -> persist && ns -> nprocs != 0 )
1193+ continue ;
11531194
11541195 if (!ns -> ns_outline )
11551196 show_namespace (ls , tab , ns , ns -> proc );
@@ -1240,6 +1281,7 @@ static void __attribute__((__noreturn__)) usage(void)
12401281 fputs (_ (" -n, --noheadings don't print headings\n" ), out );
12411282 fputs (_ (" -o, --output <list> define which output columns to use\n" ), out );
12421283 fputs (_ (" --output-all output all columns\n" ), out );
1284+ fputs (_ (" -P, --persistent namespaces without processes\n" ), out );
12431285 fputs (_ (" -p, --task <pid> print process namespaces\n" ), out );
12441286 fputs (_ (" -r, --raw use the raw output format\n" ), out );
12451287 fputs (_ (" -u, --notruncate don't truncate text in columns\n" ), out );
@@ -1275,6 +1317,7 @@ int main(int argc, char *argv[])
12751317 { "help" , no_argument , NULL , 'h' },
12761318 { "output" , required_argument , NULL , 'o' },
12771319 { "output-all" , no_argument , NULL , OPT_OUTPUT_ALL },
1320+ { "persistent" , no_argument , NULL , 'P' },
12781321 { "notruncate" , no_argument , NULL , 'u' },
12791322 { "version" , no_argument , NULL , 'V' },
12801323 { "noheadings" , no_argument , NULL , 'n' },
@@ -1288,6 +1331,7 @@ int main(int argc, char *argv[])
12881331
12891332 static const ul_excl_t excl [] = { /* rows and cols in ASCII order */
12901333 { 'J' ,'r' },
1334+ { 'P' ,'p' },
12911335 { 'l' ,'T' },
12921336 { 0 }
12931337 };
@@ -1307,7 +1351,7 @@ int main(int argc, char *argv[])
13071351 INIT_LIST_HEAD (& netnsids_cache );
13081352
13091353 while ((c = getopt_long (argc , argv ,
1310- "Jlp :o:nruhVt:T::W" , long_opts , NULL )) != -1 ) {
1354+ "JlPp :o:nruhVt:T::W" , long_opts , NULL )) != -1 ) {
13111355
13121356 err_exclusive_options (c , long_opts , excl , excl_st );
13131357
@@ -1325,6 +1369,9 @@ int main(int argc, char *argv[])
13251369 for (ncolumns = 0 ; ncolumns < ARRAY_SIZE (infos ); ncolumns ++ )
13261370 columns [ncolumns ] = ncolumns ;
13271371 break ;
1372+ case 'P' :
1373+ ls .persist = 1 ;
1374+ break ;
13281375 case 'p' :
13291376 ls .fltr_pid = strtos32_or_err (optarg , _ ("invalid PID argument" ));
13301377 break ;
@@ -1430,11 +1477,9 @@ int main(int argc, char *argv[])
14301477 if (has_column (COL_NETNSID ))
14311478 netlink_fd = socket (AF_NETLINK , SOCK_RAW , NETLINK_ROUTE );
14321479#endif
1433- if (has_column (COL_NSFS )) {
1434- ls .tab = mnt_new_table_from_file (_PATH_PROC_MOUNTINFO );
1435- if (!ls .tab )
1436- err (MNT_EX_FAIL , _ ("failed to parse %s" ), _PATH_PROC_MOUNTINFO );
1437- }
1480+ ls .tab = mnt_new_table_from_file (_PATH_PROC_MOUNTINFO );
1481+ if (!ls .tab )
1482+ err (MNT_EX_FAIL , _ ("failed to parse %s" ), _PATH_PROC_MOUNTINFO );
14381483
14391484 r = read_processes (& ls );
14401485 if (!r )
0 commit comments