RTDECL(int) RTEnvGetUtf8(const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual) { AssertPtrReturn(pszVar, VERR_INVALID_POINTER); AssertPtrNullReturn(pszValue, VERR_INVALID_POINTER); AssertReturn(pszValue || !cbValue, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pcchActual, VERR_INVALID_POINTER); AssertReturn(pcchActual || (pszValue && cbValue), VERR_INVALID_PARAMETER); AssertReturn(strchr(pszVar, '=') == NULL, VERR_ENV_INVALID_VAR_NAME); if (pcchActual) *pcchActual = 0; PRTUTF16 pwszVar; int rc = RTStrToUtf16(pszVar, &pwszVar); AssertRCReturn(rc, rc); /** @todo Consider _wgetenv_s or GetEnvironmentVariableW here to avoid the * potential race with a concurrent _wputenv/_putenv. */ PCRTUTF16 pwszValue = _wgetenv(pwszVar); RTUtf16Free(pwszVar); if (pwszValue) { if (cbValue) rc = RTUtf16ToUtf8Ex(pwszValue, RTSTR_MAX, &pszValue, cbValue, pcchActual); else rc = RTUtf16CalcUtf8LenEx(pwszValue, RTSTR_MAX, pcchActual); } else rc = VERR_ENV_VAR_NOT_FOUND; return rc; }
VMMR3DECL(int) DBGFR3AsLineByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, PRTGCINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod) { /* * Implement the special address space aliases the lazy way. */ if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL) { int rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_RC, pAddress, poffDisp, pLine, phMod); if (RT_FAILURE(rc)) rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pLine, phMod); return rc; } /* * Input validation. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER); AssertPtrReturn(pLine, VERR_INVALID_POINTER); AssertPtrNullReturn(phMod, VERR_INVALID_POINTER); if (poffDisp) *poffDisp = 0; if (phMod) *phMod = NIL_RTDBGMOD; RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; /* * Do the lookup. */ return RTDbgAsLineByAddr(hRealAS, pAddress->FlatPtr, poffDisp, pLine, phMod); }
/** * Check whether a device node points to a valid device and create a UDI and * a description for it, and store the device number, if it does. * @returns true if the device is valid, false otherwise * @param pcszNode the path to the device node * @param isDVD are we looking for a DVD device (or a floppy device)? * @param pDevice where to store the device node (optional) * @param pszDesc where to store the device description (optional) * @param cchDesc the size of the buffer in @a pszDesc * @param pszUdi where to store the device UDI (optional) * @param cchUdi the size of the buffer in @a pszUdi */ static bool devValidateDevice(const char *pcszNode, bool isDVD, dev_t *pDevice, char *pszDesc, size_t cchDesc, char *pszUdi, size_t cchUdi) { AssertPtrReturn(pcszNode, false); AssertPtrNullReturn(pDevice, false); AssertPtrNullReturn(pszDesc, false); AssertReturn(!pszDesc || cchDesc > 0, false); AssertPtrNullReturn(pszUdi, false); AssertReturn(!pszUdi || cchUdi > 0, false); RTFSOBJINFO ObjInfo; if (RT_FAILURE(RTPathQueryInfo(pcszNode, &ObjInfo, RTFSOBJATTRADD_UNIX))) return false; if (!RTFS_IS_DEV_BLOCK(ObjInfo.Attr.fMode)) return false; if (pDevice) *pDevice = ObjInfo.Attr.u.Unix.Device; if (isDVD) { char szVendor[128], szModel[128]; uint8_t u8Type; if (!isCdromDevNum(ObjInfo.Attr.u.Unix.Device)) return false; if (RT_FAILURE(cdromDoInquiry(pcszNode, &u8Type, szVendor, sizeof(szVendor), szModel, sizeof(szModel)))) return false; if (u8Type != TYPE_ROM) return false; dvdCreateDeviceStrings(szVendor, szModel, pszDesc, cchDesc, pszUdi, cchUdi); } else { /* Floppies on Linux are legacy devices with hardcoded majors and * minors */ unsigned Number; floppy_drive_name szName; if (major(ObjInfo.Attr.u.Unix.Device) != FLOPPY_MAJOR) return false; switch (minor(ObjInfo.Attr.u.Unix.Device)) { case 0: case 1: case 2: case 3: Number = minor(ObjInfo.Attr.u.Unix.Device); break; case 128: case 129: case 130: case 131: Number = minor(ObjInfo.Attr.u.Unix.Device) - 128 + 4; break; default: return false; } if (!floppyGetName(pcszNode, Number, szName)) return false; floppyCreateDeviceStrings(szName, Number, pszDesc, cchDesc, pszUdi, cchUdi); } return true; }
/** * Send an SCSI INQUIRY command to a device and return selected information. * @returns iprt status code * @returns VERR_TRY_AGAIN if the query failed but might succeed next time * @param pcszNode the full path to the device node * @param pu8Type where to store the SCSI device type on success (optional) * @param pchVendor where to store the vendor id string on success (optional) * @param cchVendor the size of the @a pchVendor buffer * @param pchModel where to store the product id string on success (optional) * @param cchModel the size of the @a pchModel buffer * @note check documentation on the SCSI INQUIRY command and the Linux kernel * SCSI headers included above if you want to understand what is going * on in this method. */ static int cdromDoInquiry(const char *pcszNode, uint8_t *pu8Type, char *pchVendor, size_t cchVendor, char *pchModel, size_t cchModel) { LogRelFlowFunc(("pcszNode=%s, pu8Type=%p, pchVendor=%p, cchVendor=%llu, pchModel=%p, cchModel=%llu\n", pcszNode, pu8Type, pchVendor, cchVendor, pchModel, cchModel)); AssertPtrReturn(pcszNode, VERR_INVALID_POINTER); AssertPtrNullReturn(pu8Type, VERR_INVALID_POINTER); AssertPtrNullReturn(pchVendor, VERR_INVALID_POINTER); AssertPtrNullReturn(pchModel, VERR_INVALID_POINTER); RTFILE hFile; int rc = RTFileOpen(&hFile, pcszNode, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK); if (RT_SUCCESS(rc)) { int rcIoCtl = 0; unsigned char u8Response[96] = { 0 }; struct cdrom_generic_command CdromCommandReq; RT_ZERO(CdromCommandReq); CdromCommandReq.cmd[0] = INQUIRY; CdromCommandReq.cmd[4] = sizeof(u8Response); CdromCommandReq.buffer = u8Response; CdromCommandReq.buflen = sizeof(u8Response); CdromCommandReq.data_direction = CGC_DATA_READ; CdromCommandReq.timeout = 5000; /* ms */ rc = RTFileIoCtl(hFile, CDROM_SEND_PACKET, &CdromCommandReq, 0, &rcIoCtl); if (RT_SUCCESS(rc) && rcIoCtl < 0) rc = RTErrConvertFromErrno(-CdromCommandReq.stat); RTFileClose(hFile); if (RT_SUCCESS(rc)) { if (pu8Type) *pu8Type = u8Response[0] & 0x1f; if (pchVendor) RTStrPrintf(pchVendor, cchVendor, "%.8s", &u8Response[8] /* vendor id string */); if (pchModel) RTStrPrintf(pchModel, cchModel, "%.16s", &u8Response[16] /* product id string */); LogRelFlowFunc(("returning success: type=%u, vendor=%.8s, product=%.16s\n", u8Response[0] & 0x1f, &u8Response[8], &u8Response[16])); return VINF_SUCCESS; } } LogRelFlowFunc(("returning %Rrc\n", rc)); return rc; }
/** * Wait for the host to signal one or more events and return which. * * The events will only be delivered by the host if they have been enabled * previously using @a VbglR3CtlFilterMask. If one or several of the events * have already been signalled but not yet waited for, this function will return * immediately and return those events. * * @returns IPRT status code. * * @param fMask The events we want to wait for, or-ed together. * @param cMillies How long to wait before giving up and returning * (VERR_TIMEOUT). Use RT_INDEFINITE_WAIT to wait until we * are interrupted or one of the events is signalled. * @param pfEvents Where to store the events signalled. Optional. */ VBGLR3DECL(int) VbglR3WaitEvent(uint32_t fMask, uint32_t cMillies, uint32_t *pfEvents) { LogFlow(("VbglR3WaitEvent: fMask=0x%x, cMillies=%u, pfEvents=%p\n", fMask, cMillies, pfEvents)); AssertReturn((fMask & ~VMMDEV_EVENT_VALID_EVENT_MASK) == 0, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pfEvents, VERR_INVALID_POINTER); VBoxGuestWaitEventInfo waitEvent; waitEvent.u32TimeoutIn = cMillies; waitEvent.u32EventMaskIn = fMask; waitEvent.u32Result = VBOXGUEST_WAITEVENT_ERROR; waitEvent.u32EventFlagsOut = 0; int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent)); if (RT_SUCCESS(rc)) { /* * If a guest requests for an event which is not available on the host side * (because of an older host version, a disabled feature or older Guest Additions), * don't trigger an assertion here even in debug builds - would be annoying. */ #if 0 AssertMsg(waitEvent.u32Result == VBOXGUEST_WAITEVENT_OK, ("%d rc=%Rrc\n", waitEvent.u32Result, rc)); #endif if (pfEvents) *pfEvents = waitEvent.u32EventFlagsOut; } LogFlow(("VbglR3WaitEvent: rc=%Rrc, u32EventFlagsOut=0x%x. u32Result=%d\n", rc, waitEvent.u32EventFlagsOut, waitEvent.u32Result)); return rc; }
/* static */ int getDriveInfoFromDev(DriveInfoList *pList, bool isDVD, bool *pfSuccess) { AssertPtrReturn(pList, VERR_INVALID_POINTER); AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER); LogFlowFunc(("pList=%p, isDVD=%d, pfSuccess=%p\n", pList, isDVD, pfSuccess)); int rc = VINF_SUCCESS; bool success = false; char szPath[RTPATH_MAX] = "/dev"; deviceNodeArray aDevices; RT_ZERO(aDevices); devFindDeviceRecursive(szPath, sizeof(szPath), aDevices, isDVD); try { for (unsigned i = 0; i < MAX_DEVICE_NODES; ++i) { if (aDevices[i].Device) { pList->push_back(DriveInfo(aDevices[i].szPath, aDevices[i].szUdi, aDevices[i].szDesc)); success = true; } } if (pfSuccess != NULL) *pfSuccess = success; } catch(std::bad_alloc &e) { rc = VERR_NO_MEMORY; } LogFlowFunc (("rc=%Rrc, success=%d\n", rc, success)); return rc; }
/** * Registers a guest OS digger. * * This will instantiate an instance of the digger and add it * to the list for us in the next call to DBGFR3OSDetect(). * * @returns VBox status code. * @param pVM Pointer to the shared VM structure. * @param pReg The registration structure. * @thread Any. */ VMMR3DECL(int) DBGFR3OSRegister(PVM pVM, PCDBGFOSREG pReg) { /* * Validate intput. */ VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pReg, VERR_INVALID_POINTER); AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(!pReg->fFlags, VERR_INVALID_PARAMETER); AssertReturn(pReg->cbData < _2G, VERR_INVALID_PARAMETER); AssertReturn(pReg->szName[0], VERR_INVALID_NAME); AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME); AssertPtrReturn(pReg->pfnConstruct, VERR_INVALID_POINTER); AssertPtrNullReturn(pReg->pfnDestruct, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnProbe, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnInit, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnRefresh, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnTerm, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnQueryVersion, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnQueryInterface, VERR_INVALID_POINTER); /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSRegister, 2, pVM, pReg); }
RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle) { /* * Validate the input. */ RTPOLLSETINTERNAL *pThis = hPollSet; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER); /* * Set the busy flag and do the job. */ AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS); int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; uint32_t i = pThis->cHandles; while (i-- > 0) if (pThis->paHandles[i].id == id) { if (pHandle) { pHandle->enmType = pThis->paHandles[i].enmType; pHandle->u = pThis->paHandles[i].u; } rc = VINF_SUCCESS; break; } ASMAtomicWriteBool(&pThis->fBusy, false); return rc; }
RTR3DECL(int) RTSha256Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser) { /* Validate input */ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER); AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER); int rc = VINF_SUCCESS; *ppszDigest = NULL; /* Initialize the hash context. */ RTSHA256CONTEXT Ctx; RTSha256Init(&Ctx); /* Buffer size for progress callback */ double rdMulti = 100.0 / (cbBuf ? cbBuf : 1); /* Working buffer */ char *pvTmp = (char*)pvBuf; /* Process the memory in blocks */ size_t cbReadTotal = 0; for (;;) { size_t cbRead = RT_MIN(cbBuf - cbReadTotal, _1M); RTSha256Update(&Ctx, pvTmp, cbRead); cbReadTotal += cbRead; pvTmp += cbRead; /* Call the progress callback if one is defined */ if (pfnProgressCallback) { rc = pfnProgressCallback((unsigned)(cbReadTotal * rdMulti), pvUser); if (RT_FAILURE(rc)) break; /* canceled */ } /* Finished? */ if (cbReadTotal == cbBuf) break; } if (RT_SUCCESS(rc)) { /* Finally calculate & format the SHA256 sum */ uint8_t abHash[RTSHA256_HASH_SIZE]; RTSha256Final(&Ctx, abHash); char *pszDigest; rc = RTStrAllocEx(&pszDigest, RTSHA256_DIGEST_LEN + 1); if (RT_SUCCESS(rc)) { rc = RTSha256ToString(abHash, pszDigest, RTSHA256_DIGEST_LEN + 1); if (RT_SUCCESS(rc)) *ppszDigest = pszDigest; else RTStrFree(pszDigest); } } return rc; }
/* static */ int getDriveInfoFromSysfs(DriveInfoList *pList, bool isDVD, bool *pfSuccess) { AssertPtrReturn(pList, VERR_INVALID_POINTER); AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER); /* Valid or Null */ LogFlowFunc (("pList=%p, isDVD=%u, pfSuccess=%p\n", pList, (unsigned) isDVD, pfSuccess)); RTDIR hDir; int rc; bool fSuccess = false; unsigned cFound = 0; if (!RTPathExists("/sys")) return VINF_SUCCESS; rc = RTDirOpen(&hDir, "/sys/block"); /* This might mean that sysfs semantics have changed */ AssertReturn(rc != VERR_FILE_NOT_FOUND, VINF_SUCCESS); fSuccess = true; if (RT_SUCCESS(rc)) { for (;;) { RTDIRENTRY entry; rc = RTDirRead(hDir, &entry, NULL); Assert(rc != VERR_BUFFER_OVERFLOW); /* Should never happen... */ if (RT_FAILURE(rc)) /* Including overflow and no more files */ break; if (entry.szName[0] == '.') continue; sysfsBlockDev dev(entry.szName, isDVD); /* This might mean that sysfs semantics have changed */ AssertBreakStmt(dev.isConsistent(), fSuccess = false); if (!dev.isValid()) continue; try { pList->push_back(DriveInfo(dev.getNode(), dev.getUdi(), dev.getDesc())); } catch(std::bad_alloc &e) { rc = VERR_NO_MEMORY; break; } ++cFound; } RTDirClose(hDir); } if (rc == VERR_NO_MORE_FILES) rc = VINF_SUCCESS; if (RT_FAILURE(rc)) /* Clean up again */ for (unsigned i = 0; i < cFound; ++i) pList->pop_back(); if (pfSuccess) *pfSuccess = fSuccess; LogFlow (("rc=%Rrc, fSuccess=%u\n", rc, (unsigned) fSuccess)); return rc; }
/** * Query a symbol by address. * * The returned symbol is the one we consider closes to the specified address. * * @returns VBox status code. See RTDbgAsSymbolByAddr. * * @param pUVM The user mode VM handle. * @param hDbgAs The address space handle. * @param pAddress The address to lookup. * @param fFlags One of the RTDBGSYMADDR_FLAGS_XXX flags. * @param poffDisp Where to return the distance between the returned * symbol and pAddress. Optional. * @param pSymbol Where to return the symbol information. The returned * symbol name will be prefixed by the module name as * far as space allows. * @param phMod Where to return the module handle. Optional. */ VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags, PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod) { /* * Implement the special address space aliases the lazy way. */ if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL) { int rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_RC, pAddress, fFlags, poffDisp, pSymbol, phMod); if (RT_FAILURE(rc)) rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, fFlags, poffDisp, pSymbol, phMod); return rc; } /* * Input validation. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER); AssertPtrReturn(pSymbol, VERR_INVALID_POINTER); AssertPtrNullReturn(phMod, VERR_INVALID_POINTER); if (poffDisp) *poffDisp = 0; if (phMod) *phMod = NIL_RTDBGMOD; RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; /* * Do the lookup. */ RTDBGMOD hMod; int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, fFlags, poffDisp, pSymbol, &hMod); if (RT_SUCCESS(rc)) { dbgfR3AsSymbolJoinNames(pSymbol, hMod); if (!phMod) RTDbgModRelease(hMod); } return rc; }
/** * Queries the name and/or version string for the guest OS. * * It goes without saying that this querying is done using the current * guest OS digger and not additions or user configuration. * * @returns VBox status code. * @param pVM Pointer to the shared VM structure. * @param pszName Where to store the OS name. Optional. * @param cchName The size of the name buffer. * @param pszVersion Where to store the version string. Optional. * @param cchVersion The size of the version buffer. * @thread Any. */ VMMR3DECL(int) DBGFR3OSQueryNameAndVersion(PVM pVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion) { AssertPtrNullReturn(pszName, VERR_INVALID_POINTER); AssertPtrNullReturn(pszVersion, VERR_INVALID_POINTER); /* * Initialize the output up front. */ if (pszName && cchName) *pszName = '\0'; if (pszVersion && cchVersion) *pszVersion = '\0'; /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSQueryNameAndVersion, 5, pVM, pszName, cchName, pszVersion, cchVersion); }
/** * Detects the guest OS and try dig out symbols and useful stuff. * * When called the 2nd time, symbols will be updated that if the OS * is the same. * * @returns VBox status code. * @retval VINF_SUCCESS if successfully detected. * @retval VINF_DBGF_OS_NOT_DETCTED if we cannot figure it out. * * @param pVM Pointer to the shared VM structure. * @param pszName Where to store the OS name. Empty string if not detected. * @param cchName Size of the buffer. * @thread Any. */ VMMR3DECL(int) DBGFR3OSDetect(PVM pVM, char *pszName, size_t cchName) { AssertPtrNullReturn(pszName, VERR_INVALID_POINTER); if (pszName && cchName) *pszName = '\0'; /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDetect, 3, pVM, pszName, cchName); }
/** * Detects the guest OS and try dig out symbols and useful stuff. * * When called the 2nd time, symbols will be updated that if the OS * is the same. * * @returns VBox status code. * @retval VINF_SUCCESS if successfully detected. * @retval VINF_DBGF_OS_NOT_DETCTED if we cannot figure it out. * * @param pUVM The user mode VM handle. * @param pszName Where to store the OS name. Empty string if not detected. * @param cchName Size of the buffer. * @thread Any. */ VMMR3DECL(int) DBGFR3OSDetect(PUVM pUVM, char *pszName, size_t cchName) { AssertPtrNullReturn(pszName, VERR_INVALID_POINTER); if (pszName && cchName) *pszName = '\0'; UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDetect, 3, pUVM, pszName, cchName); }
/** * Query a symbol by name. * * The symbol can be prefixed by a module name pattern to scope the search. The * pattern is a simple string pattern with '*' and '?' as wild chars. See * RTStrSimplePatternMatch(). * * @returns VBox status code. See RTDbgAsSymbolByAddr. * * @param pUVM The user mode VM handle. * @param hDbgAs The address space handle. * @param pszSymbol The symbol to search for, maybe prefixed by a * module pattern. * @param pSymbol Where to return the symbol information. * The returned symbol name will be prefixed by * the module name as far as space allows. * @param phMod Where to return the module handle. Optional. */ VMMR3DECL(int) DBGFR3AsSymbolByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod) { /* * Implement the special address space aliases the lazy way. */ if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL) { int rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_RC, pszSymbol, pSymbol, phMod); if (RT_FAILURE(rc)) rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_GLOBAL, pszSymbol, pSymbol, phMod); return rc; } /* * Input validation. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pSymbol, VERR_INVALID_POINTER); AssertPtrNullReturn(phMod, VERR_INVALID_POINTER); if (phMod) *phMod = NIL_RTDBGMOD; RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; /* * Do the lookup. */ RTDBGMOD hMod; int rc = RTDbgAsSymbolByName(hRealAS, pszSymbol, pSymbol, &hMod); if (RT_SUCCESS(rc)) { dbgfR3AsSymbolJoinNames(pSymbol, hMod); if (!phMod) RTDbgModRelease(hMod); } /* Temporary conversion. */ else if (hDbgAs == DBGF_AS_GLOBAL) { DBGFSYMBOL DbgfSym; rc = DBGFR3SymbolByName(pUVM->pVM, pszSymbol, &DbgfSym); if (RT_SUCCESS(rc)) dbgfR3AsSymbolConvert(pSymbol, &DbgfSym); } return rc; }
RTR3DECL(int) RTManifestVerifyFiles(const char *pszManifestFile, const char * const *papszFiles, size_t cFiles, size_t *piFailed, PFNRTPROGRESS pfnProgressCallback, void *pvUser) { /* Validate input */ AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER); AssertPtrReturn(papszFiles, VERR_INVALID_POINTER); AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER); int rc = VINF_SUCCESS; /* Create our compare list */ PRTMANIFESTTEST paFiles = (PRTMANIFESTTEST)RTMemTmpAllocZ(sizeof(RTMANIFESTTEST) * cFiles); if (!paFiles) return VERR_NO_MEMORY; RTMANIFESTCALLBACKDATA callback = { pfnProgressCallback, pvUser, cFiles, 0 }; /* Fill our compare list */ for (size_t i = 0; i < cFiles; ++i) { char *pszDigest; if (pfnProgressCallback) { callback.cCurrentFile = i; rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, rtSHAProgressCallback, &callback); } else rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, NULL, NULL); if (RT_FAILURE(rc)) break; paFiles[i].pszTestFile = (char*)papszFiles[i]; paFiles[i].pszTestDigest = pszDigest; } /* Do the verification */ if (RT_SUCCESS(rc)) rc = RTManifestVerify(pszManifestFile, paFiles, cFiles, piFailed); /* Cleanup */ for (size_t i = 0; i < cFiles; ++i) { if (paFiles[i].pszTestDigest) RTStrFree((char*)paFiles[i].pszTestDigest); } RTMemTmpFree(paFiles); return rc; }
/** * Convert an (X, Y) value pair in screen co-ordinates (starting from 1) to a * value from VMMDEV_MOUSE_RANGE_MIN to VMMDEV_MOUSE_RANGE_MAX. Sets the * optional validity value to false if the pair is not on an active screen and * to true otherwise. * @note since guests with recent versions of X.Org use a different method * to everyone else to map the valuator value to a screen pixel (they * multiply by the screen dimension, do a floating point divide by * the valuator maximum and round the result, while everyone else * does truncating integer operations) we adjust the value we send * so that it maps to the right pixel both when the result is rounded * and when it is truncated. * * @returns COM status value */ HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pxAdj, int32_t *pyAdj, bool *pfValid) { AssertPtrReturn(pxAdj, E_POINTER); AssertPtrReturn(pyAdj, E_POINTER); AssertPtrNullReturn(pfValid, E_POINTER); DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface(); ComAssertRet(pDisplay, E_FAIL); /** The amount to add to the result (multiplied by the screen width/height) * to compensate for differences in guest methods for mapping back to * pixels */ enum { ADJUST_RANGE = - 3 * VMMDEV_MOUSE_RANGE / 4 }; if (pfValid) *pfValid = true; if (!(mfVMMDevGuestCaps & VMMDEV_MOUSE_NEW_PROTOCOL)) { ULONG displayWidth, displayHeight; /* Takes the display lock */ HRESULT rc = pDisplay->getScreenResolution(0, &displayWidth, &displayHeight, NULL); if (FAILED(rc)) return rc; *pxAdj = displayWidth ? (x * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) / (LONG) displayWidth: 0; *pyAdj = displayHeight ? (y * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) / (LONG) displayHeight: 0; } else { int32_t x1, y1, x2, y2; /* Takes the display lock */ pDisplay->getFramebufferDimensions(&x1, &y1, &x2, &y2); *pxAdj = x1 < x2 ? ((x - x1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) / (x2 - x1) : 0; *pyAdj = y1 < y2 ? ((y - y1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) / (y2 - y1) : 0; if ( *pxAdj < VMMDEV_MOUSE_RANGE_MIN || *pxAdj > VMMDEV_MOUSE_RANGE_MAX || *pyAdj < VMMDEV_MOUSE_RANGE_MIN || *pyAdj > VMMDEV_MOUSE_RANGE_MAX) if (pfValid) *pfValid = false; } return S_OK; }
RTDECL(int) RTCrDigestFinal(RTCRDIGEST hDigest, void *pvHash, size_t cbHash) { PRTCRDIGESTINT pThis = hDigest; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, VERR_INVALID_HANDLE); AssertReturn(pThis->uState == RTCRDIGEST_STATE_READY || pThis->uState == RTCRDIGEST_STATE_FINAL, VERR_INVALID_STATE); AssertPtrNullReturn(pvHash, VERR_INVALID_POINTER); /* * Make sure the hash calculation is final. */ if (pThis->uState == RTCRDIGEST_STATE_READY) { pThis->pDesc->pfnFinal(pThis->pvState, &pThis->abState[pThis->offHash]); pThis->uState = RTCRDIGEST_STATE_FINAL; } else AssertReturn(pThis->uState == RTCRDIGEST_STATE_FINAL, VERR_INVALID_STATE); /* * Copy out the hash if requested. */ if (cbHash > 0) { uint32_t cbNeeded = pThis->pDesc->cbHash; if (pThis->pDesc->pfnGetHashSize) cbNeeded = pThis->pDesc->pfnGetHashSize(pThis->pvState); Assert(cbNeeded > 0); if (cbNeeded == cbHash) memcpy(pvHash, &pThis->abState[pThis->offHash], cbNeeded); else if (cbNeeded > cbHash) { memcpy(pvHash, &pThis->abState[pThis->offHash], cbNeeded); memset((uint8_t *)pvHash + cbNeeded, 0, cbHash - cbNeeded); return VINF_BUFFER_UNDERFLOW; } else { memcpy(pvHash, &pThis->abState[pThis->offHash], cbHash); return VERR_BUFFER_OVERFLOW; } } return rtCrDigestSuccessWithDigestWarnings(pThis->pDesc); }
/** * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog, Generic EMT wrapper.} */ static DECLCALLBACK(int) dbgfR3OSEmtIDmesg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages, char *pszBuf, size_t cbBuf, size_t *pcbActual) { PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.Dmesg); UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(!fFlags, VERR_INVALID_FLAGS); AssertReturn(cMessages > 0, VERR_INVALID_PARAMETER); if (cbBuf) AssertPtrReturn(pszBuf, VERR_INVALID_POINTER); AssertPtrNullReturn(pcbActual, VERR_INVALID_POINTER); return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/, (PFNRT)pWrapper->uDigger.pDmesg->pfnQueryKernelLog, 7, pWrapper->uDigger.pDmesg, pUVM, fFlags, cMessages, pszBuf, cbBuf, pcbActual); }
/* static */ int getDriveInfoFromEnv(const char *pcszVar, DriveInfoList *pList, bool isDVD, bool *pfSuccess) { AssertPtrReturn(pcszVar, VERR_INVALID_POINTER); AssertPtrReturn(pList, VERR_INVALID_POINTER); AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER); LogFlowFunc(("pcszVar=%s, pList=%p, isDVD=%d, pfSuccess=%p\n", pcszVar, pList, isDVD, pfSuccess)); int rc = VINF_SUCCESS; bool success = false; char *pszFreeMe = RTEnvDupEx(RTENV_DEFAULT, pcszVar); try { const char *pcszCurrent = pszFreeMe; while (pcszCurrent && *pcszCurrent != '\0') { const char *pcszNext = strchr(pcszCurrent, ':'); char szPath[RTPATH_MAX], szReal[RTPATH_MAX]; char szDesc[256], szUdi[256]; if (pcszNext) RTStrPrintf(szPath, sizeof(szPath), "%.*s", pcszNext - pcszCurrent - 1, pcszCurrent); else RTStrPrintf(szPath, sizeof(szPath), "%s", pcszCurrent); if ( RT_SUCCESS(RTPathReal(szPath, szReal, sizeof(szReal))) && devValidateDevice(szReal, isDVD, NULL, szDesc, sizeof(szDesc), szUdi, sizeof(szUdi))) { pList->push_back(DriveInfo(szReal, szUdi, szDesc)); success = true; } pcszCurrent = pcszNext ? pcszNext + 1 : NULL; } if (pfSuccess != NULL) *pfSuccess = success; } catch(std::bad_alloc &e) { rc = VERR_NO_MEMORY; } RTStrFree(pszFreeMe); LogFlowFunc(("rc=%Rrc, success=%d\n", rc, success)); return rc; }
static int fileOpenCallback(void * /* pvUser */, const char *pszLocation, uint32_t fOpen, PFNVDCOMPLETED pfnCompleted, void **ppInt) { /* Validate input. */ AssertPtrReturn(ppInt, VERR_INVALID_POINTER); AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER); DEBUG_PRINT_FLOW(); PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)RTMemAllocZ(sizeof(FILESTORAGEINTERNAL)); if (!pInt) return VERR_NO_MEMORY; pInt->pfnCompleted = pfnCompleted; int rc = RTFileOpen(&pInt->file, pszLocation, fOpen); if (RT_FAILURE(rc)) RTMemFree(pInt); else *ppInt = pInt; return rc; }
RTR3DECL(int) RTSha256DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser) { /* Validate input */ AssertPtrReturn(pszFile, VERR_INVALID_POINTER); AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER); AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER); *ppszDigest = NULL; /* Initialize the hash context. */ RTSHA256CONTEXT Ctx; RTSha256Init(&Ctx); /* Open the file to calculate a SHA256 sum of */ RTFILE hFile; int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) return rc; /* Fetch the file size. Only needed if there is a progress callback. */ double rdMulti = 0; if (pfnProgressCallback) { uint64_t cbFile; rc = RTFileGetSize(hFile, &cbFile); if (RT_FAILURE(rc)) { RTFileClose(hFile); return rc; } rdMulti = 100.0 / (cbFile ? cbFile : 1); } /* Allocate a reasonably large buffer, fall back on a tiny one. */ void *pvBufFree; size_t cbBuf = _1M; void *pvBuf = pvBufFree = RTMemTmpAlloc(cbBuf); if (!pvBuf) { cbBuf = 0x1000; pvBuf = alloca(cbBuf); } /* Read that file in blocks */ size_t cbReadTotal = 0; for (;;) { size_t cbRead; rc = RTFileRead(hFile, pvBuf, cbBuf, &cbRead); if (RT_FAILURE(rc) || !cbRead) break; RTSha256Update(&Ctx, pvBuf, cbRead); cbReadTotal += cbRead; /* Call the progress callback if one is defined */ if (pfnProgressCallback) { rc = pfnProgressCallback((unsigned)(cbReadTotal * rdMulti), pvUser); if (RT_FAILURE(rc)) break; /* canceled */ } } RTMemTmpFree(pvBufFree); RTFileClose(hFile); if (RT_FAILURE(rc)) return rc; /* Finally calculate & format the SHA256 sum */ uint8_t abHash[RTSHA256_HASH_SIZE]; RTSha256Final(&Ctx, abHash); char *pszDigest; rc = RTStrAllocEx(&pszDigest, RTSHA256_DIGEST_LEN + 1); if (RT_SUCCESS(rc)) { rc = RTSha256ToString(abHash, pszDigest, RTSHA256_DIGEST_LEN + 1); if (RT_SUCCESS(rc)) *ppszDigest = pszDigest; else RTStrFree(pszDigest); } return rc; }
RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual) { AssertPtrReturn(pszVar, VERR_INVALID_POINTER); AssertPtrNullReturn(pszValue, VERR_INVALID_POINTER); AssertPtrNullReturn(pcchActual, VERR_INVALID_POINTER); AssertReturn(pcchActual || (pszValue && cbValue), VERR_INVALID_PARAMETER); AssertReturn(strchr(pszVar, '=') == NULL, VERR_ENV_INVALID_VAR_NAME); if (pcchActual) *pcchActual = 0; int rc; if (Env == RTENV_DEFAULT) { #ifdef RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API rc = RTEnvGetUtf8(pszVar, pszValue, cbValue, pcchActual); #else /* * Since RTEnvGet isn't UTF-8 clean and actually expects the strings * to be in the current code page (codeset), we'll do the necessary * conversions here. */ char *pszVarOtherCP; rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar); if (RT_SUCCESS(rc)) { const char *pszValueOtherCP = RTEnvGet(pszVarOtherCP); RTStrFree(pszVarOtherCP); if (pszValueOtherCP) { char *pszValueUtf8; rc = RTStrCurrentCPToUtf8(&pszValueUtf8, pszValueOtherCP); if (RT_SUCCESS(rc)) { rc = VINF_SUCCESS; size_t cch = strlen(pszValueUtf8); if (pcchActual) *pcchActual = cch; if (pszValue && cbValue) { if (cch < cbValue) memcpy(pszValue, pszValueUtf8, cch + 1); else rc = VERR_BUFFER_OVERFLOW; } RTStrFree(pszValueUtf8); } } else rc = VERR_ENV_VAR_NOT_FOUND; } #endif } else { PRTENVINTERNAL pIntEnv = Env; AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE); AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); RTENV_LOCK(pIntEnv); /* * Locate the first variable and return it to the caller. */ rc = VERR_ENV_VAR_NOT_FOUND; const size_t cchVar = strlen(pszVar); size_t iVar; for (iVar = 0; iVar < pIntEnv->cVars; iVar++) if (!pIntEnv->pfnCompare(pIntEnv->papszEnv[iVar], pszVar, cchVar)) { if (pIntEnv->papszEnv[iVar][cchVar] == '=') { rc = VINF_SUCCESS; const char *pszValueOrg = pIntEnv->papszEnv[iVar] + cchVar + 1; size_t cch = strlen(pszValueOrg); if (pcchActual) *pcchActual = cch; if (pszValue && cbValue) { if (cch < cbValue) memcpy(pszValue, pszValueOrg, cch + 1); else rc = VERR_BUFFER_OVERFLOW; } break; } if (pIntEnv->papszEnv[iVar][cchVar] == '\0') { Assert(pIntEnv->fPutEnvBlock); rc = VERR_ENV_VAR_UNSET; break; } } RTENV_UNLOCK(pIntEnv); } return rc; }
/** * Query a symbol by address. * * The returned symbol is the one we consider closes to the specified address. * * @returns VBox status code. See RTDbgAsSymbolByAddr. * * @param pUVM The user mode VM handle. * @param hDbgAs The address space handle. * @param pAddress The address to lookup. * @param poffDisp Where to return the distance between the returned * symbol and pAddress. Optional. * @param pSymbol Where to return the symbol information. The returned * symbol name will be prefixed by the module name as * far as space allows. * @param phMod Where to return the module handle. Optional. */ VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod) { /* * Implement the special address space aliases the lazy way. */ if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL) { int rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_RC, pAddress, poffDisp, pSymbol, phMod); if (RT_FAILURE(rc)) rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pSymbol, phMod); return rc; } /* * Input validation. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER); AssertPtrReturn(pSymbol, VERR_INVALID_POINTER); AssertPtrNullReturn(phMod, VERR_INVALID_POINTER); if (poffDisp) *poffDisp = 0; if (phMod) *phMod = NIL_RTDBGMOD; RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; /* * Do the lookup. */ RTDBGMOD hMod; int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, poffDisp, pSymbol, &hMod); if (RT_SUCCESS(rc)) { dbgfR3AsSymbolJoinNames(pSymbol, hMod); if (!phMod) RTDbgModRelease(hMod); } /* Temporary conversions. */ else if (hDbgAs == DBGF_AS_GLOBAL) { DBGFSYMBOL DbgfSym; rc = DBGFR3SymbolByAddr(pUVM->pVM, pAddress->FlatPtr, poffDisp, &DbgfSym); if (RT_SUCCESS(rc)) dbgfR3AsSymbolConvert(pSymbol, &DbgfSym); } else if (hDbgAs == DBGF_AS_R0) { RTR0PTR R0PtrMod; char szNearSym[260]; RTR0PTR R0PtrNearSym; RTR0PTR R0PtrNearSym2; VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE); rc = PDMR3LdrQueryR0ModFromPC(pUVM->pVM, pAddress->FlatPtr, pSymbol->szName, sizeof(pSymbol->szName) / 2, &R0PtrMod, &szNearSym[0], sizeof(szNearSym), &R0PtrNearSym, NULL, 0, &R0PtrNearSym2); if (RT_SUCCESS(rc)) { pSymbol->offSeg = pSymbol->Value = R0PtrNearSym; pSymbol->cb = R0PtrNearSym2 > R0PtrNearSym ? R0PtrNearSym2 - R0PtrNearSym : 0; pSymbol->iSeg = 0; pSymbol->fFlags = 0; pSymbol->iOrdinal = UINT32_MAX; size_t offName = strlen(pSymbol->szName); pSymbol->szName[offName++] = '!'; size_t cchNearSym = strlen(szNearSym); if (cchNearSym + offName >= sizeof(pSymbol->szName)) cchNearSym = sizeof(pSymbol->szName) - offName - 1; strncpy(&pSymbol->szName[offName], szNearSym, cchNearSym); pSymbol->szName[offName + cchNearSym] = '\0'; if (poffDisp) *poffDisp = pAddress->FlatPtr - pSymbol->Value; } } return rc; }
RTDECL(int) RTManifestEqualsEx(RTMANIFEST hManifest1, RTMANIFEST hManifest2, const char * const *papszIgnoreEntries, const char * const *papszIgnoreAttr, uint32_t fFlags, char *pszError, size_t cbError) { /* * Validate input. */ AssertPtrNullReturn(pszError, VERR_INVALID_POINTER); if (pszError && cbError) *pszError = '\0'; RTMANIFESTINT *pThis1 = hManifest1; RTMANIFESTINT *pThis2 = hManifest2; if (pThis1 != NIL_RTMANIFEST) { AssertPtrReturn(pThis1, VERR_INVALID_HANDLE); AssertReturn(pThis1->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE); } if (pThis2 != NIL_RTMANIFEST) { AssertPtrReturn(pThis2, VERR_INVALID_HANDLE); AssertReturn(pThis2->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE); } AssertReturn(!(fFlags & ~(RTMANIFEST_EQUALS_IGN_MISSING_ATTRS)), VERR_INVALID_PARAMETER); /* * The simple cases. */ if (pThis1 == pThis2) return VINF_SUCCESS; if (pThis1 == NIL_RTMANIFEST || pThis2 == NIL_RTMANIFEST) return VERR_NOT_EQUAL; /* * Since we have to use callback style enumeration, we have to mark the * entries and attributes to make sure we've covered them all. */ RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryClearVisited, NULL); RTStrSpaceEnumerate(&pThis2->Entries, rtManifestEntryClearVisited, NULL); RTStrSpaceEnumerate(&pThis1->SelfEntry.Attributes, rtManifestAttributeClearVisited, NULL); RTStrSpaceEnumerate(&pThis2->SelfEntry.Attributes, rtManifestAttributeClearVisited, NULL); RTMANIFESTEQUALS Equals; Equals.pThis2 = pThis2; Equals.fFlags = fFlags; Equals.papszIgnoreEntries = papszIgnoreEntries; Equals.papszIgnoreAttr = papszIgnoreAttr; Equals.pszError = pszError; Equals.cbError = cbError; Equals.cIgnoredEntries2 = 0; Equals.cEntries2 = 0; Equals.cIgnoredAttributes1 = 0; Equals.cIgnoredAttributes2 = 0; Equals.cAttributes2 = 0; Equals.pAttributes2 = NULL; Equals.pszCurEntry = NULL; int rc = rtManifestEntryCompare2(&Equals, &pThis1->SelfEntry, &pThis2->SelfEntry); if (RT_SUCCESS(rc)) rc = RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryCompare, &Equals); if (RT_SUCCESS(rc)) { /* * Did we cover all entries of the 2nd manifest? */ if (Equals.cEntries2 + Equals.cIgnoredEntries2 != pThis2->cEntries) rc = RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryFindMissing2, &Equals); } return rc; }
RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags, PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser, const char *pszPassword, PRTPROCESS phProcess) { int rc; /* * Input validation */ AssertPtrReturn(pszExec, VERR_INVALID_POINTER); AssertReturn(*pszExec, VERR_INVALID_PARAMETER); AssertReturn(!(fFlags & ~RTPROC_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER); AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER); AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pszAsUser, VERR_INVALID_POINTER); AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER); AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER); #if defined(RT_OS_OS2) if (fFlags & RTPROC_FLAGS_DETACHED) return VERR_PROC_DETACH_NOT_SUPPORTED; #endif /* * Get the file descriptors for the handles we've been passed. */ PCRTHANDLE paHandles[3] = { phStdIn, phStdOut, phStdErr }; int aStdFds[3] = { -1, -1, -1 }; for (int i = 0; i < 3; i++) { if (paHandles[i]) { AssertPtrReturn(paHandles[i], VERR_INVALID_POINTER); switch (paHandles[i]->enmType) { case RTHANDLETYPE_FILE: aStdFds[i] = paHandles[i]->u.hFile != NIL_RTFILE ? (int)RTFileToNative(paHandles[i]->u.hFile) : -2 /* close it */; break; case RTHANDLETYPE_PIPE: aStdFds[i] = paHandles[i]->u.hPipe != NIL_RTPIPE ? (int)RTPipeToNative(paHandles[i]->u.hPipe) : -2 /* close it */; break; case RTHANDLETYPE_SOCKET: aStdFds[i] = paHandles[i]->u.hSocket != NIL_RTSOCKET ? (int)RTSocketToNative(paHandles[i]->u.hSocket) : -2 /* close it */; break; default: AssertMsgFailedReturn(("%d: %d\n", i, paHandles[i]->enmType), VERR_INVALID_PARAMETER); } /** @todo check the close-on-execness of these handles? */ } } for (int i = 0; i < 3; i++) if (aStdFds[i] == i) aStdFds[i] = -1; for (int i = 0; i < 3; i++) AssertMsgReturn(aStdFds[i] < 0 || aStdFds[i] > i, ("%i := %i not possible because we're lazy\n", i, aStdFds[i]), VERR_NOT_SUPPORTED); /* * Resolve the user id if specified. */ uid_t uid = ~(uid_t)0; gid_t gid = ~(gid_t)0; if (pszAsUser) { rc = rtCheckCredentials(pszAsUser, pszPassword, &gid, &uid); if (RT_FAILURE(rc)) return rc; } /* * Create the child environment if either RTPROC_FLAGS_PROFILE or * RTPROC_FLAGS_ENV_CHANGE_RECORD are in effect. */ RTENV hEnvToUse = hEnv; if ( (fFlags & (RTPROC_FLAGS_ENV_CHANGE_RECORD | RTPROC_FLAGS_PROFILE)) && ( (fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) || hEnv == RTENV_DEFAULT) ) { if (fFlags & RTPROC_FLAGS_PROFILE) rc = rtProcPosixCreateProfileEnv(&hEnvToUse, pszAsUser); else rc = RTEnvClone(&hEnvToUse, RTENV_DEFAULT); if (RT_SUCCESS(rc)) { if ((fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) && hEnv != RTENV_DEFAULT) rc = RTEnvApplyChanges(hEnvToUse, hEnv); if (RT_FAILURE(rc)) RTEnvDestroy(hEnvToUse); } if (RT_FAILURE(rc)) return rc; } /* * Check for execute access to the file. */ char szRealExec[RTPATH_MAX]; if (access(pszExec, X_OK)) { rc = errno; if ( !(fFlags & RTPROC_FLAGS_SEARCH_PATH) || rc != ENOENT || RTPathHavePath(pszExec) ) rc = RTErrConvertFromErrno(rc); else { /* search */ char *pszPath = RTEnvDupEx(hEnvToUse, "PATH"); rc = RTPathTraverseList(pszPath, ':', rtPathFindExec, (void *)pszExec, &szRealExec[0]); RTStrFree(pszPath); if (RT_SUCCESS(rc)) pszExec = szRealExec; else rc = rc == VERR_END_OF_STRING ? VERR_FILE_NOT_FOUND : rc; } if (RT_FAILURE(rc)) return rtProcPosixCreateReturn(rc, hEnvToUse, hEnv); } pid_t pid = -1; const char * const *papszEnv = RTEnvGetExecEnvP(hEnvToUse); AssertPtrReturn(papszEnv, rtProcPosixCreateReturn(VERR_INVALID_HANDLE, hEnvToUse, hEnv)); /* * Take care of detaching the process. * * HACK ALERT! Put the process into a new process group with pgid = pid * to make sure it differs from that of the parent process to ensure that * the IPRT waitpid call doesn't race anyone (read XPCOM) doing group wide * waits. setsid() includes the setpgid() functionality. * 2010-10-11 XPCOM no longer waits for anything, but it cannot hurt. */ #ifndef RT_OS_OS2 if (fFlags & RTPROC_FLAGS_DETACHED) { # ifdef RT_OS_SOLARIS int templateFd = -1; if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) { templateFd = rtSolarisContractPreFork(); if (templateFd == -1) return rtProcPosixCreateReturn(VERR_OPEN_FAILED, hEnvToUse, hEnv); } # endif /* RT_OS_SOLARIS */ pid = fork(); if (!pid) { # ifdef RT_OS_SOLARIS if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) rtSolarisContractPostForkChild(templateFd); # endif setsid(); /* see comment above */ pid = -1; /* Child falls through to the actual spawn code below. */ } else { # ifdef RT_OS_SOLARIS if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) rtSolarisContractPostForkParent(templateFd, pid); # endif if (pid > 0) { /* Must wait for the temporary process to avoid a zombie. */ int status = 0; pid_t pidChild = 0; /* Restart if we get interrupted. */ do { pidChild = waitpid(pid, &status, 0); } while ( pidChild == -1 && errno == EINTR); /* Assume that something wasn't found. No detailed info. */ if (status) return rtProcPosixCreateReturn(VERR_PROCESS_NOT_FOUND, hEnvToUse, hEnv); if (phProcess) *phProcess = 0; return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv); } return rtProcPosixCreateReturn(RTErrConvertFromErrno(errno), hEnvToUse, hEnv); } } #endif /* * Spawn the child. * * Any spawn code MUST not execute any atexit functions if it is for a * detached process. It would lead to running the atexit functions which * make only sense for the parent. libORBit e.g. gets confused by multiple * execution. Remember, there was only a fork() so far, and until exec() * is successfully run there is nothing which would prevent doing anything * silly with the (duplicated) file descriptors. */ #ifdef HAVE_POSIX_SPAWN /** @todo OS/2: implement DETACHED (BACKGROUND stuff), see VbglR3Daemonize. */ if ( uid == ~(uid_t)0 && gid == ~(gid_t)0) { /* Spawn attributes. */ posix_spawnattr_t Attr; rc = posix_spawnattr_init(&Attr); if (!rc) { /* Indicate that process group and signal mask are to be changed, and that the child should use default signal actions. */ rc = posix_spawnattr_setflags(&Attr, POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF); Assert(rc == 0); /* The child starts in its own process group. */ if (!rc) { rc = posix_spawnattr_setpgroup(&Attr, 0 /* pg == child pid */); Assert(rc == 0); } /* Unmask all signals. */ if (!rc) { sigset_t SigMask; sigemptyset(&SigMask); rc = posix_spawnattr_setsigmask(&Attr, &SigMask); Assert(rc == 0); } /* File changes. */ posix_spawn_file_actions_t FileActions; posix_spawn_file_actions_t *pFileActions = NULL; if ((aStdFds[0] != -1 || aStdFds[1] != -1 || aStdFds[2] != -1) && !rc) { rc = posix_spawn_file_actions_init(&FileActions); if (!rc) { pFileActions = &FileActions; for (int i = 0; i < 3; i++) { int fd = aStdFds[i]; if (fd == -2) rc = posix_spawn_file_actions_addclose(&FileActions, i); else if (fd >= 0 && fd != i) { rc = posix_spawn_file_actions_adddup2(&FileActions, fd, i); if (!rc) { for (int j = i + 1; j < 3; j++) if (aStdFds[j] == fd) { fd = -1; break; } if (fd >= 0) rc = posix_spawn_file_actions_addclose(&FileActions, fd); } } if (rc) break; } } } if (!rc) rc = posix_spawn(&pid, pszExec, pFileActions, &Attr, (char * const *)papszArgs, (char * const *)papszEnv); /* cleanup */ int rc2 = posix_spawnattr_destroy(&Attr); Assert(rc2 == 0); NOREF(rc2); if (pFileActions) { rc2 = posix_spawn_file_actions_destroy(pFileActions); Assert(rc2 == 0); } /* return on success.*/ if (!rc) { /* For a detached process this happens in the temp process, so * it's not worth doing anything as this process must exit. */ if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(0); if (phProcess) *phProcess = pid; return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv); } } /* For a detached process this happens in the temp process, so * it's not worth doing anything as this process must exit. */ if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(124); } else #endif { #ifdef RT_OS_SOLARIS int templateFd = -1; if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) { templateFd = rtSolarisContractPreFork(); if (templateFd == -1) return rtProcPosixCreateReturn(VERR_OPEN_FAILED, hEnvToUse, hEnv); } #endif /* RT_OS_SOLARIS */ pid = fork(); if (!pid) { #ifdef RT_OS_SOLARIS if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) rtSolarisContractPostForkChild(templateFd); #endif /* RT_OS_SOLARIS */ if (!(fFlags & RTPROC_FLAGS_DETACHED)) setpgid(0, 0); /* see comment above */ /* * Change group and user if requested. */ #if 1 /** @todo This needs more work, see suplib/hardening. */ if (pszAsUser) { int ret = initgroups(pszAsUser, gid); if (ret) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(126); else exit(126); } } if (gid != ~(gid_t)0) { if (setgid(gid)) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(126); else exit(126); } } if (uid != ~(uid_t)0) { if (setuid(uid)) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(126); else exit(126); } } #endif /* * Some final profile environment tweaks, if running as user. */ if ( (fFlags & RTPROC_FLAGS_PROFILE) && pszAsUser && ( (fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) || hEnv == RTENV_DEFAULT) ) { rc = rtProcPosixAdjustProfileEnvFromChild(hEnvToUse, fFlags, hEnv); papszEnv = RTEnvGetExecEnvP(hEnvToUse); if (RT_FAILURE(rc) || !papszEnv) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(126); else exit(126); } } /* * Unset the signal mask. */ sigset_t SigMask; sigemptyset(&SigMask); rc = sigprocmask(SIG_SETMASK, &SigMask, NULL); Assert(rc == 0); /* * Apply changes to the standard file descriptor and stuff. */ for (int i = 0; i < 3; i++) { int fd = aStdFds[i]; if (fd == -2) close(i); else if (fd >= 0) { int rc2 = dup2(fd, i); if (rc2 != i) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(125); else exit(125); } for (int j = i + 1; j < 3; j++) if (aStdFds[j] == fd) { fd = -1; break; } if (fd >= 0) close(fd); } } /* * Finally, execute the requested program. */ rc = execve(pszExec, (char * const *)papszArgs, (char * const *)papszEnv); if (errno == ENOEXEC) { /* This can happen when trying to start a shell script without the magic #!/bin/sh */ RTAssertMsg2Weak("Cannot execute this binary format!\n"); } else RTAssertMsg2Weak("execve returns %d errno=%d\n", rc, errno); RTAssertReleasePanic(); if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(127); else exit(127); } #ifdef RT_OS_SOLARIS if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) rtSolarisContractPostForkParent(templateFd, pid); #endif /* RT_OS_SOLARIS */ if (pid > 0) { /* For a detached process this happens in the temp process, so * it's not worth doing anything as this process must exit. */ if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(0); if (phProcess) *phProcess = pid; return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv); } /* For a detached process this happens in the temp process, so * it's not worth doing anything as this process must exit. */ if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(124); return rtProcPosixCreateReturn(RTErrConvertFromErrno(errno), hEnvToUse, hEnv); } return rtProcPosixCreateReturn(VERR_NOT_IMPLEMENTED, hEnvToUse, hEnv); }
RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTUINTPTR uSubtrahend, uint32_t fFlags) { /* * Input validation and lazy initialization. */ AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER); *phDbgMod = NIL_RTDBGMOD; AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); AssertReturn(*pszFilename, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pszName, VERR_INVALID_POINTER); AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); int rc = rtDbgModLazyInit(); if (RT_FAILURE(rc)) return rc; if (!pszName) pszName = RTPathFilename(pszFilename); /* * Allocate a new module instance. */ PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod)); if (!pDbgMod) return VERR_NO_MEMORY; pDbgMod->u32Magic = RTDBGMOD_MAGIC; pDbgMod->cRefs = 1; rc = RTCritSectInit(&pDbgMod->CritSect); if (RT_SUCCESS(rc)) { pDbgMod->pszName = RTStrCacheEnter(g_hDbgModStrCache, pszName); if (pDbgMod->pszName) { pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename); if (pDbgMod->pszDbgFile) { /* * Try the map file readers. */ rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT); if (RT_SUCCESS(rc)) { rc = VERR_DBG_NO_MATCHING_INTERPRETER; for (PRTDBGMODREGDBG pCur = g_pDbgHead; pCur; pCur = pCur->pNext) { if (pCur->pVt->fSupports & RT_DBGTYPE_MAP) { pDbgMod->pDbgVt = pCur->pVt; pDbgMod->pvDbgPriv = NULL; rc = pCur->pVt->pfnTryOpen(pDbgMod); if (RT_SUCCESS(rc)) { ASMAtomicIncU32(&pCur->cUsers); RTSemRWReleaseRead(g_hDbgModRWSem); *phDbgMod = pDbgMod; return rc; } } } /* bail out */ RTSemRWReleaseRead(g_hDbgModRWSem); } RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName); } RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile); } RTCritSectDelete(&pDbgMod->CritSect); } RTMemFree(pDbgMod); return rc; }
/** * Make a console instance. * * This will not return until either an 'exit' command is issued or a error code * indicating connection loss is encountered. * * @returns VINF_SUCCESS if console termination caused by the 'exit' command. * @returns The VBox status code causing the console termination. * * @param pUVM The user mode VM handle. * @param pBack Pointer to the backend structure. This must contain * a full set of function pointers to service the console. * @param fFlags Reserved, must be zero. * @remarks A forced termination of the console is easiest done by forcing the * callbacks to return fatal failures. */ DBGDECL(int) DBGCCreate(PUVM pUVM, PDBGCBACK pBack, unsigned fFlags) { /* * Validate input. */ AssertPtrNullReturn(pUVM, VERR_INVALID_VM_HANDLE); PVM pVM = NULL; if (pUVM) { pVM = VMR3GetVM(pUVM); AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE); } /* * Allocate and initialize instance data */ PDBGC pDbgc; int rc = dbgcCreate(&pDbgc, pBack, fFlags); if (RT_FAILURE(rc)) return rc; if (!HMR3IsEnabled(pUVM)) pDbgc->hDbgAs = DBGF_AS_RC_AND_GC_GLOBAL; /* * Print welcome message. */ rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Welcome to the VirtualBox Debugger!\n"); /* * Attach to the specified VM. */ if (RT_SUCCESS(rc) && pUVM) { rc = dbgcReadConfig(pDbgc, pUVM); if (RT_SUCCESS(rc)) { rc = DBGFR3Attach(pUVM); if (RT_SUCCESS(rc)) { pDbgc->pVM = pVM; pDbgc->pUVM = pUVM; pDbgc->idCpu = 0; rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Current VM is %08x, CPU #%u\n" /** @todo get and print the VM name! */ , pDbgc->pVM, pDbgc->idCpu); } else rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM); } else rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "Error reading configuration\n"); } /* * Load plugins. */ if (RT_SUCCESS(rc)) { if (pVM) DBGFR3PlugInLoadAll(pDbgc->pUVM); dbgcEventInit(pDbgc); dbgcRunInitScripts(pDbgc); rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> "); if (RT_SUCCESS(rc)) { /* * Set debug config log callback. */ RTDBGCFG hDbgCfg = DBGFR3AsGetConfig(pUVM); if ( hDbgCfg != NIL_RTDBGCFG && RTDbgCfgRetain(hDbgCfg) != UINT32_MAX) { int rc2 = RTDbgCfgSetLogCallback(hDbgCfg, dbgcDbgCfgLogCallback, pDbgc); if (RT_FAILURE(rc2)) { hDbgCfg = NIL_RTDBGCFG; RTDbgCfgRelease(hDbgCfg); } } else hDbgCfg = NIL_RTDBGCFG; /* * Run the debugger main loop. */ rc = dbgcRun(pDbgc); /* * Remove debug config log callback. */ if (hDbgCfg != NIL_RTDBGCFG) { RTDbgCfgSetLogCallback(hDbgCfg, NULL, NULL); RTDbgCfgRelease(hDbgCfg); } } dbgcEventTerm(pDbgc); } else pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nDBGCCreate error: %Rrc\n", rc); /* * Cleanup console debugger session. */ dbgcDestroy(pDbgc); return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc; }
RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER); AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); /* * Convert the paths. */ char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { RTFSOBJINFO ObjInfo; /* * If it's a no-op, we'll only verify the existance of the file. */ if (!pAccessTime && !pModificationTime) rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, fFlags); else { /* * Convert the input to timeval, getting the missing one if necessary, * and call the API which does the change. */ struct timeval aTimevals[2]; if (pAccessTime && pModificationTime) { RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]); } else { rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags); if (RT_SUCCESS(rc)) { RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]); } else Log(("RTPathSetTimes('%s',%p,%p,,): RTPathQueryInfo failed with %Rrc\n", pszPath, pAccessTime, pModificationTime, rc)); } if (RT_SUCCESS(rc)) { if (fFlags & RTPATH_F_FOLLOW_LINK) { if (utimes(pszNativePath, aTimevals)) rc = RTErrConvertFromErrno(errno); } #if (defined(RT_OS_DARWIN) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) \ || defined(RT_OS_FREEBSD) \ || defined(RT_OS_LINUX) \ || defined(RT_OS_OS2) /** @todo who really has lutimes? */ else { if (lutimes(pszNativePath, aTimevals)) rc = RTErrConvertFromErrno(errno); } #else else { if (pAccessTime && pModificationTime) rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags); if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)) rc = VERR_NS_SYMLINK_SET_TIME; else if (RT_SUCCESS(rc)) { if (utimes(pszNativePath, aTimevals)) rc = RTErrConvertFromErrno(errno); } } #endif if (RT_FAILURE(rc)) Log(("RTPathSetTimes('%s',%p,%p,,): failed with %Rrc and errno=%d\n", pszPath, pAccessTime, pModificationTime, rc, errno)); } } rtPathFreeNative(pszNativePath, pszPath); }
/** * Make a console instance. * * This will not return until either an 'exit' command is issued or a error code * indicating connection loss is encountered. * * @returns VINF_SUCCESS if console termination caused by the 'exit' command. * @returns The VBox status code causing the console termination. * * @param pVM VM Handle. * @param pBack Pointer to the backend structure. This must contain * a full set of function pointers to service the console. * @param fFlags Reserved, must be zero. * @remark A forced termination of the console is easiest done by forcing the * callbacks to return fatal failures. */ DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags) { /* * Validate input. */ AssertPtrNullReturn(pVM, VERR_INVALID_POINTER); /* * Allocate and initialize instance data */ PDBGC pDbgc; int rc = dbgcCreate(&pDbgc, pBack, fFlags); if (RT_FAILURE(rc)) return rc; /* * Print welcome message. */ rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Welcome to the VirtualBox Debugger!\n"); /* * Attach to the specified VM. */ if (RT_SUCCESS(rc) && pVM) { rc = DBGFR3Attach(pVM); if (RT_SUCCESS(rc)) { pDbgc->pVM = pVM; pDbgc->idCpu = 0; rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Current VM is %08x, CPU #%u\n" /** @todo get and print the VM name! */ , pDbgc->pVM, pDbgc->idCpu); } else rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM); } /* * Load plugins. */ if (RT_SUCCESS(rc)) { if (pVM) dbgcPlugInAutoLoad(pDbgc); rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> "); } else pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nDBGCCreate error: %Rrc\n", rc); /* * Run the debugger main loop. */ if (RT_SUCCESS(rc)) rc = dbgcRun(pDbgc); /* * Cleanup console debugger session. */ dbgcDestroy(pDbgc); return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc; }