VirtualBox

Changeset 93480 in vbox for trunk/src


Ignore:
Timestamp:
Jan 28, 2022 4:09:52 PM (3 years ago)
Author:
vboxsync
Message:

Main/Appliance: Allow users to specify a different storage controller
and/or controller port for hard disks when importing a VM. bugref:5027

'VBoxManage import foo.ova -n' has always presented a --controller
option for hard disks but the code to implement this had never been
implemented. This changeset adds the --controller functionality and
also includes a --port option for changing the controller port as well.

Location:
trunk/src/VBox
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageAppliance.cpp

    r93115 r93480  
    121121
    122122    return rc;
     123}
     124
     125/**
     126 * Helper routine to parse the ExtraData Utf8Str for a storage controller's
     127 * value or channel value.
     128 *
     129 * @param   aExtraData    The ExtraData string which can have a format of
     130 *                        either 'controller=13;channel=3' or '11'.
     131 * @param   pszKey        The string being looked up, usually either 'controller'
     132 *                        or 'channel' but can be NULL or empty.
     133 * @param   puVal         The integer value of the 'controller=' or 'channel='
     134 *                        key (or the controller number when there is no key) in
     135 *                        the ExtraData string.
     136 * @returns COM status code.
     137 */
     138static int getStorageControllerDetailsFromStr(const com::Utf8Str &aExtraData, const char *pszKey, uint32_t *puVal)
     139{
     140    int vrc;
     141
     142    if (pszKey && *pszKey)
     143    {
     144        size_t posKey = aExtraData.find(pszKey);
     145        if (posKey == Utf8Str::npos)
     146            return VERR_INVALID_PARAMETER;
     147        vrc = RTStrToUInt32Ex(aExtraData.c_str() + posKey + strlen(pszKey), NULL, 0, puVal);
     148    }
     149    else
     150    {
     151        vrc = RTStrToUInt32Ex(aExtraData.c_str(), NULL, 0, puVal);
     152    }
     153
     154    if (vrc == VWRN_NUMBER_TOO_BIG || vrc == VWRN_NEGATIVE_UNSIGNED)
     155        return VERR_INVALID_PARAMETER;
     156
     157    return vrc;
     158}
     159
     160static bool isStorageControllerType(VirtualSystemDescriptionType_T avsdType)
     161{
     162    switch (avsdType)
     163    {
     164        case VirtualSystemDescriptionType_HardDiskControllerIDE:
     165        case VirtualSystemDescriptionType_HardDiskControllerSATA:
     166        case VirtualSystemDescriptionType_HardDiskControllerSCSI:
     167        case VirtualSystemDescriptionType_HardDiskControllerSAS:
     168        case VirtualSystemDescriptionType_HardDiskControllerVirtioSCSI:
     169            return true;
     170        default:
     171            return false;
     172    }
    123173}
    124174
     
    154204    { "--type",                 'T', RTGETOPT_REQ_UINT32 },     // deprecated
    155205    { "-type",                  'T', RTGETOPT_REQ_UINT32 },     // deprecated
    156 #if 0 /* Changing the controller is fully valid, but the current design on how
    157          the params are evaluated here doesn't allow two parameter for one
    158          unit. The target disk path is more important. I leave it for future
    159          improvments. */
    160206    { "--controller",           'C', RTGETOPT_REQ_STRING },
    161 #endif
     207    { "--port",                 'E', RTGETOPT_REQ_STRING },
    162208    { "--disk",                 'D', RTGETOPT_REQ_STRING },
    163209    { "--options",              'O', RTGETOPT_REQ_STRING },
     
    343389                                       GetState.pDef->pszLong);
    344390                mapArgsMapsPerVsys[ulCurVsys][Utf8StrFmt("controller%u", ulCurUnit)] = ValueUnion.psz;
     391                break;
     392
     393            case 'E':   // --port
     394                if (enmApplType != LOCAL)
     395                    return errorSyntax(USAGE_IMPORTAPPLIANCE,
     396                                       Appliance::tr("Option \"%s\" requires preceding --vsys option."),
     397                                       GetState.pDef->pszLong);
     398                if (ulCurUnit == (uint32_t)-1)
     399                    return errorSyntax(USAGE_IMPORTAPPLIANCE,
     400                                       Appliance::tr("Option \"%s\" requires preceding --unit option."),
     401                                       GetState.pDef->pszLong);
     402                mapArgsMapsPerVsys[ulCurVsys][Utf8StrFmt("port%u", ulCurUnit)] = ValueUnion.psz;
    345403                break;
    346404
     
    845903                            {
    846904                                Utf8StrFmt strTypeArg("disk%u", a);
     905                                bool fDiskChanged = false;
     906                                int vrc;
    847907                                RTCList<ImportOptions_T> optionsList = options.toList();
    848 
    849                                 bstrFinalValue = aVBoxValues[a];
    850908
    851909                                if (findArgValue(strOverride, pmapArgs, strTypeArg))
    852910                                {
    853                                     if (!optionsList.contains(ImportOptions_ImportToVDI))
     911                                    if (optionsList.contains(ImportOptions_ImportToVDI))
     912                                        return errorSyntax(USAGE_IMPORTAPPLIANCE,
     913                                                           Appliance::tr("Option --ImportToVDI can not be used together with "
     914                                                                         "a manually set target path."));
     915                                    RTUUID uuid;
     916                                    /* Check if this is a uuid. If so, don't touch. */
     917                                    vrc = RTUuidFromStr(&uuid, strOverride.c_str());
     918                                    if (vrc != VINF_SUCCESS)
    854919                                    {
    855                                         RTUUID uuid;
    856                                         /* Check if this is a uuid. If so, don't touch. */
    857                                         int vrc = RTUuidFromStr(&uuid, strOverride.c_str());
    858                                         if (vrc != VINF_SUCCESS)
     920                                        /* Make the path absolute. */
     921                                        if (!RTPathStartsWithRoot(strOverride.c_str()))
    859922                                        {
    860                                             /* Make the path absolute. */
    861                                             if (!RTPathStartsWithRoot(strOverride.c_str()))
    862                                             {
    863                                                 char pszPwd[RTPATH_MAX];
    864                                                 vrc = RTPathGetCurrent(pszPwd, RTPATH_MAX);
    865                                                 if (RT_SUCCESS(vrc))
    866                                                     strOverride = Utf8Str(pszPwd).append(RTPATH_SLASH).append(strOverride);
    867                                             }
     923                                            char pszPwd[RTPATH_MAX];
     924                                            vrc = RTPathGetCurrent(pszPwd, RTPATH_MAX);
     925                                            if (RT_SUCCESS(vrc))
     926                                                strOverride = Utf8Str(pszPwd).append(RTPATH_SLASH).append(strOverride);
    868927                                        }
    869                                         bstrFinalValue = strOverride;
    870928                                    }
    871                                     else
    872                                     {
    873                                         //print some error about incompatible command-line arguments
    874                                         return errorSyntax(USAGE_IMPORTAPPLIANCE,
    875                                                            Appliance::tr("Option --ImportToVDI shall not be used together with "
    876                                                                          "manually set target path."));
    877 
    878                                     }
    879 
    880                                     RTPrintf(Appliance::tr("%2u: Hard disk image: source image=%ls, target path=%ls, %ls\n"),
    881                                             a,
    882                                             aOvfValues[a],
    883                                             bstrFinalValue.raw(),
    884                                             aExtraConfigValues[a]);
     929                                    bstrFinalValue = strOverride;
     930                                    fDiskChanged = true;
    885931                                }
    886 #if 0 /* Changing the controller is fully valid, but the current design on how
    887          the params are evaluated here doesn't allow two parameter for one
    888          unit. The target disk path is more important I leave it for future
    889          improvments. */
    890                                 Utf8StrFmt strTypeArg("controller%u", a);
     932
     933                                strTypeArg.printf("controller%u", a);
     934                                bool fControllerChanged = false;
     935                                uint32_t uTargetController = (uint32_t)-1;
     936                                VirtualSystemDescriptionType_T vsdControllerType = VirtualSystemDescriptionType_Ignore;
     937                                Utf8Str strExtraConfigValue;
    891938                                if (findArgValue(strOverride, pmapArgs, strTypeArg))
    892939                                {
    893                                     // strOverride now has the controller index as a number, but we
    894                                     // need a "controller=X" format string
    895                                     strOverride = Utf8StrFmt("controller=%s", strOverride.c_str());
     940                                    vrc = getStorageControllerDetailsFromStr(strOverride, NULL, &uTargetController);
     941                                    if (RT_FAILURE(vrc))
     942                                        return errorSyntax(USAGE_IMPORTAPPLIANCE,
     943                                                           Appliance::tr("Invalid controller value: '%s'"),
     944                                                           strOverride.c_str());
     945
     946                                    vsdControllerType = retTypes[uTargetController];
     947                                    if (!isStorageControllerType(vsdControllerType))
     948                                        return errorSyntax(USAGE_IMPORTAPPLIANCE,
     949                                                           Appliance::tr("Invalid storage controller specified: %u"),
     950                                                           uTargetController);
     951
     952                                    fControllerChanged = true;
     953                                }
     954
     955                                strTypeArg.printf("port%u", a);
     956                                bool fControllerPortChanged = false;
     957                                uint32_t uTargetControllerPort = (uint32_t)-1;;
     958                                if (findArgValue(strOverride, pmapArgs, strTypeArg))
     959                                {
     960                                    vrc = getStorageControllerDetailsFromStr(strOverride, NULL, &uTargetControllerPort);
     961                                    if (RT_FAILURE(vrc))
     962                                        return errorSyntax(USAGE_IMPORTAPPLIANCE,
     963                                                           Appliance::tr("Invalid port value: '%s'"),
     964                                                           strOverride.c_str());
     965
     966                                    fControllerPortChanged = true;
     967                                }
     968
     969                                /*
     970                                 * aExtraConfigValues[a] has a format of 'controller=12;channel=0' and is set by
     971                                 * Appliance::interpret() so any parsing errors here aren't due to user-supplied
     972                                 * values so different error messages here.
     973                                 */
     974                                uint32_t uOrigController;
     975                                Utf8Str strOrigController(Bstr(aExtraConfigValues[a]).raw());
     976                                vrc = getStorageControllerDetailsFromStr(strOrigController, "controller=", &uOrigController);
     977                                if (RT_FAILURE(vrc))
     978                                    return RTMsgErrorExitFailure(Appliance::tr("Failed to extract controller value from ExtraConfig: '%s'"),
     979                                                                 strOrigController.c_str());
     980
     981                                uint32_t uOrigControllerPort;
     982                                vrc = getStorageControllerDetailsFromStr(strOrigController, "channel=", &uOrigControllerPort);
     983                                if (RT_FAILURE(vrc))
     984                                    return RTMsgErrorExitFailure(Appliance::tr("Failed to extract channel value from ExtraConfig: '%s'"),
     985                                                                 strOrigController.c_str());
     986
     987                                /*
     988                                 * The 'strExtraConfigValue' string is used to display the storage controller and
     989                                 * port details for each virtual hard disk using the more accurate 'controller=' and
     990                                 * 'port=' labels. The aExtraConfigValues[a] string has a format of
     991                                 * 'controller=%u;channel=%u' from Appliance::interpret() which is required as per
     992                                 * the API but for consistency and clarity with the CLI options --controller and
     993                                 * --port we instead use strExtraConfigValue in the output below.
     994                                 */
     995                                strExtraConfigValue = Utf8StrFmt("controller=%u;port=%u", uOrigController, uOrigControllerPort);
     996
     997                                if (fControllerChanged || fControllerPortChanged)
     998                                {
     999                                    /*
     1000                                     * Verify that the new combination of controller and controller port is valid.
     1001                                     * cf. StorageController::i_checkPortAndDeviceValid()
     1002                                     */
     1003                                    if (uTargetControllerPort == (uint32_t)-1)
     1004                                        uTargetControllerPort = uOrigControllerPort;
     1005                                    if (uTargetController == (uint32_t)-1)
     1006                                        uTargetController = uOrigController;
     1007
     1008                                    if (   uOrigController == uTargetController
     1009                                        && uOrigControllerPort == uTargetControllerPort)
     1010                                        return errorSyntax(USAGE_IMPORTAPPLIANCE,
     1011                                                           Appliance::tr("Device already attached to controller %u at this port (%u) "
     1012                                                                         "location."),
     1013                                                           uTargetController,
     1014                                                           uTargetControllerPort);
     1015
     1016                                    if (vsdControllerType == VirtualSystemDescriptionType_Ignore)
     1017                                        vsdControllerType = retTypes[uOrigController];
     1018                                    if (!isStorageControllerType(vsdControllerType))
     1019                                        return errorSyntax(USAGE_IMPORTAPPLIANCE,
     1020                                                           Appliance::tr("Invalid storage controller specified: %u"),
     1021                                                           uOrigController);
     1022
     1023                                    ComPtr<IVirtualBox> pVirtualBox = arg->virtualBox;
     1024                                    ComPtr<ISystemProperties> systemProperties;
     1025                                    CHECK_ERROR(pVirtualBox, COMGETTER(SystemProperties)(systemProperties.asOutParam()));
     1026                                    ULONG maxPorts = 0;
     1027                                    StorageBus_T enmStorageBus = StorageBus_Null;;
     1028                                    switch (vsdControllerType)
     1029                                    {
     1030                                        case VirtualSystemDescriptionType_HardDiskControllerIDE:
     1031                                            enmStorageBus = StorageBus_IDE;
     1032                                           break;
     1033                                        case VirtualSystemDescriptionType_HardDiskControllerSATA:
     1034                                            enmStorageBus = StorageBus_SATA;
     1035                                            break;
     1036                                        case VirtualSystemDescriptionType_HardDiskControllerSCSI:
     1037                                            enmStorageBus = StorageBus_SCSI;
     1038                                            break;
     1039                                        case VirtualSystemDescriptionType_HardDiskControllerSAS:
     1040                                            enmStorageBus = StorageBus_SAS;
     1041                                            break;
     1042                                        case VirtualSystemDescriptionType_HardDiskControllerVirtioSCSI:
     1043                                            enmStorageBus = StorageBus_VirtioSCSI;
     1044                                            break;
     1045                                        default:  // Not reached since vsdControllerType validated above but silence gcc.
     1046                                            break;
     1047                                    }
     1048                                    CHECK_ERROR_RET(systemProperties, GetMaxPortCountForStorageBus(enmStorageBus, &maxPorts),
     1049                                        RTEXITCODE_FAILURE);
     1050                                    if (uTargetControllerPort >= maxPorts)
     1051                                        return errorSyntax(USAGE_IMPORTAPPLIANCE,
     1052                                                           Appliance::tr("Illegal port value: %u. For %ls controllers the only valid values "
     1053                                                                         "are 0 to %lu (inclusive)"),
     1054                                                           uTargetControllerPort,
     1055                                                           aVBoxValues[uTargetController],
     1056                                                           maxPorts);
     1057
     1058                                    /*
     1059                                     * The 'strOverride' string will be mapped to the strExtraConfigCurrent value in
     1060                                     * VirtualSystemDescription::setFinalValues() which is then used in the appliance
     1061                                     * import routines i_importVBoxMachine()/i_importMachineGeneric() later.  This
     1062                                     * aExtraConfigValues[] array entry must have a format of
     1063                                     * 'controller=<index>;channel=<c>' as per the API documentation.
     1064                                     */
     1065                                    strExtraConfigValue = Utf8StrFmt("controller=%u;port=%u", uTargetController,
     1066                                                                     uTargetControllerPort);
     1067                                    strOverride = Utf8StrFmt("controller=%u;channel=%u", uTargetController,
     1068                                                             uTargetControllerPort);
    8961069                                    Bstr bstrExtraConfigValue = strOverride;
    8971070                                    bstrExtraConfigValue.detachTo(&aExtraConfigValues[a]);
    898                                     RTPrintf(Appliance::tr("%2u: Hard disk image: source image=%ls, target path=%ls, %ls\n"),
    899                                             a,
    900                                             aOvfValues[a],
    901                                             aVBoxValues[a],
    902                                             aExtraConfigValues[a]);
    9031071                                }
    904 #endif
     1072
     1073                                if (fDiskChanged && !fControllerChanged && !fControllerPortChanged)
     1074                                {
     1075                                    RTPrintf(Appliance::tr("%2u: "
     1076                                             "Hard disk image specified with --disk: source image=%ls, target path=%ls, %s"
     1077                                             "\n    (change controller with \"--vsys %u --unit %u --controller <index>\";"
     1078                                             "\n    change controller port with \"--vsys %u --unit %u --port <n>\")\n"),
     1079                                             a,
     1080                                             aOvfValues[a],
     1081                                             bstrFinalValue.raw(),
     1082                                             strExtraConfigValue.c_str(),
     1083                                             i, a,
     1084                                             i, a);
     1085                                }
     1086                                else if (fDiskChanged && fControllerChanged && !fControllerPortChanged)
     1087                                {
     1088                                    RTPrintf(Appliance::tr("%2u: "
     1089                                             "Hard disk image specified with --disk and --controller: source image=%ls, target path=%ls, %s"
     1090                                             "\n    (change controller port with \"--vsys %u --unit %u --port <n>\")\n"),
     1091                                             a,
     1092                                             aOvfValues[a],
     1093                                             bstrFinalValue.raw(),
     1094                                             strExtraConfigValue.c_str(),
     1095                                             i, a);
     1096                                }
     1097                                else if (fDiskChanged && !fControllerChanged && fControllerPortChanged)
     1098                                {
     1099                                    RTPrintf(Appliance::tr("%2u: "
     1100                                             "Hard disk image specified with --disk and --port: source image=%ls, target path=%ls, %s"
     1101                                             "\n    (change controller with \"--vsys %u --unit %u --controller <index>\")\n"),
     1102                                             a,
     1103                                             aOvfValues[a],
     1104                                             bstrFinalValue.raw(),
     1105                                             strExtraConfigValue.c_str(),
     1106                                             i, a);
     1107                                }
     1108                                else if (!fDiskChanged && fControllerChanged && fControllerPortChanged)
     1109                                {
     1110                                    RTPrintf(Appliance::tr("%2u: "
     1111                                             "Hard disk image specified with --controller and --port: source image=%ls, target path=%ls, %s"
     1112                                             "\n    (change target path with \"--vsys %u --unit %u --disk path\")\n"),
     1113                                             a,
     1114                                             aOvfValues[a],
     1115                                             bstrFinalValue.raw(),
     1116                                             strExtraConfigValue.c_str(),
     1117                                             i, a);
     1118                                }
     1119                                else if (!fDiskChanged && !fControllerChanged && fControllerPortChanged)
     1120                                {
     1121                                    RTPrintf(Appliance::tr("%2u: "
     1122                                             "Hard disk image specified with --port: source image=%ls, target path=%ls, %s"
     1123                                             "\n    (change target path with \"--vsys %u --unit %u --disk path\";"
     1124                                             "\n    change controller with \"--vsys %u --unit %u --controller <index>\")\n"),
     1125                                             a,
     1126                                             aOvfValues[a],
     1127                                             bstrFinalValue.raw(),
     1128                                             strExtraConfigValue.c_str(),
     1129                                             i, a,
     1130                                             i, a);
     1131                                }
     1132                                else if (!fDiskChanged && fControllerChanged && !fControllerPortChanged)
     1133                                {
     1134                                    RTPrintf(Appliance::tr("%2u: "
     1135                                             "Hard disk image specified with --controller: source image=%ls, target path=%ls, %s"
     1136                                             "\n    (change target path with \"--vsys %u --unit %u --disk path\";"
     1137                                             "\n    change controller port with \"--vsys %u --unit %u --port <n>\")\n"),
     1138                                             a,
     1139                                             aOvfValues[a],
     1140                                             bstrFinalValue.raw(),
     1141                                             strExtraConfigValue.c_str(),
     1142                                             i, a,
     1143                                             i, a);
     1144                                }
     1145                                else if (fDiskChanged && fControllerChanged && fControllerPortChanged)
     1146                                {
     1147                                    RTPrintf(Appliance::tr("%2u: "
     1148                                             "Hard disk image specified with --disk and --controller and --port: "
     1149                                             "source image=%ls, target path=%ls, %s\n"),
     1150                                             a,
     1151                                             aOvfValues[a],
     1152                                             bstrFinalValue.raw(),
     1153                                             strExtraConfigValue.c_str());
     1154                                }
    9051155                                else
    9061156                                {
     
    9131163                                     * and creating one new function which returns
    9141164                                     * struct ovf::DiskImage for currently processed disk.
    915                                     */
     1165                                     */
    9161166
    9171167                                    /*
     
    9821232                                    bstrFinalValue = strOverride;
    9831233
    984                                     RTPrintf(Appliance::tr(
    985                                                 "%2u: Hard disk image: source image=%ls, target path=%ls, %ls"
    986                                                 "\n    (change target path with \"--vsys %u --unit %u --disk path\";"
    987                                                 "\n    disable with \"--vsys %u --unit %u --ignore\")\n"),
    988                                             a,
    989                                             aOvfValues[a],
    990                                             bstrFinalValue.raw(),
    991                                             aExtraConfigValues[a],
    992                                             i, a, i, a);
     1234                                    RTPrintf(Appliance::tr("%2u: Hard disk image: source image=%ls, target path=%ls, %s"
     1235                                            "\n    (change target path with \"--vsys %u --unit %u --disk path\";"
     1236                                            "\n    change controller with \"--vsys %u --unit %u --controller <index>\";"
     1237                                            "\n    change controller port with \"--vsys %u --unit %u --port <n>\";"
     1238                                            "\n    disable with \"--vsys %u --unit %u --ignore\")\n"),
     1239                                            a, aOvfValues[a], bstrFinalValue.raw(), strExtraConfigValue.c_str(),
     1240                                            i, a,
     1241                                            i, a,
     1242                                            i, a,
     1243                                            i, a);
    9931244                                }
    9941245                            }
  • trunk/src/VBox/Main/include/ApplianceImpl.h

    r93115 r93480  
    220220                             ImportStack &stack);
    221221    void i_importMachines(ImportStack &stack);
     222    HRESULT i_verifyStorageControllerPortValid(const StorageControllerType_T aStorageControllerType,
     223                                               const uint32_t aControllerPort,
     224                                               ULONG *ulMaxPorts);
    222225
    223226    HRESULT i_preCheckImageAvailability(ImportStack &stack);
     
    310313    std::list<VirtualSystemDescriptionEntry*> i_findByType(VirtualSystemDescriptionType_T aType);
    311314    const VirtualSystemDescriptionEntry* i_findControllerFromID(const Utf8Str &id);
     315    const VirtualSystemDescriptionEntry* i_findByIndex(const uint32_t aIndex);
    312316
    313317    void i_importVBoxMachineXML(const xml::ElementNode &elmMachine);
  • trunk/src/VBox/Main/include/Global.h

    r93410 r93480  
    168168    static const char *stringifySessionState(SessionState_T aState);
    169169
     170    /**
     171     * Stringify a device type.
     172     *
     173     * Drop the Global:: prefix and include StringifyEnums.h for an untranslated
     174     * version of this method.
     175     *
     176     * @returns Pointer to a read only string.
     177     * @param   aType       The device type.
     178     */
     179    static const char *stringifyDeviceType(DeviceType_T aType);
     180
     181    /**
     182     * Stringify a storage controller type.
     183     *
     184     * Drop the Global:: prefix and include StringifyEnums.h for an untranslated
     185     * version of this method.
     186     *
     187     * @returns Pointer to a read only string.
     188     * @param   aType       The storage controller type.
     189     */
     190    static const char *stringifyStorageControllerType(StorageControllerType_T aType);
     191
    170192#if 0 /* unused */
    171193    /**
     
    179201     */
    180202    static const char *stringifyStorageBus(StorageBus_T aBus);
    181 
    182     /**
    183      * Stringify a device type.
    184      *
    185      * Drop the Global:: prefix and include StringifyEnums.h for an untranslated
    186      * version of this method.
    187      *
    188      * @returns Pointer to a read only string.
    189      * @param   aType       The device type.
    190      */
    191     static const char *stringifyDeviceType(DeviceType_T aType);
    192203
    193204    /**
  • trunk/src/VBox/Main/src-all/Global.cpp

    r93410 r93480  
    635635}
    636636
     637/*static*/ const char *
     638Global::stringifyStorageControllerType(StorageControllerType_T aType)
     639{
     640    switch (aType)
     641    {
     642        case StorageControllerType_Null:        return GlobalCtx::tr("Null");
     643        case StorageControllerType_LsiLogic:    return GlobalCtx::tr("LsiLogic");
     644        case StorageControllerType_BusLogic:    return GlobalCtx::tr("BusLogic");
     645        case StorageControllerType_IntelAhci:   return GlobalCtx::tr("AHCI");
     646        case StorageControllerType_PIIX3:       return GlobalCtx::tr("PIIX3");
     647        case StorageControllerType_PIIX4 :      return GlobalCtx::tr("PIIX4");
     648        case StorageControllerType_ICH6:        return GlobalCtx::tr("ICH6");
     649        case StorageControllerType_I82078:      return GlobalCtx::tr("I82078");
     650        case StorageControllerType_LsiLogicSas: return GlobalCtx::tr("LsiLogicSas");
     651        case StorageControllerType_USB:         return GlobalCtx::tr("USB");
     652        case StorageControllerType_NVMe:        return GlobalCtx::tr("NVMe");
     653        case StorageControllerType_VirtioSCSI:  return GlobalCtx::tr("VirtioSCSI");
     654        default:
     655            AssertMsgFailedReturn(("%d (%#x)\n", aType, aType), ::stringifyStorageControllerType(aType));
     656    }
     657}
     658
     659/*static*/ const char *
     660Global::stringifyDeviceType(DeviceType_T aType)
     661{
     662    switch (aType)
     663    {
     664        case DeviceType_Null:         return GlobalCtx::tr("Null");
     665        case DeviceType_Floppy:       return GlobalCtx::tr("Floppy");
     666        case DeviceType_DVD:          return GlobalCtx::tr("DVD");
     667        case DeviceType_HardDisk:     return GlobalCtx::tr("HardDisk");
     668        case DeviceType_Network:      return GlobalCtx::tr("Network");
     669        case DeviceType_USB:          return GlobalCtx::tr("USB");
     670        case DeviceType_SharedFolder: return GlobalCtx::tr("ShardFolder");
     671        default:
     672            AssertMsgFailedReturn(("%d (%#x)\n", aType, aType), ::stringifyDeviceType(aType));
     673    }
     674}
     675
    637676#if 0 /* unused */
    638677
     
    656695
    657696/*static*/ const char *
    658 Global::stringifyDeviceType(DeviceType_T aType)
    659 {
    660     switch (aType)
    661     {
    662         case DeviceType_Null:         return GlobalCtx::tr("Null");
    663         case DeviceType_Floppy:       return GlobalCtx::tr("Floppy");
    664         case DeviceType_DVD:          return GlobalCtx::tr("DVD");
    665         case DeviceType_HardDisk:     return GlobalCtx::tr("HardDisk");
    666         case DeviceType_Network:      return GlobalCtx::tr("Network");
    667         case DeviceType_USB:          return GlobalCtx::tr("USB");
    668         case DeviceType_SharedFolder: return GlobalCtx::tr("ShardFolder");
    669         default:
    670             AssertMsgFailedReturn(("%d (%#x)\n", aType, aType), ::stringifyDeviceType(aType));
    671     }
    672 }
    673 
    674 /*static*/ const char *
    675697Global::stringifyReason(Reason_T aReason)
    676698{
  • trunk/src/VBox/Main/src-server/ApplianceImpl.cpp

    r93115 r93480  
    18281828}
    18291829
     1830/**
     1831 * Private method; walks through the array of VirtualSystemDescriptionEntry entries
     1832 * and returns the one matching the given index.
     1833 */
     1834const VirtualSystemDescriptionEntry* VirtualSystemDescription::i_findByIndex(const uint32_t aIndex)
     1835{
     1836    vector<VirtualSystemDescriptionEntry>::const_iterator it;
     1837    for (it = m->maDescriptions.begin();
     1838         it != m->maDescriptions.end();
     1839         ++it)
     1840    {
     1841        const VirtualSystemDescriptionEntry &d = *it;
     1842        if (d.ulIndex == aIndex)
     1843            return &d;
     1844    }
     1845
     1846    return NULL;
     1847}
     1848
  • trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp

    r93115 r93480  
    43054305
    43064306/**
     4307 * Helper routine to parse the ExtraData Utf8Str for a storage controller's
     4308 * value or channel value.
     4309 *
     4310 * @param   aExtraData    The ExtraData string with a format of
     4311 *                        'controller=13;channel=3'.
     4312 * @param   pszKey        The string being looked up, either 'controller' or
     4313 *                        'channel'.
     4314 * @param   puVal         The integer value of the 'controller=' or 'channel='
     4315 *                        key in the ExtraData string.
     4316 * @returns COM status code.
     4317 * @throws  Nothing.
     4318 */
     4319static int getStorageControllerDetailsFromStr(const com::Utf8Str &aExtraData, const char *pszKey, uint32_t *puVal)
     4320{
     4321    size_t posKey = aExtraData.find(pszKey);
     4322    if (posKey == Utf8Str::npos)
     4323        return VERR_INVALID_PARAMETER;
     4324
     4325    int vrc = RTStrToUInt32Ex(aExtraData.c_str() + posKey + strlen(pszKey), NULL, 0, puVal);
     4326    if (vrc == VWRN_NUMBER_TOO_BIG || vrc == VWRN_NEGATIVE_UNSIGNED)
     4327        return VERR_INVALID_PARAMETER;
     4328
     4329    return vrc;
     4330}
     4331
     4332/**
     4333 * Verifies the validity of a storage controller's channel (aka controller port).
     4334 *
     4335 * @param   aStorageControllerType     The type of storage controller as idenfitied
     4336 *                                     by the enum of type StorageControllerType_T.
     4337 * @param   uControllerPort            The controller port value.
     4338 * @param   aMaxPortCount              The maximum number of ports allowed for this
     4339 *                                     storage controller type.
     4340 * @returns COM status code.
     4341 * @throws  Nothing.
     4342 */
     4343HRESULT Appliance::i_verifyStorageControllerPortValid(const StorageControllerType_T aStorageControllerType,
     4344                                                      const uint32_t uControllerPort,
     4345                                                      ULONG *aMaxPortCount)
     4346{
     4347    SystemProperties *pSysProps;
     4348    pSysProps = mVirtualBox->i_getSystemProperties();
     4349    if (pSysProps == NULL)
     4350        return VBOX_E_OBJECT_NOT_FOUND;
     4351
     4352    StorageBus_T enmStorageBus = StorageBus_Null;
     4353    HRESULT vrc = pSysProps->GetStorageBusForStorageControllerType(aStorageControllerType, &enmStorageBus);
     4354    if (FAILED(vrc))
     4355        return vrc;
     4356
     4357    vrc = pSysProps->GetMaxPortCountForStorageBus(enmStorageBus, aMaxPortCount);
     4358    if (FAILED(vrc))
     4359        return vrc;
     4360
     4361    if (uControllerPort >= *aMaxPortCount)
     4362        return E_INVALIDARG;
     4363
     4364    return S_OK;
     4365}
     4366
     4367/**
    43074368 * Imports one OVF virtual system (described by the given ovf::VirtualSystem and VirtualSystemDescription)
    43084369 * into VirtualBox by creating an IMachine instance, which is returned.
     
    50145075                    throw rc;
    50155076
    5016                 // find the hard disk controller to which we should attach
    5017                 ovf::HardDiskController hdc = (*vsysThis.mapControllers.find(ovfVdisk.strIdController)).second;
    5018 
    50195077                // this is for rollback later
    50205078                MyHardDiskAttachment mhda;
    50215079                mhda.pMachine = pNewMachine;
     5080
     5081                // find the hard disk controller to which we should attach
     5082                ovf::HardDiskController hdc;
     5083
     5084                /*
     5085                 * Before importing the virtual hard disk found above (diCurrent/vsdeTargetHD) first
     5086                 * check if the user requested to change either the controller it is to be attached
     5087                 * to and/or the controller port (aka 'channel') on the controller.
     5088                 */
     5089                if (   !vsdeTargetHD->strExtraConfigCurrent.isEmpty()
     5090                    && vsdeTargetHD->strExtraConfigSuggested != vsdeTargetHD->strExtraConfigCurrent)
     5091                {
     5092                    int vrc;
     5093                    uint32_t uTargetControllerIndex;
     5094                    vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigCurrent, "controller=",
     5095                        &uTargetControllerIndex);
     5096                    if (RT_FAILURE(vrc))
     5097                        throw setError(E_FAIL,
     5098                                       tr("Target controller value invalid or missing: '%s'"),
     5099                                       vsdeTargetHD->strExtraConfigCurrent.c_str());
     5100
     5101                    uint32_t uNewControllerPortValue;
     5102                    vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigCurrent, "channel=",
     5103                        &uNewControllerPortValue);
     5104                    if (RT_FAILURE(vrc))
     5105                        throw setError(E_FAIL,
     5106                                       tr("Target controller port ('channel=') invalid or missing: '%s'"),
     5107                                       vsdeTargetHD->strExtraConfigCurrent.c_str());
     5108
     5109                    const VirtualSystemDescriptionEntry *vsdeTargetController;
     5110                    vsdeTargetController = vsdescThis->i_findByIndex(uTargetControllerIndex);
     5111                    if (!vsdeTargetController)
     5112                        throw setError(E_FAIL,
     5113                                       tr("Failed to find storage controller '%u' in the System Description list"),
     5114                                       uTargetControllerIndex);
     5115
     5116                    hdc = (*vsysThis.mapControllers.find(vsdeTargetController->strRef.c_str())).second;
     5117
     5118                    StorageControllerType_T hdStorageControllerType = StorageControllerType_Null;
     5119                    switch (hdc.system)
     5120                    {
     5121                        case ovf::HardDiskController::IDE:
     5122                            hdStorageControllerType = StorageControllerType_PIIX3;
     5123                            break;
     5124                        case ovf::HardDiskController::SATA:
     5125                            hdStorageControllerType = StorageControllerType_IntelAhci;
     5126                            break;
     5127                        case ovf::HardDiskController::SCSI:
     5128                        {
     5129                            if (hdc.strControllerType.compare("lsilogicsas")==0)
     5130                                hdStorageControllerType = StorageControllerType_LsiLogicSas;
     5131                            else
     5132                                hdStorageControllerType = StorageControllerType_LsiLogic;
     5133                            break;
     5134                        }
     5135                        case ovf::HardDiskController::VIRTIOSCSI:
     5136                            hdStorageControllerType = StorageControllerType_VirtioSCSI;
     5137                            break;
     5138                        default:
     5139                            throw setError(E_FAIL,
     5140                                           tr("Invalid hard disk contoller type: '%d'"),
     5141                                           hdc.system);
     5142                            break;
     5143                    }
     5144
     5145                    ULONG ulMaxPorts;
     5146                    rc = i_verifyStorageControllerPortValid(hdStorageControllerType,
     5147                                                            uNewControllerPortValue,
     5148                                                            &ulMaxPorts);
     5149                    if (FAILED(rc))
     5150                    {
     5151                        if (rc == E_INVALIDARG)
     5152                        {
     5153                            const char *pcszSCType = Global::stringifyStorageControllerType(hdStorageControllerType);
     5154                            throw setError(E_INVALIDARG,
     5155                                           tr("Illegal channel: '%u'.  For %s controllers the valid values are "
     5156                                           "0 to %lu (inclusive).\n"), uNewControllerPortValue, pcszSCType, ulMaxPorts-1);
     5157                        }
     5158                        else
     5159                            throw rc;
     5160                    }
     5161
     5162                    unconst(ovfVdisk.ulAddressOnParent) = uNewControllerPortValue;
     5163                }
     5164                else
     5165                    hdc = (*vsysThis.mapControllers.find(ovfVdisk.strIdController)).second;
     5166
    50225167
    50235168                i_convertDiskAttachmentValues(hdc,
     
    52625407     * failures. A long fixed bug, however the OVF files are long lived. */
    52635408    settings::StorageControllersList &llControllers = config.hardwareMachine.storage.llStorageControllers;
    5264     Guid hdUuid;
    52655409    uint32_t cDisks = 0;
    52665410    bool fInconsistent = false;
     
    52715415         ++it3)
    52725416    {
     5417        Guid hdUuid;
    52735418        settings::AttachedDevicesList &llAttachments = it3->llAttachedDevices;
    52745419        settings::AttachedDevicesList::iterator it4 = llAttachments.begin();
     
    53645509            continue;
    53655510        }
    5366 
    5367 
    5368 
    5369 
    5370 
    5371 
    5372 
    5373 
    53745511
    53755512        /*
     
    54445581                                       tr("Internal inconsistency looking up disk image '%s'"),
    54455582                                       diCurrent.strHref.c_str());
    5446 
    5447 
    5448 
    5449 
    5450 
    54515583                }
    54525584                else
     
    54735605        bool fFound = false;
    54745606        Utf8Str strUuid;
     5607
     5608        /*
     5609         * Before importing the virtual hard disk found above (diCurrent/vsdeTargetHD) first
     5610         * check if the user requested to change either the controller it is to be attached
     5611         * to and/or the controller port (aka 'channel') on the controller.
     5612         */
     5613        if (   !vsdeTargetHD->strExtraConfigCurrent.isEmpty()
     5614            && vsdeTargetHD->strExtraConfigSuggested != vsdeTargetHD->strExtraConfigCurrent)
     5615        {
     5616            /*
     5617             * First, we examine the extra configuration values for this vdisk:
     5618             *   vsdeTargetHD->strExtraConfigSuggested
     5619             *   vsdeTargetHD->strExtraConfigCurrent
     5620             * in order to extract both the "before" and "after" storage controller and port
     5621             * details. The strExtraConfigSuggested string contains the current controller
     5622             * and port the vdisk is attached to and is populated by Appliance::interpret()
     5623             * when processing the OVF data; it is in the following format:
     5624             * 'controller=12;channel=0' (the 'channel=' label for the controller port is
     5625             * historical and is documented as such in the SDK so can't be changed). The
     5626             * strExtraConfigSuggested string contains the target controller and port specified
     5627             * by the user and it has the same format. The 'controller=' value is not a
     5628             * controller-ID but rather it is the index for the corresponding storage controller
     5629             * in the array of VirtualSystemDescriptionEntry entries.
     5630             */
     5631            int vrc;
     5632            uint32_t uOrigControllerIndex;
     5633            vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigSuggested, "controller=", &uOrigControllerIndex);
     5634            if (RT_FAILURE(vrc))
     5635                throw setError(E_FAIL,
     5636                               tr("Original controller value invalid or missing: '%s'"),
     5637                               vsdeTargetHD->strExtraConfigSuggested.c_str());
     5638
     5639            uint32_t uTargetControllerIndex;
     5640            vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigCurrent, "controller=", &uTargetControllerIndex);
     5641            if (RT_FAILURE(vrc))
     5642                throw setError(E_FAIL,
     5643                               tr("Target controller value invalid or missing: '%s'"),
     5644                               vsdeTargetHD->strExtraConfigCurrent.c_str());
     5645
     5646            uint32_t uOrigControllerPortValue;
     5647            vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigSuggested, "channel=",
     5648                &uOrigControllerPortValue);
     5649            if (RT_FAILURE(vrc))
     5650                throw setError(E_FAIL,
     5651                               tr("Original controller port ('channel=') invalid or missing: '%s'"),
     5652                               vsdeTargetHD->strExtraConfigSuggested.c_str());
     5653
     5654            uint32_t uNewControllerPortValue;
     5655            vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigCurrent, "channel=", &uNewControllerPortValue);
     5656            if (RT_FAILURE(vrc))
     5657                throw setError(E_FAIL,
     5658                               tr("Target controller port ('channel=') invalid or missing: '%s'"),
     5659                               vsdeTargetHD->strExtraConfigCurrent.c_str());
     5660
     5661            /*
     5662             * Second, now that we have the storage controller indexes we locate the corresponding
     5663             * VirtualSystemDescriptionEntry (VSDE) for both storage controllers which contain
     5664             * identifying details which will be needed later when walking the list of storage
     5665             * controllers.
     5666             */
     5667            const VirtualSystemDescriptionEntry *vsdeOrigController;
     5668            vsdeOrigController = vsdescThis->i_findByIndex(uOrigControllerIndex);
     5669            if (!vsdeOrigController)
     5670                throw setError(E_FAIL,
     5671                               tr("Failed to find storage controller '%u' in the System Description list"),
     5672                               uOrigControllerIndex);
     5673
     5674            const VirtualSystemDescriptionEntry *vsdeTargetController;
     5675            vsdeTargetController = vsdescThis->i_findByIndex(uTargetControllerIndex);
     5676            if (!vsdeTargetController)
     5677                throw setError(E_FAIL,
     5678                               tr("Failed to find storage controller '%u' in the System Description list"),
     5679                               uTargetControllerIndex);
     5680
     5681            /*
     5682             * Third, grab the UUID of the current vdisk so we can identify which device
     5683             * attached to the original storage controller needs to be updated (channel) and/or
     5684             * removed.
     5685             */
     5686            ovf::DiskImagesMap::const_iterator itDiskImageMap = stack.mapDisks.find(vsdeTargetHD->strRef);
     5687            if (itDiskImageMap == stack.mapDisks.end())
     5688                throw setError(E_FAIL,
     5689                               tr("Failed to find virtual disk '%s' in DiskImagesMap"),
     5690                               vsdeTargetHD->strVBoxCurrent.c_str());
     5691            const ovf::DiskImage &targetDiskImage = itDiskImageMap->second;
     5692            Utf8Str strTargetDiskUuid = targetDiskImage.uuidVBox;;
     5693
     5694            /*
     5695             * Fourth, walk the attached devices of the original storage controller to find the
     5696             * current vdisk and update the controller port (aka channel) value if necessary and
     5697             * also remove the vdisk from this controller if needed.
     5698             *
     5699             * A short note on the choice of which items to compare when determining the type of
     5700             * storage controller here and below in the vdisk addition scenario:
     5701             *  + The VirtualSystemDescriptionEntry 'strOvf' field is populated from the OVF
     5702             *    data which can contain a value like 'vmware.sata.ahci' if created by VMWare so
     5703             *    it isn't a reliable choice.
     5704             *  + The settings::StorageController 'strName' field can have varying content based
     5705             *    on the version of the settings file, e.g. 'IDE Controller' vs. 'IDE' so it
     5706             *    isn't a reliable choice.  Further, this field can contain 'SATA' whereas
     5707             *    'AHCI' is used in 'strOvf' and 'strVBoxSuggested'.
     5708             *  + The VirtualSystemDescriptionEntry 'strVBoxSuggested' field is populated by
     5709             *    Appliance::interpret()->VirtualSystemDescription::i_addEntry() and is thus
     5710             *    under VBox's control and has a fixed format and predictable content.
     5711             */
     5712            bool fDiskRemoved = false;
     5713            settings::AttachedDevice originalAttachedDevice;
     5714            settings::StorageControllersList::iterator itSCL;
     5715            for (itSCL = config.hardwareMachine.storage.llStorageControllers.begin();
     5716                 itSCL != config.hardwareMachine.storage.llStorageControllers.end();
     5717                 ++itSCL)
     5718            {
     5719                settings::StorageController &SC = *itSCL;
     5720                const char *pcszSCType = Global::stringifyStorageControllerType(SC.controllerType);
     5721
     5722                /* There can only be one storage controller of each type in the OVF data. */
     5723                if (!vsdeOrigController->strVBoxSuggested.compare(pcszSCType, Utf8Str::CaseInsensitive))
     5724                {
     5725                    settings::AttachedDevicesList::iterator itAD;
     5726                    for (itAD = SC.llAttachedDevices.begin();
     5727                         itAD != SC.llAttachedDevices.end();
     5728                         ++itAD)
     5729                    {
     5730                        settings::AttachedDevice &AD = *itAD;
     5731
     5732                        if (AD.uuid.toString() == strTargetDiskUuid)
     5733                        {
     5734                            ULONG ulMaxPorts;
     5735                            rc = i_verifyStorageControllerPortValid(SC.controllerType,
     5736                                                                    uNewControllerPortValue,
     5737                                                                    &ulMaxPorts);
     5738                            if (FAILED(rc))
     5739                            {
     5740                                if (rc == E_INVALIDARG)
     5741                                    throw setError(E_INVALIDARG,
     5742                                                   tr("Illegal channel: '%u'.  For %s controllers the valid values are "
     5743                                                   "0 to %lu (inclusive).\n"), uNewControllerPortValue, pcszSCType, ulMaxPorts-1);
     5744                                else
     5745                                    throw rc;
     5746                            }
     5747
     5748                            if (uOrigControllerPortValue != uNewControllerPortValue)
     5749                            {
     5750                                AD.lPort = uNewControllerPortValue;
     5751                            }
     5752                            if (uOrigControllerIndex != uTargetControllerIndex)
     5753                            {
     5754                                LogFunc(("Removing vdisk '%s' (uuid = %RTuuid) from the %s storage controller.\n",
     5755                                         vsdeTargetHD->strVBoxCurrent.c_str(),
     5756                                         itAD->uuid.raw(),
     5757                                         SC.strName.c_str()));
     5758                                originalAttachedDevice = AD;
     5759                                SC.llAttachedDevices.erase(itAD);
     5760                                fDiskRemoved = true;
     5761                            }
     5762                        }
     5763                    }
     5764                }
     5765            }
     5766
     5767            /*
     5768             * Fifth, if we are moving the vdisk to a different controller and not just changing
     5769             * the channel then we walk the attached devices of the target controller and check
     5770             * for conflicts before adding the vdisk detached/removed above.
     5771             */
     5772            bool fDiskAdded = false;
     5773            if (fDiskRemoved)
     5774            {
     5775                for (itSCL = config.hardwareMachine.storage.llStorageControllers.begin();
     5776                     itSCL != config.hardwareMachine.storage.llStorageControllers.end();
     5777                     ++itSCL)
     5778                {
     5779                    settings::StorageController &SC = *itSCL;
     5780                    const char *pcszSCType = Global::stringifyStorageControllerType(SC.controllerType);
     5781
     5782                    /* There can only be one storage controller of each type in the OVF data. */
     5783                    if (!vsdeTargetController->strVBoxSuggested.compare(pcszSCType, Utf8Str::CaseInsensitive))
     5784                    {
     5785                        settings::AttachedDevicesList::iterator itAD;
     5786                        for (itAD = SC.llAttachedDevices.begin();
     5787                             itAD != SC.llAttachedDevices.end();
     5788                             ++itAD)
     5789                        {
     5790                            settings::AttachedDevice &AD = *itAD;
     5791                            if (   AD.lDevice == originalAttachedDevice.lDevice
     5792                                && AD.lPort == originalAttachedDevice.lPort)
     5793                                    throw setError(E_FAIL,
     5794                                                   tr("Device of type '%s' already attached to the %s controller at this "
     5795                                                   "port/channel (%d)."),
     5796                                                   Global::stringifyDeviceType(AD.deviceType), pcszSCType, AD.lPort);
     5797                        }
     5798
     5799                        LogFunc(("Adding vdisk '%s' (uuid = %RTuuid) to the %s storage controller\n",
     5800                                 vsdeTargetHD->strVBoxCurrent.c_str(),
     5801                                 originalAttachedDevice.uuid.raw(),
     5802                                 SC.strName.c_str()));
     5803                        SC.llAttachedDevices.push_back(originalAttachedDevice);
     5804                        fDiskAdded = true;
     5805                    }
     5806                }
     5807
     5808                if (!fDiskAdded)
     5809                    throw setError(E_FAIL,
     5810                                   tr("Failed to add disk '%s' (uuid=%RTuuid) to the %s storage controller."),
     5811                                   vsdeTargetHD->strVBoxCurrent.c_str(),
     5812                                   originalAttachedDevice.uuid.raw(),
     5813                                   vsdeTargetController->strVBoxSuggested.c_str());
     5814            }
     5815
     5816            /*
     5817             * Sixth, update the machine settings since we've changed the storage controller
     5818             * and/or controller port for this vdisk.
     5819             */
     5820            AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
     5821            mVirtualBox->i_saveSettings();
     5822            vboxLock.release();
     5823        }
    54755824
    54765825        // for each storage controller...
     
    56566005            VirtualSystemDescriptionEntry *vsdeSF1 = vsdeSettingsFile.front();
    56576006            if (vsdeSF1->strVBoxCurrent != vsdeSF1->strVBoxSuggested)
    5658             stack.strSettingsFilename = vsdeSF1->strVBoxCurrent;
     6007                stack.strSettingsFilename = vsdeSF1->strVBoxCurrent;
    56596008        }
    56606009        if (stack.strSettingsFilename.isEmpty())
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette