hooks.c revision 33f0ca5350ccc9ded3a2bfa82a988e9bd640233f
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 "sysdep.h" 32#include "vect.h" 33#include "dict.h" 34#include "options.h" 35 36static char * 37append(const char *str1, const char *str2) 38{ 39 char *ret = malloc(strlen(str1) + strlen(str2) + 2); 40 if (ret == NULL) 41 return ret; 42 strcpy(stpcpy(ret, str1), str2); 43 return ret; 44} 45 46static void 47add_dir(struct vect *dirs, const char *str1, const char *str2) 48{ 49 char *dir = append(str1, str2); 50 if (dir != NULL 51 && VECT_PUSHBACK(dirs, &dir) < 0) 52 fprintf(stderr, 53 "Couldn't store candidate config directory %s%s: %s.\n", 54 str1, str2, strerror(errno)); 55} 56 57static enum callback_status 58add_dir_component_cb(struct opt_F_t *entry, void *data) 59{ 60 struct vect *dirs = data; 61 if (opt_F_get_kind(entry) == OPT_F_DIR) 62 add_dir(dirs, entry->pathname, "/ltrace"); 63 return CBS_CONT; 64} 65 66static void 67destroy_opt_F_cb(struct opt_F_t *entry, void *data) 68{ 69 opt_F_destroy(entry); 70} 71 72static char *g_home_dir = NULL; 73 74int 75os_get_config_dirs(int private, const char ***retp) 76{ 77 /* Vector of char *. Contains first pointers to local paths, 78 * then NULL, then pointers to system paths, then another 79 * NULL. SYS_START points to the beginning of the second 80 * part. */ 81 static struct vect dirs; 82 static ssize_t sys_start = 0; 83 84again: 85 if (sys_start != 0) { 86 if (sys_start == -1) 87 return -1; 88 89 if (retp != NULL) { 90 if (private) 91 *retp = VECT_ELEMENT(&dirs, const char *, 0); 92 else 93 *retp = VECT_ELEMENT(&dirs, const char *, 94 (size_t)sys_start); 95 } 96 97 return 0; 98 } 99 100 VECT_INIT(&dirs, char *); 101 102 char *home = getenv("HOME"); 103 if (home == NULL) { 104 struct passwd *pwd = getpwuid(getuid()); 105 if (pwd != NULL) 106 home = pwd->pw_dir; 107 } 108 109 size_t home_len = home != NULL ? strlen(home) : 0; 110 111 /* The values coming from getenv and getpwuid may not be 112 * persistent. */ 113 if (home != NULL) { 114 g_home_dir = strdup(home); 115 if (g_home_dir != NULL) { 116 home = g_home_dir; 117 } else { 118 char *tmp = alloca(home_len + 1); 119 strcpy(tmp, home); 120 home = tmp; 121 } 122 } 123 124 char *xdg_home = getenv("XDG_CONFIG_HOME"); 125 if (xdg_home == NULL && home != NULL) { 126 xdg_home = alloca(home_len + sizeof "/.config"); 127 sprintf(xdg_home, "%s/.config", home); 128 } 129 if (xdg_home != NULL) 130 add_dir(&dirs, xdg_home, "/ltrace"); 131 if (home != NULL) 132 add_dir(&dirs, home, "/.ltrace"); 133 134 char *delim = NULL; 135 if (VECT_PUSHBACK(&dirs, &delim) < 0) { 136 fail: 137 /* This can't work :( */ 138 fprintf(stderr, 139 "Couldn't initialize list of config directories: %s.\n", 140 strerror(errno)); 141 VECT_DESTROY(&dirs, const char *, dict_dtor_string, NULL); 142 sys_start = -1; 143 return -1; 144 } 145 sys_start = vect_size(&dirs); 146 147 /* """preference-ordered set of base directories to search for 148 * configuration files in addition to the $XDG_CONFIG_HOME 149 * base directory. The directories in $XDG_CONFIG_DIRS should 150 * be seperated with a colon ':'.""" */ 151 char *xdg_sys = getenv("XDG_CONFIG_DIRS"); 152 if (xdg_sys != NULL) { 153 struct vect v; 154 VECT_INIT(&v, struct opt_F_t); 155 if (parse_colon_separated_list(xdg_sys, &v) < 0 156 || VECT_EACH(&v, struct opt_F_t, NULL, 157 add_dir_component_cb, &dirs) != NULL) 158 fprintf(stderr, 159 "Error processing $XDG_CONFIG_DIRS '%s': %s\n", 160 xdg_sys, strerror(errno)); 161 VECT_DESTROY(&v, struct opt_F_t, destroy_opt_F_cb, NULL); 162 } 163 164 /* SYSCONFDIF is passed via -D when compiling. */ 165 const char *sysconfdir = SYSCONFDIR; 166 if (sysconfdir != NULL) 167 add_dir(&dirs, sysconfdir, ""); 168 169 if (VECT_PUSHBACK(&dirs, &delim) < 0) 170 goto fail; 171 172 goto again; 173} 174 175int 176os_get_ltrace_conf_filename(const char **retp) 177{ 178 if (g_home_dir == NULL) 179 os_get_config_dirs(0, NULL); 180 *retp = g_home_dir; 181 return g_home_dir != NULL ? 0 : -1; 182} 183