| | 1100 | * Waits for notifications of changes to guest properties. |
|---|
| | 1101 | * This is accessed through the "VBoxGuestPropSvc" HGCM service. |
|---|
| | 1102 | * |
|---|
| | 1103 | * @returns 0 on success, 1 on failure |
|---|
| | 1104 | * @note see the command line API description for parameters |
|---|
| | 1105 | */ |
|---|
| | 1106 | int waitGuestProperty(int argc, char **argv) |
|---|
| | 1107 | { |
|---|
| | 1108 | using namespace guestProp; |
|---|
| | 1109 | |
|---|
| | 1110 | /* |
|---|
| | 1111 | * Handle arguments |
|---|
| | 1112 | */ |
|---|
| | 1113 | const char *pszPatterns = NULL; |
|---|
| | 1114 | uint64_t u64TimestampIn = 0; |
|---|
| | 1115 | uint32_t u32Timeout = RT_INDEFINITE_WAIT; |
|---|
| | 1116 | bool usageOK = true; |
|---|
| | 1117 | if (argc < 1) |
|---|
| | 1118 | usageOK = false; |
|---|
| | 1119 | pszPatterns = argv[0]; |
|---|
| | 1120 | for (int i = 1; usageOK && i < argc; ++i) |
|---|
| | 1121 | { |
|---|
| | 1122 | if (strcmp(argv[i], "-timeout") == 0) |
|---|
| | 1123 | { |
|---|
| | 1124 | if ( i + 1 >= argc |
|---|
| | 1125 | || RTStrToUInt32Full(argv[i + 1], 10, &u32Timeout) |
|---|
| | 1126 | != VINF_SUCCESS |
|---|
| | 1127 | ) |
|---|
| | 1128 | usageOK = false; |
|---|
| | 1129 | else |
|---|
| | 1130 | ++i; |
|---|
| | 1131 | } |
|---|
| | 1132 | else if (strcmp(argv[i], "-timestamp") == 0) |
|---|
| | 1133 | { |
|---|
| | 1134 | if ( i + 1 >= argc |
|---|
| | 1135 | || RTStrToUInt64Full(argv[i + 1], 10, &u64TimestampIn) |
|---|
| | 1136 | != VINF_SUCCESS |
|---|
| | 1137 | ) |
|---|
| | 1138 | usageOK = false; |
|---|
| | 1139 | else |
|---|
| | 1140 | ++i; |
|---|
| | 1141 | } |
|---|
| | 1142 | else |
|---|
| | 1143 | usageOK = false; |
|---|
| | 1144 | } |
|---|
| | 1145 | if (!usageOK) |
|---|
| | 1146 | { |
|---|
| | 1147 | usage(GUEST_PROP); |
|---|
| | 1148 | return 1; |
|---|
| | 1149 | } |
|---|
| | 1150 | |
|---|
| | 1151 | /* |
|---|
| | 1152 | * Connect to the service |
|---|
| | 1153 | */ |
|---|
| | 1154 | uint32_t u32ClientId = 0; |
|---|
| | 1155 | int rc = VINF_SUCCESS; |
|---|
| | 1156 | |
|---|
| | 1157 | rc = VbglR3GuestPropConnect(&u32ClientId); |
|---|
| | 1158 | if (!RT_SUCCESS(rc)) |
|---|
| | 1159 | VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc); |
|---|
| | 1160 | |
|---|
| | 1161 | /* |
|---|
| | 1162 | * Retrieve the notification from the host |
|---|
| | 1163 | */ |
|---|
| | 1164 | char *pszName = NULL; |
|---|
| | 1165 | char *pszValue = NULL; |
|---|
| | 1166 | uint64_t u64TimestampOut = 0; |
|---|
| | 1167 | char *pszFlags = NULL; |
|---|
| | 1168 | /* The buffer for storing the data and its initial size. We leave a bit |
|---|
| | 1169 | * of space here in case the maximum values are raised. */ |
|---|
| | 1170 | void *pvBuf = NULL; |
|---|
| | 1171 | uint32_t cbBuf = MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 1024; |
|---|
| | 1172 | /* Because there is a race condition between our reading the size of a |
|---|
| | 1173 | * property and the guest updating it, we loop a few times here and |
|---|
| | 1174 | * hope. Actually this should never go wrong, as we are generous |
|---|
| | 1175 | * enough with buffer space. */ |
|---|
| | 1176 | bool finish = false; |
|---|
| | 1177 | for (unsigned i = 0; |
|---|
| | 1178 | (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) && !finish && (i < 10); |
|---|
| | 1179 | ++i) |
|---|
| | 1180 | { |
|---|
| | 1181 | void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf); |
|---|
| | 1182 | if (NULL == pvTmpBuf) |
|---|
| | 1183 | { |
|---|
| | 1184 | rc = VERR_NO_MEMORY; |
|---|
| | 1185 | VBoxControlError("Out of memory\n"); |
|---|
| | 1186 | } |
|---|
| | 1187 | else |
|---|
| | 1188 | { |
|---|
| | 1189 | pvBuf = pvTmpBuf; |
|---|
| | 1190 | rc = VbglR3GuestPropWait(u32ClientId, pszPatterns, pvBuf, cbBuf, |
|---|
| | 1191 | u64TimestampIn, u32Timeout, |
|---|
| | 1192 | &pszName, &pszValue, &u64TimestampOut, |
|---|
| | 1193 | &pszFlags, &cbBuf); |
|---|
| | 1194 | } |
|---|
| | 1195 | if (VERR_BUFFER_OVERFLOW == rc) |
|---|
| | 1196 | /* Leave a bit of extra space to be safe */ |
|---|
| | 1197 | cbBuf += 1024; |
|---|
| | 1198 | else |
|---|
| | 1199 | finish = true; |
|---|
| | 1200 | if (rc == VERR_TOO_MUCH_DATA) |
|---|
| | 1201 | VBoxControlError("Temporarily unable to get a notification\n"); |
|---|
| | 1202 | else if (rc == VERR_INTERRUPTED) |
|---|
| | 1203 | VBoxControlError("The request timed out or was interrupted\n"); |
|---|
| | 1204 | #ifndef RT_OS_WINDOWS /* Windows guests do not do this right */ |
|---|
| | 1205 | else if (!RT_SUCCESS(rc) && (rc != VERR_NOT_FOUND)) |
|---|
| | 1206 | VBoxControlError("Failed to get a notification, error %Rrc\n", rc); |
|---|
| | 1207 | #endif |
|---|
| | 1208 | } |
|---|
| | 1209 | /* |
|---|
| | 1210 | * And display it on the guest console. |
|---|
| | 1211 | */ |
|---|
| | 1212 | if (VERR_NOT_FOUND == rc) |
|---|
| | 1213 | RTPrintf("No value set!\n"); |
|---|
| | 1214 | else if (rc == VERR_BUFFER_OVERFLOW) |
|---|
| | 1215 | RTPrintf("Internal error: unable to determine the size of the data!\n"); |
|---|
| | 1216 | else if (RT_SUCCESS(rc)) |
|---|
| | 1217 | { |
|---|
| | 1218 | RTPrintf("Name: %s\n", pszName); |
|---|
| | 1219 | RTPrintf("Value: %s\n", pszValue); |
|---|
| | 1220 | RTPrintf("Timestamp: %lld ns\n", u64TimestampOut); |
|---|
| | 1221 | RTPrintf("Flags: %s\n", pszFlags); |
|---|
| | 1222 | } |
|---|
| | 1223 | |
|---|
| | 1224 | if (u32ClientId != 0) |
|---|
| | 1225 | VbglR3GuestPropDisconnect(u32ClientId); |
|---|
| | 1226 | RTMemFree(pvBuf); |
|---|
| | 1227 | return RT_SUCCESS(rc) ? 0 : 1; |
|---|
| | 1228 | } |
|---|
| | 1229 | |
|---|
| | 1230 | |
|---|
| | 1231 | /** |
|---|