oldconfig.c 13 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
2
 * Support for converting from old configuration format
Alexandre Julliard's avatar
Alexandre Julliard committed
3
 *
4
 * Copyright 2005 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 *
6 7 8 9 10 11 12 13 14 15 16 17
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
 *
20 21
 * NOTES
 *   This file should be removed after a suitable transition period.
Alexandre Julliard's avatar
Alexandre Julliard committed
22 23
 */

24
#include "config.h"
25
#include "wine/port.h"
26

27
#include <stdarg.h>
28
#include <sys/types.h>
29
#include <stdlib.h>
30
#include <stdio.h>
31 32 33
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
34
#include <fcntl.h>
35 36 37
#ifdef HAVE_DIRENT_H
# include <dirent.h>
#endif
38 39 40 41 42 43
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_LINUX_HDREG_H
# include <linux/hdreg.h>
#endif
44

45
#include "windef.h"
46
#include "winbase.h"
47
#include "winternl.h"
48
#include "ntddscsi.h"
49
#include "wine/library.h"
50
#include "wine/unicode.h"
51
#include "wine/debug.h"
52
#include "kernel_private.h"
53

54
WINE_DEFAULT_DEBUG_CHANNEL(reg);
Alexandre Julliard's avatar
Alexandre Julliard committed
55

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
static NTSTATUS create_key( HANDLE root, const char *name, HANDLE *key, DWORD *disp )
{
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING nameW;
    NTSTATUS status;

    attr.Length = sizeof(attr);
    attr.RootDirectory = root;
    attr.ObjectName = &nameW;
    attr.Attributes = 0;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;

    if (!RtlCreateUnicodeStringFromAsciiz( &nameW, name )) return STATUS_NO_MEMORY;
    status = NtCreateKey( key, KEY_ALL_ACCESS, &attr, 0, NULL, REG_OPTION_VOLATILE, disp );
    if (status) ERR("Cannot create %s registry key\n", name );
    RtlFreeUnicodeString( &nameW );
    return status;
}

76
/******************************************************************
77
 *		create_scsi_entry
78 79 80 81 82 83
 *
 * Initializes registry to contain scsi info about the cdrom in NT.
 * All devices (even not real scsi ones) have this info in NT.
 * NOTE: programs usually read these registry entries after sending the
 *       IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
 */
84
static void create_scsi_entry( PSCSI_ADDRESS scsi_addr, LPCSTR lpDriver, UINT uDriveType,
85
    LPSTR lpDriveName, LPSTR lpUnixDeviceName )
86
{
87 88 89
    static UCHAR uCdromNumber = 0;
    static UCHAR uTapeNumber = 0;

90 91
    UNICODE_STRING nameW;
    WCHAR dataW[50];
92
    DWORD sizeW;
93 94 95
    char buffer[40];
    DWORD value;
    const char *data;
96 97 98 99
    HANDLE scsiKey;
    HANDLE portKey;
    HANDLE busKey;
    HANDLE targetKey;
100
    HANDLE lunKey;
101 102
    DWORD disp;

103
    if (create_key( 0, "\\Registry\\Machine\\HARDWARE\\DEVICEMAP", &scsiKey, &disp )) return;
104 105
    NtClose( scsiKey );

106
    /* Ensure there is Scsi key */
107
    if (create_key( 0, "\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\Scsi", &scsiKey, &disp )) return;
108

109
    snprintf(buffer,sizeof(buffer),"Scsi Port %d",scsi_addr->PortNumber);
110
    if (create_key( scsiKey, buffer, &portKey, &disp )) return;
111 112

    RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" );
113
    RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &sizeW, lpDriver, strlen(lpDriver)+1);
114
    NtSetValueKey( portKey, &nameW, 0, REG_SZ, dataW, sizeW );
115 116 117
    RtlFreeUnicodeString( &nameW );
    value = 10;
    RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" );
118
    NtSetValueKey( portKey,&nameW, 0, REG_DWORD, &value, sizeof(DWORD) );
