Warning, /utilities/isoimagewriter/isoimagewriter/platform_mac.mm is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2016 ROSA 0003 SPDX-License-Identifier: GPL-3.0-or-later 0004 */ 0005 0006 //////////////////////////////////////////////////////////////////////////////// 0007 // This file contains Mac implementation of platform-dependent functions 0008 0009 #include "common.h" 0010 #include "mainapplication.h" 0011 #include "usbdevice.h" 0012 0013 #include <Cocoa/Cocoa.h> 0014 #include <IOKit/usb/IOUSBLib.h> 0015 #include <IOKit/storage/IOMedia.h> 0016 #include <IOKit/IOBSD.h> 0017 #include <Authorization.h> 0018 #include <ServiceManagement.h> 0019 0020 bool readBooleanRegKey(io_service_t device, CFStringRef key) 0021 { 0022 CFTypeRef value = IORegistryEntrySearchCFProperty( 0023 device, 0024 kIOServicePlane, 0025 key, 0026 kCFAllocatorDefault, 0027 kIORegistryIterateRecursively 0028 ); 0029 bool res = false; 0030 if (value != nil) 0031 { 0032 if (CFGetTypeID(value) == CFBooleanGetTypeID()) 0033 res = (CFBooleanGetValue((CFBooleanRef)value) ? true : false); 0034 CFRelease(value); 0035 } 0036 return res; 0037 } 0038 0039 unsigned long long readIntegerRegKey(io_service_t device, CFStringRef key) 0040 { 0041 CFTypeRef value = IORegistryEntrySearchCFProperty( 0042 device, 0043 kIOServicePlane, 0044 key, 0045 kCFAllocatorDefault, 0046 kIORegistryIterateRecursively 0047 ); 0048 unsigned long long res = 0; 0049 if (value != nil) 0050 { 0051 CFNumberGetValue((CFNumberRef)value, kCFNumberLongLongType, &res); 0052 CFRelease(value); 0053 } 0054 return res; 0055 } 0056 0057 0058 CFStringRef readStringRegKey(io_service_t device, CFStringRef key) 0059 { 0060 CFTypeRef value = IORegistryEntrySearchCFProperty( 0061 device, 0062 kIOServicePlane, 0063 key, 0064 kCFAllocatorDefault, 0065 kIORegistryIterateRecursively 0066 ); 0067 CFStringRef res = nil; 0068 if (value != nil) 0069 { 0070 if (CFGetTypeID(value) == CFStringGetTypeID()) 0071 res = (CFStringRef)value; 0072 else 0073 CFRelease(value); 0074 } 0075 return res; 0076 } 0077 0078 0079 bool platformEnumFlashDevices(AddFlashDeviceCallbackProc callback, void* cbParam) 0080 { 0081 CFMutableDictionaryRef matchingDict; 0082 io_iterator_t iter; 0083 kern_return_t kr; 0084 io_service_t device; 0085 0086 // Set up a matching dictionary for the class 0087 matchingDict = IOServiceMatching(kIOUSBDeviceClassName); 0088 if (matchingDict == NULL) 0089 { 0090 return false; 0091 } 0092 0093 // Obtain iterator 0094 kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter); 0095 if (kr != KERN_SUCCESS) 0096 { 0097 return false; 0098 } 0099 0100 CFStringEncoding encodingMethod = CFStringGetSystemEncoding(); 0101 0102 // Enumerate the devices 0103 while ((device = IOIteratorNext(iter))) 0104 { 0105 // Skip all non-removable devices 0106 if (!readBooleanRegKey(device, CFSTR(kIOMediaRemovableKey))) 0107 { 0108 IOObjectRelease(device); 0109 continue; 0110 } 0111 0112 // Skip devices without BSD names (that is, not real disks) 0113 CFStringRef tempStr = readStringRegKey(device, CFSTR(kIOBSDNameKey)); 0114 if (tempStr == nil) 0115 { 0116 IOObjectRelease(device); 0117 continue; 0118 } 0119 0120 // Fetch the required properties and store them in the UsbDevice object 0121 UsbDevice* deviceData = new UsbDevice; 0122 0123 // Physical device name 0124 // Using "rdiskN" instead of BSD name "diskN" to work around an OS X bug when writing 0125 // to "diskN" is extremely slow 0126 QString bsdName = CFStringGetCStringPtr(tempStr, encodingMethod); 0127 CFRelease(tempStr); 0128 deviceData->m_PhysicalDevice = "/dev/r" + bsdName; 0129 // Volume names are very long, so display the device name instead 0130 deviceData->m_Volumes << "/dev/" + bsdName; 0131 0132 // User-friendly device name: vendor+product 0133 tempStr = readStringRegKey(device, CFSTR(kUSBVendorString)); 0134 if (tempStr != nil) 0135 { 0136 deviceData->m_VisibleName = CFStringGetCStringPtr(tempStr, encodingMethod); 0137 deviceData->m_VisibleName = deviceData->m_VisibleName.trimmed(); 0138 CFRelease(tempStr); 0139 } 0140 tempStr = readStringRegKey(device, CFSTR(kUSBProductString)); 0141 if (tempStr != nil) 0142 { 0143 deviceData->m_VisibleName += " "; 0144 deviceData->m_VisibleName += CFStringGetCStringPtr(tempStr, encodingMethod); 0145 deviceData->m_VisibleName = deviceData->m_VisibleName.trimmed(); 0146 CFRelease(tempStr); 0147 } 0148 0149 // Size of the flash disk 0150 deviceData->m_Size = readIntegerRegKey(device, CFSTR(kIOMediaSizeKey)); 0151 deviceData->m_SectorSize = readIntegerRegKey(device, CFSTR(kIOMediaPreferredBlockSizeKey)); 0152 0153 // The device information is now complete, append the entry 0154 callback(cbParam, deviceData); 0155 0156 // Free the resources 0157 IOObjectRelease(device); 0158 } 0159 0160 IOObjectRelease(iter); 0161 return true; 0162 } 0163 0164 bool ensureElevated() 0165 { 0166 uid_t uid = getuid(); 0167 uid_t euid = geteuid(); 0168 if ((uid == 0) || (euid == 0)) 0169 return true; 0170 0171 AuthorizationItem authItem = { kSMRightModifySystemDaemons, 0, NULL, 0 }; 0172 AuthorizationRights authRights = { 1, &authItem }; 0173 AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; 0174 0175 AuthorizationRef authRef = NULL; 0176 0177 if (AuthorizationCreate(&authRights, kAuthorizationEmptyEnvironment, flags, &authRef) != errAuthorizationSuccess) 0178 return false; 0179 0180 // Prepare list of arguments for restarting ImageWriter 0181 // We need to explicitly pass language and initial directory so that the new instance 0182 // inherited the current user's parameters rather than root's 0183 const size_t maxArgsNum = 5; 0184 // Make sure QByteArray objects live long enough, so that their data()'s were valid until execv() call 0185 QByteArray argsBA[maxArgsNum + 1]; 0186 size_t argNo = 0; 0187 // Executable is not required as first argument, so start with options 0188 QString argLang = mApp->getLocale(); 0189 if (!argLang.isEmpty()) 0190 argsBA[argNo++] = ("--lang=" + argLang).toUtf8(); 0191 QString argDir = mApp->getInitialDir(); 0192 if (!argDir.isEmpty()) 0193 argsBA[argNo++] = ("--dir=" + argDir).toUtf8(); 0194 QString argImage = mApp->getInitialImage(); 0195 if (!argImage.isEmpty()) 0196 argsBA[argNo++] = argImage.toUtf8(); 0197 0198 // Convert arguments into char*'s and append NULL element 0199 char* args[maxArgsNum + 1]; 0200 for (size_t i = 0; i < argNo; ++i) 0201 args[i] = argsBA[i].data(); 0202 args[argNo] = NULL; 0203 0204 QByteArray appPath = mApp->applicationFilePath().toUtf8(); 0205 if (AuthorizationExecuteWithPrivileges(authRef, appPath.constData(), kAuthorizationFlagDefaults, args, NULL) != errAuthorizationSuccess) 0206 return false; 0207 0208 exit(0); 0209 } 0210 0211 void disableHideOnDeactivate(WId wid) 0212 { 0213 [[reinterpret_cast<NSView*>(wid) window] setHidesOnDeactivate: NO]; 0214 }