env.c
1 /* Copyright (c) 2018 Pablo Marcos Oltra <pablo.marcos.oltra@gmail.com> 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to deal 5 * in the Software without restriction, including without limitation the rights 6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 * copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in all 11 * copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 * SOFTWARE. 20 */ 21 22 #define _GNU_SOURCE 23 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 #include <stdio.h> 28 #include <errno.h> 29 30 #include "env.h" 31 32 static char** env_allocate(size_t size) { 33 return calloc(size + 1, sizeof(char*)); 34 } 35 36 void env_free(char* const *env) { 37 size_t len = 0; 38 while (env[len] != 0) { 39 free(env[len]); 40 len++; 41 } 42 free((char**)env); 43 } 44 45 pid_t get_parent_pid() { 46 pid_t ppid = 0; 47 char *s_ppid = getenv("PPID"); 48 49 if(s_ppid) { 50 ppid = atoi(s_ppid); 51 } 52 53 if (!ppid) { 54 ppid = getppid(); 55 } 56 57 return ppid; 58 } 59 60 static size_t get_number_of_variables(FILE *file, char **buffer, size_t *len) { 61 size_t number = 0; 62 63 if (getline(buffer, len, file) < 0) 64 return -1; 65 66 char *ptr = *buffer; 67 while (ptr < *buffer + *len) { 68 size_t var_len = strlen(ptr); 69 ptr += var_len + 1; 70 if (var_len == 0) 71 break; 72 number++; 73 } 74 75 return number != 0 ? (ssize_t)number : -1; 76 } 77 78 static char* const* env_from_buffer(FILE *file) { 79 char *buffer = NULL; 80 size_t len = 0; 81 size_t num_vars = get_number_of_variables(file, &buffer, &len); 82 char** env = env_allocate(num_vars); 83 84 size_t n = 0; 85 char *ptr = buffer; 86 while (ptr < buffer + len && n < num_vars) { 87 size_t var_len = strlen(ptr); 88 if (var_len == 0) 89 break; 90 91 env[n] = calloc(sizeof(char*), var_len + 1); 92 strncpy(env[n], ptr, var_len + 1); 93 DEBUG("\tenv var copied: %s\n", env[n]); 94 ptr += var_len + 1; 95 n++; 96 } 97 free(buffer); 98 99 return env; 100 } 101 102 static char* const* read_env_from_process(pid_t pid) { 103 char buffer[256] = {0}; 104 105 snprintf(buffer, sizeof(buffer), "/proc/%d/environ", pid); 106 DEBUG("Reading env from parent process: %s\n", buffer); 107 FILE *env_file = fopen(buffer, "r"); 108 if (!env_file) { 109 DEBUG("Error reading file: %s (%s)\n", buffer, strerror(errno)); 110 return NULL; 111 } 112 113 char* const* env = env_from_buffer(env_file); 114 fclose(env_file); 115 116 return env; 117 } 118 119 char* const* read_parent_env() { 120 pid_t ppid = get_parent_pid(); 121 return read_env_from_process(ppid); 122 } 123 124 #ifdef ENV_TEST 125 int main() { 126 putenv("APPIMAGE_CHECKRT_DEBUG=1"); 127 DEBUG("ENV TEST\n"); 128 char **env = NULL; 129 read_parent_env(&env); 130 131 return 0; 132 } 133 #endif 134