119
    RtlFreeUnicodeString( &nameW );
120

121
    value = 0;
122
    if (strcmp(lpDriver, "atapi") == 0)
123
    {
124
#ifdef HDIO_GET_DMA
125
        int fd, dma;
126 127
        
        fd = open(lpUnixDeviceName, O_RDONLY|O_NONBLOCK);
128
        if (fd != -1)
129
        {
130 131
            if (ioctl(fd, HDIO_GET_DMA, &dma) != -1) value = dma;
            close(fd);
132
        }
133
#endif
134
        RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" );
135
        NtSetValueKey( portKey,&nameW, 0, REG_DWORD, &value, sizeof(DWORD) );
136 137
        RtlFreeUnicodeString( &nameW );
    }
138

139
    snprintf(buffer, sizeof(buffer),"Scsi Bus %d", scsi_addr->PathId);
140
    if (create_key( portKey, buffer, &busKey, &disp )) return;
141

142
    /* FIXME: get real controller Id for SCSI */
143
    if (create_key( busKey, buffer, &targetKey, &disp )) return;
144 145
    NtClose( targetKey );

146
    snprintf(buffer, sizeof(buffer),"Target Id %d", scsi_addr->TargetId);
147
    if (create_key( busKey, buffer, &targetKey, &disp )) return;
148

149
    snprintf(buffer, sizeof(buffer),"Logical Unit Id %d", scsi_addr->Lun);
150
    if (create_key( targetKey, buffer, &lunKey, &disp )) return;
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

    switch (uDriveType)
    {
        case DRIVE_NO_ROOT_DIR:
        default:
            data = "OtherPeripheral"; break;
        case DRIVE_FIXED:
            data = "DiskPeripheral"; break;
        case DRIVE_REMOVABLE:
            data = "TapePeripheral";
            snprintf(buffer, sizeof(buffer), "Tape%d", uTapeNumber++);
            break;
        case DRIVE_CDROM:
            data = "CdRomPeripheral";
            snprintf(buffer, sizeof(buffer), "Cdrom%d", uCdromNumber++);
            break;
    }
168
    RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" );
169
    RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &sizeW, data, strlen(data)+1);
170
    NtSetValueKey( lunKey, &nameW, 0, REG_SZ, dataW, sizeW );
171
    RtlFreeUnicodeString( &nameW );
172

173
    RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" );
174
    RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &sizeW, lpDriveName, strlen(lpDriveName)+1);
175
    NtSetValueKey( lunKey, &nameW, 0, REG_SZ, dataW, sizeW );
176
    RtlFreeUnicodeString( &nameW );
177 178 179 180

    if (uDriveType == DRIVE_CDROM || uDriveType == DRIVE_REMOVABLE)
    {
        RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" );
181
        RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &sizeW, buffer, strlen(buffer)+1);
182
        NtSetValueKey( lunKey, &nameW, 0, REG_SZ, dataW, sizeW );
183 184 185 186
        RtlFreeUnicodeString( &nameW );
    }

    RtlCreateUnicodeStringFromAsciiz( &nameW, "UnixDeviceName" );
187
    RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &sizeW, lpUnixDeviceName, strlen(lpUnixDeviceName)+1);
188
    NtSetValueKey( lunKey, &nameW, 0, REG_SZ, dataW, sizeW );
189 190
    RtlFreeUnicodeString( &nameW );

191
    NtClose( lunKey );
192 193 194 195 196 197
    NtClose( targetKey );
    NtClose( busKey );
    NtClose( portKey );
    NtClose( scsiKey );
}

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
struct LinuxProcScsiDevice
{
    int host;
    int channel;
    int target;
    int lun;
    char vendor[9];
    char model[17];
    char rev[5];
    char type[33];
    int ansirev;
};

/*
 * we need to declare white spaces explicitly via %*1[ ],
 * as there are very dainbread CD-ROM devices out there
 * which have their manufacturer name blanked out via spaces,
 * which confuses fscanf's parsing (skips all blank spaces)
 */
