/ src / env.c
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