1 /* 2 * Wine Conformance Test EXE 3 * 4 * Copyright 2003, 2004 Jakob Eriksson (for Solid Form Sweden AB) 5 * Copyright 2003 Dimitrie O. Paun 6 * Copyright 2003 Ferenc Wagner 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 * 22 * This program is dedicated to Anna Lindh, 23 * Swedish Minister of Foreign Affairs. 24 * Anna was murdered September 11, 2003. 25 * 26 */ 27 28 #include "config.h" 29 #include "wine/port.h" 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <assert.h> 34 #include <errno.h> 35 #ifdef HAVE_UNISTD_H 36 # include <unistd.h> 37 #endif 38 #include <windows.h> 39 40 #include "winetest.h" 41 #include "resource.h" 42 #include <reason.h> 43 44 struct wine_test 45 { 46 char *name; 47 int resource; 48 int subtest_count; 49 char **subtests; 50 char *exename; 51 }; 52 53 struct rev_info 54 { 55 const char* file; 56 const char* rev; 57 }; 58 59 char *tag = NULL; 60 static struct wine_test *wine_tests; 61 static int nr_of_files, nr_of_tests; 62 static struct rev_info *rev_infos = NULL; 63 static const char whitespace[] = " \t\r\n"; 64 static const char testexe[] = "_test.exe"; 65 66 static char * get_file_version(char * file_name) 67 { 68 static char version[32]; 69 DWORD size; 70 DWORD handle; 71 72 size = GetFileVersionInfoSizeA(file_name, &handle); 73 if (size) { 74 char * data = xmalloc(size); 75 if (data) { 76 if (GetFileVersionInfoA(file_name, handle, size, data)) { 77 static char backslash[] = "\\"; 78 VS_FIXEDFILEINFO *pFixedVersionInfo; 79 UINT len; 80 if (VerQueryValueA(data, backslash, (LPVOID *)&pFixedVersionInfo, &len)) { 81 sprintf(version, "%d.%d.%d.%d", 82 pFixedVersionInfo->dwFileVersionMS >> 16, 83 pFixedVersionInfo->dwFileVersionMS & 0xffff, 84 pFixedVersionInfo->dwFileVersionLS >> 16, 85 pFixedVersionInfo->dwFileVersionLS & 0xffff); 86 } else 87 sprintf(version, "version not available"); 88 } else 89 sprintf(version, "unknown"); 90 free(data); 91 } else 92 sprintf(version, "failed"); 93 } else 94 sprintf(version, "version not available"); 95 96 return version; 97 } 98 99 static int running_under_wine (void) 100 { 101 HMODULE module = GetModuleHandleA("ntdll.dll"); 102 103 if (!module) return 0; 104 return (GetProcAddress(module, "wine_server_call") != NULL); 105 } 106 107 static int running_on_visible_desktop (void) 108 { 109 HWND desktop; 110 HMODULE huser32 = GetModuleHandle("user32.dll"); 111 FARPROC pGetProcessWindowStation = GetProcAddress(huser32, "GetProcessWindowStation"); 112 FARPROC pGetUserObjectInformationA = GetProcAddress(huser32, "GetUserObjectInformationA"); 113 114 desktop = GetDesktopWindow(); 115 if (!GetWindowLongPtrW(desktop, GWLP_WNDPROC)) /* Win9x */ 116 return IsWindowVisible(desktop); 117 118 if (pGetProcessWindowStation && pGetUserObjectInformationA) 119 { 120 DWORD len; 121 HWINSTA wstation; 122 USEROBJECTFLAGS uoflags; 123 124 wstation = (HWINSTA)pGetProcessWindowStation(); 125 assert(pGetUserObjectInformationA(wstation, UOI_FLAGS, &uoflags, sizeof(uoflags), &len)); 126 return (uoflags.dwFlags & WSF_VISIBLE) != 0; 127 } 128 return IsWindowVisible(desktop); 129 } 130 131 static void print_version (void) 132 { 133 OSVERSIONINFOEX ver; 134 BOOL ext; 135 int is_win2k3_r2; 136 const char *(*wine_get_build_id)(void); 137 138 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 139 if (!(ext = GetVersionEx ((OSVERSIONINFO *) &ver))) 140 { 141 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 142 if (!GetVersionEx ((OSVERSIONINFO *) &ver)) 143 report (R_FATAL, "Can't get OS version."); 144 } 145 146 xprintf (" bRunningUnderWine=%d\n", running_under_wine ()); 147 xprintf (" bRunningOnVisibleDesktop=%d\n", running_on_visible_desktop ()); 148 xprintf (" dwMajorVersion=%ld\n dwMinorVersion=%ld\n" 149 " dwBuildNumber=%ld\n PlatformId=%ld\n szCSDVersion=%s\n", 150 ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, 151 ver.dwPlatformId, ver.szCSDVersion); 152 153 wine_get_build_id = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_build_id"); 154 if (wine_get_build_id) xprintf( " WineBuild=%s\n", wine_get_build_id() ); 155 156 is_win2k3_r2 = GetSystemMetrics(SM_SERVERR2); 157 if(is_win2k3_r2) 158 xprintf(" R2 build number=%d\n", is_win2k3_r2); 159 160 if (!ext) return; 161 162 xprintf (" wServicePackMajor=%d\n wServicePackMinor=%d\n" 163 " wSuiteMask=%d\n wProductType=%d\n wReserved=%d\n", 164 ver.wServicePackMajor, ver.wServicePackMinor, ver.wSuiteMask, 165 ver.wProductType, ver.wReserved); 166 } 167 168 static inline int is_dot_dir(const char* x) 169 { 170 return ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0)))); 171 } 172 173 static void remove_dir (const char *dir) 174 { 175 HANDLE hFind; 176 WIN32_FIND_DATA wfd; 177 char path[MAX_PATH]; 178 size_t dirlen = strlen (dir); 179 180 /* Make sure the directory exists before going further */ 181 memcpy (path, dir, dirlen); 182 strcpy (path + dirlen++, "\\*"); 183 hFind = FindFirstFile (path, &wfd); 184 if (hFind == INVALID_HANDLE_VALUE) return; 185 186 do { 187 char *lp = wfd.cFileName; 188 189 if (!lp[0]) lp = wfd.cAlternateFileName; /* ? FIXME not (!lp) ? */ 190 if (is_dot_dir (lp)) continue; 191 strcpy (path + dirlen, lp); 192 if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes) 193 remove_dir(path); 194 else if (!DeleteFile (path)) 195 report (R_WARNING, "Can't delete file %s: error %d", 196 path, GetLastError ()); 197 } while (FindNextFile (hFind, &wfd)); 198 FindClose (hFind); 199 if (!RemoveDirectory (dir)) 200 report (R_WARNING, "Can't remove directory %s: error %d", 201 dir, GetLastError ()); 202 } 203 204 static const char* get_test_source_file(const char* test, const char* subtest) 205 { 206 static const char* special_dirs[][2] = { 207 { 0, 0 } 208 }; 209 static char buffer[MAX_PATH]; 210 int i; 211 212 for (i = 0; special_dirs[i][0]; i++) { 213 if (strcmp(test, special_dirs[i][0]) == 0) { 214 test = special_dirs[i][1]; 215 break; 216 } 217 } 218 219 snprintf(buffer, sizeof(buffer), "dlls/%s/tests/%s.c", test, subtest); 220 return buffer; 221 } 222 223 static const char* get_file_rev(const char* file) 224 { 225 const struct rev_info* rev; 226 227 for(rev = rev_infos; rev->file; rev++) { 228 if (strcmp(rev->file, file) == 0) return rev->rev; 229 } 230 231 return "-"; 232 } 233 234 static void extract_rev_infos (void) 235 { 236 char revinfo[256], *p; 237 int size = 0, i; 238 unsigned int len; 239 HMODULE module = GetModuleHandle (NULL); 240 241 for (i = 0; TRUE; i++) { 242 if (i >= size) { 243 size += 100; 244 rev_infos = xrealloc (rev_infos, size * sizeof (*rev_infos)); 245 } 246 memset(rev_infos + i, 0, sizeof(rev_infos[i])); 247 248 len = LoadStringA (module, REV_INFO+i, revinfo, sizeof(revinfo)); 249 if (len == 0) break; /* end of revision info */ 250 if (len >= sizeof(revinfo) - 1) 251 report (R_FATAL, "Revision info too long."); 252 if(!(p = strrchr(revinfo, ':'))) 253 report (R_FATAL, "Revision info malformed (i=%d)", i); 254 *p = 0; 255 rev_infos[i].file = strdup(revinfo); 256 rev_infos[i].rev = strdup(p + 1); 257 } 258 } 259 260 static void* extract_rcdata (LPTSTR name, int type, DWORD* size) 261 { 262 HRSRC rsrc; 263 HGLOBAL hdl; 264 LPVOID addr; 265 266 if (!(rsrc = FindResource (NULL, name, MAKEINTRESOURCE(type))) || 267 !(*size = SizeofResource (0, rsrc)) || 268 !(hdl = LoadResource (0, rsrc)) || 269 !(addr = LockResource (hdl))) 270 return NULL; 271 return addr; 272 } 273 274 /* Fills in the name and exename fields */ 275 static void 276 extract_test (struct wine_test *test, const char *dir, LPTSTR res_name) 277 { 278 BYTE* code; 279 DWORD size; 280 FILE* fout; 281 char *exepos; 282 283 code = extract_rcdata (res_name, TESTRES, &size); 284 if (!code) report (R_FATAL, "Can't find test resource %s: %d", 285 res_name, GetLastError ()); 286 test->name = xstrdup( res_name ); 287 test->exename = strmake (NULL, "%s/%s", dir, test->name); 288 exepos = strstr (test->name, testexe); 289 if (!exepos) report (R_FATAL, "Not an .exe file: %s", test->name); 290 *exepos = 0; 291 test->name = xrealloc (test->name, exepos - test->name + 1); 292 report (R_STEP, "Extracting: %s", test->name); 293 294 if (!(fout = fopen (test->exename, "wb")) || 295 (fwrite (code, size, 1, fout) != 1) || 296 fclose (fout)) report (R_FATAL, "Failed to write file %s.", 297 test->exename); 298 } 299 300 /* Run a command for MS milliseconds. If OUT != NULL, also redirect 301 stdout to there. 302 303 Return the exit status, -2 if can't create process or the return 304 value of WaitForSingleObject. 305 */ 306 static int 307 run_ex (char *cmd, const char *out, const char *tempdir, DWORD ms) 308 { 309 STARTUPINFO si; 310 PROCESS_INFORMATION pi; 311 int fd, oldstdout = -1; 312 DWORD wait, status; 313 314 GetStartupInfo (&si); 315 si.dwFlags = 0; 316 317 if (out) { 318 fd = open (out, O_WRONLY | O_CREAT, 0666); 319 if (-1 == fd) 320 report (R_FATAL, "Can't open '%s': %d", out, errno); 321 oldstdout = dup (1); 322 if (-1 == oldstdout) 323 report (R_FATAL, "Can't save stdout: %d", errno); 324 if (-1 == dup2 (fd, 1)) 325 report (R_FATAL, "Can't redirect stdout: %d", errno); 326 close (fd); 327 } 328 329 if (!CreateProcessA (NULL, cmd, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, 330 NULL, tempdir, &si, &pi)) { 331 status = -2; 332 } else { 333 CloseHandle (pi.hThread); 334 wait = WaitForSingleObject (pi.hProcess, ms); 335 if (wait == WAIT_OBJECT_0) { 336 GetExitCodeProcess (pi.hProcess, &status); 337 } else { 338 switch (wait) { 339 case WAIT_FAILED: 340 report (R_ERROR, "Wait for '%s' failed: %d", cmd, 341 GetLastError ()); 342 break; 343 case WAIT_TIMEOUT: 344 report (R_ERROR, "Process '%s' timed out.", cmd); 345 break; 346 default: 347 report (R_ERROR, "Wait returned %d", wait); 348 } 349 status = wait; 350 if (!TerminateProcess (pi.hProcess, 257)) 351 report (R_ERROR, "TerminateProcess failed: %d", 352 GetLastError ()); 353 wait = WaitForSingleObject (pi.hProcess, 5000); 354 switch (wait) { 355 case WAIT_FAILED: 356 report (R_ERROR, 357 "Wait for termination of '%s' failed: %d", 358 cmd, GetLastError ()); 359 break; 360 case WAIT_OBJECT_0: 361 break; 362 case WAIT_TIMEOUT: 363 report (R_ERROR, "Can't kill process '%s'", cmd); 364 break; 365 default: 366 report (R_ERROR, "Waiting for termination: %d", 367 wait); 368 } 369 } 370 CloseHandle (pi.hProcess); 371 } 372 373 if (out) { 374 close (1); 375 if (-1 == dup2 (oldstdout, 1)) 376 report (R_FATAL, "Can't recover stdout: %d", errno); 377 close (oldstdout); 378 } 379 return status; 380 } 381 382 static void 383 get_subtests (const char *tempdir, struct wine_test *test, LPTSTR res_name) 384 { 385 char *subname, *cmd; 386 FILE *subfile; 387 size_t total; 388 char buffer[8192], *index; 389 static const char header[] = "Valid test names:"; 390 int allocated; 391 392 test->subtest_count = 0; 393 394 subname = tempnam (0, "sub"); 395 if (!subname) report (R_FATAL, "Can't name subtests file."); 396 397 extract_test (test, tempdir, res_name); 398 cmd = strmake (NULL, "%s --list", test->exename); 399 run_ex (cmd, subname, tempdir, 5000); 400 free (cmd); 401 402 subfile = fopen (subname, "r"); 403 if (!subfile) { 404 report (R_ERROR, "Can't open subtests output of %s: %d", 405 test->name, errno); 406 goto quit; 407 } 408 total = fread (buffer, 1, sizeof buffer, subfile); 409 fclose (subfile); 410 if (sizeof buffer == total) { 411 report (R_ERROR, "Subtest list of %s too big.", 412 test->name, sizeof buffer); 413 goto quit; 414 } 415 buffer[total] = 0; 416 417 index = strstr (buffer, header); 418 if (!index) { 419 report (R_ERROR, "Can't parse subtests output of %s", 420 test->name); 421 goto quit; 422 } 423 index += sizeof header; 424 425 allocated = 10; 426 test->subtests = xmalloc (allocated * sizeof(char*)); 427 index = strtok (index, whitespace); 428 while (index) { 429 if (test->subtest_count == allocated) { 430 allocated *= 2; 431 test->subtests = xrealloc (test->subtests, 432 allocated * sizeof(char*)); 433 } 434 test->subtests[test->subtest_count++] = strdup (index); 435 index = strtok (NULL, whitespace); 436 } 437 test->subtests = xrealloc (test->subtests, 438 test->subtest_count * sizeof(char*)); 439 440 quit: 441 if (remove (subname)) 442 report (R_WARNING, "Can't delete file '%s': %d", 443 subname, errno); 444 free (subname); 445 } 446 447 static void 448 run_test (struct wine_test* test, const char* subtest, const char *tempdir) 449 { 450 int status; 451 const char* file = get_test_source_file(test->name, subtest); 452 const char* rev = get_file_rev(file); 453 char *cmd = strmake (NULL, "%s %s", test->exename, subtest); 454 455 xprintf ("%s:%s start %s %s\n", test->name, subtest, file, rev); 456 status = run_ex (cmd, NULL, tempdir, 120000); 457 free (cmd); 458 xprintf ("%s:%s done (%d)\n", test->name, subtest, status); 459 } 460 461 static BOOL CALLBACK 462 EnumTestFileProc (HMODULE hModule, LPCTSTR lpszType, 463 LPTSTR lpszName, LONG_PTR lParam) 464 { 465 (*(int*)lParam)++; 466 return TRUE; 467 } 468 469 static BOOL CALLBACK 470 extract_test_proc (HMODULE hModule, LPCTSTR lpszType, 471 LPTSTR lpszName, LONG_PTR lParam) 472 { 473 const char *tempdir = (const char *)lParam; 474 char dllname[MAX_PATH]; 475 HMODULE dll; 476 477 /* Check if the main dll is present on this system */ 478 CharLowerA(lpszName); 479 strcpy(dllname, lpszName); 480 *strstr(dllname, testexe) = 0; 481 482 dll = LoadLibraryExA(dllname, NULL, LOAD_LIBRARY_AS_DATAFILE); 483 if (!dll) { 484 xprintf (" %s=dll is missing\n", dllname); 485 return TRUE; 486 } 487 FreeLibrary(dll); 488 489 xprintf (" %s=%s\n", dllname, get_file_version(dllname)); 490 491 get_subtests( tempdir, &wine_tests[nr_of_files], lpszName ); 492 nr_of_tests += wine_tests[nr_of_files].subtest_count; 493 nr_of_files++; 494 return TRUE; 495 } 496 497 static char * 498 run_tests (char *logname) 499 { 500 int i; 501 char *tempdir, *shorttempdir; 502 int logfile; 503 char *strres, *eol, *nextline; 504 DWORD strsize; 505 char build[64]; 506 507 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); 508 509 if (!logname) { 510 logname = tempnam (0, "res"); 511 if (!logname) report (R_FATAL, "Can't name logfile."); 512 } 513 report (R_OUT, logname); 514 515 logfile = open (logname, O_WRONLY | O_CREAT | O_EXCL | O_APPEND, 516 0666); 517 if (-1 == logfile) { 518 if (EEXIST == errno) 519 report (R_FATAL, "File %s already exists.", logname); 520 else report (R_FATAL, "Could not open logfile: %d", errno); 521 } 522 if (-1 == dup2 (logfile, 1)) 523 report (R_FATAL, "Can't redirect stdout: %d", errno); 524 close (logfile); 525 526 tempdir = tempnam (0, "wct"); 527 if (!tempdir) 528 report (R_FATAL, "Can't name temporary dir (check %%TEMP%%)."); 529 shorttempdir = strdup (tempdir); 530 if (shorttempdir) { /* try stable path for ZoneAlarm */ 531 strstr (shorttempdir, "wct")[3] = 0; 532 if (CreateDirectoryA (shorttempdir, NULL)) { 533 free (tempdir); 534 tempdir = shorttempdir; 535 } else free (shorttempdir); 536 } 537 if (tempdir != shorttempdir && !CreateDirectoryA (tempdir, NULL)) 538 report (R_FATAL, "Could not create directory: %s", tempdir); 539 report (R_DIR, tempdir); 540 541 xprintf ("Version 4\n"); 542 strres = extract_rcdata (MAKEINTRESOURCE(WINE_BUILD), STRINGRES, &strsize); 543 xprintf ("Tests from build "); 544 if (LoadStringA( 0, IDS_BUILD_ID, build, sizeof(build) )) xprintf( "%s\n", build ); 545 else if (strres) xprintf ("%.*s", strsize, strres); 546 else xprintf ("-\n"); 547 strres = extract_rcdata (MAKEINTRESOURCE(TESTS_URL), STRINGRES, &strsize); 548 xprintf ("Archive: "); 549 if (strres) xprintf ("%.*s", strsize, strres); 550 else xprintf ("-\n"); 551 xprintf ("Tag: %s\n", tag); 552 xprintf ("Build info:\n"); 553 strres = extract_rcdata (MAKEINTRESOURCE(BUILD_INFO), STRINGRES, &strsize); 554 while (strres) { 555 eol = memchr (strres, '\n', strsize); 556 if (!eol) { 557 nextline = NULL; 558 eol = strres + strsize; 559 } else { 560 strsize -= eol - strres + 1; 561 nextline = strsize?eol+1:NULL; 562 if (eol > strres && *(eol-1) == '\r') eol--; 563 } 564 xprintf (" %.*s\n", eol-strres, strres); 565 strres = nextline; 566 } 567 xprintf ("Operating system version:\n"); 568 print_version (); 569 xprintf ("Dll info:\n" ); 570 571 report (R_STATUS, "Counting tests"); 572 if (!EnumResourceNames (NULL, MAKEINTRESOURCE(TESTRES), 573 EnumTestFileProc, (LPARAM)&nr_of_files)) 574 report (R_FATAL, "Can't enumerate test files: %d", 575 GetLastError ()); 576 wine_tests = xmalloc (nr_of_files * sizeof wine_tests[0]); 577 578 report (R_STATUS, "Extracting tests"); 579 report (R_PROGRESS, 0, nr_of_files); 580 nr_of_files = 0; 581 nr_of_tests = 0; 582 if (!EnumResourceNames (NULL, MAKEINTRESOURCE(TESTRES), 583 extract_test_proc, (LPARAM)tempdir)) 584 report (R_FATAL, "Can't enumerate test files: %d", 585 GetLastError ()); 586 587 xprintf ("Test output:\n" ); 588 589 report (R_DELTA, 0, "Extracting: Done"); 590 591 report (R_STATUS, "Running tests"); 592 report (R_PROGRESS, 1, nr_of_tests); 593 for (i = 0; i < nr_of_files; i++) { 594 struct wine_test *test = wine_tests + i; 595 int j; 596 597 for (j = 0; j < test->subtest_count; j++) { 598 report (R_STEP, "Running: %s:%s", test->name, 599 test->subtests[j]); 600 run_test (test, test->subtests[j], tempdir); 601 } 602 } 603 report (R_DELTA, 0, "Running: Done"); 604 605 report (R_STATUS, "Cleaning up"); 606 close (1); 607 remove_dir (tempdir); 608 free (tempdir); 609 free (wine_tests); 610 611 return logname; 612 } 613 614 static void 615 usage (void) 616 { 617 fprintf (stderr, 618 "Usage: winetest [OPTION]...\n\n" 619 " -c console mode, no GUI\n" 620 " -e preserve the environment\n" 621 " -h print this message and exit\n" 622 " -p shutdown when the tests are done\n" 623 " -q quiet mode, no output at all\n" 624 " -o FILE put report into FILE, do not submit\n" 625 " -s FILE submit FILE, do not run tests\n" 626 " -t TAG include TAG of characters [-.0-9a-zA-Z] in the report\n"); 627 } 628 629 int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, 630 LPSTR cmdLine, int cmdShow) 631 { 632 char *logname = NULL; 633 const char *cp, *submit = NULL; 634 int reset_env = 1; 635 int poweroff = 0; 636 int interactive = 1; 637 638 /* initialize the revision information first */ 639 extract_rev_infos(); 640 641 cmdLine = strtok (cmdLine, whitespace); 642 while (cmdLine) { 643 if (cmdLine[0] != '-' || cmdLine[2]) { 644 report (R_ERROR, "Not a single letter option: %s", cmdLine); 645 usage (); 646 exit (2); 647 } 648 switch (cmdLine[1]) { 649 case 'c': 650 report (R_TEXTMODE); 651 interactive = 0; 652 break; 653 case 'e': 654 reset_env = 0; 655 break; 656 case 'h': 657 case '?': 658 usage (); 659 exit (0); 660 case 'p': 661 poweroff = 1; 662 break; 663 case 'q': 664 report (R_QUIET); 665 interactive = 0; 666 break; 667 case 's': 668 submit = strtok (NULL, whitespace); 669 if (tag) 670 report (R_WARNING, "ignoring tag for submission"); 671 send_file (submit); 672 break; 673 case 'o': 674 logname = strtok (NULL, whitespace); 675 break; 676 case 't': 677 tag = strtok (NULL, whitespace); 678 if (strlen (tag) > MAXTAGLEN) 679 report (R_FATAL, "tag is too long (maximum %d characters)", 680 MAXTAGLEN); 681 cp = findbadtagchar (tag); 682 if (cp) { 683 report (R_ERROR, "invalid char in tag: %c", *cp); 684 usage (); 685 exit (2); 686 } 687 break; 688 default: 689 report (R_ERROR, "invalid option: -%c", cmdLine[1]); 690 usage (); 691 exit (2); 692 } 693 cmdLine = strtok (NULL, whitespace); 694 } 695 if (!submit) { 696 static CHAR platform_windows[] = "WINETEST_PLATFORM=windows", 697 platform_wine[] = "WINETEST_PLATFORM=wine", 698 debug_yes[] = "WINETEST_DEBUG=1", 699 interactive_no[] = "WINETEST_INTERACTIVE=0", 700 report_success_no[] = "WINETEST_REPORT_SUCCESS=0"; 701 CHAR *platform; 702 703 report (R_STATUS, "Starting up"); 704 705 if (!running_on_visible_desktop ()) 706 report (R_FATAL, "Tests must be run on a visible desktop"); 707 708 platform = running_under_wine () ? platform_wine : platform_windows; 709 710 if (reset_env && (putenv (platform) || 711 putenv (debug_yes) || 712 putenv (interactive_no) || 713 putenv (report_success_no))) 714 report (R_FATAL, "Could not reset environment: %d", errno); 715 716 if (!tag) { 717 if (!interactive) 718 report (R_FATAL, "Please specify a tag (-t option) if " 719 "running noninteractive!"); 720 if (guiAskTag () == IDABORT) exit (1); 721 } 722 report (R_TAG); 723 724 if (!logname) { 725 logname = run_tests (NULL); 726 if (report (R_ASK, MB_YESNO, "Do you want to submit the " 727 "test results?") == IDYES) 728 if (!send_file (logname) && remove (logname)) 729 report (R_WARNING, "Can't remove logfile: %d.", errno); 730 free (logname); 731 } else run_tests (logname); 732 report (R_STATUS, "Finished"); 733 } 734 if (poweroff) 735 { 736 HANDLE hToken; 737 TOKEN_PRIVILEGES npr; 738 739 /* enable the shutdown privilege for the current process */ 740 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) 741 { 742 LookupPrivilegeValueA(0, SE_SHUTDOWN_NAME, &npr.Privileges[0].Luid); 743 npr.PrivilegeCount = 1; 744 npr.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 745 AdjustTokenPrivileges(hToken, FALSE, &npr, 0, 0, 0); 746 CloseHandle(hToken); 747 } 748 ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF | EWX_FORCEIFHUNG, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER); 749 } 750 exit (0); 751 } 752