static int SCSI_getprocentry( FILE * procfile, struct LinuxProcScsiDevice * dev )
{
    int result;

    result = fscanf( procfile,
        "Host:%*1[ ]scsi%d%*1[ ]Channel:%*1[ ]%d%*1[ ]Id:%*1[ ]%d%*1[ ]Lun:%*1[ ]%d\n",
	&dev->host,
	&dev->channel,
	&dev->target,
	&dev->lun );
    if( result == EOF )
    {
        /* "end of entries" return, so no TRACE() here */
        return EOF;
    }
    if( result != 4 )
    {
234
        ERR("bus id line scan count error (fscanf returns %d, expected 4)\n", result);
235 236 237 238 239 240 241 242 243
        return 0;
    }
    result = fscanf( procfile,
        "  Vendor:%*1[ ]%8c%*1[ ]Model:%*1[ ]%16c%*1[ ]Rev:%*1[ ]%4c\n",
        dev->vendor,
        dev->model,
        dev->rev );
    if( result != 3 )
    {
244
        ERR("model line scan count error (fscanf returns %d, expected 3)\n", result);
245 246 247 248
        return 0;
    }

    result = fscanf( procfile,
249
        "  Type:%*3[ ]%32c%*1[ ]ANSI SCSI%*1[ ]revision:%*1[ ]%x\n",
250 251 252 253
        dev->type,
        &dev->ansirev );
    if( result != 2 )
    {
254
        ERR("SCSI type line scan count error (fscanf returns %d, expected 2)\n", result);
255 256 257 258 259 260 261 262 263 264 265
        return 0;
    }
    /* Since we fscanf with %XXc instead of %s.. put a NULL at end */
    dev->vendor[8] = 0;
    dev->model[16] = 0;
    dev->rev[4] = 0;
    dev->type[32] = 0;

    return 1;
}

266 267 268 269

