| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdarg.h> |
| #include <ctype.h> |
| |
| #include "Charmonizer/Core/Compiler.h" |
| #include "Charmonizer/Core/Util.h" |
| #include "Charmonizer/Core/ConfWriter.h" |
| #include "Charmonizer/Core/OperatingSystem.h" |
| |
| #define CHAZ_OS_TARGET_PATH "_charmonizer_target" |
| #define CHAZ_OS_NAME_MAX 31 |
| |
| static struct { |
| char name[CHAZ_OS_NAME_MAX+1]; |
| char dev_null[20]; |
| char dir_sep[2]; |
| char exe_ext[5]; |
| char shared_lib_ext[7]; |
| char local_command_start[3]; |
| int shell_type; |
| } chaz_OS = { "", "", "", "", "", "", 0 }; |
| |
| void |
| chaz_OS_init(void) { |
| if (chaz_Util_verbosity) { |
| printf("Initializing Charmonizer/Core/OperatingSystem...\n"); |
| } |
| |
| if (chaz_Util_verbosity) { |
| printf("Trying to find a bit-bucket a la /dev/null...\n"); |
| } |
| |
| /* Detect shell based on whether the bitbucket is "/dev/null" or "nul". */ |
| if (chaz_Util_can_open_file("/dev/null")) { |
| char *uname; |
| size_t uname_len; |
| size_t i; |
| |
| chaz_OS.shell_type = CHAZ_OS_POSIX; |
| |
| /* Detect Unix name. */ |
| uname = chaz_OS_run_and_capture("uname", &uname_len); |
| for (i = 0; i < CHAZ_OS_NAME_MAX && i < uname_len; i++) { |
| char c = uname[i]; |
| if (!c || isspace(c)) { break; } |
| chaz_OS.name[i] = tolower(c); |
| } |
| if (i > 0) { chaz_OS.name[i] = '\0'; } |
| else { strcpy(chaz_OS.name, "unknown_unix"); } |
| free(uname); |
| |
| strcpy(chaz_OS.dev_null, "/dev/null"); |
| strcpy(chaz_OS.dir_sep, "/"); |
| strcpy(chaz_OS.exe_ext, ""); |
| if (memcmp(chaz_OS.name, "darwin", 6) == 0) { |
| strcpy(chaz_OS.shared_lib_ext, ".dylib"); |
| } |
| else if (memcmp(chaz_OS.name, "cygwin", 6) == 0) { |
| strcpy(chaz_OS.shared_lib_ext, ".dll"); |
| } |
| else { |
| strcpy(chaz_OS.shared_lib_ext, ".so"); |
| } |
| strcpy(chaz_OS.local_command_start, "./"); |
| } |
| else if (chaz_Util_can_open_file("nul")) { |
| strcpy(chaz_OS.name, "windows"); |
| strcpy(chaz_OS.dev_null, "nul"); |
| strcpy(chaz_OS.dir_sep, "\\"); |
| strcpy(chaz_OS.exe_ext, ".exe"); |
| strcpy(chaz_OS.shared_lib_ext, ".dll"); |
| strcpy(chaz_OS.local_command_start, ".\\"); |
| chaz_OS.shell_type = CHAZ_OS_CMD_EXE; |
| } |
| else { |
| /* Bail out because we couldn't find anything like /dev/null. */ |
| chaz_Util_die("Couldn't find anything like /dev/null"); |
| } |
| } |
| |
| const char* |
| chaz_OS_name(void) { |
| return chaz_OS.name; |
| } |
| |
| int |
| chaz_OS_is_darwin(void) { |
| return memcmp(chaz_OS.name, "darwin", 6) == 0; |
| } |
| |
| int |
| chaz_OS_is_cygwin(void) { |
| return memcmp(chaz_OS.name, "cygwin", 6) == 0; |
| } |
| |
| const char* |
| chaz_OS_exe_ext(void) { |
| return chaz_OS.exe_ext; |
| } |
| |
| const char* |
| chaz_OS_shared_lib_ext(void) { |
| return chaz_OS.shared_lib_ext; |
| } |
| |
| const char* |
| chaz_OS_dev_null(void) { |
| return chaz_OS.dev_null; |
| } |
| |
| const char* |
| chaz_OS_dir_sep(void) { |
| return chaz_OS.dir_sep; |
| } |
| |
| int |
| chaz_OS_shell_type(void) { |
| return chaz_OS.shell_type; |
| } |
| |
| int |
| chaz_OS_remove(const char *name) { |
| /* |
| * On Windows it can happen that another process, typically a |
| * virus scanner, still has an open handle on the file. This can |
| * make the subsequent recreation of a file with the same name |
| * fail. As a workaround, files are renamed to a random name |
| * before deletion. |
| */ |
| int retval; |
| |
| static const size_t num_random_chars = 16; |
| |
| size_t name_len = strlen(name); |
| size_t i; |
| char *temp_name = (char*)malloc(name_len + num_random_chars + 1); |
| |
| strcpy(temp_name, name); |
| for (i = 0; i < num_random_chars; i++) { |
| temp_name[name_len+i] = 'A' + rand() % 26; |
| } |
| temp_name[name_len+num_random_chars] = '\0'; |
| |
| if (rename(name, temp_name) == 0) { |
| retval = !remove(temp_name); |
| } |
| else { |
| // Error during rename, remove using old name. |
| retval = !remove(name); |
| } |
| |
| free(temp_name); |
| return retval; |
| } |
| |
| int |
| chaz_OS_run_local_redirected(const char *command, const char *path) { |
| char *local_command |
| = chaz_Util_join("", chaz_OS.local_command_start, command, NULL); |
| int retval = chaz_OS_run_redirected(local_command, path); |
| free(local_command); |
| return retval; |
| } |
| |
| int |
| chaz_OS_run_quietly(const char *command) { |
| return chaz_OS_run_redirected(command, chaz_OS.dev_null); |
| } |
| |
| int |
| chaz_OS_run_redirected(const char *command, const char *path) { |
| int retval = 1; |
| char *quiet_command = NULL; |
| if (chaz_OS.shell_type == CHAZ_OS_POSIX |
| || chaz_OS.shell_type == CHAZ_OS_CMD_EXE |
| ) { |
| quiet_command = chaz_Util_join(" ", command, ">", path, "2>&1", NULL); |
| } |
| else { |
| chaz_Util_die("Don't know the shell type"); |
| } |
| retval = system(quiet_command); |
| free(quiet_command); |
| return retval; |
| } |
| |
| char* |
| chaz_OS_run_and_capture(const char *command, size_t *output_len) { |
| char *output; |
| chaz_OS_run_redirected(command, CHAZ_OS_TARGET_PATH); |
| output = chaz_Util_slurp_file(CHAZ_OS_TARGET_PATH, output_len); |
| chaz_Util_remove_and_verify(CHAZ_OS_TARGET_PATH); |
| return output; |
| } |
| |
| void |
| chaz_OS_mkdir(const char *filepath) { |
| char *command = NULL; |
| if (chaz_OS.shell_type == CHAZ_OS_POSIX |
| || chaz_OS.shell_type == CHAZ_OS_CMD_EXE |
| ) { |
| command = chaz_Util_join(" ", "mkdir", filepath, NULL); |
| } |
| else { |
| chaz_Util_die("Don't know the shell type"); |
| } |
| chaz_OS_run_quietly(command); |
| free(command); |
| } |
| |
| void |
| chaz_OS_rmdir(const char *filepath) { |
| char *command = NULL; |
| if (chaz_OS.shell_type == CHAZ_OS_POSIX) { |
| command = chaz_Util_join(" ", "rmdir", filepath, NULL); |
| } |
| else if (chaz_OS.shell_type == CHAZ_OS_CMD_EXE) { |
| command = chaz_Util_join(" ", "rmdir", "/q", filepath, NULL); |
| } |
| else { |
| chaz_Util_die("Don't know the shell type"); |
| } |
| chaz_OS_run_quietly(command); |
| free(command); |
| } |
| |