├── CMakeLists.txt ├── COPYING ├── README.md ├── Uninstall.cmake ├── catargv.c ├── catargv.h ├── man ├── CMakeLists.txt ├── cgroupnshold.1 ├── cgroupnslist.1 ├── cgroupnsrelease.1 ├── ipcnshold.1 ├── ipcnslist.1 ├── ipcnsrelease.1 ├── mntnshold.1 ├── mntnslist.1 ├── mntnsrelease.1 ├── netnshold.1 ├── netnsjoin.1 ├── netnslist.1 ├── netnsrelease.1 ├── nshold.1 ├── nslist.1 ├── nsrelease.1 ├── pidnshold.1 ├── pidnslist.1 ├── pidnsrelease.1 ├── timenshold.1 ├── timenslist.1 ├── timensrelease.1 ├── usernshold.1 ├── usernslist.1 ├── usernsrelease.1 ├── utsnshold.1 ├── utsnslist.1 └── utsnsrelease.1 ├── memogetusername.c ├── memogetusername.h ├── netnsjoin.c ├── nshold.c ├── nslist.c ├── nsrelease.c ├── nssearch.c ├── nssearch.h ├── prefix.c ├── prefix.h ├── printflen.c ├── printflen.h └── symlinks ├── CMakeLists.txt ├── cgroupnshold ├── cgroupnslist ├── cgroupnsrelease ├── ipcnshold ├── ipcnslist ├── ipcnsrelease ├── mntnshold ├── mntnslist ├── mntnsrelease ├── netnshold ├── netnslist ├── netnsrelease ├── pidnshold ├── pidnslist ├── pidnsrelease ├── timenshold ├── timenslist ├── timensrelease ├── usernshold ├── usernslist ├── usernsrelease ├── utsnshold ├── utsnslist └── utsnsrelease /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(nsutils 3 | VERSION 0.2.1 4 | DESCRIPTION "Linux namespace utilities" 5 | HOMEPAGE_URL "https://github.com/rd235/nsutils" 6 | LANGUAGES C) 7 | 8 | include(GNUInstallDirs) 9 | add_definitions(-D_GNU_SOURCE) 10 | # string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE) 11 | # add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}") 12 | # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2 -O2 -pedantic -Wall -Wextra") 13 | 14 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 15 | 16 | find_library(TESTCAP cap) 17 | if(NOT TESTCAP) 18 | message(FATAL_ERROR "libcap not found") 19 | endif() 20 | 21 | add_executable(nshold nshold.c catargv.c prefix.c) 22 | target_link_libraries(nshold cap) 23 | install(TARGETS nshold 24 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 25 | 26 | add_executable(nslist nslist.c catargv.c memogetusername.c prefix.c printflen.c) 27 | install(TARGETS nslist 28 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 29 | 30 | add_executable(nsrelease nsrelease.c nssearch.c catargv.c prefix.c) 31 | install(TARGETS nsrelease 32 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 33 | 34 | add_executable(netnsjoin netnsjoin.c nssearch.c catargv.c prefix.c) 35 | target_link_libraries(netnsjoin cap) 36 | install(TARGETS netnsjoin 37 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 38 | 39 | install(CODE 40 | "execute_process(COMMAND setcap cap_sys_ptrace,cap_sys_admin+p ${CMAKE_INSTALL_FULL_BINDIR}/netnsjoin)" 41 | COMMAND_ECHO 42 | ) 43 | 44 | add_subdirectory(symlinks) 45 | add_subdirectory(man) 46 | 47 | add_custom_target(uninstall 48 | "${CMAKE_COMMAND}" -P "${PROJECT_SOURCE_DIR}/Uninstall.cmake") 49 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | Appendix: How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) 19yy name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Library General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #NSUTILS: Linux namespace utilities 2 | 3 | Nsutils suite includes a number of utilities to list, add/remove tag, and join namespaces. 4 | 5 | INSTALL: 6 | 7 | get the source code, from the root of the source tree run: 8 | ``` 9 | $ mkdir build 10 | $ cd build 11 | $ cmake .. 12 | $ make 13 | $ sudo make install 14 | ``` 15 | 16 | **nslist**, **nshold** and **nsrelease** restrict their action to one type 17 | of namespaces using one of the following prefixes: 18 | **cgroup**, **ipc**, **mnt**, **net**, **pid**, **user**, **uts**. 19 | i.e. use **nslist** to list namespaces of any kind, **netnslist** to list 20 | network namespaces only. 21 | 22 | The suite includes a set of man pages providing a complete description of the tools and a detailed commented 23 | list of all the options. 24 | 25 | This page gives just some examples of common usage cases to show what 26 | *nsutils* are useful for. 27 | 28 | ## nslist: list the namespaces 29 | 30 | - list the name of all the namespaces (in the entire system if run by root, available to the current user otherwise). 31 | ``` 32 | $ nslist -ss 33 | cgroup:[4026531835] 34 | ipc:[4026531839] 35 | mnt:[4026531840] 36 | mnt:[4026532879] 37 | net:[4026531969] 38 | net:[4026532508] 39 | net:[4026532883] 40 | pid:[4026531836] 41 | user:[4026531837] 42 | uts:[4026531838] 43 | ``` 44 | 45 | - list all the net namespaces and all the processes running in each namespace: 46 | ``` 47 | $ netnslist 48 | net:[4026531969] 49 | PID CMDLINE 50 | 31909 /lib/systemd/systemd --user 51 | 52 | net:[4026532508] 53 | PID CMDLINE 54 | 19395 bash 55 | 56 | net:[4026532883] 57 | PID CMDLINE 58 | 8782 -bash 59 | 8939 netnslist 60 | ``` 61 | 62 | - list all the pids of the processes running in a specific namespace: 63 | ``` 64 | $ nslist -p net:[4026532883] 65 | 8782 66 | 8989 67 | ``` 68 | 69 | - count the processes running in two namespaces 70 | ``` 71 | $ nslist -c net:[4026532508] net:[4026532883] 72 | 3 73 | ``` 74 | 75 | - return the pid namespace of a process (as nsid or as ns number) 76 | ``` 77 | $ pidnslist -ss 8782 78 | pid:[4026531836] 79 | $ pidnslist -ssn 8782 80 | 4026531836 81 | ``` 82 | 83 | - show all the namespaces of process matching a regular expression against 84 | the process name 85 | ``` 86 | $ netnslist -R "bash" 87 | net:[4026532508] 88 | PID CMDLINE 89 | 19395 bash 90 | 91 | net:[4026532883] 92 | PID CMDLINE 93 | 8782 -bash 94 | ``` 95 | 96 | - the same above but in a tabular form 97 | ``` 98 | $ netnslist -T -R "bash" 99 | NAMESPACE PID CMDLINE 100 | net:[4026532508] 19395 bash 101 | net:[4026532883] 8782 -bash 102 | ``` 103 | 104 | - list the namespaces of a specific user (for root. All the commands above 105 | can be restricted to the processes of a specific user by the `-U` option) 106 | ``` 107 | # nslist -U myuser -ss 108 | cgroup:[4026531835] 109 | ipc:[4026531839] 110 | mnt:[4026531840] 111 | mnt:[4026532879] 112 | net:[4026531969] 113 | net:[4026532508] 114 | net:[4026532883] 115 | pid:[4026531836] 116 | user:[4026531837] 117 | uts:[4026531838] 118 | ``` 119 | 120 | - list the all the namespaces where a 'vim' process is running and show 121 | include the owner of the processes in the list: 122 | ``` 123 | # mntnslist -u -R vim 124 | mnt:[4026531840] 125 | PID USER CMDLINE 126 | 9368 renzo vim -c set textwidth=75 nocindent README.md 127 | 9492 renzo vim xx 128 | ``` 129 | 130 | ## netnsjoin: join another network namespace 131 | 132 | **netnsjoin** runs a command in the net namespace of another process. 133 | This command requires root access or at least the `CAP_NET_ADMIN` capability. 134 | Users with `CAP_NET_ADMIN` capability are allowed to join all the namespaces 135 | they have access to but the *real* namespace (i.e. the net namespace of 136 | process 1). 137 | 138 | **netnsjoin** does not need the net namespace to be *mounted*, see 139 | mount(2). 140 | 141 | ``` 142 | # ip addr 143 | 1: lo: mtu 65536 qdisc noop state DOWN group default qlen 1 144 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 145 | # netnslist -ss $$ 146 | net:[4026532883] 147 | # netnsjoin 1 bash 148 | Joining net namespace net:[4026531969] 149 | # ip addr 150 | 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 151 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 152 | inet 127.0.0.1/8 scope host lo 153 | valid_lft forever preferred_lft forever 154 | 2: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 155 | link/ether 80:fa:5b:0b:a7:02 brd ff:ff:ff:ff:ff:ff 156 | inet 192.168.0.253/24 scope global eth0 157 | valid_lft forever preferred_lft forever 158 | ``` 159 | 160 | Sysadm can provide users with the ability to switch between their network 161 | namespaces using **cado** This is the [Cado on GitHub](https://github.com/rd235/cado). 162 | 163 | **netnsjoin** can join a network name space identified by: 164 | - the pid of a process 165 | - the net namespace id, i.e. something like net:[1234567890] 166 | - a tag defined by a namespace placeholder (see **nshold** below) 167 | 168 | ``` 169 | $net_admin# netnsjoin net:[4026532883] bash 170 | Joining net namespace net:[4026532883] 171 | $ netnslist -ss $$ 172 | net:[4026532883] 173 | ``` 174 | 175 | ## nshold: a tool for namespace survival and tagging 176 | 177 | A namespace survives until there is at least a process running in it (or if 178 | it has been *mounted*, see mount(2)) 179 | 180 | **nshold** creates a namespace *placeholder*: 181 | an idle process whose cmdline is the namespace id 182 | (so it can be easily found in the output of ps(1)). 183 | 184 | 185 | ``` 186 | $ pidnshold 187 | $ ps ax | grep pid: 188 | 10199 ? Ss 0:00 pid:[4026531836] 189 | 10205 pts/58 S+ 0:00 grep pid: 190 | ``` 191 | 192 | It is also possible to assign a tag to a namespace using a placeholder. 193 | ``` 194 | $ netnshold safenet 195 | $ ps ax | grep net: 196 | 10297 ? Ss 0:00 net:[4026532883] safenet 197 | 10301 pts/58 S+ 0:00 grep net: 198 | ``` 199 | 200 | User may like to add long tags consisting of several words. They can use 201 | shell quoting, or a specific syntax provided by **nshold** 202 | ``` 203 | $ netnshold -- house automation 204 | $ ps ax | grep house 205 | 10348 ? Ss 0:00 net:[4026532883] house automation 206 | 10351 pts/58 S+ 0:00 grep house 207 | ``` 208 | 209 | ## nsrelease: kill a namespace placeholder 210 | 211 | ``` 212 | $ nsrelease pid:[4026531836] 213 | ``` 214 | or 215 | ``` 216 | $ nsrelease 10199 217 | ``` 218 | or 219 | ``` 220 | $ nsrelease safenet 221 | ``` 222 | 223 | It is also possible to kill all the namespaces whose tags match a spefic 224 | regular expression. 225 | For example the following command kills all the placeholders for uts 226 | namespaces and defining four letter tags. 227 | ``` 228 | $ utsnsrelease -r "...." 229 | ``` 230 | 231 | ## netnsjoin (again, now using tags!) 232 | 233 | **netnsjoin** can join a namespace using the tag of a placeholder instead 234 | of a pid. 235 | 236 | ``` 237 | $net_admin# netnsjoin safenet bash 238 | Joining net namespace net:[4026532883] 239 | $ 240 | ``` 241 | or 242 | ``` 243 | net_admin# netnsjoin house automation -- bash 244 | Joining net namespace net:[4026532883] 245 | $ 246 | ``` 247 | 248 | ## nslist (again, now using tags!) 249 | 250 | **nslist** can use tags and match tags using regular expressions. 251 | 252 | ``` 253 | $ nslist -ss safenet 254 | net:[4026532883] 255 | ``` 256 | 257 | ``` 258 | $ nslist -T -r house 259 | NAMESPACE PID CMDLINE 260 | net:[4026532883] 10297 net:[4026532883] safenet 261 | net:[4026532883] 10348 net:[4026532883] house automation 262 | net:[4026532883] 8782 -bash 263 | net:[4026532883] 10944 bash 264 | net:[4026532883] 11195 nslist -T -r house 265 | ``` 266 | 267 | Show all the net placeholders 268 | ``` 269 | $ netnslist -HT 270 | NAMESPACE PID CMDLINE 271 | net:[4026532690] 11631 net:[4026532690] othernet 272 | net:[4026532883] 10297 net:[4026532883] safenet 273 | net:[4026532883] 10348 net:[4026532883] house automation 274 | ``` 275 | 276 | -------------------------------------------------------------------------------- /Uninstall.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") 3 | 4 | if(NOT EXISTS ${MANIFEST}) 5 | message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") 6 | endif() 7 | 8 | file(STRINGS ${MANIFEST} files) 9 | foreach(file ${files}) 10 | if(EXISTS ${file} OR IS_SYMLINK ${file}) 11 | message(STATUS "Removing: ${file}") 12 | 13 | execute_process( 14 | COMMAND rm -f ${file} 15 | RESULT_VARIABLE retcode 16 | ) 17 | 18 | if(NOT "${retcode}" STREQUAL "0") 19 | message(WARNING "Failed to remove: ${file}") 20 | endif() 21 | endif() 22 | endforeach(file) 23 | -------------------------------------------------------------------------------- /catargv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nsutils: namespace utilities 3 | * Copyright (C) 2016 Renzo Davoli, University of Bologna 4 | * 5 | * catargv: create a malloc-ed copy of all the argv arguments as a string 6 | * 7 | * Cado is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (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 copy of the GNU General Public License 18 | * along with this program; If not, see . 19 | * 20 | */ 21 | 22 | #include 23 | 24 | /* join all the args in a single string */ 25 | char *catargv(char *argv[]) { 26 | char *out = NULL; 27 | size_t len = 0; 28 | FILE *fout = open_memstream(&out, &len); 29 | if (fout) { 30 | while (*argv) { 31 | fprintf(fout, "%s",*argv++); 32 | if (*argv) fprintf(fout," "); 33 | } 34 | fclose(fout); 35 | } 36 | return out; 37 | } 38 | -------------------------------------------------------------------------------- /catargv.h: -------------------------------------------------------------------------------- 1 | #ifndef CATARGV_H 2 | #define CATARGV_H 3 | #include 4 | 5 | char *catargv(char *argv[]); 6 | 7 | #endif //CATARGV_H 8 | -------------------------------------------------------------------------------- /man/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | file(GLOB VU_MAN_PAGES ${CMAKE_CURRENT_SOURCE_DIR}/*.[1-8]) 4 | foreach(VU_MAN_PATH IN LISTS VU_MAN_PAGES) 5 | get_filename_component(VU_MANPAGE ${VU_MAN_PATH} NAME) 6 | string(REGEX REPLACE ".*\\." "" MAN_CHAPTER ${VU_MANPAGE}) 7 | install(FILES ${VU_MAN_PATH} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_CHAPTER}) 8 | endforeach(VU_MAN_PATH) 9 | -------------------------------------------------------------------------------- /man/cgroupnshold.1: -------------------------------------------------------------------------------- 1 | nshold.1 -------------------------------------------------------------------------------- /man/cgroupnslist.1: -------------------------------------------------------------------------------- 1 | nslist.1 -------------------------------------------------------------------------------- /man/cgroupnsrelease.1: -------------------------------------------------------------------------------- 1 | nsrelease.1 -------------------------------------------------------------------------------- /man/ipcnshold.1: -------------------------------------------------------------------------------- 1 | nshold.1 -------------------------------------------------------------------------------- /man/ipcnslist.1: -------------------------------------------------------------------------------- 1 | nslist.1 -------------------------------------------------------------------------------- /man/ipcnsrelease.1: -------------------------------------------------------------------------------- 1 | nsrelease.1 -------------------------------------------------------------------------------- /man/mntnshold.1: -------------------------------------------------------------------------------- 1 | nshold.1 -------------------------------------------------------------------------------- /man/mntnslist.1: -------------------------------------------------------------------------------- 1 | nslist.1 -------------------------------------------------------------------------------- /man/mntnsrelease.1: -------------------------------------------------------------------------------- 1 | nsrelease.1 -------------------------------------------------------------------------------- /man/netnshold.1: -------------------------------------------------------------------------------- 1 | nshold.1 -------------------------------------------------------------------------------- /man/netnsjoin.1: -------------------------------------------------------------------------------- 1 | .TH NETNSJOIN 1 "August 14, 2016" "VirtualSquare Labs" 2 | .SH NAME 3 | netnsjoin \- Join the net namespace of another process 4 | .SH SYNOPSIS 5 | 6 | .B netnsjoin 7 | .I pid_or_net_namespace_id_or_placeholder_tag 8 | [ 9 | .I command 10 | [ 11 | .I args 12 | ] 13 | ] 14 | 15 | .B netnsjoin 16 | .I long placeholder tag 17 | .R -- 18 | [ 19 | .I command 20 | [ 21 | .I args 22 | ] 23 | ] 24 | 25 | .SH DESCRIPTION 26 | \fBnetnsjoin\fR joins the net namespace of another process. 27 | 28 | The namespace to join can be identified by the pid of a process belonging to 29 | that namespace, by the namespace id (e.g. net:[1234567890]) or using a tag defined by \fBnetnshold(1)\fR 30 | 31 | Root access or CAP_NET_ADMIN is required to run the program. CAP_NET_ADMIN can be delegated to 32 | specific users by \fBcado(1)\fR (if installed). 33 | 34 | If \fIcommand\fR is omitted \fBnetnsjoin\fR launch the content of the 35 | environment variable $SHELL in the target namespace. 36 | 37 | .SH SEE ALSO 38 | \fBnetnshold\fR(1) 39 | \fBnetnslist\fR(1) 40 | \fBnetnsrelease\fR(1) 41 | \fBcado\fR(1) 42 | -------------------------------------------------------------------------------- /man/netnslist.1: -------------------------------------------------------------------------------- 1 | nslist.1 -------------------------------------------------------------------------------- /man/netnsrelease.1: -------------------------------------------------------------------------------- 1 | nsrelease.1 -------------------------------------------------------------------------------- /man/nshold.1: -------------------------------------------------------------------------------- 1 | .TH NSHOLD 1 "August 14, 2016" "VirtualSquare Labs" 2 | .SH NAME 3 | cgroupnshold ipcnshold mntnshold netnshold pidnshold timenshold usernshold utsnshold \- Set a placeholder for a namespace 4 | .SH SYNOPSIS 5 | 6 | .B cgroupnshold 7 | [ 8 | .I tag 9 | ] 10 | 11 | .B ipcnshold 12 | [ 13 | .I tag 14 | ] 15 | 16 | .B mntnshold 17 | [ 18 | .I tag 19 | ] 20 | 21 | .B netnshold 22 | [ 23 | .I tag 24 | ] 25 | 26 | .B pidnshold 27 | [ 28 | .I tag 29 | ] 30 | 31 | .B timenshold 32 | [ 33 | .I tag 34 | ] 35 | 36 | .B usernshold 37 | [ 38 | .I tag 39 | ] 40 | 41 | .B utsnshold 42 | [ 43 | .I tag 44 | ] 45 | 46 | .SH DESCRIPTION 47 | \fBnshold\fR commands define placeholders for namespaces. A placeholder is a small idle process whose goal is to keep 48 | the namespace alive. 49 | Each \fBnshold\fR command has a prefix to specify the type of namespace and creates a placeholder for the current 50 | namespace of that type. 51 | It is possible to assign a tag to a placeholder to later identify that namespace. 52 | 53 | \fItag\fR is a single argument. \fBnshold\fR implements a shortcut to define a tag consisting of several keywords: 54 | two dashes -- followed by all the keywords. 55 | 56 | A namespace placeholder is a process and can be terminated using \fBkill\fR(1) or \fBkill\fR(2). 57 | .nBnsrelease\fR commands provide a simpler interface to terminate placeholders. 58 | 59 | For example a placeholder for the net namespace of the current process can be defined by: 60 | .nf 61 | netnshold privatenet 62 | .fi 63 | 64 | A user can later run a shell in that namespace typing: 65 | .nf 66 | netnsjoin privatenet bash 67 | .fi 68 | 69 | Similar commands using the -- shortrcdut are: 70 | .nf 71 | netnshold -- house automation 72 | netnsjoin house automation -- bash 73 | .fi 74 | 75 | .SH SEE ALSO 76 | \fBnslist\fR(1) 77 | \fBnsrelease\fR(1) 78 | \fBnetnsjoin\fR(1) 79 | \fBcado\fR(1) 80 | -------------------------------------------------------------------------------- /man/nslist.1: -------------------------------------------------------------------------------- 1 | .TH NSLIST 1 "August 14, 2016" "VirtualSquare Labs" 2 | .SH NAME 3 | nslist cgroupnslist ipcnslist mntnslist netnslist pidnslist timenslist usernslist utsnslist \- List namespaces 4 | .SH SYNOPSIS 5 | 6 | .B nslist 7 | [ 8 | OPTIONS 9 | ] 10 | [ 11 | .I pid_or_namespace_id_or_placeholder_tag 12 | ] 13 | ... 14 | [ -- 15 | .I long placeholder tag 16 | ] 17 | 18 | .B cgroupnslist 19 | .I same syntax as nslist 20 | 21 | .B ipcnslist 22 | .I same syntax as nslist 23 | 24 | .B mntnslist 25 | .I same syntax as nslist 26 | 27 | .B netnslist 28 | .I same syntax as nslist 29 | 30 | .B pidnslist 31 | .I same syntax as nslist 32 | 33 | .B timenslist 34 | .I same syntax as nslist 35 | 36 | .B usernslist 37 | .I same syntax as nslist 38 | 39 | .B utsnslist 40 | .I same syntax as nslist 41 | 42 | .SH DESCRIPTION 43 | \fBnslist\fR commands are utility commands to list namespaces (ns from now on) 44 | and check the mapping between processes and namespaces. 45 | Each \fBnslist\fR command has a prefix to specify the type of ns. \fBnslist\fR without any prefix can be used 46 | when the ns can be identified in a non ambiguous way or to list all the namespaces of any type. 47 | 48 | The ns to list can be identified by the ns id (e.g. net:[1234567890]) or using a tag defined by a \fBnshold(1)\fR 49 | command. 50 | By the option \fB-r\fR it is possible to use regular expressions to identify ns tags. 51 | 52 | If the argument is a pid instead of a ns id or tag, these commands list the ns (or namespaces) that 53 | process belongs to. 54 | 55 | In case no argument is given (after the options) 56 | these commands list all the namespaces and for each namespace all the processes belonging 57 | to that namespace. 58 | 59 | .SH OPTIONS 60 | 61 | .TP 62 | \fB\-r 63 | .TQ 64 | \fB\-\-regex 65 | arguments are regular expressions of ns tags 66 | .TP 67 | \fB\-u 68 | .TQ 69 | \fB\-\-listuser 70 | display the owner of each process 71 | .TP 72 | \fB\-H 73 | .TQ 74 | \fB\-\-placeholder 75 | display only the placeholder processes 76 | .TP 77 | \fB\-U \fIuid_or_username\fR 78 | .TQ 79 | \fB\-\-placeholder \fIuid_or_username\fR 80 | filter the list to include only the processes belonging to a specific user 81 | .TP 82 | \fB\-H 83 | .TQ 84 | \fB\-\-placeholder 85 | show only placeholder processes 86 | .TP 87 | \fB\-C 88 | .TQ 89 | \fB\-\-listcomm 90 | show the command instead of the command line 91 | .TP 92 | \fB\-p 93 | .TQ 94 | \fB\-\-pid 95 | output just the list of pids of matching processes 96 | .TP 97 | \fB\-c 98 | .TQ 99 | \fB\-\-count 100 | output just the number of matching processes 101 | .TP 102 | \fB\-T 103 | .TQ 104 | \fB\-\-tabular 105 | give a tabular output (without titles and separations between namespaces) 106 | .TP 107 | \fB\-n 108 | .TQ 109 | \fB\-\-numeric 110 | list the ns numeric id (1234567890 instead of ipc[1234567890]) 111 | .TP 112 | \fB\-s 113 | .TQ 114 | \fB\-\-short 1 115 | short form: list only pid and ns id for each process matching the criteria defined 116 | by the other options (for scripts) 117 | .TP 118 | \fB\-s \-s 119 | .TQ 120 | \fB\-ss 121 | .TQ 122 | \fB\-\-short 2 123 | very short form: list ns id only 124 | .TP 125 | \fB\-t 126 | .TQ 127 | \fB\-\-tag 128 | show a ns tag together with the ns id (when defined) 129 | .TP 130 | \fB\-t \-t 131 | .TO 132 | \fB\-tt 133 | .TQ 134 | \fB\-\-tagonly 135 | show a ns tag instead of the ns id (when defined) 136 | .TP 137 | \fB\-R \fIregex\fR 138 | .TQ 139 | \fB\-\-recomm \fIregex\fR 140 | show only those processes whose command match regex 141 | (regex is a regular expression) 142 | .TP 143 | \fB\-h 144 | .TQ 145 | \fB\-\-help 146 | print a short usage banner and exit. 147 | 148 | .SH SEE ALSO 149 | \fBnshold\fR(1) 150 | \fBnsrelease\fR(1) 151 | \fBnetnsjoin\fR(1) 152 | \fBcado\fR(1) 153 | -------------------------------------------------------------------------------- /man/nsrelease.1: -------------------------------------------------------------------------------- 1 | .TH NSHOLD 1 "August 14, 2016" "VirtualSquare Labs" 2 | .SH NAME 3 | cgroupnsrelease ipcnsrelease mntnsrelease netnsrelease pidnsrelease timensrelease usernsrelease utsnsrelease \- Terminate a placeholder for a namespace 4 | .SH SYNOPSIS 5 | 6 | .B nsrelease 7 | [ 8 | .I OPTIONS 9 | ] 10 | .I placeholder 11 | [ 12 | .I placeholder 13 | ] ... [ \-\- 14 | .I long placeholder tag 15 | ] 16 | 17 | .B ipcnsrelease 18 | .I same syntax as nsrelease 19 | 20 | .B cgroupnsrelease 21 | .I same syntax as nsrelease 22 | 23 | .B ipcnsrelease 24 | .I same syntax as nsrelease 25 | 26 | .B mntnsrelease 27 | .I same syntax as nsrelease 28 | 29 | .B netnsrelease 30 | .I same syntax as nsrelease 31 | 32 | .B pidnsrelease 33 | .I same syntax as nsrelease 34 | 35 | .B timensrelease 36 | .I same syntax as nsrelease 37 | 38 | .B usernsrelease 39 | .I same syntax as nsrelease 40 | 41 | .B utsnsrelease 42 | .I same syntax as nsrelease 43 | 44 | .SH DESCRIPTION 45 | \fBnsrelease\fR commands terminate placeholders for namespaces defined by \fBnshold\fR(1). 46 | A prefix can be added to the command name to specify the type of namespace. 47 | 48 | The placeholder can be identified by its pid, by the namespace id (e.g. net:[1234567890]) or 49 | using the tag defined by \fBnetnshold(1)\fR. 50 | 51 | By the option \fB-r\fR it is possible to use regular expressions to identify namespace tags. 52 | 53 | A double dash argument can be used as a shortcut to write a tag composed by several keywords: 54 | all the remaining arguments following -- compose the tag. 55 | 56 | .SH OPTIONS 57 | .TP 58 | \fB\-r 59 | .TQ 60 | \fB\-\-regex 61 | placeholder arguments are regular expressions. 62 | .TP 63 | \fB\-h 64 | .TQ 65 | \fB\-\-help 66 | print a short usage banner and exit. 67 | 68 | .SH SEE ALSO 69 | \fBnshold\fR(1) 70 | \fBnslist\fR(1) 71 | \fBnetnsjoin\fR(1) 72 | \fBcado\fR(1) 73 | -------------------------------------------------------------------------------- /man/pidnshold.1: -------------------------------------------------------------------------------- 1 | nshold.1 -------------------------------------------------------------------------------- /man/pidnslist.1: -------------------------------------------------------------------------------- 1 | nslist.1 -------------------------------------------------------------------------------- /man/pidnsrelease.1: -------------------------------------------------------------------------------- 1 | nsrelease.1 -------------------------------------------------------------------------------- /man/timenshold.1: -------------------------------------------------------------------------------- 1 | nshold.1 -------------------------------------------------------------------------------- /man/timenslist.1: -------------------------------------------------------------------------------- 1 | nslist.1 -------------------------------------------------------------------------------- /man/timensrelease.1: -------------------------------------------------------------------------------- 1 | nsrelease.1 -------------------------------------------------------------------------------- /man/usernshold.1: -------------------------------------------------------------------------------- 1 | nshold.1 -------------------------------------------------------------------------------- /man/usernslist.1: -------------------------------------------------------------------------------- 1 | nslist.1 -------------------------------------------------------------------------------- /man/usernsrelease.1: -------------------------------------------------------------------------------- 1 | nsrelease.1 -------------------------------------------------------------------------------- /man/utsnshold.1: -------------------------------------------------------------------------------- 1 | nshold.1 -------------------------------------------------------------------------------- /man/utsnslist.1: -------------------------------------------------------------------------------- 1 | nslist.1 -------------------------------------------------------------------------------- /man/utsnsrelease.1: -------------------------------------------------------------------------------- 1 | nsrelease.1 -------------------------------------------------------------------------------- /memogetusername.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nsutils: namespace utilities 3 | * Copyright (C) 2016 Renzo Davoli, University of Bologna 4 | * 5 | * memogetpwuid: memoize version of getpwuid 6 | * 7 | * Cado is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (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 copy of the GNU General Public License 18 | * along with this program; If not, see . 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | struct memopw { 29 | uid_t pw_uid; /* user ID */ 30 | char *pw_name; /* username */ 31 | struct memopw *next; 32 | }; 33 | 34 | static struct memopw *memohead; 35 | 36 | static char *memogetpw(struct memopw **scan, uid_t pw_uid) { 37 | while (*scan != NULL && (*scan)->pw_uid < pw_uid) 38 | scan = &((*scan)->next); 39 | if (*scan != NULL && (*scan)->pw_uid == pw_uid) 40 | return (*scan)->pw_name; 41 | else { 42 | struct passwd *pwd = getpwuid(pw_uid); 43 | struct memopw *new = malloc(sizeof(struct memopw)); 44 | if (new) { 45 | new->pw_uid = pw_uid; 46 | if (pwd) 47 | new->pw_name = strdup(pwd->pw_name); 48 | else 49 | asprintf(&new->pw_name,"%d",pw_uid); 50 | new->next = *scan; 51 | *scan = new; 52 | return new->pw_name; 53 | } else 54 | return pwd ? pwd->pw_name : ""; 55 | } 56 | } 57 | 58 | /* return the username from the uid. Memoize the results */ 59 | char *memogetusername(uid_t pw_uid) { 60 | return memogetpw(&memohead, pw_uid); 61 | } 62 | 63 | #if 0 64 | #include 65 | int main(int argc, char *argv[]) { 66 | while (1) { 67 | uid_t uid; 68 | scanf("%d", &uid); 69 | printf("%d %s\n",uid,memogetusername(uid)); 70 | } 71 | } 72 | #endif 73 | -------------------------------------------------------------------------------- /memogetusername.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMOGETPWUID_C 2 | #define MEMOGETPWUID_C 3 | #include 4 | 5 | char *memogetusername(uid_t pw_uid); 6 | 7 | #endif // MEMOGETPWUID_C 8 | -------------------------------------------------------------------------------- /netnsjoin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nsutils: namespace utilities 3 | * Copyright (C) 2016 Renzo Davoli, University of Bologna 4 | * 5 | * netnsjoin: join a network namespace. 6 | * 7 | * Cado is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (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 copy of the GNU General Public License 18 | * along with this program; If not, see . 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | void usage_and_exit(char *progname) { 38 | fprintf(stderr, "Usage:\n" 39 | "%s pid_or_net_namespace_id [command [args]]\n" 40 | "%s pid or net namespace id -- [command [args]]\n\n", progname, progname); 41 | exit(1); 42 | } 43 | 44 | /* : if there is a -- argv: 45 | : * change it into 0 46 | : * return the index of the first argv after -- (the command to launch) 47 | : otherwise: 48 | : return 2 (i.e. command to launch) */ 49 | int cmdoptind(char **argv) { 50 | int i; 51 | for (i = 1; argv[i]; i++) { 52 | if (strcmp(argv[i], "--") == 0) { 53 | argv[i] = 0; 54 | return i + 1; 55 | } 56 | } 57 | return 2; 58 | } 59 | 60 | /* turn capabilities on and off to have "extra" powers only when needed */ 61 | int raise_effective_cap(cap_value_t cap) { 62 | cap_t caps=cap_get_proc(); 63 | cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET); 64 | return cap_set_proc(caps); 65 | } 66 | 67 | int lower_effective_cap(cap_value_t cap) { 68 | cap_t caps=cap_get_proc(); 69 | cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_CLEAR); 70 | return cap_set_proc(caps); 71 | } 72 | 73 | cap_flag_value_t get_effective_cap(cap_value_t cap) { 74 | cap_flag_value_t rval=0; 75 | cap_t caps=cap_get_proc(); 76 | cap_get_flag(caps, cap, CAP_EFFECTIVE, &rval); 77 | return rval; 78 | } 79 | 80 | cap_flag_value_t get_inheritable_cap(cap_value_t cap) { 81 | cap_flag_value_t rval=0; 82 | cap_t caps=cap_get_proc(); 83 | cap_get_flag(caps, cap, CAP_INHERITABLE, &rval); 84 | return rval; 85 | } 86 | 87 | int clear_inheritable_cap(void) { 88 | cap_t caps=cap_get_proc(); 89 | cap_clear_flag(caps, CAP_INHERITABLE); 90 | return cap_set_proc(caps); 91 | } 92 | 93 | #define PATH1 "/proc/1/ns/net" 94 | 95 | int main(int argc, char *argv[]) 96 | { 97 | pid_t pid; 98 | char *ns_path; 99 | int nsfd; 100 | char *nsname; 101 | int cmd; 102 | char *argvsh[]={getenv("SHELL"),NULL}; 103 | char **cmdargv; 104 | char ns1[PATH_MAX+1]; 105 | char nsid[PATH_MAX+1]; 106 | 107 | if (argc < 2) { 108 | usage_and_exit(basename(argv[0])); 109 | } 110 | 111 | if (geteuid() != 0 && 112 | get_effective_cap(CAP_NET_ADMIN) != CAP_SET && 113 | get_inheritable_cap(CAP_NET_ADMIN) != CAP_SET) { 114 | fprintf(stderr,"root or cap_net_admin required: permission denied\n"); 115 | exit(1); 116 | } 117 | 118 | /* if there is -- in the command line the name of the namespace 119 | consists of several args, cat them together */ 120 | if ((cmd = cmdoptind(argv)) == 2) 121 | nsname = argv[1]; 122 | else 123 | nsname = catargv(argv + 1); 124 | 125 | if (cmd < argc) 126 | cmdargv = argv + cmd; 127 | else { 128 | cmdargv = argvsh; 129 | if (cmdargv[0] == NULL) { 130 | fprintf(stderr, "Error: $SHELL env variable not set.\n"); 131 | exit(1); 132 | } 133 | } 134 | 135 | if ((pid = nssearchone("net", nsname)) <= 0) { 136 | if (pid == 0) 137 | fprintf(stderr,"%s: namespace not found\n", nsname); 138 | else 139 | fprintf(stderr,"%s: too many placeholders\n", nsname); 140 | exit(1); 141 | } 142 | 143 | asprintf(&ns_path, "/proc/%d/ns/net",pid); 144 | 145 | if (readlink(ns_path, nsid, PATH_MAX+1) < 0) { 146 | perror(ns_path); 147 | exit(1); 148 | } 149 | 150 | if (geteuid() != 0) { 151 | if (raise_effective_cap(CAP_SYS_PTRACE)) { 152 | perror("raise CAP_SYS_PTRACE"); 153 | exit(1); 154 | } 155 | if (readlink(PATH1, ns1, PATH_MAX+1) < 0) { 156 | perror("readlink " PATH1); 157 | exit(1); 158 | } 159 | if (lower_effective_cap(CAP_SYS_PTRACE)) { 160 | perror("lower CAP_SYS_PTRACE"); 161 | exit(1); 162 | } 163 | if (geteuid() != 0 && strcmp(ns1,nsid)==0) { 164 | fprintf(stderr,"%s == " PATH1 ": permission denied\n",ns_path); 165 | exit(1); 166 | } 167 | } 168 | 169 | if (raise_effective_cap(CAP_SYS_ADMIN)) { 170 | perror("raise CAP_SYS_ADMIN"); 171 | exit(1); 172 | } 173 | if ((nsfd = open(ns_path, O_RDONLY)) >= 0) { 174 | struct stat st; 175 | if (lstat(ns_path, &st) < 0) { 176 | perror(ns_path); 177 | goto close_abort; 178 | } 179 | if (geteuid() != 0 && st.st_uid != geteuid()) { 180 | fprintf (stderr, "cannot join netns %s: permission denied\n",ns_path); 181 | goto close_abort; 182 | } 183 | if (setns(nsfd, CLONE_NEWNET) != 0) { 184 | perror("setns"); 185 | goto close_abort; 186 | } 187 | close(nsfd); 188 | if (unshare(CLONE_NEWNS) < 0) { 189 | perror("unshare"); 190 | goto abort; 191 | } 192 | } else { 193 | fprintf (stderr, "open failed %s: %s\n", ns_path, strerror(errno)); 194 | goto abort; 195 | } 196 | if (lower_effective_cap(CAP_SYS_ADMIN)) { 197 | perror("lower CAP_SYS_ADMIN"); 198 | exit(1); 199 | } 200 | if (clear_inheritable_cap()) { 201 | perror("clear_inheritable_cap"); 202 | exit(1); 203 | } 204 | fprintf(stderr, "Joining net namespace %s\n",nsid); 205 | execvp(cmdargv[0], cmdargv); 206 | 207 | perror(cmdargv[0]); 208 | exit(0); 209 | 210 | close_abort: 211 | close(nsfd); 212 | abort: 213 | exit(1); 214 | } 215 | -------------------------------------------------------------------------------- /nshold.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nsutils: namespace utilities 3 | * Copyright (C) 2016 Renzo Davoli, University of Bologna 4 | * 5 | * nshold: keep-alive and give a name tag to a namespace 6 | * 7 | * Cado is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (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 copy of the GNU General Public License 18 | * along with this program; If not, see . 19 | * 20 | */ 21 | 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #define NAMELEN (strlen(basename(__FILE__)) - 2) 36 | #define NSPATH "/proc/self/ns/" 37 | 38 | int clear_all_caps(void) { 39 | cap_t caps=cap_get_proc(); 40 | cap_clear_flag(caps, CAP_EFFECTIVE); 41 | cap_clear_flag(caps, CAP_INHERITABLE); 42 | cap_clear_flag(caps, CAP_PERMITTED); 43 | return cap_set_proc(caps); 44 | } 45 | 46 | /* read a symlink and return a strdup of the link target */ 47 | static char *readlinkdup(char *pathname) { 48 | char buf[PATH_MAX + 1]; 49 | ssize_t len = readlink(pathname, buf, PATH_MAX); 50 | if (len < 0) 51 | return NULL; 52 | buf[len] = 0; 53 | return strdup(buf); 54 | } 55 | 56 | int dashdashargc(char **argv) { 57 | int i; 58 | for (i = 1; argv[i]; i++) { 59 | if (strcmp(argv[i], "--") == 0) 60 | return i; 61 | } 62 | return i; 63 | } 64 | 65 | void usage_and_exit(char *progname, char *prefix) { 66 | fprintf(stderr, "Usage:\n" 67 | "\t%s [placeholder_tag]\n" 68 | "or\n" 69 | "\t%s -- long placeholder tag\n\n", progname, progname); 70 | exit (1); 71 | } 72 | 73 | /* create a placeholder process for the namespace */ 74 | int main(int argc, char **argv, char **envp) 75 | { 76 | if (guessprefix(argv[0]) == NULL) { 77 | char *progname = basename(argv[0]); 78 | int prefixlen = strlen(progname) - NAMELEN; 79 | char *prefix = NULL; 80 | char *nspath; 81 | char *nsname; 82 | int dashdash = dashdashargc(argv); 83 | char *tag = NULL; 84 | if (prefixlen == 0) 85 | prefixerror_and_exit(progname); 86 | else 87 | asprintf(&prefix, "%.*s", prefixlen, progname); 88 | 89 | if (dashdash < argc) 90 | tag = catargv(argv+(dashdash + 1)); 91 | else if (argc == 2) { 92 | if (argv[1][0] == '-') 93 | usage_and_exit(progname, prefix); 94 | else 95 | tag = argv[1]; 96 | } else if (argc != 1) 97 | usage_and_exit(progname, prefix); 98 | 99 | clear_all_caps(); 100 | 101 | asprintf(&nspath, "%s%.*s", NSPATH, prefixlen, basename(argv[0])); 102 | if ((nsname = readlinkdup(nspath)) == NULL) 103 | return 1; 104 | 105 | static char *newargv[2]; 106 | if (tag && *tag) 107 | asprintf(&newargv[0],"%s %s", nsname, tag); 108 | else 109 | asprintf(&newargv[0],"%s", nsname); 110 | 111 | daemon(0,0); 112 | execve("/proc/self/exe", newargv, envp); 113 | return 1; 114 | 115 | } else { 116 | while (1) 117 | pause(); 118 | return 0; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /nslist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nsutils: namespace utilities 3 | * Copyright (C) 2016 Renzo Davoli, University of Bologna 4 | * 5 | * nslist: list the processes in a namespace 6 | * 7 | * Cado is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (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 copy of the GNU General Public License 18 | * along with this program; If not, see . 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #define NAMELEN (strlen(basename(__FILE__)) - 2) 41 | 42 | /* filter for scandir to pick only the /proc/[pid] directories */ 43 | static inline int isnumber(const char *s) { 44 | while (1) { 45 | if (!isdigit(*s++)) return 0; /* an empty string is *not* a number */ 46 | if (*s == 0) return 1; 47 | } 48 | } 49 | 50 | static int numberfilter(const struct dirent *de) { 51 | return isnumber(de->d_name); 52 | } 53 | 54 | /* scandir qsort comaprison: do not sort */ 55 | static int nosort(const struct dirent **a, const struct dirent **b) { 56 | return -1; 57 | } 58 | 59 | struct nsproc { 60 | int isplaceholder; 61 | pid_t pid; 62 | uid_t uid; 63 | char *cmdline; 64 | char *comm; 65 | struct nsproc *next; 66 | }; 67 | 68 | struct nslist { 69 | char *nsid; 70 | struct nsproc *proclist; 71 | struct nslist *next; 72 | }; 73 | 74 | #define BUFSIZE 1024 75 | /* get the comm of a process */ 76 | static char *dupcomm(pid_t pid) { 77 | char *out = NULL; 78 | size_t len = 0; 79 | FILE *fin, *fout; 80 | char *path; 81 | asprintf(&path, "/proc/%d/comm", pid); 82 | if (path) { 83 | if ((fin = fopen(path, "r")) != NULL) { 84 | if ((fout = open_memstream(&out, &len)) != NULL) { 85 | char buf[BUFSIZE]; 86 | size_t n; 87 | while ((n = fread(buf, 1, BUFSIZE, fin)) > 0) { 88 | fwrite(buf, 1, n, fout); 89 | } 90 | fclose(fout); 91 | if (out[len - 1] == '\n') out[len - 1] = 0; 92 | } 93 | fclose(fin); 94 | } 95 | free(path); 96 | } 97 | return out; 98 | } 99 | 100 | /* get the command line of a process. 101 | read the process status to get the name of kernel threads if cmdline is null */ 102 | static char *dupcmdline(pid_t pid, char *comm) { 103 | char *out = NULL; 104 | size_t len = 0; 105 | FILE *fin, *fout; 106 | char *path; 107 | asprintf(&path, "/proc/%d/cmdline", pid); 108 | if (path) { 109 | if ((fin = fopen(path, "r")) != NULL) { 110 | if ((fout = open_memstream(&out, &len)) != NULL) { 111 | char buf[BUFSIZE]; 112 | size_t n; 113 | while ((n = fread(buf, 1, BUFSIZE, fin)) > 0) { 114 | int i; 115 | for (i = 0; i < n; i++) 116 | if (buf[i] == 0) buf[i] = ' '; 117 | fwrite(buf, 1, n, fout); 118 | } 119 | fclose(fout); 120 | if (out[len - 1] == ' ') out[len - 1] = 0; 121 | } 122 | fclose(fin); 123 | } 124 | free(path); 125 | } 126 | if (*out == 0) { 127 | free(out); 128 | asprintf(&out, "[%s]", comm); 129 | } 130 | return out; 131 | } 132 | 133 | struct scanfilter { 134 | uid_t uid; 135 | uint32_t flags; 136 | }; 137 | #define SCANFILTER_INIT {.uid = -1, .flags=0} 138 | 139 | /* add a process in a namespace entry */ 140 | void nsproc_addproc (struct nsproc **scan, char *nsid, pid_t pid, uid_t uid, struct scanfilter *sf) { 141 | char *comm = dupcomm(pid); 142 | char *cmdline = dupcmdline(pid, comm); 143 | int isplaceholder = cmdline != NULL && strncmp(cmdline, nsid, strlen(nsid)) == 0; 144 | while (*scan != NULL && ((*scan)->isplaceholder > isplaceholder || 145 | ((*scan)->isplaceholder == isplaceholder && (*scan)->pid < pid))) 146 | scan = &((*scan)->next); 147 | struct nsproc *new = malloc(sizeof(struct nsproc)); 148 | if (new) { 149 | new->isplaceholder = isplaceholder; 150 | new->pid = pid; 151 | new->uid = uid; 152 | new->cmdline = cmdline; 153 | new->comm = comm; 154 | new->next = *scan; 155 | *scan = new; 156 | } 157 | } 158 | 159 | /* add a process in a the data structure, create a new namespace if*/ 160 | void nslist_addproc(struct nslist **scan, char *nsid, pid_t pid, uid_t uid, struct scanfilter *sf) { 161 | int cmp; 162 | while (*scan != NULL && (cmp = strcmp((*scan)->nsid, nsid)) < 0) 163 | scan = &((*scan)->next); 164 | if (cmp == 0) 165 | nsproc_addproc(&((*scan)->proclist), nsid, pid, uid, sf); 166 | else { 167 | struct nslist *new = malloc(sizeof(struct nslist)); 168 | new->nsid = strdup(nsid); 169 | new->proclist = NULL; 170 | nsproc_addproc(&(new->proclist), nsid, pid, uid, sf); 171 | new->next = *scan; 172 | *scan = new; 173 | } 174 | } 175 | 176 | /* scan /proc and create the data structure of namspaces and processes */ 177 | struct nslist *scanproc(char *prefix, struct scanfilter *sf) { 178 | struct dirent **namelist; 179 | int n; 180 | struct nslist *nslist=NULL; 181 | if ((n = scandir("/proc", &namelist, numberfilter, nosort)) > 0) { 182 | int i; 183 | for (i = 0; i < n; i++) { 184 | char path[PATH_MAX]; 185 | char nsid[PATH_MAX]; 186 | struct stat st; 187 | int len; 188 | char *typelist[] = {prefix, (char *) 0}; 189 | char **typescan; 190 | for (typescan = (prefix == NULL) ? nsnames : typelist; *typescan; typescan++) { 191 | char *type = *typescan; 192 | snprintf(path,PATH_MAX,"/proc/%s/ns/%s",namelist[i]->d_name,type); 193 | if (lstat(path, &st) == 0 && 194 | (sf->uid == -1 || sf->uid == st.st_uid)) { 195 | len = readlink(path, nsid, PATH_MAX); 196 | if (len > 0) { 197 | nsid[len] = 0; 198 | nslist_addproc(&nslist, nsid, atoi(namelist[i]->d_name), st.st_uid, sf); 199 | } 200 | } 201 | } 202 | free(namelist[i]); 203 | } 204 | free(namelist); 205 | } 206 | return nslist; 207 | } 208 | 209 | /* seach for a namespace id in the data structure */ 210 | struct nslist *nstag(struct nslist *head, char *tag) { 211 | for (; head; head = head->next) { 212 | struct nsproc *proc; 213 | if (strcmp(tag, head->nsid) == 0) 214 | return head; 215 | for (proc = head->proclist; proc; proc = proc->next) 216 | if (proc->isplaceholder) { 217 | if (strcmp(tag, proc->cmdline + (strlen(head->nsid) + 1)) == 0) 218 | return head; 219 | } else 220 | break; 221 | } 222 | return NULL; 223 | } 224 | 225 | struct nslist **nstagre(struct nslist *head, regex_t *re) { 226 | char *out = NULL; 227 | size_t outlen = 0; 228 | FILE *fout = open_memstream(&out, &outlen); 229 | if (fout) { 230 | for (; head; head = head->next) { 231 | struct nsproc *proc; 232 | for (proc = head->proclist; proc; proc = proc->next) { 233 | if (proc->isplaceholder) { 234 | if (regexec(re, proc->cmdline + (strlen(head->nsid) + 1), (size_t) 0, NULL, 0) == 0) { 235 | fwrite(&head, sizeof(struct nslist *), 1, fout); 236 | break; 237 | } 238 | } 239 | } 240 | } 241 | fwrite(&head, sizeof(struct nslist *), 1, fout); 242 | fclose(fout); 243 | return (struct nslist **) out; 244 | } 245 | return NULL; 246 | } 247 | 248 | #define PRINTFLAG_SHOWUSER 0x1 249 | #define PRINTFLAG_PLACEHOLDER_ONLY 0x2 250 | #define PRINTFLAG_SHOWCOMM 0x4 251 | #define PRINTFLAG_PIDONLY 0x8 252 | #define PRINTFLAG_COUNT 0x10 253 | #define PRINTFLAG_NSID_HEADER 0x20 254 | #define PRINTFLAG_TABULAR 0x40 255 | #define PRINTFLAG_NUMERIC_NSID 0x80 256 | #define PRINTFLAG_TAG 0x100 257 | #define PRINTFLAG_TAGONLY 0x200 258 | #define PRINTFLAG_SHORT1 0x1000 259 | #define PRINTFLAG_SHORT2 0x2000 260 | //#define PRINTFLAG_SHORT3 0x4000 261 | //#define PRINTFLAG_SHORT4 0x8000 262 | 263 | /* returns s[n] if it is the last char in s, ' ' if the s is shorter, '+' if it is longer. */ 264 | char strplus(char *s, int n) { 265 | size_t last = strlen(s) - 1; 266 | if (last < n) 267 | return ' '; 268 | else if (last == n) 269 | return s[n]; 270 | else 271 | return '+'; 272 | } 273 | 274 | /* nsid or nsid + tag */ 275 | char *nsidx(struct nslist *ns, uint32_t flags) { 276 | if (flags & PRINTFLAG_TAG) { 277 | if (ns->proclist && ns->proclist->isplaceholder) { 278 | if (flags & PRINTFLAG_TAGONLY && !(flags & PRINTFLAG_NUMERIC_NSID)) { 279 | char *tag = strchr(ns->proclist->cmdline, ' '); 280 | if (tag) 281 | return (tag+1); 282 | } 283 | return ns->proclist->cmdline; 284 | } 285 | } 286 | return ns->nsid; 287 | } 288 | 289 | /* print nsid (numeric if requested) */ 290 | void print_nsid(const char *nsid, uint32_t flags, int aligned) { 291 | if (flags & PRINTFLAG_NUMERIC_NSID) { 292 | char *begin = strchr(nsid, '['); 293 | char *end = strchr(nsid, ']'); 294 | if (begin && end) { 295 | unsigned long long nsidnum = strtoull(begin+1, NULL, 10); 296 | printflen("%*llu%s",end-begin-1,nsidnum,aligned ? " " : ""); 297 | } 298 | } else { 299 | if (aligned) 300 | printflen("%*s%s ",nsalign(nsid),"",nsid); 301 | else 302 | printflen("%s",nsid); 303 | } 304 | } 305 | 306 | /* print header lines */ 307 | void print_header(char *nsid, uint32_t flags){ 308 | if (flags & PRINTFLAG_NSID_HEADER) { 309 | print_nsid(nsid, flags, 0); 310 | printflen("\n"); 311 | } 312 | if (!(flags & PRINTFLAG_SHORT1)) { 313 | ssize_t nsidlen; 314 | if (!(flags & PRINTFLAG_NSID_HEADER)) { 315 | if (flags & PRINTFLAG_NUMERIC_NSID) { 316 | char *begin = strchr(nsid, '['); 317 | char *end = strchr(nsid, ']'); 318 | nsidlen = end-begin-1; 319 | } else 320 | nsidlen = nsalign(nsid) + strlen(nsid); 321 | printflen("%*s ",nsidlen,"NAMESPACE"); 322 | } 323 | printflen("%8s ", "PID"); 324 | if (flags & PRINTFLAG_SHOWUSER) 325 | printflen("%-9s ", "USER"); 326 | if (flags & PRINTFLAG_SHOWCOMM) 327 | printflen("COMMAND\n"); 328 | else 329 | printflen("CMDLINE\n"); 330 | } 331 | } 332 | 333 | /* nslist output for one process */ 334 | void print_oneproc(struct nsproc *proc, char *nsid, uint32_t flags) { 335 | static int count; 336 | if (proc == NULL) { 337 | if (count > 0) printflen("\n"); 338 | count = 0; 339 | return; 340 | } 341 | if (count++ == 0) 342 | print_header(nsid, flags); 343 | if (flags & PRINTFLAG_SHORT1) { 344 | if (!(flags & PRINTFLAG_SHORT2)) 345 | printflen("%8d ", proc->pid); 346 | print_nsid(nsid, flags, 0); 347 | printflen("\n"); 348 | } else { 349 | if (!(flags & PRINTFLAG_NSID_HEADER)) 350 | print_nsid(nsid, flags, 1); 351 | if (!(flags & PRINTFLAG_PLACEHOLDER_ONLY) || proc->isplaceholder) { 352 | printflen("%8d ", proc->pid); 353 | if (flags & PRINTFLAG_SHOWUSER) { 354 | char *user = memogetusername(proc->uid); 355 | printflen("%-8.8s%c ",user,strplus(user,8)); 356 | } 357 | if (flags & PRINTFLAG_SHOWCOMM) 358 | printflen("%s\n",proc->comm); 359 | else 360 | printflen("%s\n",proc->cmdline); 361 | } 362 | } 363 | } 364 | 365 | /* scan the processes of the namespace pointed by 'head' and print_oneproc for each one */ 366 | int print_ns_proc(struct nslist *head, regex_t *re, pid_t pid, uint32_t flags) { 367 | int count = 0; 368 | struct nsproc *proc; 369 | // list all + PRINTFLAG_SHORT2, print only one line per namespace 370 | if (flags & PRINTFLAG_SHORT2 && pid < 0 && head->proclist) 371 | pid = head->proclist->pid; 372 | if (pid < 0 && !(flags & PRINTFLAG_TABULAR)) 373 | flags |= PRINTFLAG_NSID_HEADER; 374 | else if (!(flags & PRINTFLAG_SHORT1)) 375 | flags &= ~PRINTFLAG_TAG; 376 | if (flags & PRINTFLAG_NSID_HEADER) 377 | print_oneproc(NULL, NULL, flags); //set line count to zero 378 | for (proc = head->proclist; proc; proc = proc->next) { 379 | if (pid == -1 || pid == proc->pid) { 380 | if (regexec(re, proc->comm, (size_t) 0, NULL, 0) == 0) { 381 | if (!(flags & PRINTFLAG_PLACEHOLDER_ONLY) || proc->isplaceholder) { 382 | if (!(flags & PRINTFLAG_COUNT)) { 383 | if (flags & PRINTFLAG_PIDONLY) { 384 | printf("%d\n",proc->pid); 385 | } else 386 | print_oneproc(proc, nsidx(head, flags), flags); 387 | } 388 | count++; 389 | } 390 | } 391 | } 392 | } 393 | return count; 394 | } 395 | 396 | /* scan all the namespace and print what is requested */ 397 | int print_ns(struct nslist *head, regex_t *re, char *args, uint32_t flags) { 398 | pid_t pid = isnumber(args) ? atoi(args) : -1; 399 | struct nslist *thisns = NULL; 400 | int count = 0; 401 | if (pid == -1 && *args) { 402 | thisns = nstag(head, args); 403 | if (thisns == NULL) { 404 | fprintf(stderr,"%s: namespace not found\n",args); 405 | return 0; 406 | } 407 | } 408 | for (; head; head = head->next) { 409 | if (thisns == NULL || thisns == head) 410 | count += print_ns_proc(head, re, pid, flags); 411 | } 412 | return count; 413 | } 414 | 415 | void usage_and_exit(char *progname, char *prefix) { 416 | if (prefix == NULL) 417 | prefix = randomprefix(); 418 | fprintf(stderr, "Usage: %s [options] [pid_nsid_tag] [pid_nsid_tag] ... [-- long ns tag]\n" 419 | " pid_nsid_tag can be:\n" 420 | " * a pid\n" 421 | " * a namespace (ns from now on) id (e.g. %s:[1234567890])\n" 422 | " * the tag of a ns holder defined by a nshold(1) command (e.g. %snshold)\n" 423 | " or a regular expression of a tag (if -r)\n" 424 | "\n", progname, prefix, prefix); 425 | fprintf(stderr, "OPTIONS:\n" 426 | " -h | --help Display this information\n" 427 | " -r | --regex arguments are regular expressions of ns tags\n" 428 | " -u | --listuser show process owners' usernames\n" 429 | " -U username |\n" 430 | " --user username only match processes belonging to this username (or uid).\n" 431 | " -H | --placeholder show only placeholder processes\n" 432 | " -C | --listcomm show the command instead of the command line\n" 433 | " -p | --pid return just the list of pids of matching processes\n" 434 | " -c | --count return just the number of matching processes\n" 435 | " -T | --tabular give a tabular output\n" 436 | " (without titles and separations between namespaces)\n" 437 | " -n | --numeric list the ns numeric id\n" 438 | " (1234567890 instead of %s[1234567890])\n" 439 | " -s short form: list only pid and ns id (for scripts)\n" 440 | " -ss | -s -s very short form: list ns id only\n" 441 | " --short n --short n has the same meaning of -s repeated n times\n" 442 | " -t | -tag show a ns tag together with the ns id (when defined)\n" 443 | " -tt | -t -t |\n" 444 | " --tagonly show a ns tag instead of the ns id (when defined)\n" 445 | " -R regex |\n" 446 | " --recomm regex show only those processes whose command match regex\n" 447 | " (regex is a regular expression)\n" 448 | "\n", prefix); 449 | exit (1); 450 | } 451 | 452 | static char *short_options = "hU:uHCR:rpctsnT"; 453 | static struct option long_options[] = { 454 | {"help", no_argument, 0, 'h' }, 455 | {"user", required_argument, 0, 'U' }, 456 | {"listuser", no_argument, 0, 'u' }, 457 | {"placeholder", no_argument, 0, 'H' }, 458 | {"listcomm", no_argument, 0, 'C' }, 459 | {"recomm", required_argument, 0, 'R' }, 460 | {"regex", no_argument, 0, 'r' }, 461 | {"pid", no_argument , 0, 'p' }, 462 | {"count", no_argument , 0, 'c' }, 463 | {"tabular", no_argument , 0, 'T' }, 464 | {"numeric", no_argument , 0, 'n' }, 465 | {"tag", no_argument , 0, 't' }, 466 | {"short", required_argument, 0, 0x100 + 's' }, 467 | {"tagonly", no_argument , 0, 0x100 + 't' }, 468 | {0, 0, 0, 0 } 469 | }; 470 | 471 | static regex_t *getrefilter(const char *regex, int cflags) { 472 | regex_t *preg = malloc(sizeof(regex_t)); 473 | if (preg) { 474 | int err = regcomp(preg, regex, cflags); 475 | if (err != 0) { 476 | size_t errsize = regerror(err, preg, NULL, 0); 477 | char errbuf[errsize]; 478 | regerror(err, preg, errbuf, errsize); 479 | fprintf(stderr, "regex error: %s\n", errbuf); 480 | free(preg); 481 | preg = NULL; 482 | } 483 | } 484 | return preg; 485 | } 486 | 487 | int dashdashargc(char **argv) { 488 | int i; 489 | for (i = 1; argv[i]; i++) { 490 | if (strcmp(argv[i], "--") == 0) 491 | return i; 492 | } 493 | return i; 494 | } 495 | 496 | int main(int argc, char *argv[]) { 497 | char *progname = basename(argv[0]); 498 | int prefixlen = strlen(progname) - NAMELEN; 499 | char *prefix = NULL; 500 | struct nslist *nslist; 501 | static struct scanfilter scanfilter = SCANFILTER_INIT; 502 | static uint32_t printflags; 503 | regex_t *refilter = NULL; 504 | int refilter_flags = REG_NOSUB; 505 | int dashdash = dashdashargc(argv); 506 | char *finalarg = NULL; 507 | int regex_mode = 0; 508 | int count = 0; 509 | 510 | if (dashdash < argc) { 511 | argc = dashdash + 1; 512 | argv[dashdash] = finalarg = catargv(argv+argc); 513 | argv[argc] = 0; 514 | } 515 | 516 | if (prefixlen != 0) 517 | asprintf(&prefix, "%.*s", prefixlen, progname); 518 | 519 | while (1) { 520 | int c, option_index = 0; 521 | c = getopt_long(argc, argv, short_options, long_options, &option_index); 522 | if (c < 0) 523 | break; 524 | switch (c) { 525 | case 'u': 526 | printflags |= PRINTFLAG_SHOWUSER; 527 | break; 528 | case 'U': 529 | if (isnumber(optarg)) 530 | scanfilter.uid = atoi(optarg); 531 | else { 532 | struct passwd *pwd = getpwnam(optarg); 533 | if (pwd == NULL) { 534 | fprintf(stderr,"User %s not found\n",optarg); 535 | usage_and_exit(progname, prefix); 536 | } 537 | scanfilter.uid = pwd->pw_uid; 538 | } 539 | break; 540 | case 'H': 541 | printflags |= PRINTFLAG_PLACEHOLDER_ONLY; 542 | break; 543 | case 'C': 544 | printflags |= PRINTFLAG_SHOWCOMM; 545 | break; 546 | case 'R': 547 | if ((refilter = getrefilter(optarg, refilter_flags)) == NULL) 548 | exit(1); 549 | break; 550 | case 'T': 551 | printflags |= PRINTFLAG_TABULAR; 552 | break; 553 | case 'p': 554 | printflags |= PRINTFLAG_PIDONLY; 555 | printflags |= PRINTFLAG_TABULAR; 556 | break; 557 | case 'c': 558 | printflags |= PRINTFLAG_COUNT; 559 | printflags |= PRINTFLAG_TABULAR; 560 | break; 561 | case 'n': 562 | printflags |= PRINTFLAG_NUMERIC_NSID; 563 | break; 564 | case 0x100 + 't': 565 | printflags |= PRINTFLAG_TAG; 566 | case 't': 567 | if (printflags & PRINTFLAG_TAG) printflags |= PRINTFLAG_TAGONLY; 568 | printflags |= PRINTFLAG_TAG; 569 | break; 570 | case 's': 571 | //if (printflags & PRINTFLAG_SHORT3) printflags |= PRINTFLAG_SHORT4; 572 | //if (printflags & PRINTFLAG_SHORT2) printflags |= PRINTFLAG_SHORT3; 573 | if (printflags & PRINTFLAG_SHORT1) printflags |= PRINTFLAG_SHORT2; 574 | printflags |= PRINTFLAG_SHORT1; 575 | printflags |= PRINTFLAG_TABULAR; 576 | break; 577 | case 0x100 + 's': { 578 | int n = atoi(optarg); 579 | switch (n) { 580 | //case 4: printflags |= PRINTFLAG_SHORT4; 581 | //case 3: printflags |= PRINTFLAG_SHORT3; 582 | case 2: printflags |= PRINTFLAG_SHORT2; 583 | case 1: printflags |= PRINTFLAG_SHORT1; 584 | printflags |= PRINTFLAG_TABULAR; 585 | break; 586 | default: 587 | fprintf(stderr,"\nshort level must be 1, 2, 3 or 4\n\n"); 588 | usage_and_exit(progname, prefix); 589 | } 590 | } 591 | break; 592 | case 'r': 593 | regex_mode = 1; 594 | break; 595 | case 'h': 596 | default: 597 | usage_and_exit(progname, prefix); 598 | break; 599 | } 600 | } 601 | 602 | argc -= optind; 603 | argv += optind; 604 | 605 | nslist = scanproc(prefix, &scanfilter); 606 | 607 | if (refilter == NULL) 608 | refilter = getrefilter(".*", 0); 609 | 610 | if (argc == 0 && !finalarg) 611 | count += print_ns(nslist, refilter, "", printflags); 612 | else { 613 | for (; *argv; argv++) { 614 | if (regex_mode && *argv != finalarg) { 615 | regex_t *regex = getrefilter(*argv, refilter_flags); 616 | if (regex) { 617 | struct nslist **nstags = nstagre(nslist, regex); 618 | if (nstags) { 619 | struct nslist **scan; 620 | for (scan=nstags; *scan; scan++) 621 | count += print_ns_proc(*scan, refilter, -1, printflags); 622 | } 623 | regfree(regex); 624 | free(regex); 625 | } 626 | } else 627 | count += print_ns(nslist, refilter, *argv, printflags); 628 | } 629 | } 630 | if (printflags & PRINTFLAG_COUNT) 631 | printf("%d\n", count); 632 | return 0; 633 | } 634 | -------------------------------------------------------------------------------- /nsrelease.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nsutils: namespace utilities 3 | * Copyright (C) 2016 Renzo Davoli, University of Bologna 4 | * 5 | * nsrelease: release a "keepalive" process 6 | * 7 | * Cado is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (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 copy of the GNU General Public License 18 | * along with this program; If not, see . 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #define NAMELEN (strlen(basename(__FILE__)) - 2) 36 | 37 | static char *short_options = "hr"; 38 | static struct option long_options[] = { 39 | {"help", no_argument, 0, 'h' }, 40 | {"regex", no_argument, 0, 'r' }, 41 | {0, 0, 0, 0 } 42 | }; 43 | 44 | void usage_and_exit(char *progname, char *prefix) { 45 | if (prefix == NULL) 46 | prefix = randomprefix(); 47 | fprintf(stderr, "Usage:\n" 48 | " %s [-r | --regex] placeholder [placeholder] [-- long placeholder tag]\n" 49 | " placeholder can be dentified by (if not -r):\n" 50 | " * a pid\n" 51 | " * a namespace id (e.g. %s:[1234567890])\n" 52 | " * the tag of a namespace holder defined by some nshold(1) command (e.g. %snshold)\n" 53 | " or a regular expression of a tag (if -r)\n" 54 | "\n", progname, prefix, prefix); 55 | exit (1); 56 | } 57 | 58 | int dashdashargc(char **argv) { 59 | int i; 60 | for (i = 1; argv[i]; i++) { 61 | if (strcmp(argv[i], "--") == 0) 62 | return i; 63 | } 64 | return i; 65 | } 66 | 67 | /* kill placeholder processes */ 68 | int main(int argc, char *argv[]) 69 | { 70 | char *progname = basename(argv[0]); 71 | int prefixlen = strlen(progname) - NAMELEN; 72 | char *prefix = NULL; 73 | int regex_mode = 0; 74 | int dashdash = dashdashargc(argv); 75 | char *finalarg = NULL; 76 | int count = 0; 77 | int reflags = 0; 78 | 79 | if (dashdash < argc) { 80 | argc = dashdash + 1; 81 | argv[dashdash] = finalarg = catargv(argv+argc); 82 | argv[argc] = 0; 83 | } 84 | 85 | if (prefixlen != 0) 86 | asprintf(&prefix, "%.*s", prefixlen, progname); 87 | 88 | while (1) { 89 | int c, option_index = 0; 90 | c = getopt_long(argc, argv, short_options, long_options, &option_index); 91 | if (c < 0) 92 | break; 93 | switch (c) { 94 | case 'r': 95 | regex_mode = 1; 96 | break; 97 | case 'h': 98 | default: 99 | usage_and_exit(progname, prefix); 100 | break; 101 | } 102 | } 103 | 104 | argc -= optind; 105 | argv += optind; 106 | 107 | for (; *argv; argv++) { 108 | if (regex_mode && *argv != finalarg) { 109 | regex_t re; 110 | int err = regcomp(&re, *argv, reflags); 111 | if (err != 0) { 112 | size_t errsize = regerror(err, &re, NULL, 0); 113 | char errbuf[errsize]; 114 | regerror(err, &re, errbuf, errsize); 115 | fprintf(stderr, "%s: regex error: %s\n", *argv, errbuf); 116 | } else { 117 | pid_t *pids = nssearchre(prefix, &re); 118 | if (*pids) { 119 | pid_t *scan; 120 | for (scan = pids; *scan; scan ++) { 121 | kill(*scan, SIGTERM); 122 | count++; 123 | } 124 | } else 125 | fprintf(stderr,"no namespace placeholder matches \"%s\"\n", *argv); 126 | free(pids); 127 | regfree(&re); 128 | } 129 | } else { 130 | pid_t pid; 131 | if ((pid = nssearch(prefix ? prefix : guessprefix(*argv), *argv)) <= 0) { 132 | if (pid == 0) 133 | fprintf(stderr,"%s: namespace placeholder not found\n", *argv); 134 | else 135 | fprintf(stderr,"%s: too many namespace placeholders match\n", *argv); 136 | } else { 137 | kill(pid, SIGTERM); 138 | count ++; 139 | } 140 | } 141 | } 142 | return count == 0 ? 1 : 0; 143 | } 144 | -------------------------------------------------------------------------------- /nssearch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nsutils: namespace utilities 3 | * Copyright (C) 2016 Renzo Davoli, University of Bologna 4 | * 5 | * nssearch: search a namespace by pid, identifier or name-tag 6 | * 7 | * Cado is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (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 copy of the GNU General Public License 18 | * along with this program; If not, see . 19 | * 20 | */ 21 | 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #define MAX_NSHOLD_CMDLINE_LEN 1024 35 | 36 | static inline int isnumber(const char *s) { 37 | while (1) { 38 | if (!isdigit(*s++)) return 0; 39 | if (*s == 0) return 1; 40 | } 41 | } 42 | 43 | /* is cmd a namespaceid for type? (or for any type if type == NULL)? */ 44 | static inline int isnsid(const char *cmd, const char *type) { 45 | if (type == NULL) 46 | return guessprefix(cmd) != NULL; 47 | else 48 | return checkprefix(cmd, type); 49 | } 50 | 51 | /* read cmdline and store it in linebuf */ 52 | static void readcmdline(const char *pidstr, char linebuf[MAX_NSHOLD_CMDLINE_LEN]) { 53 | char *path; 54 | linebuf[0]=0; 55 | /* get the commandline: build the path, open the file */ 56 | if (asprintf(&path, "/proc/%s/cmdline", pidstr) >= 0) { 57 | FILE *cmdline = fopen(path, "r"); 58 | if (cmdline) { 59 | /* read the commandline anche check if this is a placeholder */ 60 | fgets(linebuf, MAX_NSHOLD_CMDLINE_LEN, cmdline); 61 | fclose(cmdline); 62 | } 63 | free(path); 64 | } 65 | } 66 | 67 | static int ckcmdline_pid(const char *pidstr, const char *type) { 68 | char linebuf[MAX_NSHOLD_CMDLINE_LEN]; 69 | readcmdline(pidstr, linebuf); 70 | return isnsid(linebuf, type); 71 | } 72 | 73 | /* check if the pid is a specific namespace placeholder */ 74 | /* name is "" when re != NULL */ 75 | static int ckcmdline(const char *pidstr, const char *name, const char *type) { 76 | char linebuf[MAX_NSHOLD_CMDLINE_LEN]; 77 | readcmdline(pidstr, linebuf); 78 | if (isnsid(linebuf, type)) { 79 | char *tail = strchr(linebuf, ' '); 80 | if (tail) { 81 | /* this holder has a tag. Check if 'name' matches the namespace id or the holder tag */ 82 | return strncmp(name, linebuf, tail-linebuf) == 0 || strcmp(tail+1, name) == 0; 83 | } else 84 | /* this holder has no tag. Check if 'name' matches the entire cmdline */ 85 | return strcmp(name, linebuf) == 0; 86 | } 87 | return 0; 88 | } 89 | 90 | static int ckcmdline_re(const char *pidstr, regex_t *re, const char *type) { 91 | char linebuf[MAX_NSHOLD_CMDLINE_LEN]; 92 | readcmdline(pidstr, linebuf); 93 | if (isnsid(linebuf, type)) { 94 | char *tail = strchr(linebuf, ' '); 95 | if (tail) 96 | return regexec(re, tail+1, 0, NULL, 0) == 0; 97 | } 98 | return 0; 99 | } 100 | 101 | /* if nssearchone: check if this process (not a placeholder) 102 | is running in the desired namespace */ 103 | static int ckns(const char *pidstr, const char *name, const char *type) { 104 | char *path; 105 | int rval = 0; 106 | if (getpid() != atoi(pidstr) && // for some reason the nsjoin fails on the process itself 107 | asprintf(&path, "/proc/%s/ns/%s", pidstr, type) >= 0) { 108 | char nsid[PATH_MAX+1]; 109 | int len; 110 | if ((len = readlink(path, nsid, PATH_MAX+1)) > 0) { 111 | nsid[len] = 0; 112 | rval = strcmp(name, nsid) == 0; 113 | } 114 | free(path); 115 | } 116 | return rval; 117 | } 118 | 119 | static int numberfilter(const struct dirent *de) { 120 | return isnumber(de->d_name); 121 | } 122 | 123 | static int nosort(const struct dirent **a, const struct dirent **b) { 124 | return -1; 125 | } 126 | 127 | /* search a pid of a placeholder */ 128 | /* type is the type of namespace e.g. "net", "ipc", "pid", "user" etc 129 | name can be: 130 | * a numeric string (a pid) e.g. "4242" 131 | * a namespace id e.g. "net:[1234567890]" 132 | * a tag of a namespace holder 133 | */ 134 | /* return 0 if not found, -1 if too many, > 0 in case of a successful search */ 135 | pid_t nssearch(char *type, char *name) { 136 | pid_t rval = 0; 137 | if (isnumber(name) && ckcmdline_pid(name, type)) /* PID: ok if it is a placeholder */ 138 | return atoi(name); 139 | else { 140 | struct dirent **namelist; 141 | int n; 142 | 143 | if ((n = scandir("/proc", &namelist, numberfilter, nosort)) > 0) { 144 | int i; 145 | for (i = 0; i < n; i++) { 146 | if (ckcmdline(namelist[i]->d_name, name, type)) { 147 | rval = rval > 0 ? -1 : atoi(namelist[i]->d_name); 148 | if (rval < 0) break; /* the first placeholder of a nsid fits */ 149 | } 150 | } 151 | for (i = 0; i < n; i++) 152 | free(namelist[n]); 153 | free(namelist); 154 | } 155 | } 156 | return rval; 157 | } 158 | 159 | pid_t *nssearchre(char *type, regex_t *re) { 160 | struct dirent **namelist; 161 | int n; 162 | char *out = NULL; 163 | size_t outlen = 0; 164 | pid_t pid; 165 | FILE *fout = open_memstream(&out, &outlen); 166 | if (fout) { 167 | if ((n = scandir("/proc", &namelist, numberfilter, nosort)) > 0) { 168 | int i; 169 | for (i = 0; i < n; i++) { 170 | if (ckcmdline_re(namelist[i]->d_name, re, type)) { 171 | pid = atoi(namelist[i]->d_name); 172 | fwrite(&pid, sizeof(pid), 1, fout); 173 | } 174 | free(namelist[n]); 175 | } 176 | free(namelist); 177 | } 178 | pid = 0; 179 | fwrite(&pid, sizeof(pid), 1, fout); 180 | fclose(fout); 181 | return (pid_t *) out; 182 | } else 183 | return NULL; 184 | } 185 | 186 | /* search a pid of a placeholder or any pid running in the desired namespace */ 187 | /* type is the type of namespace e.g. "net", "ipc", "pid", "user" etc 188 | name can be: 189 | * a numeric string (a pid) e.g. "4242" 190 | * a namespace id e.g. "net:[1234567890]" 191 | * a tag of a namespace holder 192 | */ 193 | /* return 0 if not found, -1 if too many, > 0 in case of a successful search */ 194 | pid_t nssearchone(char *type, char *name) { 195 | if (isnumber(name)) 196 | return atoi(name); 197 | else { 198 | pid_t rval = 0; 199 | struct dirent **namelist; 200 | int isnsid = checkprefix(name, type); 201 | int n; 202 | 203 | if ((n = scandir("/proc", &namelist, numberfilter, nosort)) > 0) { 204 | int i; 205 | for (i = 0; i < n; i++) { 206 | if (ckcmdline(namelist[i]->d_name, name, type)) { 207 | rval = rval > 0 ? -1 : atoi(namelist[i]->d_name); 208 | if (isnsid || rval < 0) break; /* the first placeholder of a nsid fits */ 209 | } 210 | } 211 | if (isnsid && rval == 0) { 212 | for (i = 0; i < n; i++) { 213 | if (rval < 0 && ckns(namelist[i]->d_name, name, type)) { 214 | rval = atoi(namelist[i]->d_name); 215 | break; 216 | } 217 | } 218 | } 219 | for (i = 0; i < n; i++) 220 | free(namelist[n]); 221 | free(namelist); 222 | } 223 | return rval; 224 | } 225 | } 226 | 227 | -------------------------------------------------------------------------------- /nssearch.h: -------------------------------------------------------------------------------- 1 | #ifndef NSSEARCH_H 2 | #define NSSEARCH_H 3 | #include 4 | #include 5 | 6 | pid_t nssearch(char *type, char *name); 7 | 8 | pid_t *nssearchre(char *type, regex_t *re); 9 | 10 | pid_t nssearchone(char *type, char *name); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /prefix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nsutils: namespace utilities 3 | * Copyright (C) 2016 Renzo Davoli, University of Bologna 4 | * 5 | * prefix: management of ns prefix. 6 | * 7 | * Cado is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (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 copy of the GNU General Public License 18 | * along with this program; If not, see . 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | char *nsnames[] = { "cgroup", "ipc", "mnt", "net", "pid", "user", "time", "uts", (char *)0}; 29 | size_t nsnames_maxlen = 6; 30 | 31 | void prefixerror_and_exit(char *progname) { 32 | char **ns; 33 | fprintf(stderr, "use a prefix to specify the type of namespace:\n "); 34 | for (ns = nsnames; *ns; ns++) 35 | fprintf(stderr, " %s%s",*ns,progname); 36 | fprintf(stderr, "\n"); 37 | exit(2); 38 | } 39 | 40 | #define SUFFIX ":[" 41 | int checkprefix(const char *str, const char *type) { 42 | if (type == NULL) 43 | return 0; 44 | ssize_t typelen=strlen(type); 45 | return strncmp(str, type, typelen) == 0 && 46 | strncmp(str+typelen, SUFFIX, sizeof(SUFFIX)-1) == 0; 47 | } 48 | 49 | char *guessprefix(const char *str) { 50 | if (str) { 51 | char **ns; 52 | for (ns = nsnames; *ns; ns++) 53 | if (checkprefix(str, *ns)) 54 | return *ns; 55 | } 56 | return NULL; 57 | } 58 | 59 | char *randomprefix(void) { 60 | srand(time(NULL)); 61 | return nsnames[rand() % (sizeof(nsnames)/sizeof(char *) - 1)]; 62 | } 63 | -------------------------------------------------------------------------------- /prefix.h: -------------------------------------------------------------------------------- 1 | #ifndef PREFIXERROR_H 2 | #define PREFIXERROR_H 3 | 4 | extern char *nsnames[]; 5 | extern size_t nsnames_maxlen; 6 | 7 | void prefixerror_and_exit(char *progname); 8 | 9 | int checkprefix(const char *str, const char *type); 10 | 11 | char *guessprefix(const char *str); 12 | 13 | static inline ssize_t nsalign(const char *s) { 14 | char *col = strchr(s,':'); 15 | return col ? nsnames_maxlen - (col - s) : 0; 16 | } 17 | 18 | char *randomprefix(void); 19 | #endif // PREFIXERROR_H 20 | -------------------------------------------------------------------------------- /printflen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | /* get the current width of the terminal line. 10 | returns -1 is the output is not a terminal. 11 | it memoizes the result */ 12 | 13 | static int getlinewidth(void) { 14 | static int linewidth; 15 | if (__builtin_expect((linewidth == 0), 0)) { 16 | if (isatty(STDOUT_FILENO)) { 17 | struct winsize w; 18 | ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); 19 | 20 | linewidth = w.ws_col; 21 | } else 22 | linewidth = -1; 23 | } 24 | return linewidth; 25 | } 26 | 27 | /* printf cutting the line to the terminal width (only if the STDOUT is a terminal */ 28 | int printflen(const char *format, ...) { 29 | va_list ap; 30 | int linewidth = getlinewidth(); 31 | int rval = -1; 32 | va_start(ap, format); 33 | if (linewidth < 0) 34 | rval = vprintf(format, ap); 35 | else { 36 | static char *linebuf; 37 | static int pos = 0; 38 | char *printfout; 39 | int i; 40 | if (__builtin_expect(linebuf == NULL, 0)) 41 | linebuf = malloc(linewidth+1); 42 | if (__builtin_expect(linebuf == NULL, 0)) 43 | goto error; 44 | rval = vasprintf(&printfout, format, ap); 45 | if (__builtin_expect(rval < 0, 0)) 46 | goto error; 47 | for (i = 0; i < rval; i++) { 48 | if (printfout[i] == '\n') { 49 | linebuf[pos]=0; 50 | printf("%s\n",linebuf); 51 | pos=0; 52 | } else { 53 | if (pos < linewidth) 54 | linebuf[pos++] = printfout[i]; 55 | else 56 | linebuf[pos - 1] = '+'; 57 | } 58 | } 59 | free(printfout); 60 | } 61 | error: 62 | va_end(ap); 63 | return rval; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /printflen.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINTFLEN_H 2 | #define PRINTFLEN_H 3 | 4 | int printflen(const char *format, ...); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /symlinks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SYMLINKS ${CMAKE_CURRENT_SOURCE_DIR}/*ns*) 2 | foreach(SYMLINK_PATH IN LISTS SYMLINKS) 3 | get_filename_component(SYMLINK ${SYMLINK_PATH} NAME) 4 | install(FILES ${SYMLINK} DESTINATION ${CMAKE_INSTALL_BINDIR}) 5 | endforeach(SYMLINK_PATH) 6 | -------------------------------------------------------------------------------- /symlinks/cgroupnshold: -------------------------------------------------------------------------------- 1 | nshold -------------------------------------------------------------------------------- /symlinks/cgroupnslist: -------------------------------------------------------------------------------- 1 | nslist -------------------------------------------------------------------------------- /symlinks/cgroupnsrelease: -------------------------------------------------------------------------------- 1 | nsrelease -------------------------------------------------------------------------------- /symlinks/ipcnshold: -------------------------------------------------------------------------------- 1 | nshold -------------------------------------------------------------------------------- /symlinks/ipcnslist: -------------------------------------------------------------------------------- 1 | nslist -------------------------------------------------------------------------------- /symlinks/ipcnsrelease: -------------------------------------------------------------------------------- 1 | nsrelease -------------------------------------------------------------------------------- /symlinks/mntnshold: -------------------------------------------------------------------------------- 1 | nshold -------------------------------------------------------------------------------- /symlinks/mntnslist: -------------------------------------------------------------------------------- 1 | nslist -------------------------------------------------------------------------------- /symlinks/mntnsrelease: -------------------------------------------------------------------------------- 1 | nsrelease -------------------------------------------------------------------------------- /symlinks/netnshold: -------------------------------------------------------------------------------- 1 | nshold -------------------------------------------------------------------------------- /symlinks/netnslist: -------------------------------------------------------------------------------- 1 | nslist -------------------------------------------------------------------------------- /symlinks/netnsrelease: -------------------------------------------------------------------------------- 1 | nsrelease -------------------------------------------------------------------------------- /symlinks/pidnshold: -------------------------------------------------------------------------------- 1 | nshold -------------------------------------------------------------------------------- /symlinks/pidnslist: -------------------------------------------------------------------------------- 1 | nslist -------------------------------------------------------------------------------- /symlinks/pidnsrelease: -------------------------------------------------------------------------------- 1 | nsrelease -------------------------------------------------------------------------------- /symlinks/timenshold: -------------------------------------------------------------------------------- 1 | nshold -------------------------------------------------------------------------------- /symlinks/timenslist: -------------------------------------------------------------------------------- 1 | nslist -------------------------------------------------------------------------------- /symlinks/timensrelease: -------------------------------------------------------------------------------- 1 | nsrelease -------------------------------------------------------------------------------- /symlinks/usernshold: -------------------------------------------------------------------------------- 1 | nshold -------------------------------------------------------------------------------- /symlinks/usernslist: -------------------------------------------------------------------------------- 1 | nslist -------------------------------------------------------------------------------- /symlinks/usernsrelease: -------------------------------------------------------------------------------- 1 | nsrelease -------------------------------------------------------------------------------- /symlinks/utsnshold: -------------------------------------------------------------------------------- 1 | nshold -------------------------------------------------------------------------------- /symlinks/utsnslist: -------------------------------------------------------------------------------- 1 | nslist -------------------------------------------------------------------------------- /symlinks/utsnsrelease: -------------------------------------------------------------------------------- 1 | nsrelease --------------------------------------------------------------------------------