├── CMakeLists.txt ├── LICENSE ├── LICENSE2 ├── NOTICE ├── README.md ├── api_for_osxiec_script.h ├── example ├── bin │ └── hello ├── config.txt ├── container_config.txt ├── file.txt ├── run.sh ├── test.c └── test │ └── test.osxs ├── osxiec.c ├── osxiec.h ├── osxiec_script ├── osxiec_script.c └── osxiec_script.h ├── plugin_manager ├── plugin.h ├── plugin_manager.c └── plugin_manager.h ├── samples ├── Dockerfile ├── container1 ├── container2 ├── container_config.txt ├── deploy_config ├── deploy_multiple_config └── sample_plugin.c └── scripts ├── install.sh └── osxiec_deploy_multiple.sh /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.27) 2 | project(osxiec C) 3 | 4 | set(CMAKE_C_STANDARD 11) 5 | 6 | # List shared sources 7 | set(OSXIEC_SOURCES 8 | osxiec.c 9 | plugin_manager/plugin.h 10 | plugin_manager/plugin_manager.h 11 | plugin_manager/plugin_manager.c 12 | osxiec_script/osxiec_script.h 13 | osxiec_script/osxiec_script.c 14 | api_for_osxiec_script.h 15 | ) 16 | 17 | # Build shared library (.dylib) 18 | add_library(osxiec_shared SHARED 19 | ${OSXIEC_SOURCES} 20 | ) 21 | 22 | set_target_properties(osxiec_shared PROPERTIES OUTPUT_NAME "osxiec") 23 | 24 | # Build executable 25 | add_executable(osxiec ${OSXIEC_SOURCES}) 26 | 27 | # Find and link CURL 28 | find_package(CURL REQUIRED) 29 | target_link_libraries(osxiec PRIVATE CURL::libcurl) 30 | target_link_libraries(osxiec_shared PRIVATE CURL::libcurl) 31 | 32 | # Find and link Readline 33 | include_directories(/opt/homebrew/opt/readline/include) 34 | target_link_directories(osxiec PRIVATE /opt/homebrew/opt/readline/lib) 35 | target_link_directories(osxiec_shared PRIVATE /opt/homebrew/opt/readline/lib) 36 | 37 | target_link_libraries(osxiec PRIVATE readline) 38 | target_link_libraries(osxiec_shared PRIVATE readline) 39 | 40 | # Find and link json-c 41 | include_directories(/opt/homebrew/Cellar/json-c/0.18/include) 42 | target_link_directories(osxiec PRIVATE /opt/homebrew/Cellar/json-c/0.18/lib) 43 | target_link_directories(osxiec_shared PRIVATE /opt/homebrew/Cellar/json-c/0.18/lib) 44 | 45 | target_link_libraries(osxiec PRIVATE json-c) 46 | target_link_libraries(osxiec_shared PRIVATE json-c) 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 2.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 4 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION 5 | OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial content 12 | Distributed under this Agreement, and 13 | 14 | b) in the case of each subsequent Contributor: 15 | i) changes to the Program, and 16 | ii) additions to the Program; 17 | where such changes and/or additions to the Program originate from 18 | and are Distributed by that particular Contributor. A Contribution 19 | "originates" from a Contributor if it was added to the Program by 20 | such Contributor itself or anyone acting on such Contributor's behalf. 21 | Contributions do not include changes or additions to the Program that 22 | are not Modified Works. 23 | 24 | "Contributor" means any person or entity that Distributes the Program. 25 | 26 | "Licensed Patents" mean patent claims licensable by a Contributor which 27 | are necessarily infringed by the use or sale of its Contribution alone 28 | or when combined with the Program. 29 | 30 | "Program" means the Contributions Distributed in accordance with this 31 | Agreement. 32 | 33 | "Recipient" means anyone who receives the Program under this Agreement 34 | or any Secondary License (as applicable), including Contributors. 35 | 36 | "Derivative Works" shall mean any work, whether in Source Code or other 37 | form, that is based on (or derived from) the Program and for which the 38 | editorial revisions, annotations, elaborations, or other modifications 39 | represent, as a whole, an original work of authorship. 40 | 41 | "Modified Works" shall mean any work in Source Code or other form that 42 | results from an addition to, deletion from, or modification of the 43 | contents of the Program, including, for purposes of clarity any new file 44 | in Source Code form that contains any contents of the Program. Modified 45 | Works shall not include works that contain only declarations, 46 | interfaces, types, classes, structures, or files of the Program solely 47 | in each case in order to link to, bind by name, or subclass the Program 48 | or Modified Works thereof. 49 | 50 | "Distribute" means the acts of a) distributing or b) making available 51 | in any manner that enables the transfer of a copy. 52 | 53 | "Source Code" means the form of a Program preferred for making 54 | modifications, including but not limited to software source code, 55 | documentation source, and configuration files. 56 | 57 | "Secondary License" means either the GNU General Public License, 58 | Version 2.0, or any later versions of that license, including any 59 | exceptions or additional permissions as identified by the initial 60 | Contributor. 61 | 62 | 2. GRANT OF RIGHTS 63 | 64 | a) Subject to the terms of this Agreement, each Contributor hereby 65 | grants Recipient a non-exclusive, worldwide, royalty-free copyright 66 | license to reproduce, prepare Derivative Works of, publicly display, 67 | publicly perform, Distribute and sublicense the Contribution of such 68 | Contributor, if any, and such Derivative Works. 69 | 70 | b) Subject to the terms of this Agreement, each Contributor hereby 71 | grants Recipient a non-exclusive, worldwide, royalty-free patent 72 | license under Licensed Patents to make, use, sell, offer to sell, 73 | import and otherwise transfer the Contribution of such Contributor, 74 | if any, in Source Code or other form. This patent license shall 75 | apply to the combination of the Contribution and the Program if, at 76 | the time the Contribution is added by the Contributor, such addition 77 | of the Contribution causes such combination to be covered by the 78 | Licensed Patents. The patent license shall not apply to any other 79 | combinations which include the Contribution. No hardware per se is 80 | licensed hereunder. 81 | 82 | c) Recipient understands that although each Contributor grants the 83 | licenses to its Contributions set forth herein, no assurances are 84 | provided by any Contributor that the Program does not infringe the 85 | patent or other intellectual property rights of any other entity. 86 | Each Contributor disclaims any liability to Recipient for claims 87 | brought by any other entity based on infringement of intellectual 88 | property rights or otherwise. As a condition to exercising the 89 | rights and licenses granted hereunder, each Recipient hereby 90 | assumes sole responsibility to secure any other intellectual 91 | property rights needed, if any. For example, if a third party 92 | patent license is required to allow Recipient to Distribute the 93 | Program, it is Recipient's responsibility to acquire that license 94 | before distributing the Program. 95 | 96 | d) Each Contributor represents that to its knowledge it has 97 | sufficient copyright rights in its Contribution, if any, to grant 98 | the copyright license set forth in this Agreement. 99 | 100 | e) Notwithstanding the terms of any Secondary License, no 101 | Contributor makes additional grants to any Recipient (other than 102 | those set forth in this Agreement) as a result of such Recipient's 103 | receipt of the Program under the terms of a Secondary License 104 | (if permitted under the terms of Section 3). 105 | 106 | 3. REQUIREMENTS 107 | 108 | 3.1 If a Contributor Distributes the Program in any form, then: 109 | 110 | a) the Program must also be made available as Source Code, in 111 | accordance with section 3.2, and the Contributor must accompany 112 | the Program with a statement that the Source Code for the Program 113 | is available under this Agreement, and informs Recipients how to 114 | obtain it in a reasonable manner on or through a medium customarily 115 | used for software exchange; and 116 | 117 | b) the Contributor may Distribute the Program under a license 118 | different than this Agreement, provided that such license: 119 | i) effectively disclaims on behalf of all other Contributors all 120 | warranties and conditions, express and implied, including 121 | warranties or conditions of title and non-infringement, and 122 | implied warranties or conditions of merchantability and fitness 123 | for a particular purpose; 124 | 125 | ii) effectively excludes on behalf of all other Contributors all 126 | liability for damages, including direct, indirect, special, 127 | incidental and consequential damages, such as lost profits; 128 | 129 | iii) does not attempt to limit or alter the recipients' rights 130 | in the Source Code under section 3.2; and 131 | 132 | iv) requires any subsequent distribution of the Program by any 133 | party to be under a license that satisfies the requirements 134 | of this section 3. 135 | 136 | 3.2 When the Program is Distributed as Source Code: 137 | 138 | a) it must be made available under this Agreement, or if the 139 | Program (i) is combined with other material in a separate file or 140 | files made available under a Secondary License, and (ii) the initial 141 | Contributor attached to the Source Code the notice described in 142 | Exhibit A of this Agreement, then the Program may be made available 143 | under the terms of such Secondary Licenses, and 144 | 145 | b) a copy of this Agreement must be included with each copy of 146 | the Program. 147 | 148 | 3.3 Contributors may not remove or alter any copyright, patent, 149 | trademark, attribution notices, disclaimers of warranty, or limitations 150 | of liability ("notices") contained within the Program from any copy of 151 | the Program which they Distribute, provided that Contributors may add 152 | their own appropriate notices. 153 | 154 | 4. COMMERCIAL DISTRIBUTION 155 | 156 | Commercial distributors of software may accept certain responsibilities 157 | with respect to end users, business partners and the like. While this 158 | license is intended to facilitate the commercial use of the Program, 159 | the Contributor who includes the Program in a commercial product 160 | offering should do so in a manner which does not create potential 161 | liability for other Contributors. Therefore, if a Contributor includes 162 | the Program in a commercial product offering, such Contributor 163 | ("Commercial Contributor") hereby agrees to defend and indemnify every 164 | other Contributor ("Indemnified Contributor") against any losses, 165 | damages and costs (collectively "Losses") arising from claims, lawsuits 166 | and other legal actions brought by a third party against the Indemnified 167 | Contributor to the extent caused by the acts or omissions of such 168 | Commercial Contributor in connection with its distribution of the Program 169 | in a commercial product offering. The obligations in this section do not 170 | apply to any claims or Losses relating to any actual or alleged 171 | intellectual property infringement. In order to qualify, an Indemnified 172 | Contributor must: a) promptly notify the Commercial Contributor in 173 | writing of such claim, and b) allow the Commercial Contributor to control, 174 | and cooperate with the Commercial Contributor in, the defense and any 175 | related settlement negotiations. The Indemnified Contributor may 176 | participate in any such claim at its own expense. 177 | 178 | For example, a Contributor might include the Program in a commercial 179 | product offering, Product X. That Contributor is then a Commercial 180 | Contributor. If that Commercial Contributor then makes performance 181 | claims, or offers warranties related to Product X, those performance 182 | claims and warranties are such Commercial Contributor's responsibility 183 | alone. Under this section, the Commercial Contributor would have to 184 | defend claims against the other Contributors related to those performance 185 | claims and warranties, and if a court requires any other Contributor to 186 | pay any damages as a result, the Commercial Contributor must pay 187 | those damages. 188 | 189 | 5. NO WARRANTY 190 | 191 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 192 | PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" 193 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 194 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF 195 | TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 196 | PURPOSE. Each Recipient is solely responsible for determining the 197 | appropriateness of using and distributing the Program and assumes all 198 | risks associated with its exercise of rights under this Agreement, 199 | including but not limited to the risks and costs of program errors, 200 | compliance with applicable laws, damage to or loss of data, programs 201 | or equipment, and unavailability or interruption of operations. 202 | 203 | 6. DISCLAIMER OF LIABILITY 204 | 205 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 206 | PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS 207 | SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 208 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST 209 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 210 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 211 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 212 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE 213 | POSSIBILITY OF SUCH DAMAGES. 214 | 215 | 7. GENERAL 216 | 217 | If any provision of this Agreement is invalid or unenforceable under 218 | applicable law, it shall not affect the validity or enforceability of 219 | the remainder of the terms of this Agreement, and without further 220 | action by the parties hereto, such provision shall be reformed to the 221 | minimum extent necessary to make such provision valid and enforceable. 222 | 223 | If Recipient institutes patent litigation against any entity 224 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 225 | Program itself (excluding combinations of the Program with other software 226 | or hardware) infringes such Recipient's patent(s), then such Recipient's 227 | rights granted under Section 2(b) shall terminate as of the date such 228 | litigation is filed. 229 | 230 | All Recipient's rights under this Agreement shall terminate if it 231 | fails to comply with any of the material terms or conditions of this 232 | Agreement and does not cure such failure in a reasonable period of 233 | time after becoming aware of such noncompliance. If all Recipient's 234 | rights under this Agreement terminate, Recipient agrees to cease use 235 | and distribution of the Program as soon as reasonably practicable. 236 | However, Recipient's obligations under this Agreement and any licenses 237 | granted by Recipient relating to the Program shall continue and survive. 238 | 239 | Everyone is permitted to copy and distribute copies of this Agreement, 240 | but in order to avoid inconsistency the Agreement is copyrighted and 241 | may only be modified in the following manner. The Agreement Steward 242 | reserves the right to publish new versions (including revisions) of 243 | this Agreement from time to time. No one other than the Agreement 244 | Steward has the right to modify this Agreement. The Eclipse Foundation 245 | is the initial Agreement Steward. The Eclipse Foundation may assign the 246 | responsibility to serve as the Agreement Steward to a suitable separate 247 | entity. Each new version of the Agreement will be given a distinguishing 248 | version number. The Program (including Contributions) may always be 249 | Distributed subject to the version of the Agreement under which it was 250 | received. In addition, after a new version of the Agreement is published, 251 | Contributor may elect to Distribute the Program (including its 252 | Contributions) under the new version. 253 | 254 | Except as expressly stated in Sections 2(a) and 2(b) above, Recipient 255 | receives no rights or licenses to the intellectual property of any 256 | Contributor under this Agreement, whether expressly, by implication, 257 | estoppel or otherwise. All rights in the Program not expressly granted 258 | under this Agreement are reserved. Nothing in this Agreement is intended 259 | to be enforceable by any entity that is not a Contributor or Recipient. 260 | No third-party beneficiary rights are created under this Agreement. 261 | 262 | Exhibit A - Form of Secondary Licenses Notice 263 | 264 | "This Source Code may also be made available under the following 265 | Secondary Licenses when the conditions for such availability set forth 266 | in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), 267 | version(s), and exceptions or additional permissions here}." 268 | 269 | Simply including a copy of this Agreement, including this Exhibit A 270 | is not sufficient to license the Source Code under Secondary Licenses. 271 | 272 | If it is not possible or desirable to put the notice in a particular 273 | file, then You may include the notice in a location (such as a LICENSE 274 | file in a relevant directory) where a recipient would be likely to 275 | look for such a notice. 276 | 277 | You may add additional accurate notices of copyright ownership. 278 | -------------------------------------------------------------------------------- /LICENSE2: -------------------------------------------------------------------------------- 1 | ------------------------------------------ 2 | @Okerew, Okral Lesser License 2024 3 | ------------------------------------------ 4 | 5 | This software is free and open-source and is released into the public domain. 6 | 7 | Anyone is free to copy, modify, publish, use, compile, or distribute this software, either in source code form or as a compiled binary. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | WHEN CREATING A FORK OF THIS SOFTWARE, YOU MUST USE THE SAME LICENSE. MODIFICATIONS TO THIS LICENSE ARE NOT ALLOWED. YOU MUST CREDIT THE ORIGINAL AUTHOR OF THIS SOFTWARE. 12 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | NOTICE 2 | Copyright 2025 Witold Warchol 3 | 4 | This software is licensed under the Eclipse License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | https://www.eclipse.org/legal/epl-2.0/ 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Osxiec 2 | 3 | OSXIEC is a native docker-like solution for macOS developed by Okerew. It leverages native macOS features to provide containerization capabilities, albeit with some limitations compared to Docker. 4 | 5 | 6 | Watch the video 7 | 8 | If it says that macOS can't identify if it is malware or not, close it go into settings and allow it to be executed. 9 | 10 | ____ 11 | 12 | ## Maintaince mode 13 | 14 | With the realease of version 1.0 I won't update osxiec regularly anymore. I had done all the features I wanted in it, but I will fix bugs or any issues listed in the repo's Issues and if apple breaks stuff that osxiec uses I will update it. 15 | ____ 16 | 17 | 18 | ## Dependencies 19 | **HomeBrew for installing dependencies** 20 | ```sh 21 | /arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 22 | ``` 23 | **Curl** 24 | ```sh 25 | brew install curl 26 | ``` 27 | **Readline** 28 | ```sh 29 | brew install readline 30 | ``` 31 | 32 | **Json-c** 33 | ```sh 34 | brew install json-c@0.18 35 | ``` 36 | 37 | **Xcode** 38 | https://apps.apple.com/us/app/xcode/id497799835?mt=12 39 | 40 | ### Build Dependencies 41 | **Ninja for building** 42 | ```sh 43 | brew install ninja 44 | ``` 45 | **Cmake for building** 46 | ``` sh 47 | brew install cmake 48 | ``` 49 | ## Installation 50 | 51 | **Quick way with command line** 52 | 53 | Arm architecture 54 | ```sh 55 | curl -L -o osxiec_cli.tar.gz https://github.com/Okerew/osxiec/releases/download/%s/osxiec_cli.tar.gz && tar -xvzf osxiec_cli.tar.gz && cd osxiec_cli && sudo sh install.sh 56 | ``` 57 | replace %s with the latest version 58 | ______ 59 | 60 | 86_64 architecture 61 | ```sh 62 | curl -L -o osxiec_cli_86_64.tar.gz https://github.com/Okerew/osxiec/releases/download/%s/osxiec_cli_86_64.tar.gz && tar -xvzf osxiec_cli_86_64.tar.gz && cd osxiec_cli_86_64 && sudo sh install.sh 63 | ``` 64 | replace %s with the latest version 65 | ____ 66 | Gui 67 | ```sh 68 | curl -L -o osxiec_gui.tar.gz https://github.com/Okerew/osxiec/releases/download/%s/osxiec_gui.tar.gz && sudo cp osxiec_gui.tar.gz /Applications 69 | ``` 70 | replace %s with the latest version 71 | 72 | ______ 73 | 1. **Download the Release**: 74 | Download the `osxiec_cli.tar.gz` and `osxiec_gui.tar.gz` if you want a gui app file from the releases section. 75 | 2. **Extract the Archive**: 76 | ```sh 77 | tar -xvzf osxiec_cli.tar.gz 78 | ``` 79 | For gui version 80 | ```sh 81 | tar -xvzf osxiec_gui.tar.gz 82 | ``` 83 | 84 | 3. **Run installation script in the extracted cli directory**: 85 | ```sh 86 | sudo sh install.sh 87 | ``` 88 | 4. **If downloaded osxiec_gui** 89 | ``` 90 | Copy app bundle from osxiec_gui.tar.gz to /Applications then run the app bundle or run osxiec.jar 91 | ``` 92 | 93 | To update to a new release, repeat steps 1, 2, and 3 if using osxiec_gui also step 4. 94 | ## Usage 95 | 96 | **Containerize a Directory**: containerizes a directory 97 | ```sh 98 | sudo osxiec -contain {directory_path} {some_name}.bin {path_to_config_file_in_directory_path} {container_config_file} 99 | ``` 100 | 101 | **Create a cluster ( virtualized network )** create a cluster 102 | ```sh 103 | sudo osxiec -network create {network_name} {vlan_id} {optional_ip_adress_to_only_connect_to} 104 | ``` 105 | **Remove a vlan network** removes a vlan network 106 | ```sh 107 | sudo osxiec -network remove {network_name} {vlan_id} 108 | ``` 109 | **Run with vlan config** run with vlan config 110 | ``` sh 111 | sudo osxiec -run {some_name.bin} {network_name} -port {PORT_NUMBER} 112 | ``` 113 | port argument is optional 114 | 115 | **Version** checks the current version, updates 116 | ```sh 117 | osxiec --version 118 | ``` 119 | **Pull** pulls an image from osxiec hub 120 | ```sh 121 | osxiec -pull {container_name} 122 | ``` 123 | **Search** searches osxiec hub 124 | ```sh 125 | osxiec -search {search_term_for_osxiec_hub} 126 | ``` 127 | **Upload** allows to upload a file to osxiec hub 128 | ```sh 129 | osxiec -upload {filename} {username} {password} {description} 130 | ``` 131 | **Convert to Docker** converts to docker 132 | ```sh 133 | osxiec -convert-to-docker {bin_file} {output_directory} {base_image} [custom_dockerfile] 134 | ``` 135 | **Clean** this will clean the container volume images from /tmp 136 | ```sh 137 | sudo osxiec -clean 138 | ``` 139 | 140 | **Detach** detaches the container images 141 | ```sh 142 | osxiec -detach 143 | ``` 144 | 145 | **Help** shows all the commands 146 | ```sh 147 | osxiec -help 148 | ``` 149 | 150 | **Deploy** deploys a container 151 | ```sh 152 | sudo osxiec -deploy {path_to_config} -port {PORT_NUMBER} 153 | ``` 154 | 155 | **Scan** scans a container for security vulnerabilities 156 | ```sh 157 | osxiec -scan {some_name.bin} 158 | ``` 159 | 160 | **Deploym** deploys multiple containers, this is a work in progress, for now it works mostly fine with start config 161 | ```sh 162 | sudo osxiec -deploym {config_file} 163 | ``` 164 | 165 | **Oexec** executes a container in offline mode without any networking or usage of ports 166 | ```sh 167 | sudo osxiec -oexec {bin_file_path} 168 | ``` 169 | **Gexec** executes a container in gui mode 170 | ```sh 171 | sudo osxiec -gexec {bin_file_path} 172 | ``` 173 | **Extract** extracts files and folders from a container 174 | ```sh 175 | sudo osxiec -extract {bin_file_path} 176 | ``` 177 | 178 | **Convert to oci** converts to an oci container 179 | ```sh 180 | osxiec -convert-to-oci {bin_file_path} {output_path} {arch} {author} 181 | ``` 182 | 183 | **Craft** crafts a container from a directory and a bin input file 184 | ```sh 185 | sudo osxiec -craft {directory_path} {bin_input_file} {output_file} {start_config_file} {container_config_file} 186 | ``` 187 | 188 | **Start** starts a container a stopped container 189 | ```sh 190 | sudo osxiec -start {volume_name} {network} -port {PORT_NUMBER} 191 | ``` 192 | port is optional 193 | 194 | **Ostart** starts a container a stopped container in offline mode 195 | ```sh 196 | sudo osxiec -ostart {volume_name} 197 | ``` 198 | **Gstart** starts a container a stopped container in gui mode 199 | ```sh 200 | sudo osxiec -gstart {volume_name} 201 | ``` 202 | **Api** an api that exposes some more functions of the cli 203 | ```sh 204 | osxiec -api {argument} 205 | ``` 206 | 207 | **Update** updates configuration of a container 208 | ```sh 209 | sudo osxiec -update 210 | ``` 211 | 212 | **Check for update** checks for update 213 | ```sh 214 | sudo osxiec -check-for-update 215 | ``` 216 | **copy-volume** Copies files form a container volume to a directory 217 | ```sh 218 | sudo osxiec -copy-volume {volume_name} {target_directory} 219 | ``` 220 | 221 | **bcn** Broadcasts a command to the container network 222 | ```sh 223 | sudo osxiec -bcn {network_name} {command} 224 | ``` 225 | 226 | ## Creating a container 227 | Make sure to include any dependencies or executables you can obtain these by searching for where a dependency or executable is located and copying it along with it's dependencies. 228 | 229 | 230 | **Example structure** 231 | ``` 232 | [ 233 | "container_name", 234 | { 235 | "some_content", 236 | "subfolder1" [ 237 | executable1 238 | "some_content" 239 | ] 240 | "start_config_file" 241 | "some_executable" 242 | "dependency" 243 | } 244 | 245 | ] 246 | ``` 247 |
248 | 249 | **Script Example:** 250 | For example if you have a node project make sure to include somewhere the node executable in the directory you want to contain, then run the script with the node executable. 251 | 252 | ``` js 253 | console.log("Hello World") 254 | ``` 255 | 256 | Do `path/to/node_executable_in_container/ script.js` 257 | 258 |
259 | 260 | **Containing** 261 | 262 | To contain a directory run the `osxiec -contain {directory_path} {container_name} {start_config_file}` 263 | 264 | This will also scan the container for security vulnerabilities. 265 | ## Executing a container 266 | After creating a container or downloading one. 267 | **You can execute one with** 268 | 269 | `osxiec -oexec {container_name}` 270 | 271 | This will execute it in offline mode. If you want to execute it in online mode see the next point. 272 | 273 | **Run with vlan** 274 | 275 | If you have created a vlan network like said in the next point you can run the container with 276 | 277 | ```osxiec -run {container_name} {network_name}``` 278 | 279 | You can also add the port argument with `-port {PORT_NUMBER}` 280 | 281 | **When executing** 282 |
283 | Normally it will start a listener which will allow it to communicate with other containers. 284 | ![Screenshot 2024-07-24 at 18 11 30](https://github.com/user-attachments/assets/50d308ce-60bc-4355-a60d-a05430cea2df) 285 | 286 | If you want to access the container terminal just press enter. 287 | ![Screenshot 2024-07-24 at 18 11 45](https://github.com/user-attachments/assets/32762bb2-0eb0-492e-9d04-1fcf1b8b80f8) 288 | 289 | 290 | ## Container commands 291 | 1. **help** shows all the commands 292 | 2. **debug** debugs the container 293 | 3. **scale** scales the resources of the container 294 | 4. **osxs** Execute an osxs script file 295 | 5. **xs** Execute an osxs script command 296 | 6. **autoscale** automatically scales the resources of the container 297 | 7. **status** shows the status of the container 298 | 8. **stop** stops the container. 299 | 9. **wait** waits for a command(background task) in a container to stop. 300 | 10. **ps** shows all the running commands(background tasks) in the container. 301 | 11. **pause** pauses all background tasks in the container 302 | 12. **unpause** unpauses all background tasks in the container 303 | 13. **br** runs a command in background 304 | 14 **network start** starts a network listener 305 | 15 **network stop** stops a network listener 306 | 16 **network status** shows the status of a network listener 307 | 17 **network restart** restarts a network listener 308 | 18 **trace** shows the trace of a command 309 | 19 **proctrace** Trace system calls of a running 310 | 20 **attach** Attach to a running background process 311 | 21 **schedule** Schedule a command to run at a specific time 312 | 22 **lschedule** List scheduled commands 313 | 314 | ## Creating a vlan network 315 | To create a network you can run `osxiec -network create {network_name} {vlan_id} {optional_ip_adress_to_only_connect_to}` 316 | 317 | The network_name can be any string like "test" for example. 318 | 319 | The vlan id can be any number from 1-4094. 320 | 321 | For example `osxiec -network create test 6` 322 | ## Converting to Docker 323 | **Create docker file** 324 | ``` dockerfile 325 | # Test Dockerfile for osxiec to Docker conversion 326 | 327 | # Use a lightweight base image 328 | FROM alpine:latest 329 | 330 | # Set the working directory in the container 331 | WORKDIR /app 332 | 333 | # Copy the application files from the osxiec container 334 | # Note: This will be handled by the conversion script, so we don't need COPY instructions here 335 | 336 | # Install any needed packages 337 | RUN apk add --no-cache python3 py3-pip 338 | 339 | # Set environment variables (these will be overwritten by the conversion script if not using a custom Dockerfile) 340 | ENV MEMORY_SOFT_LIMIT=256m 341 | ENV MEMORY_HARD_LIMIT=512m 342 | ENV CPU_PRIORITY=20 343 | 344 | # Make port 8080 available to the world outside this container 345 | EXPOSE 8080 346 | 347 | # Run a simple Python HTTP server when the container launches 348 | CMD ["python3", "-m", "http.server", "8080"] 349 | ``` 350 | **Run convert-to-docker** 351 | 352 | For this example 353 | ```sh 354 | osxiec -convert-to-docker {container_name} {output_directory} alpine:latest samples/dockerfile 355 | ``` 356 | 357 | ## Deploying 358 | **Create a config file** 359 | ``` 360 | source_dir=/path/to/source/directory 361 | container_file=/path/to/output/container.bin 362 | network_name=my_network 363 | start_config=/path/to/start_config.sh 364 | ``` 365 | **Deploy** 366 | ```sh 367 | sudo osxiec -deploy {path_to_config_file} 368 | ``` 369 | You can also use `-port {PORT_NUMBER}` 370 | 371 | **Deploym** 372 | you can also deploy multiple containers, this is a work in progress though. 373 | ```sh 374 | sudo osxiec -deploym {config_file} {PORT_NUMBER1} {PORT_NUMBER2} etc. 375 | ``` 376 | **Config** 377 | 378 | ``` 379 | path_to_container1_config {network_name} 380 | path_to_container2_config {network_name} 381 | ``` 382 | 383 | ## Osxiec Script 384 | Osxiec script is a scripting language created for managing osxiec containers. 385 | ### Syntax 386 | **Set Memory** 387 | ```sh 388 | SET_MEMORY {memory_soft} {memory_hard} 389 | ``` 390 | **Set CPU Priority** 391 | ```sh 392 | SET_CPU {cpu_priority} 393 | ``` 394 | **Execute** 395 | ```sh 396 | EXECUTE {command} 397 | ``` 398 | **Conditional Execution** 399 | ```sh 400 | IF {condition} EXECUTE {command} 401 | ``` 402 | **Sleep** 403 | ```sh 404 | SLEEP {seconds} 405 | ``` 406 | **Log** 407 | ```sh 408 | LOG {message} 409 | ``` 410 | **Execute File** 411 | ```sh 412 | EXECUTE_FILE {path_to_script} 413 | ``` 414 | **Set Variable** 415 | ```sh 416 | SET {variable} {value} 417 | ``` 418 | **While Loop** 419 | ```sh 420 | WHILE {condition} {commands} END 421 | ``` 422 | **For Loop** 423 | ```sh 424 | FOR {variable} TO {2variable} STEP {value} {commands} END 425 | ``` 426 | 427 | **ELSE** 428 | ```sh 429 | IF {condition} ELSE {commands} END 430 | ``` 431 | Note ELSE statement for now doesn't work with LOG and is a work in progress 432 | 433 | **Example** 434 | ``` 435 | # This is an example script for the OSXIEC scripting language 436 | SET counter 0 437 | SET limit 10 438 | 439 | # Loop from 0 to 10 440 | FOR counter=0 TO limit STEP 2 441 | IF counter==5 442 | LOG "Counter is 5" 443 | END 444 | SLEEP 1 445 | END 446 | 447 | IF $var==5 LOG Variable is 5 ELSE LOG Variable is not 5 448 | 449 | # Loop while counter is less than limit 450 | WHILE counter 487 | To start debugging `debug` 488 |
489 | Then you can use these commands 490 | ___ 491 | ``` 492 | step 493 | ``` 494 | which steps to the next command 495 | ___ 496 | ``` 497 | break 498 | ``` 499 | Creates a breakpoint at the specified command 500 | ___ 501 | ``` 502 | print 503 | ``` 504 | Prints the value of the specified variable of the container 505 | ___ 506 | ``` 507 | print 508 | ``` 509 | Prints the whole container state 510 | ___ 511 | ``` 512 | help 513 | ``` 514 | Shows what you can do 515 | ___ 516 | ``` 517 | continue 518 | ``` 519 | Continues execution of the container 520 | _____ 521 | ### Osxiec Container Hub 522 | This is a place where you can upload your containers to. 523 | ![Screenshot 2024-07-24 at 18 25 20](https://github.com/user-attachments/assets/451f7851-ac64-4d59-9654-6729906fd01d) 524 | 525 | ___ 526 | ### Osxiec Gui 527 | This is the source code for the gui version of osxiec. 528 | ![Screenshot 2024-07-24 at 12 05 58](https://github.com/user-attachments/assets/42d858e1-e4fd-4a82-b2e8-f86a7c35be38) 529 | 530 | ___ 531 | ### Osxiec Terminal 532 | A terminal emulator specifically created for osxiec 533 | ___ 534 | ## Building 535 | **Git clone the repository** 536 | ``` sh 537 | git clone https://github.com/Okerew/osxiec.git 538 | ``` 539 | **Go to the directory** 540 | ``` sh 541 | cd osxiec 542 | ``` 543 | **Build the osxiec executable** 544 | ``` sh 545 | mkdir {build-directory} 546 | cd {build-directory} 547 | cmake -S .. -B . -G "Ninja" 548 | ninja 549 | ``` 550 | 551 | **Give permissions to scripts if needed** 552 | ``` sh 553 | sudo chmod +x scripts/osxiec_deploy_multiple.sh 554 | sudo chmod +x scripts/install.sh 555 | ``` 556 | **Finalize** 557 | to make it work put all executables in a one folder, copy there install.sh and run it 558 | 559 | ### Build java gui 560 | Git clone the gui 561 | ```sh 562 | git clone https://github.com/Okerew/osxiec_gui.git 563 | ``` 564 | 565 | Go to the directory 566 | ```sh 567 | cd osxiec_gui 568 | ``` 569 | Build the class 570 | ```sh 571 | javac OsxiecApp.java 572 | ``` 573 | Build the jar 574 | ```sh 575 | jar -cvfe osxiec.jar OsxiecApp OsxiecApp.class 576 | ``` 577 | 578 | Copy jar into app bundle, remove the previous one 579 | ```sh 580 | cp osxiec.jar osxiec.app/Contents/Resources 581 | ``` 582 | If using the one from release, delete the previous one 583 | 584 | Copy the icon into Contents/Resources 585 | 586 | Finally, copy the run_app_bundle.sh into the bundle as osxiec_gui 587 | ```sh 588 | cp run_app_bundle.sh osxiec.app/Contents/MacOS/osxiec_gui 589 | ``` 590 | ## Plugins 591 | **Example plugin** can be seen in samples/sample_plugin.c, this should make you understand how osxiec loads plugins. 592 | 593 | **Build plugin** 594 | ``` sh 595 | gcc -shared -fPIC -o {plugin_name}.so {plugin_name}.c 596 | ``` 597 | 598 | **Install plugin** 599 | 600 | ``` sh 601 | sudo cp {plugin_name}.so ~/.osxiec/plugins 602 | ``` 603 | After this on the execution of osxiec command the plugin will be loaded. 604 | ## Notes 605 | 606 | - **Not a Docker Replacement**: 607 | While OSXIEC offers similar functionality to Docker, it lacks some advanced features of Docker. It is more supposed to be a quicker testing tool than docker on macOS, it is not designed to replace it, just to test basic ideas and software, distribute macOS software. 608 | - **macOS Only**: 609 | OSXIEC uses native macOS features and is not compatible with other operating systems. 610 | - **Isolation Limitations**: 611 | Due to macOS limitations, complete isolation like in Linux is not possible. The contained directory will have some access to the outside environment, you can have a start config file if needed. 612 | - **Supported Features**: 613 | Despite its limitations, OSXIEC provides isolation using namespaces, setuid, image layers, basic user process control, memory and CPU control, and special permissions using user IDs and group IDs, unpacking the image into a disk image(APFS), vlans. 614 | - **Support**: Remember that not everything will work fully for example node won't work fully because it is making sys calls which spawn things outside the container, in this example local things that do not rely on the repl server will work. 615 | - **Temps**: If you need a lot of storage for the moment, and you used a container use the clean command. 616 | - **Why is chroot not used?** 617 | Chroot requires for SIP to be disabled, which causes many security risks, chroot can be easily exited by any process, using the normal macOS restrictions is way more secure, reliable, 618 | having it disabled causes many permission issues. 619 | - **Sandbox deprecation error** yes I know that sandbox innit is deprecated but there isn't really an alternative for it unless I would use xcode and there is no way I am using it to rebuild this. 620 | 621 | - **If you want to remove ips from the network do it by editing the file in private/etc/network_{network_name}.conf file** 622 | -------------------------------------------------------------------------------- /api_for_osxiec_script.h: -------------------------------------------------------------------------------- 1 | #ifndef OSXIEC_H 2 | #define OSXIEC_H 3 | 4 | void execute_command(const char *command, const char *container_root); 5 | 6 | void scale_container_resources(int soft_limit, int hard_limit, 7 | int cpu_priority); 8 | 9 | #endif // OSXIEC_H 10 | -------------------------------------------------------------------------------- /example/bin/hello: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Okerew/osxiec/bdfc395b014851802ecd66e17fbb0ea75dc947d3/example/bin/hello -------------------------------------------------------------------------------- /example/config.txt: -------------------------------------------------------------------------------- 1 | echo test 2 | -------------------------------------------------------------------------------- /example/container_config.txt: -------------------------------------------------------------------------------- 1 | name=my_custom_container 2 | memory_soft_limit=59870912 3 | memory_hard_limit=1073741824 4 | cpu_priority=10 5 | network_mode=bridge 6 | container_uid=1001 7 | container_gid=1001 8 | dependencies=neofetch 9 | -------------------------------------------------------------------------------- /example/file.txt: -------------------------------------------------------------------------------- 1 | test -------------------------------------------------------------------------------- /example/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Hello from inside the container!" 3 | -------------------------------------------------------------------------------- /example/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | // printf() displays the string inside quotation 4 | printf("Hello, World!"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /example/test/test.osxs: -------------------------------------------------------------------------------- 1 | # This is an example script for the OSXIEC scripting language 2 | SET counter 0 3 | SET limit 10 4 | 5 | # Loop from 0 to 10 6 | FOR counter=0 TO limit STEP 2 7 | IF counter==5 8 | LOG "Counter is 5" 9 | END 10 | SLEEP 1 11 | END 12 | 13 | IF $var==5 LOG Variable is 5 ELSE LOG Variable is not 5 14 | 15 | # Loop while counter is less than limit 16 | WHILE counter 4 | #include 5 | #include 6 | 7 | #define MAX_PATH_LEN 256 8 | #define MAX_SECRETS 64 9 | #define MAX_VAR_LEN 1024 10 | #define MAX_COMMAND_LEN 1024 11 | typedef struct { 12 | char name[MAX_PATH_LEN]; 13 | size_t size; 14 | char *data; 15 | } File; 16 | 17 | #define MAX_CLIENTS 15 18 | 19 | typedef struct { 20 | char name[MAX_PATH_LEN]; 21 | long memory_soft_limit; 22 | long memory_hard_limit; 23 | int cpu_priority; 24 | char network_mode[20]; 25 | uid_t container_uid; 26 | gid_t container_gid; 27 | char network_name[MAX_PATH_LEN]; 28 | int vlan_id; 29 | char start_config[MAX_PATH_LEN]; 30 | } ContainerConfig; 31 | 32 | typedef struct { 33 | char name[MAX_PATH_LEN]; 34 | int vlan_id; 35 | int num_containers; 36 | char container_names[MAX_CLIENTS][MAX_PATH_LEN]; 37 | char container_ips[MAX_CLIENTS][16]; 38 | } ContainerNetwork; 39 | 40 | typedef struct { 41 | char name[MAX_PATH_LEN]; 42 | char data[4096]; 43 | char audit_data[2048]; 44 | char outdated_data[1024]; 45 | } BrewInfo; 46 | 47 | typedef struct { 48 | char name[MAX_VAR_LEN]; 49 | char *encrypted_value; 50 | size_t length; 51 | } SecretVariable; 52 | 53 | typedef struct { 54 | char current_directory[MAX_PATH_LEN]; 55 | char last_executed_command[MAX_COMMAND_LEN]; 56 | int num_processes; 57 | long memory_usage; 58 | char network_status[50]; 59 | char **environment_variables; 60 | int num_env_vars; 61 | SecretVariable secrets[MAX_SECRETS]; 62 | int num_secrets; 63 | } ContainerState; 64 | 65 | void execute_command(const char *command, const char *container_root); 66 | void containerize_directory_with_bin_file(const char *dir_path, 67 | const char *input_bin_file, 68 | const char *output_file, 69 | const char *start_config_file, 70 | const char *container_config_file); 71 | void containerize_directory(const char *dir_path, const char *output_file, 72 | const char *start_config_file, 73 | const char *container_config_file); 74 | void read_config_file(const char *filename, ContainerConfig *config); 75 | void extract_container(const char *osxiec_file, const char *output_dir); 76 | void security_scan(const char *bin_file); 77 | ContainerNetwork load_container_network(const char *name); 78 | void deploy_container(const char *config_file, int deploy_port); 79 | void apply_resource_limits(const ContainerConfig *config); 80 | void *monitor_memory_usage(void *arg); 81 | void setup_pf_rules(ContainerNetwork *network); 82 | void create_and_save_container_network(const char *name, int vlan_id); 83 | void remove_container_network(const char *name); 84 | void auto_scale_resources(const ContainerConfig *config); 85 | void start_auto_scaling(ContainerConfig *config); 86 | void handle_client(int client_socket, const char *container_root); 87 | void start_network_listener(const char *container_root); 88 | void create_isolated_environment(FILE *bin_file, const char *bin_file_path, 89 | ContainerNetwork *network); 90 | void ocreate_isolated_environment(FILE *bin_file, const char *bin_file_path); 91 | static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, 92 | void *userp); 93 | void search(const char *term); 94 | void download_file(const char *file_name); 95 | void upload_file(const char *filename, const char *username, 96 | const char *password, const char *description); 97 | void convert_to_docker(const char *osxiec_file, const char *output_dir, 98 | const char *base_image, const char *custom_dockerfile); 99 | void clean_container_dmgs(); 100 | void convert_to_oci(const char *osxiec_file, const char *output_dir, 101 | const char *arch, const char *author, const char *created); 102 | char *find_latest_bin_file(const char *volume_name); 103 | int copy_file(const char *source, const char *destination_folder, 104 | const char *new_file_name); 105 | size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp); 106 | char *fetch_latest_version(void); 107 | int compare_versions(const char *v1, const char *v2); 108 | int add_plugin(const char *plugin_source); 109 | int copy_file(const char *source, const char *destination_folder, 110 | const char *new_file_name); 111 | char *find_latest_bin_file(const char *volume_name); 112 | void create_directory_if_needed(const char *path); 113 | void handle_signal(int sig); 114 | void *logger_thread(void *arg); 115 | void signal_handler(); 116 | void navigate_history(char *command, int *command_index, int *cursor_pos, 117 | int direction); 118 | void add_to_history(const char *command); 119 | void clear_line(); 120 | void move_cursor_right(int n); 121 | void move_cursor_left(int n); 122 | void set_terminal_canonical_mode(); 123 | void set_terminal_raw_mode(); 124 | void detach_container_images(const char *volume_name); 125 | void print_current_resource_usage(ContainerConfig *config); 126 | void start_auto_scaling(ContainerConfig *config); 127 | double get_cpu_usage(); 128 | void create_directories(const char *file_path); 129 | void create_shared_folder(); 130 | void handle_script_file(const char *filename); 131 | void handle_script_command(const char *script_content); 132 | void scale_container_resources(long memory_soft_limit, long memory_hard_limit, 133 | int cpu_priority); 134 | void enable_container_communication(ContainerNetwork *network); 135 | void setup_network_isolation(ContainerConfig *config, 136 | ContainerNetwork *network); 137 | char *get_ip_address(); 138 | void execute_start_config(const char *config_file, const char *container_root); 139 | int is_subpath(const char *path, const char *base); 140 | void handle_debug_command(char *command); 141 | void print_container_state(); 142 | void update_container_state(); 143 | void broadcast_command_to_network(const char *network_name, const char *command, 144 | int port); 145 | int copy_volume_to_directory(const char *volume_name, const char *target_dir); 146 | void update_container_config(const char *container_file, 147 | const char *new_config_file); 148 | int remove_plugin(const char *plugin_name); 149 | int link_system_directories(const char *container_root); 150 | int process_dependencies_recursive(const char *dep_name, 151 | const char *homebrew_prefix, File *files, 152 | int *file_count, int max_files, 153 | char processed[][MAX_PATH_LEN], 154 | int *processed_count); 155 | int process_dependency(const char *dep_name, const char *homebrew_prefix, 156 | File *files, int *file_count, int max_files); 157 | int get_brew_info(const char *package_name, BrewInfo *info); 158 | const char *get_homebrew_prefix(); 159 | void analyze_security_findings(const BrewInfo *info); 160 | int parse_brew_dependencies(const char *brew_info_data, 161 | char deps[][MAX_PATH_LEN], int max_deps); 162 | int file_exists(const char *path); 163 | int copy_single_file(const char *src_path, const char *dest_path, File *files, 164 | int *file_count, int max_files); 165 | 166 | int copy_path(const char *src_path, const char *dest_path, File *files, 167 | int *file_count, int max_files); 168 | void handle_secret_command(const char *args); 169 | void handle_getsecret_command(const char *args); 170 | void save_container_state(FILE *state_file, const ContainerConfig *config, 171 | const ContainerState *state); 172 | void clean_container_plists(); 173 | void cleanup_all_container_users(void); 174 | #endif // OSXIEC_H 175 | -------------------------------------------------------------------------------- /osxiec_script/osxiec_script.c: -------------------------------------------------------------------------------- 1 | #include "osxiec_script.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../api_for_osxiec_script.h" 9 | 10 | #define MAX_VARIABLES 100 11 | #define MAX_VAR_NAME 50 12 | #define MAX_VAR_VALUE 255 13 | #define SCRIPT_EXTENSION ".osxs" 14 | 15 | // Structure to hold variables 16 | typedef struct { 17 | char name[MAX_VAR_NAME]; 18 | char value[MAX_VAR_VALUE]; 19 | } Variable; 20 | 21 | Variable variables[MAX_VARIABLES]; 22 | int variable_count = 0; 23 | 24 | void set_variable(const char *name, const char *value); 25 | char *get_variable(const char *name); 26 | void replace_variables(char *line); 27 | int evaluate_condition(const char *condition); 28 | 29 | void execute_script(const char *script) { 30 | char *line = strtok((char *)script, "\n"); 31 | while (line != NULL) { 32 | // Skip comments and empty lines 33 | if (line[0] != '#' && line[0] != '\0') { 34 | replace_variables(line); 35 | execute_cs_command(line); 36 | } 37 | line = strtok(NULL, "\n"); 38 | } 39 | } 40 | 41 | void execute_script_file(const char *filename) { 42 | // Check if the filename ends with .osxs 43 | size_t len = strlen(filename); 44 | size_t ext_len = strlen(SCRIPT_EXTENSION); 45 | if (len <= ext_len || 46 | strcmp(filename + len - ext_len, SCRIPT_EXTENSION) != 0) { 47 | printf("Error: Invalid file extension. Expected %s\n", SCRIPT_EXTENSION); 48 | return; 49 | } 50 | 51 | FILE *file = fopen(filename, "r"); 52 | if (file == NULL) { 53 | printf("Error: Unable to open file %s\n", filename); 54 | return; 55 | } 56 | 57 | char line[MAX_COMMAND_LEN]; 58 | while (fgets(line, sizeof(line), file)) { 59 | // Remove newline character if present 60 | size_t line_len = strlen(line); 61 | if (line_len > 0 && line[line_len - 1] == '\n') { 62 | line[line_len - 1] = '\0'; 63 | } 64 | 65 | // Skip comments and empty lines 66 | if (line[0] != '#' && line[0] != '\0') { 67 | execute_cs_command(line); 68 | } 69 | } 70 | 71 | fclose(file); 72 | } 73 | 74 | void execute_for_loop(char args[MAX_ARGS][MAX_COMMAND_LEN], int arg_count) { 75 | char var_name[MAX_VAR_NAME]; 76 | int start, end, step; 77 | char loop_body[MAX_COMMAND_LEN] = ""; 78 | 79 | sscanf(args[0], "%[^=]=", var_name); 80 | start = atoi(strchr(args[0], '=') + 1); 81 | end = atoi(args[2]); 82 | step = (arg_count > 5 && strcmp(args[3], "STEP") == 0) ? atoi(args[4]) : 1; 83 | 84 | int body_start = (arg_count > 5 && strcmp(args[3], "STEP") == 0) ? 5 : 3; 85 | for (int i = body_start; i < arg_count; i++) { 86 | strcat(loop_body, args[i]); 87 | if (i < arg_count - 1) 88 | strcat(loop_body, " "); 89 | } 90 | 91 | char value[MAX_VAR_VALUE]; 92 | for (int i = start; i < end; i += step) { 93 | snprintf(value, sizeof(value), "%d", i); 94 | set_variable(var_name, value); 95 | execute_cs_command(loop_body); 96 | } 97 | } 98 | 99 | void execute_while_loop(char args[MAX_ARGS][MAX_COMMAND_LEN], int arg_count) { 100 | char condition[MAX_COMMAND_LEN]; 101 | char loop_body[MAX_COMMAND_LEN] = ""; 102 | 103 | strcpy(condition, args[0]); 104 | for (int i = 1; i < arg_count; i++) { 105 | strcat(loop_body, args[i]); 106 | if (i < arg_count - 1) 107 | strcat(loop_body, " "); 108 | } 109 | 110 | while (evaluate_condition(condition)) { 111 | execute_cs_command(loop_body); 112 | } 113 | } 114 | 115 | void execute_cs_command(const char *command) { 116 | char cmd[MAX_COMMAND_LEN]; 117 | char args[MAX_ARGS][MAX_COMMAND_LEN]; 118 | int arg_count = 0; 119 | 120 | // Parse command and arguments 121 | sscanf(command, "%s", cmd); 122 | char *arg_start = strchr(command, ' '); 123 | if (arg_start != NULL) { 124 | arg_start++; // Move past the space 125 | char *token = strtok((char *)arg_start, " "); 126 | while (token != NULL && arg_count < MAX_ARGS) { 127 | strcpy(args[arg_count++], token); 128 | token = strtok(NULL, " "); 129 | } 130 | } 131 | 132 | // Convert to uppercase for case-insensitive comparison 133 | for (int i = 0; cmd[i]; i++) 134 | cmd[i] = toupper(cmd[i]); 135 | 136 | // Execute appropriate function based on command 137 | if (strcmp(cmd, "SET_MEMORY") == 0 && arg_count == 2) { 138 | long soft_limit = atol(args[0]); 139 | long hard_limit = atol(args[1]); 140 | scale_container_resources(soft_limit, hard_limit, 141 | -1); // -1 for unchanged CPU priority 142 | } else if (strcmp(cmd, "SET_CPU") == 0 && arg_count == 1) { 143 | int cpu_priority = atoi(args[0]); 144 | scale_container_resources(-1, -1, 145 | cpu_priority); // -1 for unchanged memory limits 146 | } else if (strcmp(cmd, "EXECUTE") == 0 && arg_count >= 1) { 147 | char full_command[MAX_COMMAND_LEN] = ""; 148 | for (int i = 0; i < arg_count; i++) { 149 | strcat(full_command, args[i]); 150 | if (i < arg_count - 1) 151 | strcat(full_command, " "); 152 | } 153 | execute_command(full_command, NULL); 154 | } else if (strcmp(cmd, "LOG") == 0 && arg_count >= 1) { 155 | char message[MAX_COMMAND_LEN] = ""; 156 | for (int i = 0; i < arg_count; i++) { 157 | strcat(message, args[i]); 158 | if (i < arg_count - 1) 159 | strcat(message, " "); 160 | } 161 | printf("LOG: %s\n", message); 162 | } else if (strcmp(cmd, "EXECUTE_FILE") == 0 && arg_count == 1) { 163 | execute_script_file(args[0]); 164 | } else if (strcmp(cmd, "SET") == 0 && arg_count == 2) { 165 | set_variable(args[0], args[1]); 166 | } else if (strcmp(cmd, "IF") == 0 && arg_count >= 3) { 167 | char true_command[MAX_COMMAND_LEN] = ""; 168 | char false_command[MAX_COMMAND_LEN] = ""; 169 | int else_index = -1; 170 | 171 | // Find the ELSE keyword 172 | for (int i = 1; i < arg_count; i++) { 173 | if (strcmp(args[i], "ELSE") == 0) { 174 | else_index = i; 175 | break; 176 | } 177 | } 178 | 179 | // Construct true and false commands 180 | if (else_index != -1) { 181 | for (int i = 1; i < else_index; i++) { 182 | strcat(true_command, args[i]); 183 | if (i < else_index - 1) 184 | strcat(true_command, " "); 185 | } 186 | for (int i = else_index + 1; i < arg_count; i++) { 187 | strcat(false_command, args[i]); 188 | if (i < arg_count - 1) 189 | strcat(false_command, " "); 190 | } 191 | } else { 192 | for (int i = 1; i < arg_count; i++) { 193 | strcat(true_command, args[i]); 194 | if (i < arg_count - 1) 195 | strcat(true_command, " "); 196 | } 197 | } 198 | 199 | if (evaluate_condition(args[0])) { 200 | execute_cs_command(true_command); 201 | } else if (else_index != -1) { 202 | execute_cs_command(false_command); 203 | } 204 | } 205 | 206 | else if (strcmp(cmd, "SLEEP") == 0 && arg_count == 1) { 207 | int sleep_time = atoi(args[0]); 208 | sleep(sleep_time); 209 | } else if (strcmp(cmd, "FOR") == 0 && arg_count >= 5) { 210 | execute_for_loop(args, arg_count); 211 | } else if (strcmp(cmd, "WHILE") == 0 && arg_count >= 2) { 212 | execute_while_loop(args, arg_count); 213 | } 214 | } 215 | 216 | void set_variable(const char *name, const char *value) { 217 | for (int i = 0; i < variable_count; i++) { 218 | if (strcmp(variables[i].name, name) == 0) { 219 | strcpy(variables[i].value, value); 220 | return; 221 | } 222 | } 223 | if (variable_count < MAX_VARIABLES) { 224 | strcpy(variables[variable_count].name, name); 225 | strcpy(variables[variable_count].value, value); 226 | variable_count++; 227 | } else { 228 | printf("Error: Maximum number of variables reached\n"); 229 | } 230 | } 231 | 232 | char *get_variable(const char *name) { 233 | for (int i = 0; i < variable_count; i++) { 234 | if (strcmp(variables[i].name, name) == 0) { 235 | return variables[i].value; 236 | } 237 | } 238 | return NULL; 239 | } 240 | 241 | void replace_variables(char *line) { 242 | char *var_start, *var_end; 243 | char var_name[MAX_VAR_NAME]; 244 | char *var_value; 245 | char new_line[MAX_COMMAND_LEN]; 246 | 247 | while ((var_start = strchr(line, '$')) != NULL) { 248 | var_end = var_start + 1; 249 | while (*var_end && (isalnum(*var_end) || *var_end == '_')) 250 | var_end++; 251 | 252 | strncpy(var_name, var_start + 1, var_end - var_start - 1); 253 | var_name[var_end - var_start - 1] = '\0'; 254 | 255 | var_value = get_variable(var_name); 256 | if (var_value != NULL) { 257 | strncpy(new_line, line, var_start - line); 258 | new_line[var_start - line] = '\0'; 259 | strcat(new_line, var_value); 260 | strcat(new_line, var_end); 261 | strcpy(line, new_line); 262 | } else { 263 | // Variable not found, move past this occurrence 264 | line = var_end; 265 | } 266 | } 267 | } 268 | 269 | int evaluate_condition(const char *condition) { 270 | char var_name[MAX_VAR_NAME]; 271 | char operator[3]; 272 | char expected_value[MAX_VAR_VALUE]; 273 | 274 | sscanf(condition, "%s%2s%s", var_name, operator, expected_value); 275 | 276 | char *actual_value = get_variable(var_name); 277 | if (actual_value == NULL) 278 | return 0; 279 | 280 | int actual_int = atoi(actual_value); 281 | int expected_int = atoi(expected_value); 282 | 283 | if (strcmp(operator, "==") == 0) 284 | return strcmp(actual_value, expected_value) == 0; 285 | if (strcmp(operator, "!=") == 0) 286 | return strcmp(actual_value, expected_value) != 0; 287 | if (strcmp(operator, "<") == 0) 288 | return actual_int < expected_int; 289 | if (strcmp(operator, "<=") == 0) 290 | return actual_int <= expected_int; 291 | if (strcmp(operator, ">") == 0) 292 | return actual_int > expected_int; 293 | if (strcmp(operator, ">=") == 0) 294 | return actual_int >= expected_int; 295 | 296 | return 0; // Invalid operator 297 | } 298 | -------------------------------------------------------------------------------- /osxiec_script/osxiec_script.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTAINER_SCRIPT_H 2 | #define CONTAINER_SCRIPT_H 3 | 4 | #define MAX_COMMAND_LEN 1024 5 | #define MAX_ARGS 10 6 | 7 | void execute_script(const char *script); 8 | void execute_cs_command(const char *command); 9 | void execute_script_file(const char *filename); 10 | #endif // CONTAINER_SCRIPT_H -------------------------------------------------------------------------------- /plugin_manager/plugin.h: -------------------------------------------------------------------------------- 1 | #ifndef PLUGIN_H 2 | #define PLUGIN_H 3 | 4 | typedef struct { 5 | const char* name; 6 | const char* version; 7 | int (*initialize)(void); 8 | int (*execute)(const char* command); 9 | int (*cleanup)(void); 10 | } OsxiecPlugin; 11 | 12 | #endif -------------------------------------------------------------------------------- /plugin_manager/plugin_manager.c: -------------------------------------------------------------------------------- 1 | #include "plugin_manager.h" 2 | #include 3 | #include 4 | #include 5 | 6 | void plugin_manager_init(PluginManager* manager) { 7 | memset(manager, 0, sizeof(PluginManager)); 8 | } 9 | 10 | int plugin_manager_load(PluginManager* manager, const char* plugin_path) { 11 | if (manager->plugin_count >= MAX_PLUGINS) { 12 | fprintf(stderr, "Maximum number of plugins reached\n"); 13 | return -1; 14 | } 15 | 16 | void* handle = dlopen(plugin_path, RTLD_LAZY); 17 | if (!handle) { 18 | fprintf(stderr, "Cannot open plugin %s: %s\n", plugin_path, dlerror()); 19 | return -1; 20 | } 21 | 22 | OsxiecPlugin* plugin = dlsym(handle, "osxiec_plugin"); 23 | if (!plugin) { 24 | fprintf(stderr, "Cannot load symbol osxiec_plugin: %s\n", dlerror()); 25 | dlclose(handle); 26 | return -1; 27 | } 28 | 29 | if (plugin->initialize && plugin->initialize() != 0) { 30 | fprintf(stderr, "Plugin initialization failed\n"); 31 | dlclose(handle); 32 | return -1; 33 | } 34 | 35 | manager->plugins[manager->plugin_count++] = plugin; 36 | printf("Loaded plugin: %s (version %s)\n", plugin->name, plugin->version); 37 | return 0; 38 | } 39 | 40 | int plugin_manager_execute(PluginManager* manager, const char* command) { 41 | for (int i = 0; i < manager->plugin_count; i++) { 42 | if (manager->plugins[i]->execute(command) == 0) { 43 | return 0; // Command was handled by a plugin 44 | } 45 | } 46 | return -1; // No plugin handled the command 47 | } 48 | 49 | void plugin_manager_cleanup(PluginManager* manager) { 50 | for (int i = 0; i < manager->plugin_count; i++) { 51 | if (manager->plugins[i]->cleanup) { 52 | manager->plugins[i]->cleanup(); 53 | } 54 | } 55 | manager->plugin_count = 0; 56 | } -------------------------------------------------------------------------------- /plugin_manager/plugin_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef PLUGIN_MANAGER_H 2 | #define PLUGIN_MANAGER_H 3 | 4 | #include "plugin.h" 5 | 6 | #define MAX_PLUGINS 50 7 | 8 | typedef struct { 9 | OsxiecPlugin* plugins[MAX_PLUGINS]; 10 | int plugin_count; 11 | } PluginManager; 12 | 13 | void plugin_manager_init(PluginManager* manager); 14 | int plugin_manager_load(PluginManager* manager, const char* plugin_path); 15 | int plugin_manager_execute(PluginManager* manager, const char* command); 16 | void plugin_manager_cleanup(PluginManager* manager); 17 | 18 | #endif -------------------------------------------------------------------------------- /samples/Dockerfile: -------------------------------------------------------------------------------- 1 | # Test Dockerfile for osxiec to Docker conversion 2 | 3 | # Use a lightweight base image 4 | FROM alpine:latest 5 | 6 | # Set the working directory in the container 7 | WORKDIR /app 8 | 9 | # Copy the application files from the osxiec container 10 | # Note: This will be handled by the conversion script, so we don't need COPY instructions here 11 | 12 | # Install any needed packages 13 | RUN apk add --no-cache python3 py3-pip 14 | 15 | # Set environment variables (these will be overwritten by the conversion script if not using a custom Dockerfile) 16 | ENV MEMORY_SOFT_LIMIT=256m 17 | ENV MEMORY_HARD_LIMIT=512m 18 | ENV CPU_PRIORITY=20 19 | 20 | # Make port 8080 available to the world outside this container 21 | EXPOSE 8080 22 | 23 | # Run a simple Python HTTP server when the container launches 24 | CMD ["python3", "-m", "http.server", "8080"] 25 | -------------------------------------------------------------------------------- /samples/container1: -------------------------------------------------------------------------------- 1 | source_dir=example 2 | container_file=test.bin 3 | network_name=test 4 | start_config=config.txt -------------------------------------------------------------------------------- /samples/container2: -------------------------------------------------------------------------------- 1 | source_dir=example 2 | container_file=example.bin 3 | network_name=test 4 | start_config=config.txt -------------------------------------------------------------------------------- /samples/container_config.txt: -------------------------------------------------------------------------------- 1 | name=my_custom_container 2 | memory_soft_limit=59870912 3 | memory_hard_limit=1073741824 4 | cpu_priority=10 5 | network_mode=bridge 6 | container_uid=1001 7 | container_gid=1001 8 | dependencies=neofetch 9 | -------------------------------------------------------------------------------- /samples/deploy_config: -------------------------------------------------------------------------------- 1 | source_dir=example 2 | container_file=test.bin 3 | network_name=test 4 | start_config=config.txt -------------------------------------------------------------------------------- /samples/deploy_multiple_config: -------------------------------------------------------------------------------- 1 | container1 test 2 | container2 test -------------------------------------------------------------------------------- /samples/sample_plugin.c: -------------------------------------------------------------------------------- 1 | // sample_plugin.c 2 | #include "plugin_manager/plugin.h" 3 | #include 4 | #include 5 | #include "osxiec.h" 6 | 7 | static int sample_initialize(void) { 8 | printf("Sample plugin initialized\n"); 9 | execute_command("echo hello", ""); 10 | return 0; 11 | } 12 | 13 | static int sample_execute(const char* command) { 14 | if (strcmp(command, "sample") == 0) { 15 | printf("Sample plugin executed\n"); 16 | return 0; 17 | } 18 | return -1; // Command not handled 19 | } 20 | 21 | static int sample_cleanup(void) { 22 | printf("Sample plugin cleaned up\n"); 23 | return 0; 24 | } 25 | 26 | OsxiecPlugin osxiec_plugin = { 27 | .name = "Sample Plugin", 28 | .version = "1.0", 29 | .initialize = sample_initialize, 30 | .execute = sample_execute, 31 | .cleanup = sample_cleanup 32 | }; 33 | -------------------------------------------------------------------------------- /scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Define the version of the installation 4 | OSXIEC_VERSION="1.0" 5 | 6 | # Check if the script is run as root 7 | if [ "$EUID" -ne 0 ] 8 | then echo "Please run as root or use sudo" 9 | exit 10 | fi 11 | 12 | # Define the files and directories to copy 13 | files_to_copy=("osxiec" "libosxiec.dylib" "osxiec_deploy_multiple.sh" "include" "README.md" "LICENSE") 14 | 15 | # Define the destination directory 16 | install_dir="/usr/local/Cellar/osxiec/$OSXIEC_VERSION" 17 | 18 | # Create the installation directories 19 | mkdir -p "$install_dir/lib" "$install_dir/include" "$install_dir/bin" 20 | 21 | # Copy each file or directory 22 | for item in "${files_to_copy[@]}" 23 | do 24 | # Check if it's a directory or file 25 | if [ -d "$item" ]; then 26 | if [ "$item" == "include" ]; then 27 | if [ -d "$install_dir/include/osxiec" ]; then 28 | rm -rf "$install_dir/include/osxiec" 29 | echo "Deleted existing directory $install_dir/include/osxiec" 30 | fi 31 | cp -r "$item" "$install_dir/include/osxiec/" 32 | 33 | # Check if the copy was successful 34 | if [ $? -eq 0 ]; then 35 | echo "Directory $item copied successfully to $install_dir/include/osxiec" 36 | else 37 | echo "Failed to copy the directory $item" 38 | fi 39 | else 40 | # For any other directory, copy it directly to the version folder 41 | cp -r "$item" "$install_dir/" 42 | 43 | # Check if the copy was successful 44 | if [ $? -eq 0 ]; then 45 | echo "Directory $item copied successfully to $install_dir" 46 | else 47 | echo "Failed to copy the directory $item" 48 | fi 49 | fi 50 | elif [ -f "$item" ]; then 51 | if [ "$item" == "osxiec" ]; then 52 | # Check and delete existing symbolic link if present 53 | if [ -L "/usr/local/bin/osxiec" ]; then 54 | rm "/usr/local/bin/osxiec" 55 | echo "Deleted existing symbolic link /usr/local/bin/osxiec" 56 | fi 57 | 58 | # Copy the executable to the bin folder in the versioned directory 59 | if [ -f "$install_dir/bin/$item" ]; then 60 | rm "$install_dir/bin/$item" 61 | echo "Deleted existing file $install_dir/bin/$item" 62 | fi 63 | cp "$item" "$install_dir/bin/" 64 | 65 | # Check if the copy was successful 66 | if [ $? -eq 0 ]; then 67 | echo "Executable $item copied successfully to $install_dir/bin" 68 | else 69 | echo "Failed to copy the executable $item" 70 | fi 71 | 72 | # Create a new symbolic link in /usr/local/bin pointing to the executable in the bin folder 73 | ln -s "$install_dir/bin/osxiec" "/usr/local/bin/osxiec" 74 | if [ $? -eq 0 ]; then 75 | echo "Symbolic link created in /usr/local/bin pointing to $install_dir/bin/osxiec" 76 | else 77 | echo "Failed to create symbolic link in /usr/local/bin" 78 | fi 79 | elif [ "$item" == "libosxiec.dylib" ]; then 80 | # Check and delete existing symbolic link if present 81 | if [ -L "/usr/local/lib/libosxiec.dylib" ]; then 82 | rm "/usr/local/lib/libosxiec.dylib" 83 | echo "Deleted existing symbolic link /usr/local/lib/libosxiec.dylib" 84 | fi 85 | 86 | # For libosxiec.dylib, copy to the lib folder in the versioned directory 87 | if [ -f "$install_dir/lib/$item" ]; then 88 | rm "$install_dir/lib/$item" 89 | echo "Deleted existing file $install_dir/lib/$item" 90 | fi 91 | cp "$item" "$install_dir/lib/" 92 | 93 | # Check if the copy was successful 94 | if [ $? -eq 0 ]; then 95 | echo "File $item copied successfully to $install_dir/lib" 96 | else 97 | echo "Failed to copy the file $item" 98 | fi 99 | 100 | # Create a new symbolic link in /usr/local/lib to the library 101 | ln -s "$install_dir/lib/libosxiec.dylib" "/usr/local/lib/libosxiec.dylib" 102 | if [ $? -eq 0 ]; then 103 | echo "Symbolic link created in /usr/local/lib pointing to $install_dir/lib/libosxiec.dylib" 104 | else 105 | echo "Failed to create symbolic link in /usr/local/lib" 106 | fi 107 | elif [ "$item" == "osxiec_deploy_multiple.sh" ]; then 108 | if [ -f "/usr/local/bin/$item" ]; then 109 | rm "/usr/local/bin/$item" 110 | echo "Deleted existing file /usr/local/bin/$item" 111 | fi 112 | 113 | cp "$item" /usr/local/bin/ 114 | if [ $? -eq 0 ]; then 115 | echo "File $item copied successfully to /usr/local/bin" 116 | else 117 | echo "Failed to copy the file $item" 118 | fi 119 | else 120 | # For any other file, copy it directly into the version folder 121 | cp "$item" "$install_dir/" 122 | 123 | # Check if the copy was successful 124 | if [ $? -eq 0 ]; then 125 | echo "File $item copied successfully to $install_dir" 126 | else 127 | echo "Failed to copy the file $item" 128 | fi 129 | fi 130 | else 131 | echo "$item does not exist or is not a valid file or directory" 132 | fi 133 | done 134 | 135 | echo "Installation complete!" 136 | -------------------------------------------------------------------------------- /scripts/osxiec_deploy_multiple.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This is a work in progress. 3 | 4 | # Check for minimum number of arguments 5 | if [ "$#" -lt 1 ]; then 6 | echo "Usage: osxiec -deploym [port1 port2 ...]" 7 | exit 1 8 | fi 9 | 10 | multi_config_file="$1" 11 | shift 12 | 13 | # Array to store PIDs and ports 14 | pids=() 15 | ports=("$@") 16 | 17 | # Function to deploy and keep a container running 18 | deploy_container() { 19 | local config_file="$1" 20 | local network_name="$2" 21 | local port="$3" 22 | echo "Deploying container with config: $config_file on network: $network_name with port: $port" 23 | while true; do 24 | osxiec -deploy "$config_file" "$network_name" -port "$port" 25 | exit_status=$? 26 | if [ $exit_status -ne 0 ]; then 27 | echo "Container exited with status $exit_status, restarting in 5 seconds..." 28 | sleep 5 29 | else 30 | echo "Container exited normally. Not restarting." 31 | break 32 | fi 33 | done 34 | } 35 | 36 | # Read the multi_config_file and start each deployment in a separate thread 37 | i=0 38 | while IFS=' ' read -r config_file network_name || [[ -n "$config_file" ]]; do 39 | if [[ -n "$config_file" && -n "$network_name" ]]; then 40 | port=${ports[$i]:-$((8080 + i))} # Increment default port to avoid conflicts 41 | (deploy_container "$config_file" "$network_name" "$port") & # Run in background 42 | pids+=($!) 43 | echo "Started container process with PID: $! and port: $port" 44 | ((i++)) 45 | fi 46 | done < "$multi_config_file" 47 | 48 | echo "All container processes started. PIDs: ${pids[*]}" 49 | 50 | # Function to handle script termination 51 | cleanup() { 52 | echo "Terminating all container processes..." 53 | for pid in "${pids[@]}"; do 54 | kill $pid 2>/dev/null 55 | done 56 | exit 57 | } 58 | 59 | # Set up trap to call cleanup function on script termination 60 | trap cleanup SIGINT SIGTERM 61 | 62 | # Wait for all processes to finish 63 | for pid in "${pids[@]}"; do 64 | wait $pid 65 | done 66 | --------------------------------------------------------------------------------