hooks.c revision 364753a1cfe46998946a42badd9099591a00325a
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2012 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 /* The values coming from getenv and getpwuid may not be 110 * persistent. */ 111 if (home != NULL) { 112 g_home_dir = strdup(home); 113 if (g_home_dir != NULL) { 114 home = g_home_dir; 115 } else { 116 char *tmp = alloca(strlen(home) + 1); 117 strcpy(tmp, home); 118 home = tmp; 119 } 120 } 121 122 char *xdg_home = getenv("XDG_CONFIG_HOME"); 123 if (xdg_home == NULL && home != NULL) { 124 xdg_home = alloca(strlen(home) + sizeof "/.config"); 125 strcpy(stpcpy(xdg_home, home), "/.config"); 126 } 127 if (xdg_home != NULL) 128 add_dir(&dirs, xdg_home, "/ltrace"); 129 if (home != NULL) 130 add_dir(&dirs, home, "/.ltrace"); 131 132 char *delim = NULL; 133 if (VECT_PUSHBACK(&dirs, &delim) < 0) { 134 fail: 135 /* This can't work :( */ 136 fprintf(stderr, 137 "Couldn't initialize list of config directories: %s.\n", 138 strerror(errno)); 139 VECT_DESTROY(&dirs, const char *, dict_dtor_string, NULL); 140 sys_start = -1; 141 return -1; 142 } 143 sys_start = vect_size(&dirs); 144 145 /* """preference-ordered set of base directories to search for 146 * configuration files in addition to the $XDG_CONFIG_HOME 147 * base directory. The directories in $XDG_CONFIG_DIRS should 148 * be seperated with a colon ':'.""" */ 149 char *xdg_sys = getenv("XDG_CONFIG_DIRS"); 150 if (xdg_sys != NULL) { 151 struct vect v; 152 VECT_INIT(&v, struct opt_F_t); 153 if (parse_colon_separated_list(xdg_sys, &v) < 0 154 || VECT_EACH(&v, struct opt_F_t, NULL, 155 add_dir_component_cb, &dirs) != NULL) 156 fprintf(stderr, 157 "Error processing $XDG_CONFIG_DIRS '%s': %s\n", 158 xdg_sys, strerror(errno)); 159 VECT_DESTROY(&v, struct opt_F_t, destroy_opt_F_cb, NULL); 160 } 161 162 /* SYSCONFDIF is passed via -D when compiling. */ 163 const char *sysconfdir = SYSCONFDIR; 164 if (sysconfdir != NULL) 165 add_dir(&dirs, sysconfdir, ""); 166 167 if (VECT_PUSHBACK(&dirs, &delim) < 0) 168 goto fail; 169 170 goto again; 171} 172 173int 174os_get_ltrace_conf_filename(const char **retp) 175{ 176 if (g_home_dir == NULL) 177 os_get_config_dirs(0, NULL); 178 *retp = g_home_dir; 179 return g_home_dir != NULL ? 0 : -1; 180} 181