├── LICENSE ├── README.md ├── Ubuntu.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── kanav.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist └── Ubuntu ├── AddDiskSheetController.swift ├── AppDelegate.swift ├── Assets.xcassets ├── AccentColor.colorset │ └── Contents.json ├── AppIcon.appiconset │ ├── Contents.json │ ├── UbuntuCoF-1.png │ └── UbuntuCoF.png ├── Contents.json ├── UbuntuCoF.imageset │ ├── Contents.json │ └── UbuntuCoF.png └── ubuntu-white.imageset │ ├── Contents.json │ └── ubuntu-white.png ├── Authorization.m ├── Base.lproj └── Main.storyboard ├── DiskManagerViewController.swift ├── Info.plist ├── MainWindowController.swift ├── ProgressSheetController.swift ├── Ubuntu-Bridging-Header.h ├── Ubuntu.entitlements ├── ViewController.swift ├── boot ├── initrd.img-4.4.0-131-generic └── vmlinuz-4.4.0-131-generic ├── disk ├── DiskTools.swift ├── mkfs └── qemu-img ├── hypervisor ├── hyperkit └── xhyve └── updates └── 00-automount.sh /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Kanav Gupta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DSL 2 | 3 | Darwin subsytem for Linux. Not actually a subsystem like WSL, but runs an Ubuntu 16 VM on a hypervisor ([xhyve](https://github.com/machyve/xhyve) or [hyperkit](https://github.com/moby/hyperkit)) and adds a nice frontend to manage the VM. 4 | Goal is to make running Ubuntu or any flavour of linux as seamless as possible using existing technologies. 5 | 6 |

7 | 8 | ## Installation 9 | 10 | Head over to [releases page](https://github.com/sdslabs/DSL/releases) to download the latest version of Ubuntu.dmg and move the App to Applications folder. On the first run, it will make you download a base image, which is 3 Gb in size. You can later make and attach other disks to the VM. Login via SSH using username `default` and password `password`. 11 | 12 | ## Licensing 13 | 14 | We do not own the Ubuntu image - the hosted base image is derived from Ubuntu Server 16.04.5 and Canonical Ltd. is the rightful owner of Ubuntu. Please open an issue if this needs a proper licensing. 15 | -------------------------------------------------------------------------------- /Ubuntu.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6F03EEAE25AE1706005ABD99 /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 6F03EEAD25AE1706005ABD99 /* SwiftyJSON */; }; 11 | 6F03EEB225AE26B5005ABD99 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F03EEB125AE26B5005ABD99 /* MainWindowController.swift */; }; 12 | 6F155D2C25B064820050A2E8 /* hyperkit in Resources */ = {isa = PBXBuildFile; fileRef = 6F155D2B25B064820050A2E8 /* hyperkit */; }; 13 | 6F155D3225B0742E0050A2E8 /* DiskManagerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F155D3125B0742E0050A2E8 /* DiskManagerViewController.swift */; }; 14 | 6F155D3625B075900050A2E8 /* AddDiskSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F155D3525B075900050A2E8 /* AddDiskSheetController.swift */; }; 15 | 6F2EE07525A99FB300B4E169 /* Authorization.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F2EE07425A99FB300B4E169 /* Authorization.m */; }; 16 | 6F2F8C6425ADE91B004C231D /* ProgressSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2F8C6325ADE91B004C231D /* ProgressSheetController.swift */; }; 17 | 6F8923A025B2263C00D8118F /* DiskTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F89239F25B2263C00D8118F /* DiskTools.swift */; }; 18 | 6F8FF14125B21C41003DF0A7 /* qemu-img in Resources */ = {isa = PBXBuildFile; fileRef = 6F8FF14025B21C41003DF0A7 /* qemu-img */; }; 19 | 6F8FF14525B21C87003DF0A7 /* mkfs in Resources */ = {isa = PBXBuildFile; fileRef = 6F8FF14425B21C87003DF0A7 /* mkfs */; }; 20 | 6FB349AF25A8C3F500666240 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB349AE25A8C3F500666240 /* AppDelegate.swift */; }; 21 | 6FB349B125A8C3F500666240 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB349B025A8C3F500666240 /* ViewController.swift */; }; 22 | 6FB349B325A8C3F700666240 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FB349B225A8C3F700666240 /* Assets.xcassets */; }; 23 | 6FB349B625A8C3F700666240 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FB349B425A8C3F700666240 /* Main.storyboard */; }; 24 | 6FB349C625A8E4C400666240 /* xhyve in Resources */ = {isa = PBXBuildFile; fileRef = 6FB349C525A8E4C400666240 /* xhyve */; }; 25 | 6FB349CB25A8ECF800666240 /* initrd.img-4.4.0-131-generic in Resources */ = {isa = PBXBuildFile; fileRef = 6FB349C925A8ECF800666240 /* initrd.img-4.4.0-131-generic */; }; 26 | 6FB349CC25A8ECF800666240 /* vmlinuz-4.4.0-131-generic in Resources */ = {isa = PBXBuildFile; fileRef = 6FB349CA25A8ECF800666240 /* vmlinuz-4.4.0-131-generic */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 6F03EEB125AE26B5005ABD99 /* MainWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainWindowController.swift; sourceTree = ""; }; 31 | 6F155D2B25B064820050A2E8 /* hyperkit */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = hyperkit; sourceTree = ""; }; 32 | 6F155D3125B0742E0050A2E8 /* DiskManagerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskManagerViewController.swift; sourceTree = ""; }; 33 | 6F155D3525B075900050A2E8 /* AddDiskSheetController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddDiskSheetController.swift; sourceTree = ""; }; 34 | 6F2EE07325A99FB300B4E169 /* Ubuntu-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ubuntu-Bridging-Header.h"; sourceTree = ""; }; 35 | 6F2EE07425A99FB300B4E169 /* Authorization.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Authorization.m; sourceTree = ""; }; 36 | 6F2F8C6325ADE91B004C231D /* ProgressSheetController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressSheetController.swift; sourceTree = ""; }; 37 | 6F89239F25B2263C00D8118F /* DiskTools.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskTools.swift; sourceTree = ""; }; 38 | 6F8FF14025B21C41003DF0A7 /* qemu-img */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = "qemu-img"; sourceTree = ""; }; 39 | 6F8FF14425B21C87003DF0A7 /* mkfs */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = mkfs; path = ../../../../../ubuntu/mkfs; sourceTree = ""; }; 40 | 6FB349AB25A8C3F500666240 /* Ubuntu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ubuntu.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 6FB349AE25A8C3F500666240 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 42 | 6FB349B025A8C3F500666240 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 43 | 6FB349B225A8C3F700666240 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 44 | 6FB349B525A8C3F700666240 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 45 | 6FB349B725A8C3F700666240 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | 6FB349B825A8C3F700666240 /* Ubuntu.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ubuntu.entitlements; sourceTree = ""; }; 47 | 6FB349C525A8E4C400666240 /* xhyve */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = xhyve; sourceTree = ""; }; 48 | 6FB349C925A8ECF800666240 /* initrd.img-4.4.0-131-generic */ = {isa = PBXFileReference; lastKnownFileType = file; path = "initrd.img-4.4.0-131-generic"; sourceTree = ""; }; 49 | 6FB349CA25A8ECF800666240 /* vmlinuz-4.4.0-131-generic */ = {isa = PBXFileReference; lastKnownFileType = file; path = "vmlinuz-4.4.0-131-generic"; sourceTree = ""; }; 50 | 6FD78FBB25B306BE00AD4942 /* 00-automount.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "00-automount.sh"; sourceTree = ""; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | 6FB349A825A8C3F500666240 /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | 6F03EEAE25AE1706005ABD99 /* SwiftyJSON in Frameworks */, 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 6F155D3825B0D3090050A2E8 /* hypervisor */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 6FB349C525A8E4C400666240 /* xhyve */, 69 | 6F155D2B25B064820050A2E8 /* hyperkit */, 70 | ); 71 | path = hypervisor; 72 | sourceTree = ""; 73 | }; 74 | 6F8FF13C25B21B81003DF0A7 /* disk */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 6F8FF14425B21C87003DF0A7 /* mkfs */, 78 | 6F8FF14025B21C41003DF0A7 /* qemu-img */, 79 | 6F89239F25B2263C00D8118F /* DiskTools.swift */, 80 | ); 81 | path = disk; 82 | sourceTree = ""; 83 | }; 84 | 6FB349A225A8C3F500666240 = { 85 | isa = PBXGroup; 86 | children = ( 87 | 6FB349AD25A8C3F500666240 /* Ubuntu */, 88 | 6FB349AC25A8C3F500666240 /* Products */, 89 | 6FB349BF25A8E11100666240 /* Frameworks */, 90 | ); 91 | sourceTree = ""; 92 | }; 93 | 6FB349AC25A8C3F500666240 /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 6FB349AB25A8C3F500666240 /* Ubuntu.app */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | 6FB349AD25A8C3F500666240 /* Ubuntu */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 6FD78FBA25B3069900AD4942 /* updates */, 105 | 6F8FF13C25B21B81003DF0A7 /* disk */, 106 | 6F155D3825B0D3090050A2E8 /* hypervisor */, 107 | 6FB349C825A8ECC600666240 /* boot */, 108 | 6FB349AE25A8C3F500666240 /* AppDelegate.swift */, 109 | 6F03EEB125AE26B5005ABD99 /* MainWindowController.swift */, 110 | 6FB349B025A8C3F500666240 /* ViewController.swift */, 111 | 6F155D3125B0742E0050A2E8 /* DiskManagerViewController.swift */, 112 | 6F155D3525B075900050A2E8 /* AddDiskSheetController.swift */, 113 | 6F2F8C6325ADE91B004C231D /* ProgressSheetController.swift */, 114 | 6F2EE07325A99FB300B4E169 /* Ubuntu-Bridging-Header.h */, 115 | 6F2EE07425A99FB300B4E169 /* Authorization.m */, 116 | 6FB349B425A8C3F700666240 /* Main.storyboard */, 117 | 6FB349B225A8C3F700666240 /* Assets.xcassets */, 118 | 6FB349B725A8C3F700666240 /* Info.plist */, 119 | 6FB349B825A8C3F700666240 /* Ubuntu.entitlements */, 120 | ); 121 | path = Ubuntu; 122 | sourceTree = ""; 123 | }; 124 | 6FB349BF25A8E11100666240 /* Frameworks */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | ); 128 | name = Frameworks; 129 | sourceTree = ""; 130 | }; 131 | 6FB349C825A8ECC600666240 /* boot */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 6FB349C925A8ECF800666240 /* initrd.img-4.4.0-131-generic */, 135 | 6FB349CA25A8ECF800666240 /* vmlinuz-4.4.0-131-generic */, 136 | ); 137 | path = boot; 138 | sourceTree = ""; 139 | }; 140 | 6FD78FBA25B3069900AD4942 /* updates */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 6FD78FBB25B306BE00AD4942 /* 00-automount.sh */, 144 | ); 145 | path = updates; 146 | sourceTree = ""; 147 | }; 148 | /* End PBXGroup section */ 149 | 150 | /* Begin PBXNativeTarget section */ 151 | 6FB349AA25A8C3F500666240 /* Ubuntu */ = { 152 | isa = PBXNativeTarget; 153 | buildConfigurationList = 6FB349BB25A8C3F700666240 /* Build configuration list for PBXNativeTarget "Ubuntu" */; 154 | buildPhases = ( 155 | 6FB349A725A8C3F500666240 /* Sources */, 156 | 6FB349A825A8C3F500666240 /* Frameworks */, 157 | 6FB349A925A8C3F500666240 /* Resources */, 158 | ); 159 | buildRules = ( 160 | ); 161 | dependencies = ( 162 | ); 163 | name = Ubuntu; 164 | packageProductDependencies = ( 165 | 6F03EEAD25AE1706005ABD99 /* SwiftyJSON */, 166 | ); 167 | productName = Ubuntu; 168 | productReference = 6FB349AB25A8C3F500666240 /* Ubuntu.app */; 169 | productType = "com.apple.product-type.application"; 170 | }; 171 | /* End PBXNativeTarget section */ 172 | 173 | /* Begin PBXProject section */ 174 | 6FB349A325A8C3F500666240 /* Project object */ = { 175 | isa = PBXProject; 176 | attributes = { 177 | KnownAssetTags = ( 178 | xhyve, 179 | ); 180 | LastSwiftUpdateCheck = 1230; 181 | LastUpgradeCheck = 1230; 182 | TargetAttributes = { 183 | 6FB349AA25A8C3F500666240 = { 184 | CreatedOnToolsVersion = 12.3; 185 | LastSwiftMigration = 1230; 186 | }; 187 | }; 188 | }; 189 | buildConfigurationList = 6FB349A625A8C3F500666240 /* Build configuration list for PBXProject "Ubuntu" */; 190 | compatibilityVersion = "Xcode 9.3"; 191 | developmentRegion = en; 192 | hasScannedForEncodings = 0; 193 | knownRegions = ( 194 | en, 195 | Base, 196 | ); 197 | mainGroup = 6FB349A225A8C3F500666240; 198 | packageReferences = ( 199 | 6F03EEAC25AE1706005ABD99 /* XCRemoteSwiftPackageReference "SwiftyJSON" */, 200 | ); 201 | productRefGroup = 6FB349AC25A8C3F500666240 /* Products */; 202 | projectDirPath = ""; 203 | projectRoot = ""; 204 | targets = ( 205 | 6FB349AA25A8C3F500666240 /* Ubuntu */, 206 | ); 207 | }; 208 | /* End PBXProject section */ 209 | 210 | /* Begin PBXResourcesBuildPhase section */ 211 | 6FB349A925A8C3F500666240 /* Resources */ = { 212 | isa = PBXResourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | 6F155D2C25B064820050A2E8 /* hyperkit in Resources */, 216 | 6FB349C625A8E4C400666240 /* xhyve in Resources */, 217 | 6F8FF14125B21C41003DF0A7 /* qemu-img in Resources */, 218 | 6FB349B325A8C3F700666240 /* Assets.xcassets in Resources */, 219 | 6FB349CB25A8ECF800666240 /* initrd.img-4.4.0-131-generic in Resources */, 220 | 6F8FF14525B21C87003DF0A7 /* mkfs in Resources */, 221 | 6FB349CC25A8ECF800666240 /* vmlinuz-4.4.0-131-generic in Resources */, 222 | 6FB349B625A8C3F700666240 /* Main.storyboard in Resources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXResourcesBuildPhase section */ 227 | 228 | /* Begin PBXSourcesBuildPhase section */ 229 | 6FB349A725A8C3F500666240 /* Sources */ = { 230 | isa = PBXSourcesBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | 6F155D3225B0742E0050A2E8 /* DiskManagerViewController.swift in Sources */, 234 | 6FB349B125A8C3F500666240 /* ViewController.swift in Sources */, 235 | 6FB349AF25A8C3F500666240 /* AppDelegate.swift in Sources */, 236 | 6F2F8C6425ADE91B004C231D /* ProgressSheetController.swift in Sources */, 237 | 6F155D3625B075900050A2E8 /* AddDiskSheetController.swift in Sources */, 238 | 6F2EE07525A99FB300B4E169 /* Authorization.m in Sources */, 239 | 6F8923A025B2263C00D8118F /* DiskTools.swift in Sources */, 240 | 6F03EEB225AE26B5005ABD99 /* MainWindowController.swift in Sources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXSourcesBuildPhase section */ 245 | 246 | /* Begin PBXVariantGroup section */ 247 | 6FB349B425A8C3F700666240 /* Main.storyboard */ = { 248 | isa = PBXVariantGroup; 249 | children = ( 250 | 6FB349B525A8C3F700666240 /* Base */, 251 | ); 252 | name = Main.storyboard; 253 | sourceTree = ""; 254 | }; 255 | /* End PBXVariantGroup section */ 256 | 257 | /* Begin XCBuildConfiguration section */ 258 | 6FB349B925A8C3F700666240 /* Debug */ = { 259 | isa = XCBuildConfiguration; 260 | buildSettings = { 261 | ALWAYS_SEARCH_USER_PATHS = NO; 262 | CLANG_ANALYZER_NONNULL = YES; 263 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 264 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 265 | CLANG_CXX_LIBRARY = "libc++"; 266 | CLANG_ENABLE_MODULES = YES; 267 | CLANG_ENABLE_OBJC_ARC = YES; 268 | CLANG_ENABLE_OBJC_WEAK = YES; 269 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 270 | CLANG_WARN_BOOL_CONVERSION = YES; 271 | CLANG_WARN_COMMA = YES; 272 | CLANG_WARN_CONSTANT_CONVERSION = YES; 273 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 274 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 275 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 276 | CLANG_WARN_EMPTY_BODY = YES; 277 | CLANG_WARN_ENUM_CONVERSION = YES; 278 | CLANG_WARN_INFINITE_RECURSION = YES; 279 | CLANG_WARN_INT_CONVERSION = YES; 280 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 281 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 282 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 283 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 284 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 285 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 286 | CLANG_WARN_STRICT_PROTOTYPES = YES; 287 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 288 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | COPY_PHASE_STRIP = NO; 292 | DEBUG_INFORMATION_FORMAT = dwarf; 293 | ENABLE_STRICT_OBJC_MSGSEND = YES; 294 | ENABLE_TESTABILITY = YES; 295 | GCC_C_LANGUAGE_STANDARD = gnu11; 296 | GCC_DYNAMIC_NO_PIC = NO; 297 | GCC_NO_COMMON_BLOCKS = YES; 298 | GCC_OPTIMIZATION_LEVEL = 0; 299 | GCC_PREPROCESSOR_DEFINITIONS = ( 300 | "DEBUG=1", 301 | "$(inherited)", 302 | ); 303 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 304 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 305 | GCC_WARN_UNDECLARED_SELECTOR = YES; 306 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 307 | GCC_WARN_UNUSED_FUNCTION = YES; 308 | GCC_WARN_UNUSED_VARIABLE = YES; 309 | MACOSX_DEPLOYMENT_TARGET = 11.1; 310 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 311 | MTL_FAST_MATH = YES; 312 | ONLY_ACTIVE_ARCH = YES; 313 | SDKROOT = macosx; 314 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 315 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 316 | }; 317 | name = Debug; 318 | }; 319 | 6FB349BA25A8C3F700666240 /* Release */ = { 320 | isa = XCBuildConfiguration; 321 | buildSettings = { 322 | ALWAYS_SEARCH_USER_PATHS = NO; 323 | CLANG_ANALYZER_NONNULL = YES; 324 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 325 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 326 | CLANG_CXX_LIBRARY = "libc++"; 327 | CLANG_ENABLE_MODULES = YES; 328 | CLANG_ENABLE_OBJC_ARC = YES; 329 | CLANG_ENABLE_OBJC_WEAK = YES; 330 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 331 | CLANG_WARN_BOOL_CONVERSION = YES; 332 | CLANG_WARN_COMMA = YES; 333 | CLANG_WARN_CONSTANT_CONVERSION = YES; 334 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 335 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 336 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 337 | CLANG_WARN_EMPTY_BODY = YES; 338 | CLANG_WARN_ENUM_CONVERSION = YES; 339 | CLANG_WARN_INFINITE_RECURSION = YES; 340 | CLANG_WARN_INT_CONVERSION = YES; 341 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 342 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 343 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 344 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 345 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 346 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 347 | CLANG_WARN_STRICT_PROTOTYPES = YES; 348 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 349 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 350 | CLANG_WARN_UNREACHABLE_CODE = YES; 351 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 352 | COPY_PHASE_STRIP = NO; 353 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 354 | ENABLE_NS_ASSERTIONS = NO; 355 | ENABLE_STRICT_OBJC_MSGSEND = YES; 356 | GCC_C_LANGUAGE_STANDARD = gnu11; 357 | GCC_NO_COMMON_BLOCKS = YES; 358 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 359 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 360 | GCC_WARN_UNDECLARED_SELECTOR = YES; 361 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 362 | GCC_WARN_UNUSED_FUNCTION = YES; 363 | GCC_WARN_UNUSED_VARIABLE = YES; 364 | MACOSX_DEPLOYMENT_TARGET = 11.1; 365 | MTL_ENABLE_DEBUG_INFO = NO; 366 | MTL_FAST_MATH = YES; 367 | SDKROOT = macosx; 368 | SWIFT_COMPILATION_MODE = wholemodule; 369 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 370 | }; 371 | name = Release; 372 | }; 373 | 6FB349BC25A8C3F700666240 /* Debug */ = { 374 | isa = XCBuildConfiguration; 375 | buildSettings = { 376 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 377 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 378 | CLANG_ENABLE_MODULES = YES; 379 | CODE_SIGN_ENTITLEMENTS = Ubuntu/Ubuntu.entitlements; 380 | CODE_SIGN_STYLE = Automatic; 381 | COMBINE_HIDPI_IMAGES = YES; 382 | INFOPLIST_FILE = Ubuntu/Info.plist; 383 | LD_RUNPATH_SEARCH_PATHS = ( 384 | "$(inherited)", 385 | "@executable_path/../Frameworks", 386 | ); 387 | MARKETING_VERSION = 0.2.0; 388 | PRODUCT_BUNDLE_IDENTIFIER = org.sdslabs.Ubuntu; 389 | PRODUCT_NAME = "$(TARGET_NAME)"; 390 | SWIFT_OBJC_BRIDGING_HEADER = "Ubuntu/Ubuntu-Bridging-Header.h"; 391 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 392 | SWIFT_VERSION = 5.0; 393 | }; 394 | name = Debug; 395 | }; 396 | 6FB349BD25A8C3F700666240 /* Release */ = { 397 | isa = XCBuildConfiguration; 398 | buildSettings = { 399 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 400 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 401 | CLANG_ENABLE_MODULES = YES; 402 | CODE_SIGN_ENTITLEMENTS = Ubuntu/Ubuntu.entitlements; 403 | CODE_SIGN_STYLE = Automatic; 404 | COMBINE_HIDPI_IMAGES = YES; 405 | INFOPLIST_FILE = Ubuntu/Info.plist; 406 | LD_RUNPATH_SEARCH_PATHS = ( 407 | "$(inherited)", 408 | "@executable_path/../Frameworks", 409 | ); 410 | MARKETING_VERSION = 0.2.0; 411 | PRODUCT_BUNDLE_IDENTIFIER = org.sdslabs.Ubuntu; 412 | PRODUCT_NAME = "$(TARGET_NAME)"; 413 | SWIFT_OBJC_BRIDGING_HEADER = "Ubuntu/Ubuntu-Bridging-Header.h"; 414 | SWIFT_VERSION = 5.0; 415 | }; 416 | name = Release; 417 | }; 418 | /* End XCBuildConfiguration section */ 419 | 420 | /* Begin XCConfigurationList section */ 421 | 6FB349A625A8C3F500666240 /* Build configuration list for PBXProject "Ubuntu" */ = { 422 | isa = XCConfigurationList; 423 | buildConfigurations = ( 424 | 6FB349B925A8C3F700666240 /* Debug */, 425 | 6FB349BA25A8C3F700666240 /* Release */, 426 | ); 427 | defaultConfigurationIsVisible = 0; 428 | defaultConfigurationName = Release; 429 | }; 430 | 6FB349BB25A8C3F700666240 /* Build configuration list for PBXNativeTarget "Ubuntu" */ = { 431 | isa = XCConfigurationList; 432 | buildConfigurations = ( 433 | 6FB349BC25A8C3F700666240 /* Debug */, 434 | 6FB349BD25A8C3F700666240 /* Release */, 435 | ); 436 | defaultConfigurationIsVisible = 0; 437 | defaultConfigurationName = Release; 438 | }; 439 | /* End XCConfigurationList section */ 440 | 441 | /* Begin XCRemoteSwiftPackageReference section */ 442 | 6F03EEAC25AE1706005ABD99 /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = { 443 | isa = XCRemoteSwiftPackageReference; 444 | repositoryURL = "https://github.com/SwiftyJSON/SwiftyJSON"; 445 | requirement = { 446 | kind = upToNextMajorVersion; 447 | minimumVersion = 5.0.0; 448 | }; 449 | }; 450 | /* End XCRemoteSwiftPackageReference section */ 451 | 452 | /* Begin XCSwiftPackageProductDependency section */ 453 | 6F03EEAD25AE1706005ABD99 /* SwiftyJSON */ = { 454 | isa = XCSwiftPackageProductDependency; 455 | package = 6F03EEAC25AE1706005ABD99 /* XCRemoteSwiftPackageReference "SwiftyJSON" */; 456 | productName = SwiftyJSON; 457 | }; 458 | /* End XCSwiftPackageProductDependency section */ 459 | }; 460 | rootObject = 6FB349A325A8C3F500666240 /* Project object */; 461 | } 462 | -------------------------------------------------------------------------------- /Ubuntu.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Ubuntu.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Ubuntu.xcodeproj/xcuserdata/kanav.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Playground (Playground) 1.xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 2 13 | 14 | Playground (Playground) 2.xcscheme 15 | 16 | isShown 17 | 18 | orderHint 19 | 3 20 | 21 | Playground (Playground).xcscheme 22 | 23 | isShown 24 | 25 | orderHint 26 | 0 27 | 28 | Ubuntu.xcscheme_^#shared#^_ 29 | 30 | orderHint 31 | 0 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Ubuntu/AddDiskSheetController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AddDiskSheetController.swift 3 | // Ubuntu 4 | // 5 | // Created by Kanav Gupta on 14/01/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | enum DiskFormat { 11 | case qcow2, raw 12 | } 13 | 14 | enum StorageUnit { 15 | case gb, mb 16 | } 17 | 18 | struct DiskImage { 19 | var name: String 20 | var format: DiskFormat 21 | var storage: Int32 22 | var storageUnit: StorageUnit 23 | var mounted: Bool 24 | } 25 | 26 | func formatDescription(_ format: DiskFormat) -> String { 27 | switch format { 28 | case .qcow2: 29 | return "QCoW2 Image" 30 | case .raw: 31 | return "Raw Image" 32 | } 33 | } 34 | 35 | func unitDescription(_ unit: StorageUnit) -> String { 36 | switch unit { 37 | case .gb: 38 | return "GB" 39 | case .mb: 40 | return "MB" 41 | } 42 | } 43 | 44 | class AddDiskSheetController: NSViewController { 45 | @IBOutlet weak var formatPopUpButton: NSPopUpButton! 46 | @IBOutlet weak var spaceSuffixPopUpButton: NSPopUpButton! 47 | @IBOutlet weak var spaceTextField: NSTextField! 48 | @IBOutlet weak var nameTextField: NSTextField! 49 | 50 | @IBOutlet weak var spinner: NSProgressIndicator! 51 | @IBOutlet weak var errorLabel: NSTextField! 52 | 53 | var parentController: DiskManagerViewController! 54 | 55 | override func viewDidAppear() { 56 | nameTextField.stringValue = "" 57 | spaceTextField.integerValue = 1 58 | formatPopUpButton.selectItem(at: 0) 59 | spaceSuffixPopUpButton.selectItem(at: 1) 60 | errorLabel.isHidden = true 61 | spinner.isHidden = true 62 | } 63 | 64 | @IBAction func onCreateClicked(_ sender: Any) { 65 | errorLabel.isHidden = true 66 | spinner.isHidden = false 67 | spinner.startAnimation(nil) 68 | let format = formatPopUpButton.indexOfSelectedItem == 1 ? DiskFormat.raw : .qcow2 69 | let storageUnit = spaceSuffixPopUpButton.indexOfSelectedItem == 1 ? StorageUnit.gb : .mb 70 | let disk = DiskImage(name: nameTextField.stringValue, format: format, storage: spaceTextField.intValue, storageUnit: storageUnit, mounted: true) 71 | // Validation and Creation 72 | DispatchQueue.global().async { 73 | for d in self.parentController.disks { 74 | if d.name == disk.name { 75 | // duplicate 76 | DispatchQueue.main.async { 77 | self.errorLabel.isHidden = false 78 | self.spinner.stopAnimation(nil) 79 | self.spinner.isHidden = true 80 | self.errorLabel.stringValue = "Disk by this name already exists" 81 | } 82 | return 83 | } 84 | } 85 | 86 | if DiskTools.diskExistWithName(d: disk.name) { 87 | DispatchQueue.main.async { 88 | self.errorLabel.isHidden = false 89 | self.spinner.stopAnimation(nil) 90 | self.spinner.isHidden = true 91 | self.errorLabel.stringValue = "File already exists by same name" 92 | } 93 | return 94 | } 95 | 96 | do { 97 | try DiskTools.createDisk(d: disk) 98 | } 99 | catch { 100 | DispatchQueue.main.async { 101 | self.errorLabel.isHidden = false 102 | self.spinner.stopAnimation(nil) 103 | self.spinner.isHidden = true 104 | self.errorLabel.stringValue = "Err something went wrong.." 105 | } 106 | return 107 | } 108 | DispatchQueue.main.async { 109 | self.parentController.addDisk(disk) 110 | self.dismiss(nil) 111 | } 112 | } 113 | } 114 | 115 | @IBAction func onCancelClicked(_ sender: Any) { 116 | self.dismiss(nil) 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /Ubuntu/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Ubuntu 4 | // 5 | // Created by Kanav Gupta on 08/01/21. 6 | // 7 | 8 | import Cocoa 9 | import SwiftyJSON 10 | 11 | enum State { 12 | case notInstalled, installing, off, on 13 | } 14 | 15 | @main 16 | class AppDelegate: NSObject, NSApplicationDelegate { 17 | 18 | var statusItem : NSStatusItem? = nil 19 | 20 | var state: State = .off 21 | 22 | var osThread : DispatchWorkItem? = nil 23 | var startStopMenuItem : NSMenuItem? = nil 24 | var preferencesViewController: ViewController? 25 | var mainWindow: NSWindow! 26 | var osTask: Process? = nil 27 | var macAddress: String = "" 28 | var ipAddress: String = "" 29 | 30 | var memory: Int = 1 31 | var vCPU: Int = 2 32 | var diskImagePath: URL! 33 | var configPath: URL! 34 | var disks: [DiskImage] = [] 35 | 36 | var hypervisor: String = "hyperkit" 37 | 38 | func applicationDidFinishLaunching(_ aNotification: Notification) { 39 | // Insert code here to initialize your application 40 | 41 | initializeStatusItem() 42 | initializeConfiguration() 43 | initializePreferencesWindow() // Preferences window should always be initialized after config 44 | } 45 | 46 | func initializeStatusItem() { 47 | statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) 48 | statusItem?.image = NSImage(named: "ubuntu-white") 49 | 50 | let statusMenu = NSMenu() 51 | startStopMenuItem = NSMenuItem(title: "Boot Ubuntu", action: #selector(AppDelegate.bootUbuntu), keyEquivalent: "") 52 | statusMenu.addItem(startStopMenuItem!) 53 | statusMenu.addItem(NSMenuItem(title: "Preferences", action: #selector(AppDelegate.showPreferencesWindow), keyEquivalent: "")) 54 | statusMenu.addItem(NSMenuItem(title: "Quit", action: #selector(AppDelegate.quitApplication), keyEquivalent: "")) 55 | statusItem?.menu = statusMenu 56 | } 57 | 58 | func initializePreferencesWindow() { 59 | mainWindow = NSApplication.shared.windows.first 60 | mainWindow.close() 61 | preferencesViewController = mainWindow.contentViewController as! ViewController 62 | preferencesViewController?.setApp(appDel: self) 63 | } 64 | 65 | func initializeConfiguration() { 66 | let appSupportDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] 67 | let sdslabsPath = appSupportDirectory.appendingPathComponent("SDSLabs") 68 | configPath = sdslabsPath.appendingPathComponent("config.json") 69 | diskImagePath = sdslabsPath.appendingPathComponent("hdd.img") 70 | 71 | do 72 | { 73 | // Check if `~/Library/Application Support/SDSLabs` exist 74 | var isDirectory = ObjCBool(true) 75 | if FileManager.default.fileExists(atPath: sdslabsPath.path, isDirectory: &isDirectory) { 76 | if !isDirectory.boolValue { 77 | print("File with same path exists") 78 | quitApplication() 79 | } 80 | } 81 | else { 82 | try FileManager.default.createDirectory(at: sdslabsPath, withIntermediateDirectories: false, attributes: nil) 83 | } 84 | 85 | // Check if config.json exists 86 | if FileManager.default.fileExists(atPath: configPath.path) { 87 | let configData = try String(contentsOf: configPath, encoding: .utf8) 88 | let config = JSON(parseJSON: configData) 89 | if let jsonCPU = config["cpu"].int { 90 | vCPU = jsonCPU 91 | } 92 | if let jsonMem = config["memory"].int { 93 | memory = jsonMem 94 | } 95 | if let jsonDisks = config["disks"].array { 96 | for j in jsonDisks { 97 | disks.append(DiskImage(name: j["name"].string!, format: j["format"].string! == "qcow2" ? .qcow2 : .raw, storage: j["storage"].int32!, storageUnit: j["unit"].string! == "gb" ? .gb : .mb, mounted: j["mount"].bool!)) 98 | } 99 | } 100 | } 101 | else { 102 | let config = JSON(dictionaryLiteral: ("cpu", vCPU), ("memory", memory), ("disks", JSON([]))) 103 | print(config.description) 104 | print(configPath.path) 105 | try config.description.write(to: configPath, atomically: false, encoding: .utf8) 106 | } 107 | 108 | // Check if hdd.img exists 109 | if !FileManager.default.fileExists(atPath: diskImagePath.path) { 110 | setStateNotInstalled() 111 | } 112 | else { 113 | setStateTurnedOff() 114 | } 115 | } 116 | catch { quitApplication() } 117 | } 118 | 119 | func applicationWillTerminate(_ aNotification: Notification) { 120 | // Insert code here to tear down your application 121 | if state == .on { 122 | stopUbuntu() 123 | } 124 | } 125 | 126 | @objc func showPreferencesWindow() { 127 | NSApp.setActivationPolicy(.regular) 128 | NSApp.activate(ignoringOtherApps: true) 129 | mainWindow.makeKeyAndOrderFront(nil) 130 | } 131 | 132 | @objc func downloadUbuntuImage() { 133 | let imageDownloadURL = "https://s3.ap-south-1.amazonaws.com/ubuntu-server-16.04.5-preinstalled/base.img" 134 | showPreferencesWindow() 135 | preferencesViewController?.showProgressSheet() 136 | preferencesViewController?.progressSheet 137 | .download(from: URL(string: imageDownloadURL)!, to: diskImagePath.path) 138 | setStateInstalling() 139 | } 140 | 141 | func diskArgs() -> [String] { 142 | var i = 5 143 | let basePath: URL 144 | do { 145 | basePath = try DiskTools.getDisksDirectory() 146 | } 147 | catch { 148 | return [] 149 | } 150 | var args: [String] = [] 151 | for disk in disks { 152 | if disk.mounted { 153 | args.append("-s") 154 | var arg = "\(i),virtio-blk," 155 | i += 1 156 | if disk.format == .qcow2 { 157 | let diskPath = basePath.appendingPathComponent("\(disk.name).qcow2") 158 | arg += "file://\(diskPath.path),format=qcow" 159 | } 160 | else if disk.format == .raw { 161 | let diskPath = basePath.appendingPathComponent("\(disk.name).img") 162 | arg += diskPath.path 163 | } 164 | args.append(arg) 165 | } 166 | } 167 | return args 168 | } 169 | 170 | @objc func bootUbuntu() { 171 | 172 | if let hypervisorExecutableURL = Bundle.main.url(forResource: hypervisor, withExtension: "") { 173 | if let vmlinuzURL = Bundle.main.url(forResource: "vmlinuz-4.4.0-131-generic", withExtension: "") { 174 | if let initrdURL = Bundle.main.url(forResource: "initrd.img-4.4.0-131-generic", withExtension: "") { 175 | // Step 1: Set setuid bit for xhyve 176 | setuid_file(hypervisorExecutableURL.path) 177 | 178 | let arguments = [ 179 | "-c", String(vCPU), 180 | "-U", "8e7af180-c54d-4aa2-9bef-59d94a1ac572", 181 | "-m", "\(memory)G", 182 | "-s", "0:0,hostbridge", 183 | "-s", "31,lpc", 184 | "-s", "2:0,virtio-net", 185 | "-s", "4,virtio-blk,\(diskImagePath.path)", 186 | "-f", "kexec,\(vmlinuzURL.path),\(initrdURL.path),\"acpi=off root=/dev/vda1 ro quiet\"" 187 | ] + diskArgs() 188 | 189 | // Step 2: Get MAC Address for the VM 190 | let macAddressPipe = Pipe() 191 | let macAddressTask = Process() 192 | macAddressTask.launchPath = hypervisorExecutableURL.path 193 | macAddressTask.standardOutput = macAddressPipe 194 | macAddressTask.arguments = arguments + ["-M"] 195 | macAddressTask.launch() 196 | macAddressTask.waitUntilExit() 197 | let macAddressHandle = macAddressPipe.fileHandleForReading 198 | macAddressHandle.readData(ofLength: 5) // Read out "MAC: " 199 | // Next 17 bytes contain the mac address 200 | macAddress = String(data: macAddressHandle.readData(ofLength: 17), encoding: String.Encoding.utf8)! 201 | print("Got MAC Address: \(macAddress)") 202 | preferencesViewController?.macAddressField.stringValue = macAddress 203 | 204 | // Step 3: Run OS 205 | let outputData = Pipe() 206 | osTask = Process() 207 | osTask!.launchPath = hypervisorExecutableURL.path 208 | osTask!.arguments = arguments 209 | osTask!.standardOutput = outputData 210 | osTask!.launch() 211 | DispatchQueue.global().async { 212 | self.osTask!.waitUntilExit() 213 | DispatchQueue.main.async { 214 | self.setStateTurnedOff() 215 | } 216 | } 217 | setStateTurnedOn() 218 | 219 | // Step 4: Get IP address from /var/db/dhcpd_leases 220 | DispatchQueue.global().asyncAfter(deadline: .now() + 3) { 221 | self.fetchIP() 222 | } 223 | } 224 | } 225 | } 226 | } 227 | 228 | func fetchIP() { 229 | do { 230 | let data = try String(contentsOfFile: "/var/db/dhcpd_leases", encoding: .utf8) 231 | let lines = data.components(separatedBy: .newlines) 232 | var currIPAddress = "" 233 | var currHWAddress = "" 234 | for line in lines { 235 | let trimmedLine = line.trimmingCharacters(in: .whitespacesAndNewlines) 236 | if trimmedLine == "{" { 237 | currIPAddress = "" 238 | currHWAddress = "" 239 | } 240 | else if trimmedLine == "}" { 241 | if currHWAddress == macAddress { 242 | ipAddress = currIPAddress 243 | DispatchQueue.main.async { 244 | self.preferencesViewController?.ipAddressField.stringValue = currIPAddress 245 | } 246 | print("found IP address \(ipAddress)") 247 | break 248 | } 249 | } 250 | else { 251 | if trimmedLine.starts(with: "hw_address=") { 252 | currHWAddress = String(trimmedLine.split(separator: "=")[1].split(separator: ",")[1]) 253 | } 254 | else if trimmedLine.starts(with: "ip_address=") { 255 | currIPAddress = String(trimmedLine.split(separator: "=")[1]) 256 | } 257 | } 258 | } 259 | } 260 | catch { 261 | print("couldn't find leases file") 262 | } 263 | } 264 | 265 | @objc func stopUbuntu() { 266 | // let killer = Process() 267 | // killer.launchPath = "/usr/bin/ssh" 268 | // killer.arguments = [ 269 | // "default@" + ipAddress, 270 | // "-C", "sudo poweroff" 271 | // ] 272 | // killer.launch() 273 | // TODO: This is not a graceful way to shut down, 274 | // TODO: Simulate ACPI shutdown 275 | osTask?.terminate() 276 | setStateTurnedOff() 277 | } 278 | 279 | @objc func quitApplication() { 280 | NSApplication.shared.terminate(self) 281 | } 282 | 283 | /* 284 | Update Configuration 285 | */ 286 | func updateCPU(_ c: Int) { 287 | vCPU = c 288 | updateJSON() 289 | } 290 | 291 | func updateMemory(_ m: Int) { 292 | memory = m 293 | updateJSON() 294 | } 295 | 296 | func updateDisks(_ d: [DiskImage]) { 297 | disks = d 298 | updateJSON() 299 | } 300 | 301 | func updateJSON() { 302 | var jsonDiskArray: [JSON] = [] 303 | for d in disks { 304 | jsonDiskArray.append(JSON(dictionaryLiteral: ("name", d.name), ("format", d.format == .qcow2 ? "qcow2" : "raw"), ("storage", d.storage), ("unit", d.storageUnit == .gb ? "gb" : "mb"), ("mount", d.mounted))) 305 | } 306 | let disksJSON = JSON(jsonDiskArray) 307 | let config = JSON(dictionaryLiteral: ("cpu", vCPU), ("memory", memory), ("disks", disksJSON)) 308 | do { try config.description.write(to: configPath, atomically: false, encoding: .utf8) } 309 | catch {} 310 | } 311 | 312 | /* 313 | Set states of UI 314 | */ 315 | func setStateNotInstalled() { 316 | DispatchQueue.main.async { 317 | self.state = .notInstalled 318 | self.startStopMenuItem?.title = "Download Ubuntu.." 319 | self.startStopMenuItem?.isEnabled = true 320 | self.startStopMenuItem?.action = #selector(AppDelegate.downloadUbuntuImage) 321 | self.preferencesViewController?.bootButton.title = "Download" 322 | self.preferencesViewController?.bootButton.isEnabled = true 323 | self.preferencesViewController?.terminalButton.isEnabled = false 324 | self.preferencesViewController?.manageDisksButton.isEnabled = false 325 | self.preferencesViewController?.cpuSlider.isEnabled = false 326 | self.preferencesViewController?.memorySlider.isEnabled = false 327 | } 328 | } 329 | 330 | func setStateInstalling() { 331 | DispatchQueue.main.async { 332 | self.state = .installing 333 | self.startStopMenuItem?.title = "Downloading..." 334 | self.startStopMenuItem?.isEnabled = false 335 | self.startStopMenuItem?.action = nil 336 | self.preferencesViewController?.bootButton.title = "Download" 337 | self.preferencesViewController?.bootButton.isEnabled = false 338 | self.preferencesViewController?.terminalButton.isEnabled = false 339 | self.preferencesViewController?.manageDisksButton.isEnabled = false 340 | self.preferencesViewController?.cpuSlider.isEnabled = false 341 | self.preferencesViewController?.memorySlider.isEnabled = false 342 | } 343 | } 344 | 345 | func setStateTurnedOff() { 346 | DispatchQueue.main.async { 347 | self.state = .off 348 | self.startStopMenuItem?.title = "Boot-up" 349 | self.startStopMenuItem?.isEnabled = true 350 | self.startStopMenuItem?.action = #selector(AppDelegate.bootUbuntu) 351 | self.preferencesViewController?.bootButton.title = "Boot" 352 | self.preferencesViewController?.bootButton.isEnabled = true 353 | self.preferencesViewController?.terminalButton.isEnabled = false 354 | self.preferencesViewController?.manageDisksButton.isEnabled = true 355 | self.preferencesViewController?.cpuSlider.isEnabled = true 356 | self.preferencesViewController?.memorySlider.isEnabled = true 357 | self.preferencesViewController?.ipAddressField.stringValue = "" 358 | self.preferencesViewController?.macAddressField.stringValue = "" 359 | } 360 | } 361 | 362 | func setStateTurnedOn() { 363 | DispatchQueue.main.async { 364 | self.state = .on 365 | self.startStopMenuItem?.title = "Shut Down" 366 | self.startStopMenuItem?.isEnabled = true 367 | self.startStopMenuItem?.action = #selector(AppDelegate.stopUbuntu) 368 | self.preferencesViewController?.bootButton.title = "Shut down" 369 | self.preferencesViewController?.bootButton.isEnabled = true 370 | self.preferencesViewController?.terminalButton.isEnabled = true 371 | self.preferencesViewController?.manageDisksButton.isEnabled = false 372 | self.preferencesViewController?.cpuSlider.isEnabled = false 373 | self.preferencesViewController?.memorySlider.isEnabled = false 374 | } 375 | } 376 | } 377 | 378 | -------------------------------------------------------------------------------- /Ubuntu/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Ubuntu/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "filename" : "UbuntuCoF.png", 40 | "idiom" : "mac", 41 | "scale" : "2x", 42 | "size" : "256x256" 43 | }, 44 | { 45 | "filename" : "UbuntuCoF-1.png", 46 | "idiom" : "mac", 47 | "scale" : "1x", 48 | "size" : "512x512" 49 | }, 50 | { 51 | "idiom" : "mac", 52 | "scale" : "2x", 53 | "size" : "512x512" 54 | } 55 | ], 56 | "info" : { 57 | "author" : "xcode", 58 | "version" : 1 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Ubuntu/Assets.xcassets/AppIcon.appiconset/UbuntuCoF-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/Assets.xcassets/AppIcon.appiconset/UbuntuCoF-1.png -------------------------------------------------------------------------------- /Ubuntu/Assets.xcassets/AppIcon.appiconset/UbuntuCoF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/Assets.xcassets/AppIcon.appiconset/UbuntuCoF.png -------------------------------------------------------------------------------- /Ubuntu/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Ubuntu/Assets.xcassets/UbuntuCoF.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "UbuntuCoF.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Ubuntu/Assets.xcassets/UbuntuCoF.imageset/UbuntuCoF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/Assets.xcassets/UbuntuCoF.imageset/UbuntuCoF.png -------------------------------------------------------------------------------- /Ubuntu/Assets.xcassets/ubuntu-white.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "ubuntu-white.png", 9 | "idiom" : "mac", 10 | "scale" : "2x" 11 | } 12 | ], 13 | "info" : { 14 | "author" : "xcode", 15 | "version" : 1 16 | }, 17 | "properties" : { 18 | "template-rendering-intent" : "template" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Ubuntu/Assets.xcassets/ubuntu-white.imageset/ubuntu-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/Assets.xcassets/ubuntu-white.imageset/ubuntu-white.png -------------------------------------------------------------------------------- /Ubuntu/Authorization.m: -------------------------------------------------------------------------------- 1 | // 2 | // Authorization.m 3 | // Ubuntu 4 | // 5 | // Created by Kanav Gupta on 09/01/21. 6 | // 7 | 8 | #import 9 | #include 10 | 11 | int auth (NSString *command, NSMutableArray *args, NSPipe *outputBuf) { 12 | @autoreleasepool { 13 | // Create authorization reference 14 | AuthorizationRef authorizationRef; 15 | OSStatus status; 16 | unsigned long numArgs = [args count]; 17 | NSFileHandle *writer = [outputBuf fileHandleForWriting]; 18 | 19 | status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef); 20 | 21 | // Run the tool using the authorization reference 22 | char *argList[numArgs+1]; 23 | for (int i = 0; i < numArgs; ++i) { 24 | argList[i] = [(NSString *) args[i] UTF8String]; 25 | } 26 | argList[numArgs] = NULL; 27 | FILE *pipe = NULL; 28 | 29 | status = AuthorizationExecuteWithPrivileges(authorizationRef, (char *)[command UTF8String], kAuthorizationFlagDefaults, argList, &pipe); 30 | 31 | // Print to standard output 32 | char readBuffer[128]; 33 | if (status == errAuthorizationSuccess) { 34 | for (;;) { 35 | ssize_t bytesRead = read(fileno(pipe), readBuffer, sizeof(readBuffer)); 36 | if (bytesRead < 1) break; 37 | [writer writeData: [NSData dataWithBytes:(const void *) readBuffer length: bytesRead]]; 38 | } 39 | } else { 40 | NSLog(@"Authorization Result Code: %d", status); 41 | } 42 | } 43 | return 0; 44 | } 45 | 46 | int setuid_file (NSString *binaryPath) { 47 | @autoreleasepool { 48 | char* binary = (char *)[binaryPath UTF8String]; 49 | struct stat info; 50 | stat(binary, &info); 51 | if (info.st_uid == 0 && info.st_mode & 1<<11) 52 | { 53 | return 0; 54 | } 55 | 56 | // Create authorization reference 57 | AuthorizationRef authorizationRef; 58 | OSStatus status; 59 | char readBuffer[128]; 60 | 61 | status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef); 62 | 63 | // Run the tool using the authorization reference 64 | char *argListChown[] = { "root", binary, NULL }; 65 | FILE *pipe = NULL; 66 | 67 | status = AuthorizationExecuteWithPrivileges(authorizationRef, "/usr/sbin/chown", kAuthorizationFlagDefaults, argListChown, &pipe); 68 | 69 | // Print to standard output 70 | if (status == errAuthorizationSuccess) { 71 | printf("success\n"); 72 | for (;;) { 73 | ssize_t bytesRead = read(fileno(pipe), readBuffer, sizeof(readBuffer)); 74 | if (bytesRead < 1) break; 75 | write(fileno(stdout), readBuffer, bytesRead); 76 | } 77 | } else { 78 | NSLog(@"Authorization Result Code: %d", status); 79 | return -1; 80 | } 81 | 82 | char *argListChmod[] = { "u+s", binary, NULL }; 83 | status = AuthorizationExecuteWithPrivileges(authorizationRef, "/bin/chmod", kAuthorizationFlagDefaults, argListChmod, &pipe); 84 | if (status == errAuthorizationSuccess) { 85 | for (;;) { 86 | ssize_t bytesRead = read(fileno(pipe), readBuffer, sizeof(readBuffer)); 87 | if (bytesRead < 1) break; 88 | write(fileno(stdout), readBuffer, bytesRead); 89 | } 90 | } else { 91 | NSLog(@"Authorization Result Code: %d", status); 92 | return -1; 93 | } 94 | } 95 | return 0; 96 | } 97 | 98 | -------------------------------------------------------------------------------- /Ubuntu/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | Default 530 | 531 | 532 | 533 | 534 | 535 | 536 | Left to Right 537 | 538 | 539 | 540 | 541 | 542 | 543 | Right to Left 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | Default 555 | 556 | 557 | 558 | 559 | 560 | 561 | Left to Right 562 | 563 | 564 | 565 | 566 | 567 | 568 | Right to Left 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 836 | 847 | 858 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1099 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1218 | 1219 | 1220 | 1221 | 1222 | 1223 | 1224 | 1225 | 1226 | 1227 | 1241 | 1242 | 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1263 | -------------------------------------------------------------------------------- /Ubuntu/DiskManagerViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DiskManager.swift 3 | // Ubuntu 4 | // 5 | // Created by Kanav Gupta on 14/01/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | class MountCell: NSTableCellView { 11 | @IBOutlet weak var checkBox: NSButton! 12 | } 13 | 14 | class DiskManagerViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate { 15 | var app: AppDelegate! 16 | 17 | @IBOutlet weak var addImageButton: NSButton! 18 | @IBOutlet weak var saveButton: NSButton! 19 | 20 | @IBOutlet weak var outlineView: NSOutlineView! 21 | 22 | var disks: [DiskImage] = [] 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | outlineView.dataSource = self 27 | outlineView.delegate = self 28 | } 29 | 30 | override func viewDidAppear() { 31 | outlineView.reloadData() 32 | } 33 | 34 | lazy var addDiskSheet: AddDiskSheetController = { 35 | var sheet = NSStoryboard.main!.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("add-disk")) as! AddDiskSheetController 36 | sheet.parentController = self 37 | return sheet 38 | }() 39 | 40 | @IBAction func addImageButtonClicked(_ sender: Any) { 41 | self.presentAsSheet(addDiskSheet) 42 | } 43 | 44 | @IBAction func saveAndClose(_ sender: Any) { 45 | for i in 0.. Int { 55 | return disks.count 56 | } 57 | 58 | func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { 59 | return disks[index] 60 | } 61 | 62 | func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { 63 | return false 64 | } 65 | 66 | // Delegate Methods 67 | func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { 68 | guard let colIdentifier = tableColumn?.identifier else { return nil } 69 | var cellIdentifier: NSUserInterfaceItemIdentifier 70 | var val: String = "" 71 | 72 | if let disk = item as? DiskImage { 73 | switch colIdentifier { 74 | case NSUserInterfaceItemIdentifier(rawValue: "imageColumn"): 75 | cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "imageCell") 76 | val = disk.name 77 | case NSUserInterfaceItemIdentifier(rawValue: "summaryColumn"): 78 | cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "summaryCell") 79 | val = "\(disk.storage) \(unitDescription(disk.storageUnit)) \(formatDescription(disk.format))" 80 | case NSUserInterfaceItemIdentifier(rawValue: "mountColumn"): 81 | cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "mountCell") 82 | guard let cell = outlineView.makeView(withIdentifier: cellIdentifier, owner: nil) as? MountCell else { return nil } 83 | cell.checkBox.state = disk.mounted ? .on : .off 84 | return cell 85 | default: 86 | return nil 87 | } 88 | 89 | guard let cell = outlineView.makeView(withIdentifier: cellIdentifier, owner: nil) as? NSTableCellView else { return nil } 90 | cell.textField?.stringValue = val 91 | return cell 92 | } 93 | return nil 94 | } 95 | 96 | func addDisk(_ disk: DiskImage) { 97 | disks.append(disk) 98 | app.updateDisks(disks) 99 | outlineView.reloadData() 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Ubuntu/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | 1 21 | LSMinimumSystemVersion 22 | $(MACOSX_DEPLOYMENT_TARGET) 23 | LSUIElement 24 | 25 | NSMainStoryboardFile 26 | Main 27 | NSPrincipalClass 28 | NSApplication 29 | 30 | 31 | -------------------------------------------------------------------------------- /Ubuntu/MainWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainWindowController.swift 3 | // Ubuntu 4 | // 5 | // Created by Kanav Gupta on 13/01/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | class MainWindowController: NSWindowController, NSWindowDelegate { 11 | required init?(coder: NSCoder) { 12 | super.init(coder: coder) 13 | } 14 | 15 | override func windowDidLoad() { 16 | super.windowDidLoad() 17 | self.window?.delegate = self 18 | } 19 | 20 | func windowShouldClose(_ sender: NSWindow) -> Bool { 21 | NSApp.setActivationPolicy(.accessory) 22 | return true 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Ubuntu/ProgressSheetController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressSheetController.swift 3 | // Ubuntu 4 | // 5 | // Created by Kanav Gupta on 12/01/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | 11 | class ProgressSheetController: NSViewController, URLSessionDownloadDelegate { 12 | 13 | var mainViewController: ViewController? 14 | 15 | @IBOutlet weak var cancelButton: NSButton! 16 | @IBOutlet weak var progressBar: NSProgressIndicator! 17 | @IBOutlet weak var progressLabel: NSTextField! 18 | 19 | var task: URLSessionDownloadTask! 20 | var destPath: String! 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | 25 | // Do any additional setup after loading the view. 26 | } 27 | 28 | override var representedObject: Any? { 29 | didSet { 30 | // Update the view, if already loaded. 31 | } 32 | } 33 | 34 | @IBAction func onCancel(_ sender: Any) { 35 | task.cancel() 36 | mainViewController?.dismiss(self) 37 | } 38 | 39 | func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) 40 | { 41 | if downloadTask == task { 42 | let percentDownloaded = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite) 43 | let totalGigabytesWritten = String(format: "%.2f", Double(totalBytesWritten) / Double(1024 * 1024 * 1024)) 44 | let totalGigabytesExpected = String(format: "%.2f", Double(totalBytesExpectedToWrite) / Double(1024 * 1024 * 1024)) 45 | DispatchQueue.main.async { 46 | self.progressBar.doubleValue = percentDownloaded * 100 47 | self.progressLabel.stringValue = "\(totalGigabytesWritten) / \(totalGigabytesExpected) GB" 48 | } 49 | print(percentDownloaded * 100) 50 | } 51 | } 52 | 53 | func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) 54 | { 55 | do { 56 | try FileManager.default.moveItem(atPath: location.path, toPath: destPath) 57 | mainViewController?.app.setStateTurnedOff() 58 | } 59 | catch {} 60 | 61 | DispatchQueue.main.async { 62 | self.progressBar.stopAnimation(nil) 63 | self.mainViewController?.app.setStateTurnedOff() 64 | self.mainViewController?.dismiss(self) 65 | } 66 | } 67 | 68 | func download(from url: URL, to path: String) { 69 | progressBar.startAnimation(nil) 70 | let configuration = URLSessionConfiguration.default 71 | let operationQueue = OperationQueue() 72 | let session = URLSession(configuration: configuration, delegate: self, delegateQueue: operationQueue) 73 | 74 | let downloadTask = session.downloadTask(with: url) 75 | downloadTask.resume() 76 | task = downloadTask 77 | destPath = path 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /Ubuntu/Ubuntu-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import 6 | 7 | int auth (NSString *command, NSMutableArray *args, NSPipe *outputBuf); 8 | int setuid_file (NSString *binaryPath); 9 | 10 | -------------------------------------------------------------------------------- /Ubuntu/Ubuntu.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Ubuntu/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Ubuntu 4 | // 5 | // Created by Kanav Gupta on 08/01/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | class ViewController: NSViewController { 11 | 12 | var app: AppDelegate! 13 | 14 | @IBOutlet weak var macAddressField: NSTextField! 15 | @IBOutlet weak var ipAddressField: NSTextField! 16 | 17 | 18 | @IBOutlet weak var copyMacAddressButton: NSButton! 19 | @IBOutlet weak var copyIpAddressButton: NSButton! 20 | 21 | @IBOutlet weak var cpuSlider: NSSlider! 22 | @IBOutlet weak var cpuLabel: NSTextField! 23 | @IBOutlet weak var memorySlider: NSSlider! 24 | @IBOutlet weak var memoryLabel: NSTextField! 25 | @IBOutlet weak var bootButton: NSButton! 26 | @IBOutlet weak var terminalButton: NSButton! 27 | @IBOutlet weak var manageDisksButton: NSButton! 28 | 29 | lazy var progressSheet: ProgressSheetController = { 30 | var sheet = self.storyboard!.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("progress")) as! ProgressSheetController 31 | sheet.mainViewController = self 32 | return sheet 33 | }() 34 | 35 | lazy var diskManagerViewController: DiskManagerViewController = { 36 | var vc = self.storyboard!.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("disk-manager")) as! DiskManagerViewController 37 | vc.app = app 38 | vc.disks = app.disks 39 | return vc 40 | }() 41 | 42 | override func viewDidLoad() { 43 | super.viewDidLoad() 44 | 45 | // Do any additional setup after loading the view. 46 | } 47 | 48 | override var representedObject: Any? { 49 | didSet { 50 | // Update the view, if already loaded. 51 | } 52 | } 53 | 54 | func setApp(appDel: AppDelegate) { 55 | app = appDel 56 | cpuSlider.integerValue = app.vCPU 57 | cpuLabel.integerValue = app.vCPU 58 | memorySlider.integerValue = app.memory 59 | memoryLabel.stringValue = "\(memorySlider.integerValue)G" 60 | } 61 | 62 | @IBAction func onCPUChange(_ sender: Any) { 63 | cpuLabel.integerValue = cpuSlider.integerValue 64 | app.updateCPU(cpuSlider.integerValue) 65 | } 66 | 67 | @IBAction func onMemoryChange(_ sender: Any) { 68 | memoryLabel.stringValue = "\(memorySlider.integerValue)G" 69 | app.updateMemory(memorySlider.integerValue) 70 | } 71 | 72 | func setControls(val: Bool) { 73 | cpuSlider.isEnabled = val 74 | memorySlider.isEnabled = val 75 | terminalButton.isEnabled = !val 76 | } 77 | 78 | @IBAction func bootUbuntu(_ sender: Any) { 79 | switch app.state { 80 | case .on: 81 | app.stopUbuntu() 82 | case .off: 83 | app.bootUbuntu() 84 | case .notInstalled: 85 | app.downloadUbuntuImage() 86 | case .installing: 87 | return 88 | } 89 | } 90 | 91 | @IBAction func openTerminal(_ sender: Any) { 92 | // let terminalTask = Process() 93 | // terminalTask.launchPath = "/usr/bin/open" 94 | // terminalTask.arguments = [ 95 | // "-a", "Terminal", "ssh kanav@\(app.ipAddress)" 96 | // ] 97 | // terminalTask.launch() 98 | 99 | // let script = NSAppleScript.init(source: "tell application \"Terminal\" to do script \"cd ~/Desktop\"") 100 | // script?.executeAndReturnError(nil) 101 | 102 | } 103 | 104 | @IBAction func openDiskManager(_ sender: Any) { 105 | self.presentAsModalWindow(diskManagerViewController) 106 | } 107 | 108 | 109 | func showProgressSheet() { 110 | presentAsSheet(progressSheet) 111 | } 112 | 113 | @IBAction func copyMac(_ sender: Any) { 114 | let pasteboard = NSPasteboard.general 115 | pasteboard.declareTypes([.string], owner: nil) 116 | pasteboard.setString(macAddressField.stringValue, forType: .string) 117 | } 118 | 119 | @IBAction func copyIp(_ sender: Any) { 120 | let pasteboard = NSPasteboard.general 121 | pasteboard.declareTypes([.string], owner: nil) 122 | pasteboard.setString(ipAddressField.stringValue, forType: .string) 123 | } 124 | } 125 | 126 | -------------------------------------------------------------------------------- /Ubuntu/boot/initrd.img-4.4.0-131-generic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/boot/initrd.img-4.4.0-131-generic -------------------------------------------------------------------------------- /Ubuntu/boot/vmlinuz-4.4.0-131-generic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/boot/vmlinuz-4.4.0-131-generic -------------------------------------------------------------------------------- /Ubuntu/disk/DiskTools.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DiskTools.swift 3 | // Ubuntu 4 | // 5 | // Created by Kanav Gupta on 16/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | class DiskTools { 11 | static let qemuImg = Bundle.main.url(forResource: "qemu-img", withExtension: "")!.path 12 | static let mkfs = Bundle.main.url(forResource: "mkfs", withExtension: "")!.path 13 | 14 | static func removeExtension(path: String) -> String { 15 | var components = path.components(separatedBy: ".") 16 | if components.count > 1 { 17 | components.removeLast() 18 | return components.joined(separator: ".") 19 | } 20 | else { 21 | return path 22 | } 23 | } 24 | 25 | static func createQcowImage(path: URL, sizeInMegaBytes: Int) { 26 | let process = Process() 27 | process.launchPath = qemuImg 28 | process.arguments = [ 29 | "create", 30 | "-f", 31 | "qcow2", 32 | path.path, 33 | "\(sizeInMegaBytes)M" 34 | ] 35 | process.launch() 36 | process.waitUntilExit() 37 | } 38 | 39 | static func createRawImage(path: URL, sizeInMegaBytes: Int) { 40 | let process = Process() 41 | process.launchPath = qemuImg 42 | process.arguments = [ 43 | "create", 44 | "-f", 45 | "raw", 46 | path.path, 47 | "\(sizeInMegaBytes)M" 48 | ] 49 | process.launch() 50 | process.waitUntilExit() 51 | } 52 | 53 | static func raw2qcow(path: URL) throws { 54 | let process = Process() 55 | process.launchPath = qemuImg 56 | process.arguments = [ 57 | "convert", 58 | "-f", 59 | "raw", 60 | "-O", 61 | "qcow2", 62 | path.path, 63 | "\(removeExtension(path: path.path)).qcow2" 64 | ] 65 | process.launch() 66 | process.waitUntilExit() 67 | try deleteFile(path: path) 68 | } 69 | 70 | static func deleteFile(path: URL) throws { 71 | try FileManager.default.removeItem(atPath: path.path) 72 | } 73 | 74 | static func mkfs(path: URL, label: String) { 75 | let process = Process() 76 | process.launchPath = mkfs 77 | process.arguments = [ 78 | "-L", 79 | label, 80 | "-F", 81 | path.path 82 | ] 83 | process.launch() 84 | process.waitUntilExit() 85 | } 86 | 87 | static func createRawFilesystem(path: URL, sizeInMegaBytes: Int, label: String) { 88 | createRawImage(path: path, sizeInMegaBytes: sizeInMegaBytes) 89 | mkfs(path: path, label: label) 90 | } 91 | 92 | static func createQcowFileSystem(path: URL, sizeInMegaBytes: Int, label: String) throws { 93 | createRawFilesystem(path: path, sizeInMegaBytes: sizeInMegaBytes, label: label) 94 | try raw2qcow(path: path) 95 | } 96 | 97 | static func getDisksDirectory() throws -> URL { 98 | let appSupportDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] 99 | let sdslabsPath = appSupportDirectory.appendingPathComponent("SDSLabs") 100 | let disksPath = sdslabsPath.appendingPathComponent("disks") 101 | if !FileManager.default.fileExists(atPath: disksPath.path) { 102 | try FileManager.default.createDirectory(at: disksPath, withIntermediateDirectories: false, attributes: nil) 103 | } 104 | return disksPath 105 | } 106 | 107 | static func diskExistWithName(d: String) -> Bool { 108 | let appSupportDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] 109 | let sdslabsPath = appSupportDirectory.appendingPathComponent("SDSLabs") 110 | let disksPath = sdslabsPath.appendingPathComponent("disks") 111 | let qcowPath = disksPath.appendingPathComponent("\(d).qcow2") 112 | let rawPath = disksPath.appendingPathComponent("\(d).img") 113 | return FileManager.default.fileExists(atPath: qcowPath.path) || FileManager.default.fileExists(atPath: rawPath.path) 114 | } 115 | 116 | static func createDisk(d: DiskImage) throws { 117 | let sizeInMegaBytes = d.storageUnit == .gb ? d.storage * 1024 : d.storage 118 | let disksPath = try getDisksDirectory() 119 | switch d.format { 120 | case .qcow2: 121 | try createQcowFileSystem(path: disksPath.appendingPathComponent("\(d.name).img"), sizeInMegaBytes: Int(sizeInMegaBytes), label: d.name) 122 | case .raw: 123 | createRawFilesystem(path: disksPath.appendingPathComponent("\(d.name).img"), sizeInMegaBytes: Int(sizeInMegaBytes), label: d.name) 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Ubuntu/disk/mkfs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/disk/mkfs -------------------------------------------------------------------------------- /Ubuntu/disk/qemu-img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/disk/qemu-img -------------------------------------------------------------------------------- /Ubuntu/hypervisor/hyperkit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/hypervisor/hyperkit -------------------------------------------------------------------------------- /Ubuntu/hypervisor/xhyve: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdslabs/DSL/1b30210bf426d559491ab016401cf39f3e6b1cb8/Ubuntu/hypervisor/xhyve -------------------------------------------------------------------------------- /Ubuntu/updates/00-automount.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 00-automount.sh 4 | # Ubuntu 5 | # 6 | # Created by Kanav Gupta on 16/01/21. 7 | # 8 | 9 | echo """\ 10 | [Unit] 11 | Description=Automount disks according to disk labels 12 | 13 | [Service] 14 | ExecStart=/opt/sdslabs/automount.sh 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | """ > /etc/systemd/system/automount.service 19 | 20 | mkdir -p /opt/sdslabs 21 | 22 | echo """\ 23 | #!/bin/bash 24 | 25 | for disk in /dev/disk/by-label/*; do 26 | label=\"\$(basename \$disk)\" 27 | mkdir -p \"/mnt/\$label\" 28 | mount \"\$disk\" \"/mnt/\$label\" 29 | chown default \"/mnt/\$label\" 30 | chgrp default \"/mnt/\$label\" 31 | done 32 | """ > /opt/sdslabs/automount.sh 33 | 34 | chmod +x /opt/sdslabs/automount.sh 35 | systemctl enable automount.service 36 | --------------------------------------------------------------------------------