static void ensure_drive_c_is_mapped(void) { struct stat buf; const char *configdir = wine_get_config_dir(); int len; char *drive_c_dir; if (drives[2].in_use) return; len = snprintf(NULL, 0, "%s/../drive_c", configdir); drive_c_dir = HeapAlloc(GetProcessHeap(), 0, len); snprintf(drive_c_dir, len, "%s/../drive_c", configdir); HeapFree(GetProcessHeap(), 0, drive_c_dir); if (stat(drive_c_dir, &buf) == 0) { WCHAR label[64]; LoadStringW (GetModuleHandle (NULL), IDS_SYSTEM_DRIVE_LABEL, label, sizeof(label)/sizeof(label[0])); add_drive('C', "../drive_c", NULL, label, 0, DRIVE_FIXED); } else { report_error(NO_DRIVE_C); } }
/* inspired by write_desktop_entry() in xdg support code */ static BOOL generate_bundle_script(const char *file, const char *path, const char *args, const char *workdir) { FILE *fp; const char *libpath; WINE_TRACE("Creating Bundle helper script at %s\n", wine_dbgstr_a(file)); fp = fopen(file, "w"); if (fp == NULL) return FALSE; fprintf(fp, "#!/bin/sh\n"); fprintf(fp, "PATH=\"%s\"\nexport PATH\n", getenv("PATH")); libpath = getenv("DYLD_FALLBACK_LIBRARY_PATH"); if (libpath) fprintf(fp, "DYLD_FALLBACK_LIBRARY_PATH=\"%s\"\nexport DYLD_FALLBACK_LIBRARY_PATH\n", libpath); fprintf(fp, "WINEPREFIX=\"%s\"\nexport WINEPREFIX\n\n", wine_get_config_dir()); if (workdir) fprintf(fp, "cd \"%s\"\n", workdir); fprintf(fp, "exec sh -c \"exec wine %s %s\"\n\n", path, args); fprintf(fp, "#EOF\n"); fclose(fp); chmod(file, 0755); return TRUE; }
/*********************************************************************** * start_dosbox */ static void start_dosbox( const char *appname, const char *args ) { static const WCHAR cfgW[] = {'c','f','g',0}; const char *config_dir = wine_get_config_dir(); WCHAR path[MAX_PATH], config[MAX_PATH]; HANDLE file; char *p, *buffer, app[MAX_PATH]; int i; int ret = 1; DWORD written, drives = GetLogicalDrives(); char *dosbox = find_dosbox(); if (!dosbox) return; if (!GetTempPathW( MAX_PATH, path )) return; if (!GetTempFileNameW( path, cfgW, 0, config )) return; if (!GetCurrentDirectoryW( MAX_PATH, path )) return; if (!GetShortPathNameA( appname, app, MAX_PATH )) return; GetShortPathNameW( path, path, MAX_PATH ); file = CreateFileW( config, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); if (file == INVALID_HANDLE_VALUE) return; buffer = HeapAlloc( GetProcessHeap(), 0, sizeof("[autoexec]") + sizeof("mount -z c") + sizeof("config -securemode") + 25 * (strlen(config_dir) + sizeof("mount c /dosdevices/c:")) + 4 * strlenW( path ) + 6 + strlen( app ) + strlen( args ) + 20 ); p = buffer; p += sprintf( p, "[autoexec]\n" ); for (i = 25; i >= 0; i--) if (!(drives & (1 << i))) { p += sprintf( p, "mount -z %c\n", 'a' + i ); break; } for (i = 0; i <= 25; i++) if (drives & (1 << i)) p += sprintf( p, "mount %c %s/dosdevices/%c:\n", 'a' + i, config_dir, 'a' + i ); p += sprintf( p, "%c:\ncd ", path[0] ); p += WideCharToMultiByte( CP_UNIXCP, 0, path + 2, -1, p, 4 * strlenW(path), NULL, NULL ) - 1; p += sprintf( p, "\nconfig -securemode\n" ); p += sprintf( p, "%s %s\n", app, args ); p += sprintf( p, "exit\n" ); if (WriteFile( file, buffer, strlen(buffer), &written, NULL ) && written == strlen(buffer)) { const char *args[5]; char *config_file = wine_get_unix_file_name( config ); args[0] = dosbox; args[1] = "-userconf"; args[2] = "-conf"; args[3] = config_file; args[4] = NULL; ret = _spawnvp( _P_WAIT, args[0], args ); } CloseHandle( file ); DeleteFileW( config ); HeapFree( GetProcessHeap(), 0, buffer ); ExitProcess( ret ); }
/*********************************************************************** * start_dosbox */ static void start_dosbox( const char *appname, const char *args ) { static const WCHAR cfgW[] = {'c','f','g',0}; const char *config_dir = wine_get_config_dir(); WCHAR path[MAX_PATH], config[MAX_PATH]; HANDLE file; char *p, *buffer; int i; int ret = 1; DWORD written, drives = GetLogicalDrives(); char *dosbox = find_dosbox(); if (!dosbox) return; if (tolower(appname[0]) == 'z') { WINE_MESSAGE( "winevdm: Cannot start DOS application %s\n", appname ); WINE_MESSAGE( " because DOSBox doesn't support running from the Z: drive.\n" ); ExitProcess(1); } if (!GetTempPathW( MAX_PATH, path )) return; if (!GetTempFileNameW( path, cfgW, 0, config )) return; if (!GetCurrentDirectoryW( MAX_PATH, path )) return; file = CreateFileW( config, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); if (file == INVALID_HANDLE_VALUE) return; buffer = HeapAlloc( GetProcessHeap(), 0, sizeof("[autoexec]") + 25 * (strlen(config_dir) + sizeof("mount c /dosdevices/c:")) + 4 * strlenW( path ) + 6 + strlen( appname ) + strlen( args ) + 20 ); p = buffer; p += sprintf( p, "[autoexec]\n" ); for (i = 0; i < 25; i++) if (drives & (1 << i)) p += sprintf( p, "mount %c %s/dosdevices/%c:\n", 'a' + i, config_dir, 'a' + i ); p += sprintf( p, "%c:\ncd ", path[0] ); p += WideCharToMultiByte( CP_UNIXCP, 0, path + 2, -1, p, 4 * strlenW(path), NULL, NULL ) - 1; p += sprintf( p, "\n%s %s\n", appname, args ); p += sprintf( p, "exit\n" ); if (WriteFile( file, buffer, strlen(buffer), &written, NULL ) && written == strlen(buffer)) { const char *args[4]; char *config_file = wine_get_unix_file_name( config ); args[0] = dosbox; args[1] = "-conf"; args[2] = config_file; args[3] = NULL; ret = spawnvp( _P_WAIT, args[0], args ); } CloseHandle( file ); DeleteFileW( config ); HeapFree( GetProcessHeap(), 0, buffer ); ExitProcess( ret ); }
static char *get_dosdevices_path(void) { const char *config_dir = wine_get_config_dir(); size_t len = strlen(config_dir) + sizeof("/dosdevices/a::"); char *path = HeapAlloc( GetProcessHeap(), 0, len ); if (path) { strcpy( path, config_dir ); strcat( path, "/dosdevices/a::" ); } return path; }
/*********************************************************************** * setup_config_dir * * Setup the wine configuration dir. */ static void setup_config_dir(void) { const char *p, *config_dir = wine_get_config_dir(); if (chdir( config_dir ) == -1) { if (errno != ENOENT) fatal_perror( "chdir to %s\n", config_dir ); if ((p = strrchr( config_dir, '/' )) && p != config_dir) { struct stat st; char *tmp_dir; if (!(tmp_dir = malloc( p + 1 - config_dir ))) fatal_error( "out of memory\n" ); memcpy( tmp_dir, config_dir, p - config_dir ); tmp_dir[p - config_dir] = 0; if (!stat( tmp_dir, &st ) && st.st_uid != getuid()) fatal_error( "'%s' is not owned by you, refusing to create a configuration directory there\n", tmp_dir ); free( tmp_dir ); } mkdir( config_dir, 0777 ); if (chdir( config_dir ) == -1) fatal_perror( "chdir to %s\n", config_dir ); if ((p = getenv( "WINEARCH" )) && !strcmp( p, "win32" )) { /* force creation of a 32-bit prefix */ int fd = open( "system.reg", O_WRONLY | O_CREAT | O_EXCL, 0666 ); if (fd != -1) { static const char regfile[] = "WINE REGISTRY Version 2\n\n#arch=win32\n"; write( fd, regfile, sizeof(regfile) - 1 ); close( fd ); } } MESSAGE( "wine: created the configuration directory '%s'\n", config_dir ); } if (mkdir( "dosdevices", 0777 ) == -1) { if (errno == EEXIST) return; fatal_perror( "cannot create %s/dosdevices\n", config_dir ); } /* create the drive symlinks */ mkdir( "drive_c", 0777 ); symlink( "../drive_c", "dosdevices/c:" ); symlink( "/", "dosdevices/z:" ); }
/* execute rundll32 on the wine.inf file if necessary */ static void update_wineprefix( int force ) { const char *config_dir = wine_get_config_dir(); char *inf_path = get_wine_inf_path(); int fd; struct stat st; if (!inf_path) { WINE_MESSAGE( "wine: failed to update %s, wine.inf not found\n", config_dir ); return; } if ((fd = open( inf_path, O_RDONLY )) == -1) { WINE_MESSAGE( "wine: failed to update %s with %s: %s\n", config_dir, inf_path, strerror(errno) ); goto done; } fstat( fd, &st ); close( fd ); if (update_timestamp( config_dir, st.st_mtime ) || force) { HANDLE process; DWORD count = 0; if ((process = start_rundll32( inf_path, FALSE ))) { HWND hwnd = show_wait_window(); for (;;) { MSG msg; DWORD res = MsgWaitForMultipleObjects( 1, &process, FALSE, INFINITE, QS_ALLINPUT ); if (res == WAIT_OBJECT_0) { CloseHandle( process ); if (count++ || !(process = start_rundll32( inf_path, TRUE ))) break; } else while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); } DestroyWindow( hwnd ); } WINE_MESSAGE( "wine: configuration in '%s' has been updated.\n", config_dir ); } done: HeapFree( GetProcessHeap(), 0, inf_path ); }
static HWND show_wait_window(void) { const char *config_dir = wine_get_config_dir(); WCHAR *name; HWND hwnd; DWORD len; len = MultiByteToWideChar( CP_UNIXCP, 0, config_dir, -1, NULL, 0 ); name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); MultiByteToWideChar( CP_UNIXCP, 0, config_dir, -1, name, len ); hwnd = CreateDialogParamW( GetModuleHandleW(0), MAKEINTRESOURCEW(IDD_WAITDLG), 0, wait_dlgproc, (LPARAM)name ); ShowWindow( hwnd, SW_SHOWNORMAL ); HeapFree( GetProcessHeap(), 0, name ); return hwnd; }
/*********************************************************************** * setup_config_dir * * Setup the wine configuration dir. */ static void setup_config_dir(void) { const char *p, *config_dir = wine_get_config_dir(); if (chdir( config_dir ) == -1) { if (errno != ENOENT) fatal_perror( "chdir to %s\n", config_dir ); if ((p = strrchr( config_dir, '/' )) && p != config_dir) { struct stat st; char *tmp_dir; if (!(tmp_dir = malloc( p + 1 - config_dir ))) fatal_error( "out of memory\n" ); memcpy( tmp_dir, config_dir, p - config_dir ); tmp_dir[p - config_dir] = 0; if (!stat( tmp_dir, &st ) && st.st_uid != getuid()) fatal_error( "'%s' is not owned by you, refusing to create a configuration directory there\n", tmp_dir ); free( tmp_dir ); } mkdir( config_dir, 0777 ); if (chdir( config_dir ) == -1) fatal_perror( "chdir to %s\n", config_dir ); MESSAGE( "wine: created the configuration directory '%s'\n", config_dir ); } if (mkdir( "dosdevices", 0777 ) == -1) { if (errno == EEXIST) return; fatal_perror( "cannot create %s/dosdevices\n", config_dir ); } /* create the drive symlinks */ mkdir( "drive_c", 0777 ); symlink( "../drive_c", "dosdevices/c:" ); symlink( "/", "dosdevices/z:" ); }
/*********************************************************************** * server_init_thread * * Send an init thread request. Return 0 if OK. */ size_t server_init_thread( void *entry_point ) { static const int is_win64 = (sizeof(void *) > sizeof(int)); const char *arch = getenv( "WINEARCH" ); int ret; int reply_pipe[2]; struct sigaction sig_act; size_t info_size; sig_act.sa_handler = SIG_IGN; sig_act.sa_flags = 0; sigemptyset( &sig_act.sa_mask ); /* ignore SIGPIPE so that we get an EPIPE error instead */ sigaction( SIGPIPE, &sig_act, NULL ); /* create the server->client communication pipes */ if (server_pipe( reply_pipe ) == -1) server_protocol_perror( "pipe" ); if (server_pipe( ntdll_get_thread_data()->wait_fd ) == -1) server_protocol_perror( "pipe" ); wine_server_send_fd( reply_pipe[1] ); wine_server_send_fd( ntdll_get_thread_data()->wait_fd[1] ); ntdll_get_thread_data()->reply_fd = reply_pipe[0]; close( reply_pipe[1] ); SERVER_START_REQ( init_thread ) { req->unix_pid = getpid(); req->unix_tid = get_unix_tid(); req->teb = wine_server_client_ptr( NtCurrentTeb() ); req->entry = wine_server_client_ptr( entry_point ); req->reply_fd = reply_pipe[1]; req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; req->debug_level = (TRACE_ON(server) != 0); req->cpu = client_cpu; ret = wine_server_call( req ); NtCurrentTeb()->ClientId.UniqueProcess = ULongToHandle(reply->pid); NtCurrentTeb()->ClientId.UniqueThread = ULongToHandle(reply->tid); info_size = reply->info_size; server_start_time = reply->server_start; server_cpus = reply->all_cpus; } SERVER_END_REQ; is_wow64 = !is_win64 && (server_cpus & (1 << CPU_x86_64)) != 0; ntdll_get_thread_data()->wow64_redir = is_wow64; switch (ret) { case STATUS_SUCCESS: if (arch) { if (!strcmp( arch, "win32" ) && (is_win64 || is_wow64)) fatal_error( "WINEARCH set to win32 but '%s' is a 64-bit installation.\n", wine_get_config_dir() ); if (!strcmp( arch, "win64" ) && !is_win64 && !is_wow64) fatal_error( "WINEARCH set to win64 but '%s' is a 32-bit installation.\n", wine_get_config_dir() ); } return info_size; case STATUS_NOT_REGISTRY_FILE: fatal_error( "'%s' is a 32-bit installation, it cannot support 64-bit applications.\n", wine_get_config_dir() ); case STATUS_NOT_SUPPORTED: if (is_win64) fatal_error( "wineserver is 32-bit, it cannot support 64-bit applications.\n" ); else fatal_error( "'%s' is a 64-bit installation, it cannot be used with a 32-bit wineserver.\n", wine_get_config_dir() ); default: server_protocol_error( "init_thread failed with status %x\n", ret ); } }
/* open the master server socket and start waiting for new clients */ void open_master_socket(void) { const char *server_dir = wine_get_server_dir(); const char *config_dir = wine_get_config_dir(); int fd, pid, status, sync_pipe[2]; char dummy; /* make sure no request is larger than the maximum size */ assert( sizeof(union generic_request) == sizeof(struct request_max_size) ); assert( sizeof(union generic_reply) == sizeof(struct request_max_size) ); /* make sure the stdio fds are open */ fd = open( "/dev/null", O_RDWR ); while (fd >= 0 && fd <= 2) fd = dup( fd ); if (!server_dir) fatal_error( "directory %s cannot be accessed\n", config_dir ); if (chdir( config_dir ) == -1) fatal_perror( "chdir to %s", config_dir ); if ((config_dir_fd = open( ".", O_RDONLY )) == -1) fatal_perror( "open %s", config_dir ); create_server_dir( server_dir ); if (!foreground) { if (pipe( sync_pipe ) == -1) fatal_perror( "pipe" ); pid = fork(); switch( pid ) { case 0: /* child */ setsid(); close( sync_pipe[0] ); acquire_lock(); /* close stdin and stdout */ dup2( fd, 0 ); dup2( fd, 1 ); /* signal parent */ dummy = 0; write( sync_pipe[1], &dummy, 1 ); close( sync_pipe[1] ); break; case -1: fatal_perror( "fork" ); break; default: /* parent */ close( sync_pipe[1] ); /* wait for child to signal us and then exit */ if (read( sync_pipe[0], &dummy, 1 ) == 1) _exit(0); /* child terminated, propagate exit status */ waitpid( pid, &status, 0 ); if (WIFEXITED(status)) _exit( WEXITSTATUS(status) ); _exit(1); } } else /* remain in the foreground */ { acquire_lock(); } /* init the process tracing mechanism */ init_tracing_mechanism(); close( fd ); }
/* open the master server socket and start waiting for new clients */ void open_master_socket(void) { const char *server_dir = wine_get_server_dir(); int fd, pid, status, sync_pipe[2]; char dummy; /* make sure no request is larger than the maximum size */ assert( sizeof(union generic_request) == sizeof(struct request_max_size) ); assert( sizeof(union generic_reply) == sizeof(struct request_max_size) ); if (!server_dir) fatal_error( "directory %s cannot be accessed\n", wine_get_config_dir() ); create_server_dir( server_dir ); if (!foreground) { if (pipe( sync_pipe ) == -1) fatal_perror( "pipe" ); pid = fork(); switch( pid ) { case 0: /* child */ setsid(); close( sync_pipe[0] ); acquire_lock(); /* close stdin and stdout */ if ((fd = open( "/dev/null", O_RDWR )) != -1) { dup2( fd, 0 ); dup2( fd, 1 ); close( fd ); } /* signal parent */ dummy = 0; write( sync_pipe[1], &dummy, 1 ); close( sync_pipe[1] ); break; case -1: fatal_perror( "fork" ); break; default: /* parent */ close( sync_pipe[1] ); /* wait for child to signal us and then exit */ if (read( sync_pipe[0], &dummy, 1 ) == 1) _exit(0); /* child terminated, propagate exit status */ wait4( pid, &status, 0, NULL ); if (WIFEXITED(status)) _exit( WEXITSTATUS(status) ); _exit(1); } } else /* remain in the foreground */ { acquire_lock(); } /* setup msghdr structure constant fields */ msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = &myiovec; msghdr.msg_iovlen = 1; /* init startup time */ gettimeofday( &server_start_time, NULL ); }