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 }