1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 24 июл. 2019 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins 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 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <core/debug.h> 23 #include <core/ipc/Process.h> 24 #include <unistd.h> 25 #include <string.h> 26 #include <errno.h> 27 #include <data/cstorage.h> 28 #include <time.h> 29 #include <core/io/OutFileStream.h> 30 #include <core/io/InFileStream.h> 31 32 #if defined(PLATFORM_WINDOWS) 33 #include <processthreadsapi.h> 34 #include <namedpipeapi.h> 35 #include <synchapi.h> 36 #include <processenv.h> 37 #else 38 #include <spawn.h> 39 #include <sys/wait.h> 40 41 #ifndef _GNU_SOURCE 42 extern char **environ; // Define environment variables 43 #endif /* _GNU_SOURCE */ 44 #endif /* PLATFORM_WINDOWS */ 45 46 namespace lsp 47 { 48 namespace ipc 49 { 50 Process()51 Process::Process() 52 { 53 nStatus = PSTATUS_CREATED; 54 nExitCode = 0; 55 56 #ifdef PLATFORM_WINDOWS 57 hProcess = NULL; 58 nPID = 0; 59 hStdIn = NULL; 60 hStdOut = NULL; 61 hStdErr = NULL; 62 #else 63 nPID = 0; 64 hStdIn = -1; 65 hStdOut = -1; 66 hStdErr = -1; 67 #endif 68 69 pStdIn = NULL; 70 pStdOut = NULL; 71 pStdErr = NULL; 72 73 if (copy_env() != STATUS_OK) 74 nStatus = PSTATUS_ERROR; 75 } 76 ~Process()77 Process::~Process() 78 { 79 destroy_args(&vArgs); 80 destroy_env(&vEnv); 81 close_handles(); 82 83 if (pStdIn != NULL) 84 { 85 pStdIn->close(); 86 delete pStdIn; 87 pStdIn = NULL; 88 } 89 90 if (pStdOut != NULL) 91 { 92 pStdOut->close(); 93 delete pStdOut; 94 pStdOut = NULL; 95 } 96 97 if (pStdErr != NULL) 98 { 99 pStdErr->close(); 100 delete pStdErr; 101 pStdErr = NULL; 102 } 103 104 #ifdef PLATFORM_WINDOWS 105 if (hProcess != NULL) 106 { 107 ::CloseHandle(hProcess); 108 hProcess = NULL; 109 } 110 #endif /* PLATFORM_WINDOWS */ 111 } 112 destroy_args(cvector<LSPString> * args)113 void Process::destroy_args(cvector<LSPString> *args) 114 { 115 for (size_t i=0, n=args->size(); i<n; ++i) 116 { 117 LSPString *arg = args->at(i); 118 delete arg; 119 } 120 args->flush(); 121 } 122 destroy_env(cvector<envvar_t> * env)123 void Process::destroy_env(cvector<envvar_t> *env) 124 { 125 for (size_t i=0, n=env->size(); i<n; ++i) 126 { 127 envvar_t *var= env->at(i); 128 delete var; 129 } 130 env->flush(); 131 } 132 set_command(const LSPString * cmd)133 status_t Process::set_command(const LSPString *cmd) 134 { 135 if (nStatus != PSTATUS_CREATED) 136 return STATUS_BAD_STATE; 137 138 if (cmd == NULL) 139 { 140 sCommand.clear(); 141 return STATUS_OK; 142 } 143 144 return (sCommand.set(cmd)) ? STATUS_OK : STATUS_NO_MEM; 145 } 146 set_command(const char * cmd)147 status_t Process::set_command(const char *cmd) 148 { 149 if (nStatus != PSTATUS_CREATED) 150 return STATUS_BAD_STATE; 151 152 if (cmd == NULL) 153 { 154 sCommand.clear(); 155 return STATUS_OK; 156 } 157 158 return (sCommand.set_utf8(cmd)) ? STATUS_OK : STATUS_NO_MEM; 159 } 160 args() const161 size_t Process::args() const 162 { 163 return vArgs.size(); 164 } 165 add_arg(const LSPString * value)166 status_t Process::add_arg(const LSPString *value) 167 { 168 if (value == NULL) 169 return STATUS_BAD_ARGUMENTS; 170 if (nStatus != PSTATUS_CREATED) 171 return STATUS_BAD_STATE; 172 173 LSPString *arg = new LSPString(); 174 if (arg == NULL) 175 return STATUS_NO_MEM; 176 177 if (!arg->set(value)) 178 { 179 delete arg; 180 return STATUS_NO_MEM; 181 } 182 if (!vArgs.add(arg)) 183 { 184 delete arg; 185 return STATUS_NO_MEM; 186 } 187 188 return STATUS_OK; 189 } 190 add_arg(const char * value)191 status_t Process::add_arg(const char *value) 192 { 193 if (value == NULL) 194 return STATUS_BAD_ARGUMENTS; 195 if (nStatus != PSTATUS_CREATED) 196 return STATUS_BAD_STATE; 197 198 LSPString *arg = new LSPString(); 199 if (arg == NULL) 200 return STATUS_NO_MEM; 201 202 if (!arg->set_utf8(value)) 203 { 204 delete arg; 205 return STATUS_NO_MEM; 206 } 207 if (!vArgs.add(arg)) 208 { 209 delete arg; 210 return STATUS_NO_MEM; 211 } 212 213 return STATUS_OK; 214 } 215 set_arg(size_t index,const LSPString * value)216 status_t Process::set_arg(size_t index, const LSPString *value) 217 { 218 if (value == NULL) 219 return STATUS_BAD_ARGUMENTS; 220 if (nStatus != PSTATUS_CREATED) 221 return STATUS_BAD_STATE; 222 223 LSPString *ptr = vArgs.get(index); 224 if (ptr == NULL) 225 return STATUS_BAD_ARGUMENTS; 226 return (ptr->set(value)) ? STATUS_OK : STATUS_NO_MEM; 227 } 228 set_arg(size_t index,const char * value)229 status_t Process::set_arg(size_t index, const char *value) 230 { 231 if (value == NULL) 232 return STATUS_BAD_ARGUMENTS; 233 if (nStatus != PSTATUS_CREATED) 234 return STATUS_BAD_STATE; 235 236 LSPString *ptr = vArgs.get(index); 237 if (ptr == NULL) 238 return STATUS_BAD_ARGUMENTS; 239 return (ptr->set_utf8(value)) ? STATUS_OK : STATUS_NO_MEM; 240 } 241 get_arg(size_t index,LSPString * value)242 status_t Process::get_arg(size_t index, LSPString *value) 243 { 244 LSPString *ptr = vArgs.get(index); 245 if (ptr == NULL) 246 return STATUS_BAD_ARGUMENTS; 247 if (value == NULL) 248 return STATUS_OK; 249 return (value->set(ptr)) ? STATUS_OK : STATUS_NO_MEM; 250 } 251 get_arg(size_t index,char ** value)252 status_t Process::get_arg(size_t index, char **value) 253 { 254 LSPString *ptr = vArgs.get(index); 255 if (ptr == NULL) 256 return STATUS_BAD_ARGUMENTS; 257 if (value == NULL) 258 return STATUS_OK; 259 260 char *dup = ptr->clone_utf8(); 261 if (dup == NULL) 262 return STATUS_NO_MEM; 263 264 *value = dup; 265 return STATUS_OK; 266 } 267 remove_arg(size_t index,LSPString * value)268 status_t Process::remove_arg(size_t index, LSPString *value) 269 { 270 if (nStatus != PSTATUS_CREATED) 271 return STATUS_BAD_STATE; 272 273 LSPString *ptr = vArgs.get(index); 274 if (ptr == NULL) 275 return STATUS_BAD_ARGUMENTS; 276 if (value != NULL) 277 value->swap(ptr); 278 279 vArgs.remove(index); 280 delete ptr; 281 return STATUS_OK; 282 } 283 remove_arg(size_t index,char ** value)284 status_t Process::remove_arg(size_t index, char **value) 285 { 286 if (nStatus != PSTATUS_CREATED) 287 return STATUS_BAD_STATE; 288 289 LSPString *ptr = vArgs.get(index); 290 if (ptr == NULL) 291 return STATUS_BAD_ARGUMENTS; 292 if (value != NULL) 293 { 294 char *dup = ptr->clone_utf8(); 295 if (dup == NULL) 296 return STATUS_NO_MEM; 297 298 *value = dup; 299 } 300 301 vArgs.remove(index); 302 delete ptr; 303 return STATUS_OK; 304 } 305 insert_arg(size_t index,const LSPString * value)306 status_t Process::insert_arg(size_t index, const LSPString *value) 307 { 308 if (nStatus != PSTATUS_CREATED) 309 return STATUS_BAD_STATE; 310 if (value == NULL) 311 return STATUS_BAD_ARGUMENTS; 312 313 LSPString *arg = new LSPString(); 314 if (arg == NULL) 315 return STATUS_NO_MEM; 316 317 if (!arg->set(value)) 318 { 319 delete arg; 320 return STATUS_NO_MEM; 321 } 322 if (!vArgs.insert(arg, index)) 323 { 324 delete arg; 325 return STATUS_NO_MEM; 326 } 327 328 return STATUS_OK; 329 } 330 insert_arg(size_t index,const char * value)331 status_t Process::insert_arg(size_t index, const char *value) 332 { 333 if (nStatus != PSTATUS_CREATED) 334 return STATUS_BAD_STATE; 335 if (value == NULL) 336 return STATUS_BAD_ARGUMENTS; 337 338 LSPString *arg = new LSPString(); 339 if (arg == NULL) 340 return STATUS_NO_MEM; 341 342 if (!arg->set_utf8(value)) 343 { 344 delete arg; 345 return STATUS_NO_MEM; 346 } 347 if (!vArgs.insert(arg, index)) 348 { 349 delete arg; 350 return STATUS_NO_MEM; 351 } 352 353 return STATUS_OK; 354 } 355 clear_args()356 status_t Process::clear_args() 357 { 358 if (nStatus != PSTATUS_CREATED) 359 return STATUS_BAD_STATE; 360 destroy_args(&vArgs); 361 return STATUS_OK; 362 } 363 envs() const364 size_t Process::envs() const 365 { 366 return vEnv.size(); 367 } 368 set_env(const LSPString * key,const LSPString * value)369 status_t Process::set_env(const LSPString *key, const LSPString *value) 370 { 371 if (nStatus != PSTATUS_CREATED) 372 return STATUS_BAD_STATE; 373 if ((key == NULL) || (value == NULL)) 374 return STATUS_BAD_ARGUMENTS; 375 if (key->index_of('=') >= 0) 376 return STATUS_BAD_FORMAT; 377 378 envvar_t *var; 379 for (size_t i=0, n=vEnv.size(); i<n; ++i) 380 { 381 var = vEnv.at(i); 382 if (var->name.equals(key)) 383 return (var->value.set(value)) ? STATUS_OK : STATUS_NO_MEM; 384 } 385 386 if ((var = new envvar_t) == NULL) 387 return STATUS_NO_MEM; 388 389 if ((!var->name.set(key)) || (!var->value.set(value))) 390 { 391 delete var; 392 return STATUS_NO_MEM; 393 } 394 if (!vEnv.add(var)) 395 { 396 delete var; 397 return STATUS_NO_MEM; 398 } 399 return STATUS_OK; 400 } 401 set_env(const char * key,const char * value)402 status_t Process::set_env(const char *key, const char *value) 403 { 404 if (nStatus != PSTATUS_CREATED) 405 return STATUS_BAD_STATE; 406 if ((key == NULL) || (value == NULL)) 407 return STATUS_BAD_ARGUMENTS; 408 if (strchr(key, '=') != NULL) 409 return STATUS_BAD_FORMAT; 410 411 LSPString k, v; 412 if ((!k.set_utf8(key)) || (!v.set_utf8(value))) 413 return STATUS_NO_MEM; 414 return set_env(&k, &v); 415 } 416 remove_env(const LSPString * key,LSPString * value)417 status_t Process::remove_env(const LSPString *key, LSPString *value) 418 { 419 if (nStatus != PSTATUS_CREATED) 420 return STATUS_BAD_STATE; 421 if (key == NULL) 422 return STATUS_BAD_ARGUMENTS; 423 424 for (size_t i=0, n=vEnv.size(); i<n; ++i) 425 { 426 envvar_t *var = vEnv.at(i); 427 if (var->name.equals(key)) 428 { 429 if (value != NULL) 430 value->swap(&var->value); 431 delete var; 432 vEnv.remove(i, true); 433 return STATUS_OK; 434 } 435 } 436 437 return STATUS_NOT_FOUND; 438 } 439 remove_env(const char * key,char ** value)440 status_t Process::remove_env(const char *key, char **value) 441 { 442 if (nStatus != PSTATUS_CREATED) 443 return STATUS_BAD_STATE; 444 if (key == NULL) 445 return STATUS_BAD_ARGUMENTS; 446 447 LSPString k; 448 if (!k.set_utf8(key)) 449 return STATUS_NO_MEM; 450 451 for (size_t i=0, n=vEnv.size(); i<n; ++i) 452 { 453 envvar_t *var = vEnv.at(i); 454 if (var->name.equals(&k)) 455 { 456 if (value != NULL) 457 { 458 char *dup = var->value.clone_utf8(); 459 if (dup == NULL) 460 return STATUS_NO_MEM; 461 *value = dup; 462 } 463 delete var; 464 vEnv.remove(i, true); 465 return STATUS_OK; 466 } 467 } 468 469 return STATUS_NOT_FOUND; 470 } 471 remove_env(const char * key,LSPString * value)472 status_t Process::remove_env(const char *key, LSPString *value) 473 { 474 if (nStatus != PSTATUS_CREATED) 475 return STATUS_BAD_STATE; 476 if (key == NULL) 477 return STATUS_BAD_ARGUMENTS; 478 479 LSPString k; 480 if (!k.set_utf8(key)) 481 return STATUS_NO_MEM; 482 483 for (size_t i=0, n=vEnv.size(); i<n; ++i) 484 { 485 envvar_t *var = vEnv.at(i); 486 if (!var->name.equals(&k)) 487 continue; 488 489 if (value != NULL) 490 value->swap(&var->value); 491 delete var; 492 vEnv.remove(i, true); 493 return STATUS_OK; 494 } 495 496 return STATUS_NOT_FOUND; 497 } 498 get_env(const LSPString * key,LSPString * value)499 status_t Process::get_env(const LSPString *key, LSPString *value) 500 { 501 if (key == NULL) 502 return STATUS_BAD_ARGUMENTS; 503 504 if (nStatus != PSTATUS_CREATED) 505 return STATUS_BAD_STATE; 506 if (key == NULL) 507 return STATUS_BAD_ARGUMENTS; 508 509 for (size_t i=0, n=vEnv.size(); i<n; ++i) 510 { 511 envvar_t *var = vEnv.at(i); 512 if (!var->name.equals(key)) 513 continue; 514 515 if (value != NULL) 516 { 517 if (!value->set(&var->value)) 518 return STATUS_NO_MEM; 519 } 520 return STATUS_OK; 521 } 522 523 return STATUS_NOT_FOUND; 524 } 525 get_env(const char * key,LSPString * value)526 status_t Process::get_env(const char *key, LSPString *value) 527 { 528 if (key == NULL) 529 return STATUS_BAD_ARGUMENTS; 530 531 LSPString k; 532 if (!k.set_utf8(key)) 533 return STATUS_NO_MEM; 534 535 for (size_t i=0, n=vEnv.size(); i<n; ++i) 536 { 537 envvar_t *var = vEnv.at(i); 538 if (!var->name.equals(&k)) 539 continue; 540 541 if (value != NULL) 542 { 543 if (!value->set(&var->value)) 544 return STATUS_NO_MEM; 545 } 546 return STATUS_OK; 547 } 548 549 return STATUS_NOT_FOUND; 550 } 551 get_env(const char * key,char ** value)552 status_t Process::get_env(const char *key, char **value) 553 { 554 if (key == NULL) 555 return STATUS_BAD_ARGUMENTS; 556 557 LSPString k; 558 if (!k.set_utf8(key)) 559 return STATUS_NO_MEM; 560 561 for (size_t i=0, n=vEnv.size(); i<n; ++i) 562 { 563 envvar_t *var = vEnv.at(i); 564 if (!var->name.equals(&k)) 565 continue; 566 567 if (value != NULL) 568 { 569 char *dup = var->value.clone_utf8(); 570 if (dup == NULL) 571 return STATUS_NO_MEM; 572 *value = dup; 573 } 574 return STATUS_OK; 575 } 576 577 return STATUS_NOT_FOUND; 578 } 579 read_env(size_t idx,LSPString * key,LSPString * value)580 status_t Process::read_env(size_t idx, LSPString *key, LSPString *value) 581 { 582 if ((key == NULL) && (value == NULL)) 583 return STATUS_BAD_ARGUMENTS; 584 585 envvar_t *var = vEnv.get(idx); 586 if (var == NULL) 587 return STATUS_BAD_ARGUMENTS; 588 589 LSPString tk, tv; 590 if (key != NULL) 591 { 592 if (!tk.set(&var->name)) 593 return STATUS_NO_MEM; 594 if (value != NULL) 595 { 596 if (!tv.set(&var->value)) 597 return STATUS_NO_MEM; 598 value->swap(&tv); 599 } 600 601 key->swap(&tk); 602 return STATUS_OK; 603 } 604 605 if (!tv.set(&var->value)) 606 return STATUS_NO_MEM; 607 608 value->swap(&tv); 609 return STATUS_OK; 610 } 611 read_env(size_t idx,char ** key,char ** value)612 status_t Process::read_env(size_t idx, char **key, char **value) 613 { 614 if ((key == NULL) && (value == NULL)) 615 return STATUS_BAD_ARGUMENTS; 616 617 envvar_t *var = vEnv.get(idx); 618 if (var == NULL) 619 return STATUS_BAD_ARGUMENTS; 620 621 char *tk, *tv; 622 623 if (key != NULL) 624 { 625 if ((tk = var->name.clone_utf8()) == NULL) 626 return STATUS_NO_MEM; 627 628 if (value != NULL) 629 { 630 if ((tv = var->value.clone_utf8()) == NULL) 631 { 632 ::free(tk); 633 return STATUS_NO_MEM; 634 } 635 636 *value = tv; 637 } 638 639 *key = tk; 640 return STATUS_OK; 641 } 642 643 if ((tv = var->value.clone_utf8()) == NULL) 644 return STATUS_NO_MEM; 645 646 *value = tv; 647 return STATUS_OK; 648 } 649 clear_env()650 status_t Process::clear_env() 651 { 652 if (nStatus != PSTATUS_CREATED) 653 return STATUS_BAD_STATE; 654 destroy_env(&vEnv); 655 return STATUS_OK; 656 } 657 status()658 size_t Process::status() 659 { 660 wait(0); // Try to update status 661 return nStatus; 662 } 663 exited()664 bool Process::exited() 665 { 666 return status() == PSTATUS_EXITED; 667 } 668 running()669 bool Process::running() 670 { 671 return status() == PSTATUS_RUNNING; 672 } 673 valid()674 bool Process::valid() 675 { 676 return status() != PSTATUS_ERROR; 677 } 678 process_id() const679 ssize_t Process::process_id() const 680 { 681 switch (nStatus) 682 { 683 case PSTATUS_RUNNING: 684 case PSTATUS_EXITED: 685 return nPID; 686 default: 687 break; 688 } 689 return -1; 690 } 691 exit_code(int * code)692 status_t Process::exit_code(int *code) 693 { 694 if (code == NULL) 695 return STATUS_BAD_ARGUMENTS; 696 697 if (nStatus == PSTATUS_CREATED) 698 return STATUS_BAD_STATE; 699 if (nStatus == PSTATUS_RUNNING) 700 { 701 status_t res = wait(0); 702 if (res != STATUS_OK) 703 return STATUS_BAD_STATE; 704 } 705 706 *code = nExitCode; 707 return STATUS_OK; 708 } 709 710 #ifdef PLATFORM_WINDOWS append_arg_escaped(LSPString * dst,const LSPString * value)711 status_t Process::append_arg_escaped(LSPString *dst, const LSPString *value) 712 { 713 if (value->is_empty()) 714 return (dst->append_ascii("\"\"")) ? STATUS_OK : STATUS_NO_MEM; 715 716 for (size_t i=0, n=value->length(); i<n; ++i) 717 { 718 lsp_wchar_t ch = value->char_at(i); 719 switch (ch) 720 { 721 case ' ': 722 if (!dst->append_ascii("\" \"", 3)) 723 return STATUS_NO_MEM; 724 break; 725 case '"': 726 if (!dst->append_ascii("\\\"", 2)) 727 return STATUS_NO_MEM; 728 break; 729 default: 730 if (!dst->append(ch)) 731 return STATUS_NO_MEM; 732 break; 733 } 734 } 735 736 return STATUS_OK; 737 } 738 build_argv(LSPString * dst)739 status_t Process::build_argv(LSPString *dst) 740 { 741 status_t res = append_arg_escaped(dst, &sCommand); 742 if (res != STATUS_OK) 743 return res; 744 745 for (size_t i=0, n=vArgs.size(); i<n; ++i) 746 { 747 LSPString *arg = vArgs.at(i); 748 if (!dst->append(' ')) 749 return STATUS_NO_MEM; 750 res = append_arg_escaped(dst, arg); 751 if (res != STATUS_OK) 752 return res; 753 } 754 755 return STATUS_OK; 756 } 757 build_envp(LSPString * dst)758 status_t Process::build_envp(LSPString *dst) 759 { 760 for (size_t i=0, n=vEnv.size(); i<n; ++i) 761 { 762 envvar_t *env = vEnv.at(i); 763 if (!dst->append(&env->name)) 764 return STATUS_NO_MEM; 765 if (!dst->append('=')) 766 return STATUS_NO_MEM; 767 if (!dst->append(&env->value)) 768 return STATUS_NO_MEM; 769 if (!dst->append('\0')) 770 return STATUS_NO_MEM; 771 } 772 773 // Note that an ANSI environment block is terminated by two zero bytes: 774 // one for the last string, one more to terminate the block. A Unicode 775 // environment block is terminated by four zero bytes: two for the last 776 // string, two more to terminate the block. 777 return (dst->append('\0')) ? STATUS_OK : STATUS_NO_MEM; 778 } 779 launch()780 status_t Process::launch() 781 { 782 if (nStatus != PSTATUS_CREATED) 783 return STATUS_BAD_STATE; 784 if (sCommand.is_empty()) 785 return STATUS_BAD_STATE; 786 787 // Form argv 788 LSPString argv; 789 status_t res = build_argv(&argv); 790 if (res != STATUS_OK) 791 return res; 792 793 // Form envp 794 LSPString envp; 795 res = build_envp(&envp); 796 if (res != STATUS_OK) 797 return res; 798 799 // Launch child process 800 STARTUPINFOW si; 801 PROCESS_INFORMATION pi; 802 803 ZeroMemory( &si, sizeof(STARTUPINFOW) ); 804 ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) ); 805 si.cb = sizeof(si); 806 807 // Override STDIN, STDOUT, STDERR 808 if (hStdIn != NULL) 809 { 810 si.dwFlags |= STARTF_USESTDHANDLES; 811 si.hStdInput = hStdIn; 812 } 813 if (hStdOut != NULL) 814 { 815 si.dwFlags |= STARTF_USESTDHANDLES; 816 si.hStdOutput = hStdOut; 817 } 818 if (hStdErr != NULL) 819 { 820 si.dwFlags |= STARTF_USESTDHANDLES; 821 si.hStdError = hStdErr; 822 } 823 824 // Prepare buffers 825 WCHAR *wargv = argv.clone_utf16(); 826 if (wargv == NULL) 827 return STATUS_NO_MEM; 828 829 WCHAR *wenvp = envp.clone_utf16(); 830 if (wenvp == NULL) 831 { 832 ::free(wargv); 833 return STATUS_NO_MEM; 834 } 835 836 // Start the child process. 837 if( !::CreateProcessW( 838 sCommand.get_utf16(), // Module name (use command line) 839 wargv, // Command line 840 NULL, // Process handle not inheritable 841 NULL, // Thread handle not inheritable 842 FALSE, // Set handle inheritance to FALSE 843 CREATE_UNICODE_ENVIRONMENT, // Use unicode environment 844 wenvp, // Set-up environment block 845 NULL, // Use parent's starting directory 846 &si, // Pointer to STARTUPINFO structure 847 &pi // Pointer to PROCESS_INFORMATION structure 848 )) 849 { 850 int error = ::GetLastError(); 851 ::fprintf(stderr, "Failed to create child process (%d)\n", error); 852 ::fflush(stderr); 853 854 ::free(wenvp); 855 ::free(wargv); 856 857 return STATUS_UNKNOWN_ERR; 858 } 859 860 // Free resources and close redirected file handles 861 ::free(wenvp); 862 ::free(wargv); 863 close_handles(); 864 865 // Update state 866 hProcess = pi.hProcess; 867 nPID = pi.dwProcessId; 868 nStatus = PSTATUS_RUNNING; 869 870 return res; 871 } 872 wait(wssize_t millis)873 status_t Process::wait(wssize_t millis) 874 { 875 if (nStatus != PSTATUS_RUNNING) 876 return STATUS_BAD_STATE; 877 878 DWORD res = ::WaitForSingleObject(hProcess, (millis < 0) ? INFINITE : millis); 879 switch (res) 880 { 881 case WAIT_OBJECT_0: 882 { 883 // Obtain exit status of process 884 DWORD code = 0; 885 ::GetExitCodeProcess(hProcess, &code); 886 ::CloseHandle(hProcess); 887 hProcess = NULL; 888 889 // Update state 890 nStatus = PSTATUS_EXITED; 891 nExitCode = code; 892 return STATUS_OK; 893 } 894 895 case WAIT_TIMEOUT: 896 return STATUS_OK; 897 898 default: 899 break; 900 } 901 902 return STATUS_UNKNOWN_ERR; 903 } 904 close_handles()905 void Process::close_handles() 906 { 907 if (hStdIn != NULL) 908 { 909 ::CloseHandle(hStdIn); 910 hStdIn = NULL; 911 } 912 if (hStdOut != NULL) 913 { 914 ::CloseHandle(hStdOut); 915 hStdOut = NULL; 916 } 917 if (hStdErr != NULL) 918 { 919 ::CloseHandle(hStdErr); 920 hStdErr = NULL; 921 } 922 } 923 get_stdin()924 io::IOutStream *Process::get_stdin() 925 { 926 if ((nStatus != PSTATUS_CREATED) || (pStdIn != NULL)) 927 return pStdIn; 928 929 HANDLE hRead = NULL, hWrite = NULL; 930 if (!::CreatePipe(&hRead, &hWrite, NULL, 0)) 931 return NULL; 932 933 // Create stream and wrap 934 io::OutFileStream *strm = new io::OutFileStream(); 935 if ((strm == NULL) || (strm->wrap_native(hWrite, true) != STATUS_OK)) 936 { 937 ::CloseHandle(hRead); 938 ::CloseHandle(hWrite); 939 return NULL; 940 } 941 942 // All is OK 943 pStdIn = strm; 944 hStdIn = hRead; 945 946 return pStdIn; 947 } 948 get_stdout()949 io::IInStream *Process::get_stdout() 950 { 951 if ((nStatus != PSTATUS_CREATED) || (pStdOut != NULL)) 952 return pStdOut; 953 954 HANDLE hRead = NULL, hWrite = NULL; 955 if (!::CreatePipe(&hRead, &hWrite, NULL, 0)) 956 return NULL; 957 958 // Create stream and wrap 959 io::InFileStream *strm = new io::InFileStream(); 960 if ((strm == NULL) || (strm->wrap_native(hRead, true) != STATUS_OK)) 961 { 962 ::CloseHandle(hRead); 963 ::CloseHandle(hWrite); 964 return NULL; 965 } 966 967 // All is OK 968 pStdOut = strm; 969 hStdOut = hWrite; 970 971 return pStdOut; 972 } 973 get_stderr()974 io::IInStream *Process::get_stderr() 975 { 976 if ((nStatus != PSTATUS_CREATED) || (pStdErr != NULL)) 977 return pStdErr; 978 979 HANDLE hRead = NULL, hWrite = NULL; 980 if (!::CreatePipe(&hRead, &hWrite, NULL, 0)) 981 return NULL; 982 983 // Create stream and wrap 984 io::InFileStream *strm = new io::InFileStream(); 985 if ((strm == NULL) || (strm->wrap_native(hRead, true) != STATUS_OK)) 986 { 987 ::CloseHandle(hRead); 988 ::CloseHandle(hWrite); 989 return NULL; 990 } 991 992 // All is OK 993 pStdErr = strm; 994 hStdErr = hWrite; 995 996 return pStdErr; 997 } 998 #else drop_data(cvector<char> * v)999 static void drop_data(cvector<char> *v) 1000 { 1001 for (size_t i=0, n=v->size(); i<n; ++i) 1002 { 1003 char *ptr = v->at(i); 1004 if (ptr != NULL) 1005 ::free(ptr); 1006 } 1007 v->flush(); 1008 } 1009 close_handles()1010 void Process::close_handles() 1011 { 1012 if (hStdIn >= 0) 1013 { 1014 ::close(hStdIn); 1015 hStdIn = -1; 1016 } 1017 if (hStdOut >= 0) 1018 { 1019 ::close(hStdOut); 1020 hStdOut = -1; 1021 } 1022 if (hStdErr >= 0) 1023 { 1024 ::close(hStdErr); 1025 hStdErr = -1; 1026 } 1027 } 1028 build_argv(cvector<char> * dst)1029 status_t Process::build_argv(cvector<char> *dst) 1030 { 1031 char *s; 1032 1033 // Add command as argv[0] 1034 if ((s = sCommand.clone_native()) == NULL) 1035 return STATUS_NO_MEM; 1036 if (!dst->add(s)) 1037 return STATUS_NO_MEM; 1038 1039 // Add all other arguments 1040 for (size_t i=0, n=vArgs.size(); i<n; ++i) 1041 { 1042 LSPString *arg = vArgs.at(i); 1043 if (arg == NULL) 1044 continue; 1045 1046 if ((s = arg->clone_native()) == NULL) 1047 return STATUS_NO_MEM; 1048 if (!dst->add(s)) 1049 { 1050 ::free(s); 1051 return STATUS_NO_MEM; 1052 } 1053 } 1054 1055 // Add terminator 1056 return (dst->add(static_cast<char *>(NULL))) ? STATUS_OK : STATUS_NO_MEM; 1057 } 1058 build_envp(cvector<char> * dst)1059 status_t Process::build_envp(cvector<char> *dst) 1060 { 1061 char *s; 1062 1063 LSPString tmp; 1064 for (size_t i=0, n=vEnv.size(); i<n; ++i) 1065 { 1066 envvar_t *var = vEnv.at(i); 1067 if (var == NULL) 1068 continue; 1069 if (!tmp.set(&var->name)) 1070 return STATUS_NO_MEM; 1071 if (!tmp.append('=')) 1072 return STATUS_NO_MEM; 1073 if (!tmp.append(&var->value)) 1074 return STATUS_NO_MEM; 1075 1076 if ((s = tmp.clone_native()) == NULL) 1077 return STATUS_NO_MEM; 1078 1079 if (!dst->add(s)) 1080 { 1081 ::free(s); 1082 return STATUS_NO_MEM; 1083 } 1084 } 1085 return (dst->add(static_cast<char *>(NULL))) ? STATUS_OK : STATUS_NO_MEM; 1086 } 1087 spawn_process(const char * cmd,char * const * argv,char * const * envp)1088 status_t Process::spawn_process(const char *cmd, char * const *argv, char * const *envp) 1089 { 1090 lsp_trace("Creating child process using posix_spawn..."); 1091 1092 // Initialize spawn routines 1093 posix_spawnattr_t attr; 1094 if (::posix_spawnattr_init(&attr)) 1095 return STATUS_UNKNOWN_ERR; 1096 1097 #if defined(__USE_GNU) || defined(POSIX_SPAWN_USEVFORK) 1098 // Prever vfork() over fork() 1099 if (::posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK)) 1100 { 1101 ::posix_spawnattr_destroy(&attr); 1102 return STATUS_UNKNOWN_ERR; 1103 } 1104 #endif /* __USE_GNU */ 1105 1106 posix_spawn_file_actions_t actions; 1107 if (::posix_spawn_file_actions_init(&actions)) 1108 { 1109 ::posix_spawnattr_destroy(&attr); 1110 return STATUS_UNKNOWN_ERR; 1111 } 1112 1113 // Override STDIN, STDOUT, STDERR 1114 if (hStdIn >= 0) 1115 { 1116 if (::posix_spawn_file_actions_adddup2(&actions, hStdIn, STDIN_FILENO)) 1117 { 1118 ::posix_spawnattr_destroy(&attr); 1119 return STATUS_UNKNOWN_ERR; 1120 } 1121 if (::posix_spawn_file_actions_addclose(&actions, hStdIn)) 1122 { 1123 ::posix_spawnattr_destroy(&attr); 1124 return STATUS_UNKNOWN_ERR; 1125 } 1126 } 1127 1128 if (hStdOut >= 0) 1129 { 1130 if (::posix_spawn_file_actions_adddup2(&actions, hStdOut, STDOUT_FILENO)) 1131 { 1132 ::posix_spawnattr_destroy(&attr); 1133 return STATUS_UNKNOWN_ERR; 1134 } 1135 if (::posix_spawn_file_actions_addclose(&actions, hStdOut)) 1136 { 1137 ::posix_spawnattr_destroy(&attr); 1138 return STATUS_UNKNOWN_ERR; 1139 } 1140 } 1141 1142 if (hStdErr >= 0) 1143 { 1144 if (::posix_spawn_file_actions_adddup2(&actions, hStdErr, STDERR_FILENO)) 1145 { 1146 ::posix_spawnattr_destroy(&attr); 1147 return STATUS_UNKNOWN_ERR; 1148 } 1149 if (::posix_spawn_file_actions_addclose(&actions, hStdErr)) 1150 { 1151 ::posix_spawnattr_destroy(&attr); 1152 return STATUS_UNKNOWN_ERR; 1153 } 1154 } 1155 1156 // Perform posix_spawn() 1157 pid_t pid; 1158 status_t res = STATUS_OK; 1159 while (true) 1160 { 1161 int x = ::posix_spawnp(&pid, cmd, &actions, &attr, argv, envp); 1162 switch (x) 1163 { 1164 case 0: break; 1165 case EAGAIN: continue; 1166 case ENOMEM: res = STATUS_NO_MEM; break; 1167 default: res = STATUS_UNKNOWN_ERR; break; 1168 } 1169 break; 1170 } 1171 1172 // Success execution? 1173 if (res == STATUS_OK) 1174 { 1175 nPID = pid; 1176 nStatus = PSTATUS_RUNNING; 1177 } 1178 1179 ::posix_spawn_file_actions_destroy(&actions); 1180 ::posix_spawnattr_destroy(&attr); 1181 1182 return res; 1183 } 1184 execve_process(const char * cmd,char * const * argv,char * const * envp,bool soft_exit)1185 void Process::execve_process(const char *cmd, char * const *argv, char * const *envp, bool soft_exit) 1186 { 1187 // Override STDIN, STDOUT, STDERR 1188 if (hStdIn >= 0) 1189 { 1190 ::dup2(hStdIn, STDIN_FILENO); 1191 ::close(hStdIn); 1192 hStdIn = -1; 1193 } 1194 1195 if (hStdOut >= 0) 1196 { 1197 ::dup2(hStdOut, STDOUT_FILENO); 1198 ::close(hStdOut); 1199 hStdOut = -1; 1200 } 1201 1202 if (hStdErr >= 0) 1203 { 1204 ::dup2(hStdErr, STDERR_FILENO); 1205 ::close(hStdErr); 1206 hStdErr = -1; 1207 } 1208 1209 // Launch the process 1210 ::execve(cmd, argv, envp); 1211 1212 lsp_trace("execve failed for pid=%d\n", int(getpid())); 1213 1214 // Return error only if ::execvpe failed 1215 if (soft_exit) 1216 ::_exit(STATUS_UNKNOWN_ERR); 1217 else 1218 ::exit(STATUS_UNKNOWN_ERR); 1219 } 1220 vfork_process(const char * cmd,char * const * argv,char * const * envp)1221 status_t Process::vfork_process(const char *cmd, char * const *argv, char * const *envp) 1222 { 1223 lsp_trace("Creating child process using vfork()..."); 1224 errno = 0; 1225 pid_t pid = ::vfork(); 1226 1227 // Failed to fork()? 1228 if (pid < 0) 1229 { 1230 int code = errno; 1231 switch (code) 1232 { 1233 case ENOMEM: return STATUS_NO_MEM; 1234 case EAGAIN: return STATUS_NO_MEM; 1235 default: return STATUS_UNKNOWN_ERR; 1236 } 1237 } 1238 1239 // The child process stuff 1240 if (pid == 0) 1241 execve_process(cmd, argv, envp, true); 1242 1243 // The parent process stuff 1244 nPID = pid; 1245 nStatus = PSTATUS_RUNNING; 1246 1247 return STATUS_OK; 1248 } 1249 fork_process(const char * cmd,char * const * argv,char * const * envp)1250 status_t Process::fork_process(const char *cmd, char * const *argv, char * const *envp) 1251 { 1252 lsp_trace("Creating child process using fork()..."); 1253 errno = 0; 1254 pid_t pid = ::fork(); 1255 1256 // Failed to fork()? 1257 if (pid < 0) 1258 { 1259 int code = errno; 1260 switch (code) 1261 { 1262 case ENOMEM: return STATUS_NO_MEM; 1263 case EAGAIN: return STATUS_NO_MEM; 1264 default: return STATUS_UNKNOWN_ERR; 1265 } 1266 } 1267 1268 // The child process stuff 1269 if (pid == 0) 1270 execve_process(cmd, argv, envp, false); 1271 1272 // The parent process stuff 1273 nPID = pid; 1274 nStatus = PSTATUS_RUNNING; 1275 1276 return STATUS_OK; 1277 } 1278 launch()1279 status_t Process::launch() 1280 { 1281 if (nStatus != PSTATUS_CREATED) 1282 return STATUS_BAD_STATE; 1283 if (sCommand.is_empty()) 1284 return STATUS_BAD_STATE; 1285 1286 // Copy command 1287 char *cmd = sCommand.clone_native(); 1288 if (cmd == NULL) 1289 return STATUS_NO_MEM; 1290 1291 // Form argv 1292 cvector<char> argv; 1293 status_t res = build_argv(&argv); 1294 if (res != STATUS_OK) 1295 { 1296 ::free(cmd); 1297 drop_data(&argv); 1298 return res; 1299 } 1300 1301 // Form envp 1302 cvector<char> envp; 1303 res = build_envp(&envp); 1304 if (res == STATUS_OK) 1305 { 1306 // Different behaviour, depending on POSIX_SPAWN_USEVFORK presence 1307 #if defined(__USE_GNU) || defined(POSIX_SPAWN_USEVFORK) 1308 res = spawn_process(cmd, argv.get_array(), envp.get_array()); 1309 if (res != STATUS_OK) 1310 res = vfork_process(cmd, argv.get_array(), envp.get_array()); 1311 #else 1312 res = vfork_process(cmd, argv.get_array(), envp.get_array()); 1313 if (res != STATUS_OK) 1314 res = spawn_process(cmd, argv.get_array(), envp.get_array()); 1315 #endif /* __USE_GNU */ 1316 1317 if (res != STATUS_OK) 1318 res = fork_process(cmd, argv.get_array(), envp.get_array()); 1319 } 1320 1321 // Close redirected file handles 1322 if (res == STATUS_OK) 1323 close_handles(); 1324 1325 // Free temporary data and return result 1326 ::free(cmd); 1327 drop_data(&argv); 1328 drop_data(&envp); 1329 return res; 1330 } 1331 wait(wssize_t millis)1332 status_t Process::wait(wssize_t millis) 1333 { 1334 if (nStatus != PSTATUS_RUNNING) 1335 return STATUS_BAD_STATE; 1336 1337 int status; 1338 1339 if (millis < 0) 1340 { 1341 do 1342 { 1343 // Wait for child process 1344 pid_t pid = ::waitpid(nPID, &status, WUNTRACED | WCONTINUED); 1345 if (pid < 0) 1346 { 1347 status = errno; 1348 if (status == EINTR) 1349 continue; 1350 return STATUS_UNKNOWN_ERR; 1351 } 1352 } while ((!WIFEXITED(status)) && (!WIFSIGNALED(status))); 1353 1354 nStatus = PSTATUS_EXITED; 1355 nExitCode = WEXITSTATUS(status); 1356 } 1357 else if (millis == 0) 1358 { 1359 // Wait for child process 1360 pid_t pid = ::waitpid(nPID, &status, WUNTRACED | WCONTINUED | WNOHANG); 1361 if (pid < 0) 1362 { 1363 status = errno; 1364 return (status == EINTR) ? STATUS_OK : STATUS_UNKNOWN_ERR; 1365 } 1366 1367 // Child has exited? 1368 if ((pid == nPID) && ((WIFEXITED(status)) || (WIFSIGNALED(status)))) 1369 { 1370 nStatus = PSTATUS_EXITED; 1371 nExitCode = WEXITSTATUS(status); 1372 } 1373 } 1374 else 1375 { 1376 struct timespec ts; 1377 wssize_t deadline, left; 1378 ::clock_gettime(CLOCK_REALTIME, &ts); 1379 deadline = millis + (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); 1380 1381 while (true) 1382 { 1383 // Wait for child process 1384 pid_t pid = ::waitpid(nPID, &status, WUNTRACED | WCONTINUED | WNOHANG); 1385 if (pid < 0) 1386 { 1387 status = errno; 1388 if (status == EINTR) 1389 continue; 1390 return STATUS_UNKNOWN_ERR; 1391 } 1392 1393 // Child process has exited? 1394 if ((pid == nPID) && ((WIFEXITED(status)) || (WIFSIGNALED(status)))) 1395 break; 1396 1397 // Get time 1398 ::clock_gettime(CLOCK_REALTIME, &ts); 1399 left = deadline - (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); 1400 if (left <= 0) 1401 return STATUS_OK; // Just leave, no changes 1402 1403 // Perform short sleep 1404 ts.tv_sec = 0; 1405 ts.tv_nsec = ((left > 50) ? 50 : left) * 1000000; 1406 ::nanosleep(&ts, NULL); 1407 } 1408 1409 nStatus = PSTATUS_EXITED; 1410 nExitCode = WEXITSTATUS(status); 1411 } 1412 1413 return STATUS_OK; 1414 } 1415 get_stdin()1416 io::IOutStream *Process::get_stdin() 1417 { 1418 if ((nStatus != PSTATUS_CREATED) || (pStdIn != NULL)) 1419 return pStdIn; 1420 1421 int fd[2]; // rw 1422 if (::pipe(fd) != 0) 1423 return NULL; 1424 1425 // Create stream and wrap 1426 io::OutFileStream *strm = new io::OutFileStream(); 1427 if ((strm == NULL) || (strm->wrap_native(fd[1], true) != STATUS_OK)) 1428 { 1429 ::close(fd[0]); 1430 ::close(fd[1]); 1431 return NULL; 1432 } 1433 1434 // All is OK 1435 pStdIn = strm; 1436 hStdIn = fd[0]; 1437 1438 return pStdIn; 1439 } 1440 get_stdout()1441 io::IInStream *Process::get_stdout() 1442 { 1443 if ((nStatus != PSTATUS_CREATED) || (pStdOut != NULL)) 1444 return pStdOut; 1445 1446 int fd[2]; // rw 1447 if (::pipe(fd) != 0) 1448 return NULL; 1449 1450 // Create stream and wrap 1451 io::InFileStream *strm = new io::InFileStream(); 1452 if ((strm == NULL) || (strm->wrap_native(fd[0], true) != STATUS_OK)) 1453 { 1454 ::close(fd[0]); 1455 ::close(fd[1]); 1456 return NULL; 1457 } 1458 1459 // All is OK 1460 pStdOut = strm; 1461 hStdOut = fd[1]; 1462 1463 return pStdOut; 1464 } 1465 get_stderr()1466 io::IInStream *Process::get_stderr() 1467 { 1468 if ((nStatus != PSTATUS_CREATED) || (pStdErr != NULL)) 1469 return pStdErr; 1470 1471 int fd[2]; // rw 1472 if (::pipe(fd) != 0) 1473 return NULL; 1474 1475 // Create stream and wrap 1476 io::InFileStream *strm = new io::InFileStream(); 1477 if ((strm == NULL) || (strm->wrap_native(fd[0], true) != STATUS_OK)) 1478 { 1479 ::close(fd[0]); 1480 ::close(fd[1]); 1481 return NULL; 1482 } 1483 1484 // All is OK 1485 pStdErr = strm; 1486 hStdErr = fd[1]; 1487 1488 return pStdErr; 1489 } 1490 1491 1492 #endif /* PLATFORM_WINDOWS */ 1493 copy_env()1494 status_t Process::copy_env() 1495 { 1496 cvector<envvar_t> env; 1497 LSPString k, v; 1498 1499 #ifdef PLATFORM_WINDOWS 1500 for (WCHAR *item = GetEnvironmentStringsW(); (*item) != 0; ) 1501 { 1502 size_t len = wcslen(item); 1503 1504 // Fetch environment variable 1505 if (!k.set_utf16(item, len)) 1506 { 1507 destroy_env(&env); 1508 return STATUS_NO_MEM; 1509 } 1510 item += (len + 1); // length + terminating character 1511 #else 1512 for (char **item=environ; *item != NULL; ++item) 1513 { 1514 // Fetch environment variable 1515 if (!k.set_native(*item)) 1516 { 1517 destroy_env(&env); 1518 return STATUS_NO_MEM; 1519 } 1520 #endif /* PLATFORM_WINDOWS */ 1521 1522 // Parse record 1523 ssize_t idx = k.index_of('='); 1524 if (idx >= 0) 1525 { 1526 if (!v.set(&k, idx+1)) 1527 { 1528 destroy_env(&env); 1529 return STATUS_NO_MEM; 1530 } 1531 if (!k.truncate(idx)) 1532 { 1533 destroy_env(&env); 1534 return STATUS_NO_MEM; 1535 } 1536 } 1537 1538 // Allocate && add env var 1539 envvar_t *var = new envvar_t(); 1540 if ((var == NULL) || (!env.add(var))) 1541 { 1542 destroy_env(&env); 1543 return STATUS_NO_MEM; 1544 } 1545 1546 // Store value to env 1547 var->name.swap(&k); 1548 var->value.swap(&v); 1549 1550 } // for 1551 1552 // Commit result 1553 vEnv.swap_data(&env); 1554 destroy_env(&env); 1555 1556 return STATUS_OK; 1557 } 1558 } /* namespace ipc */ 1559 } /* namespace lsp */ 1560