hooks.c revision 1031614c095f00454326deb460a83381e98d5166
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2012, 2013 Petr Machata 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 * 02110-1301 USA 19 */ 20 21#define _POSIX_C_SOURCE 200809L 22#include <sys/types.h> 23#include <alloca.h> 24#include <errno.h> 25#include <pwd.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <unistd.h> 30 31#include "backend.h" 32#include "dict.h" 33#include "options.h" 34#include "sysdep.h" 35#include "vect.h" 36 37static char * 38append(const char *str1, const char *str2) 39{ 40 char *ret = malloc(strlen(str1) + strlen(str2) + 2); 41 if (ret == NULL) 42 return ret; 43 /* BEGIN android-changed */ 44 strcpy(ret, str1); 45 strcat(ret, str2); 46 /* END android-changed */ 47 return ret; 48} 49 50static void 51add_dir(struct vect *dirs, const char *str1, const char *str2) 52{ 53 char *dir = append(str1, str2); 54 if (dir != NULL 55 && VECT_PUSHBACK(dirs, &dir) < 0) 56 fprintf(stderr, 57 "Couldn't store candidate config directory %s%s: %s.\n", 58 str1, str2, strerror(errno)); 59} 60 61static enum callback_status 62add_dir_component_cb(struct opt_F_t *entry, void *data) 63{ 64 struct vect *dirs = data; 65 if (opt_F_get_kind(entry) == OPT_F_DIR) 66 add_dir(dirs, entry->pathname, "/ltrace"); 67 return CBS_CONT; 68} 69 70static void 71destroy_opt_F_cb(struct opt_F_t *entry, void *data) 72{ 73 opt_F_destroy(entry); 74} 75 76static char *g_home_dir = NULL; 77 78int 79os_get_config_dirs(int private, const char ***retp) 80{ 81 /* Vector of char *. Contains first pointers to local paths, 82 * then NULL, then pointers to system paths, then another 83 * NULL. SYS_START points to the beginning of the second 84 * part. */ 85 static struct vect dirs; 86 static ssize_t sys_start = 0; 87 88again: 89 if (sys_start != 0) { 90 if (sys_start == -1) 91 return -1; 92 93 if (retp != NULL) { 94 if (private) 95 *retp = VECT_ELEMENT(&dirs, const char *, 0); 96 else 97 *retp = VECT_ELEMENT(&dirs, const char *, 98 (size_t)sys_start); 99 } 100 101 return 0; 102 } 103 104 VECT_INIT(&dirs, char *); 105 106 char *home = getenv("HOME"); 107 if (home == NULL) { 108 struct passwd *pwd = getpwuid(getuid()); 109 if (pwd != NULL) 110 home = pwd->pw_dir; 111 } 112 113 size_t home_len = home != NULL ? strlen(home) : 0; 114 115 /* The values coming from getenv and getpwuid may not be 116 * persistent. */ 117 if (home != NULL) { 118 free(g_home_dir); 119 g_home_dir = strdup(home); 120 if (g_home_dir != NULL) { 121 home = g_home_dir; 122 } else { 123 char *tmp = alloca(home_len + 1); 124 strcpy(tmp, home); 125 home = tmp; 126 } 127 } 128 129 char *xdg_home = getenv("XDG_CONFIG_HOME"); 130 if (xdg_home == NULL && home != NULL) { 131 xdg_home = alloca(home_len + sizeof "/.config"); 132 sprintf(xdg_home, "%s/.config", home); 133 } 134 if (xdg_home != NULL) 135 add_dir(&dirs, xdg_home, "/ltrace"); 136 if (home != NULL) 137 add_dir(&dirs, home, "/.ltrace"); 138 139 char *delim = NULL; 140 if (VECT_PUSHBACK(&dirs, &delim) < 0) { 141 fail: 142 /* This can't work :( */ 143 fprintf(stderr, 144 "Couldn't initialize list of config directories: %s.\n", 145 strerror(errno)); 146 VECT_DESTROY(&dirs, const char *, dict_dtor_string, NULL); 147 sys_start = -1; 148 return -1; 149 } 150 sys_start = vect_size(&dirs); 151 152 /* """preference-ordered set of base directories to search for 153 * configuration files in addition to the $XDG_CONFIG_HOME 154 * base directory. The directories in $XDG_CONFIG_DIRS should 155 * be seperated with a colon ':'.""" */ 156 char *xdg_sys = getenv("XDG_CONFIG_DIRS"); 157 if (xdg_sys != NULL) { 158 struct vect v; 159 VECT_INIT(&v, struct opt_F_t); 160 if (parse_colon_separated_list(xdg_sys, &v) < 0 161 || VECT_EACH(&v, struct opt_F_t, NULL, 162 add_dir_component_cb, &dirs) != NULL) 163 fprintf(stderr, 164 "Error processing $XDG_CONFIG_DIRS '%s': %s\n", 165 xdg_sys, strerror(errno)); 166 VECT_DESTROY(&v, struct opt_F_t, destroy_opt_F_cb, NULL); 167 } 168 169 /* PKGDATADIR is passed via -D when compiling. */ 170 const char *pkgdatadir = PKGDATADIR; 171 if (pkgdatadir != NULL) 172 add_dir(&dirs, pkgdatadir, ""); 173 174 if (VECT_PUSHBACK(&dirs, &delim) < 0) 175 goto fail; 176 177 goto again; 178} 179 180int 181os_get_ltrace_conf_filenames(struct vect *retp) 182{ 183 char *homepath = NULL; 184 char *syspath = NULL; 185 186#define FN ".ltrace.conf" 187 if (g_home_dir == NULL) 188 os_get_config_dirs(0, NULL); 189 190 if (g_home_dir != NULL) { 191 homepath = malloc(strlen(g_home_dir) + 1 + sizeof FN); 192 if (homepath == NULL 193 || sprintf(homepath, "%s/%s", g_home_dir, FN) < 0) { 194 fail: 195 free(syspath); 196 free(homepath); 197 return -1; 198 } 199 } 200 201 /* SYSCONFDIR is passed via -D when compiling. */ 202 const char *sysconfdir = SYSCONFDIR; 203 if (sysconfdir != NULL && *sysconfdir != '\0') { 204 /* No +1, we skip the initial period. */ 205 syspath = malloc(strlen(sysconfdir) + sizeof FN); 206 if (syspath == NULL 207 || sprintf(syspath, "%s/%s", sysconfdir, FN + 1) < 0) 208 goto fail; 209 } 210 211 if (VECT_PUSHBACK(retp, &homepath) < 0 212 || VECT_PUSHBACK(retp, &syspath) < 0) 213 goto fail; 214 215 return 0; 216} 217