/* create the hardware registry branch */
static void create_hardware_branch(void)
{
270 271
    /* The following mostly will work on Linux, but should not cause
     * problems on other systems. */
272 273 274 275 276 277 278 279 280 281 282 283
    static const char procname_ide_media[] = "/proc/ide/%s/media";
    static const char procname_ide_model[] = "/proc/ide/%s/model";
    static const char procname_scsi[] = "/proc/scsi/scsi";
    DIR *idedir;
    struct dirent *dent = NULL;
    FILE *procfile = NULL;
    char cStr[40], cDevModel[40], cUnixDeviceName[40], read1[10] = "\0", read2[10] = "\0";
    SCSI_ADDRESS scsi_addr;
    UINT nType;
    struct LinuxProcScsiDevice dev;
    int result = 0, nSgNumber = 0;
    UCHAR uFirstSCSIPort = 0;
284

285 286
    /* Enumerate all ide devices first */
    idedir = opendir("/proc/ide");
287
    if (idedir)
288
    {
289
        while ((dent = readdir(idedir)))
290
        {
291
            if (strncmp(dent->d_name, "hd", 2) == 0)
292
            {
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
                sprintf(cStr, procname_ide_media, dent->d_name);
                procfile = fopen(cStr, "r");
                if (!procfile)
                {
                    ERR("Could not open %s\n", cStr);
                    continue;
                } else {
                    fgets(cStr, sizeof(cStr), procfile);
                    fclose(procfile);
                    nType = DRIVE_UNKNOWN;
                    if (strncasecmp(cStr, "disk", 4)  == 0) nType = DRIVE_FIXED;
                    if (strncasecmp(cStr, "cdrom", 5) == 0) nType = DRIVE_CDROM;

                    if (nType == DRIVE_UNKNOWN) continue;
                }
308

309 310 311
                sprintf(cStr, procname_ide_model, dent->d_name);
                procfile = fopen(cStr, "r");
                if (!procfile)
312
                {
313 314 315
                    ERR("Could not open %s\n", cStr);
                    switch (nType)
                    {
316 317
                    case DRIVE_FIXED: strcpy(cDevModel, "Wine harddisk"); break;
                    case DRIVE_CDROM: strcpy(cDevModel, "Wine CDROM"); break;
318 319 320 321 322
                    }
                } else {
                    fgets(cDevModel, sizeof(cDevModel), procfile);
                    fclose(procfile);
                    cDevModel[strlen(cDevModel) - 1] = 0;
323
                }
324 325 326 327 328 329 330 331 332 333

                sprintf(cUnixDeviceName, "/dev/%s", dent->d_name);
                scsi_addr.PortNumber = (dent->d_name[2] - 'a') / 2;
                scsi_addr.PathId = 0;
                scsi_addr.TargetId = (dent->d_name[2] - 'a') % 2;
                scsi_addr.Lun = 0;
                if (scsi_addr.PortNumber + 1 > uFirstSCSIPort)
                    uFirstSCSIPort = scsi_addr.PortNumber + 1;

                create_scsi_entry(&scsi_addr, "atapi", nType, cDevModel, cUnixDeviceName);
334 335
            }
        }
336
        closedir(idedir);
337
    }
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374

    /* Now goes SCSI */
    procfile = fopen(procname_scsi, "r");
    if (!procfile)
    {
        TRACE("Could not open %s\n", procname_scsi);
        return;
    }
    fgets(cStr, 40, procfile);
    sscanf(cStr, "Attached %9s %9s", read1, read2);

    if (strcmp(read1, "devices:") != 0)
    {
        WARN("Incorrect %s format\n", procname_scsi);
        fclose( procfile );
        return;
    }
    if (strcmp(read2, "none") == 0)
    {
        TRACE("No SCSI devices found in %s.\n", procname_scsi);
        fclose( procfile );
        return;
    }

    /* Read info for one device */
    while ((result = SCSI_getprocentry(procfile, &dev)) > 0)
    {
        scsi_addr.PortNumber = dev.host;
        scsi_addr.PathId = dev.channel;
        scsi_addr.TargetId = dev.target;
        scsi_addr.Lun = dev.lun;

        scsi_addr.PortNumber += uFirstSCSIPort;
        if (strncmp(dev.type, "Direct-Access", 13) == 0) nType = DRIVE_FIXED;
        else if (strncmp(dev.type, "Sequential-Access", 17) == 0) nType = DRIVE_REMOVABLE;
        else if (strncmp(dev.type, "CD-ROM", 6) == 0) nType = DRIVE_CDROM;
        else if (strncmp(dev.type, "Processor", 9) == 0) nType = DRIVE_NO_ROOT_DIR;
375 376
        else if (strncmp(dev.type, "Scanner", 7) == 0) nType = DRIVE_NO_ROOT_DIR;
        else if (strncmp(dev.type, "Printer", 7) == 0) nType = DRIVE_NO_ROOT_DIR;
377 378 379 380 381 382 383 384 385 386 387 388
        else continue;

        strcpy(cDevModel, dev.vendor);
        strcat(cDevModel, dev.model);
        strcat(cDevModel, dev.rev);
        sprintf(cUnixDeviceName, "/dev/sg%d", nSgNumber++);
        /* FIXME: get real driver name */
        create_scsi_entry(&scsi_addr, "WINE SCSI", nType, cDevModel, cUnixDeviceName);
    }
    if( result != EOF )
        WARN("Incorrect %s format\n", procname_scsi);
    fclose( procfile );
389 390 391 392 393 394 395 396
}


/***********************************************************************
 *              convert_old_config
 */
void convert_old_config(void)
{
397 398 399
    HANDLE key;
    DWORD disp;

400
    /* create some hardware keys (FIXME: should not be done here) */
401
    if (create_key( 0, "\\Registry\\Machine\\HARDWARE", &key, &disp )) return;
402 403
    NtClose( key );
    if (disp != REG_OPENED_EXISTING_KEY) create_hardware_branch();
404
}