1d5ac70f0Sopenharmony_ci/*
2d5ac70f0Sopenharmony_ci *  Get full filename
3d5ac70f0Sopenharmony_ci *  Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
4d5ac70f0Sopenharmony_ci *
5d5ac70f0Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
6d5ac70f0Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as
7d5ac70f0Sopenharmony_ci *   published by the Free Software Foundation; either version 2.1 of
8d5ac70f0Sopenharmony_ci *   the License, or (at your option) any later version.
9d5ac70f0Sopenharmony_ci *
10d5ac70f0Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
11d5ac70f0Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12d5ac70f0Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13d5ac70f0Sopenharmony_ci *   GNU Lesser General Public License for more details.
14d5ac70f0Sopenharmony_ci *
15d5ac70f0Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public
16d5ac70f0Sopenharmony_ci *   License along with this library; if not, write to the Free Software
17d5ac70f0Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18d5ac70f0Sopenharmony_ci *
19d5ac70f0Sopenharmony_ci */
20d5ac70f0Sopenharmony_ci
21d5ac70f0Sopenharmony_ci#include "config.h"
22d5ac70f0Sopenharmony_ci#include <string.h>
23d5ac70f0Sopenharmony_ci#include <errno.h>
24d5ac70f0Sopenharmony_ci#include <assert.h>
25d5ac70f0Sopenharmony_ci
26d5ac70f0Sopenharmony_ci/**
27d5ac70f0Sopenharmony_ci * \brief Get the full file name
28d5ac70f0Sopenharmony_ci * \param file The file name string to parse
29d5ac70f0Sopenharmony_ci * \param result The pointer to store the resultant file name
30d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code
31d5ac70f0Sopenharmony_ci *
32d5ac70f0Sopenharmony_ci * Parses the given file name with POSIX-Shell-like expansion and
33d5ac70f0Sopenharmony_ci * stores the first matchine one.  The returned string is strdup'ed.
34d5ac70f0Sopenharmony_ci */
35d5ac70f0Sopenharmony_ci
36d5ac70f0Sopenharmony_ci#ifdef HAVE_WORDEXP
37d5ac70f0Sopenharmony_ci#include <wordexp.h>
38d5ac70f0Sopenharmony_ciint snd_user_file(const char *file, char **result)
39d5ac70f0Sopenharmony_ci{
40d5ac70f0Sopenharmony_ci	wordexp_t we;
41d5ac70f0Sopenharmony_ci	int err;
42d5ac70f0Sopenharmony_ci
43d5ac70f0Sopenharmony_ci	assert(file && result);
44d5ac70f0Sopenharmony_ci	err = wordexp(file, &we, WRDE_NOCMD);
45d5ac70f0Sopenharmony_ci	switch (err) {
46d5ac70f0Sopenharmony_ci	case WRDE_NOSPACE:
47d5ac70f0Sopenharmony_ci		wordfree(&we);
48d5ac70f0Sopenharmony_ci		return -ENOMEM;
49d5ac70f0Sopenharmony_ci	case 0:
50d5ac70f0Sopenharmony_ci		if (we.we_wordc == 1)
51d5ac70f0Sopenharmony_ci			break;
52d5ac70f0Sopenharmony_ci		wordfree(&we);
53d5ac70f0Sopenharmony_ci		/* fall thru */
54d5ac70f0Sopenharmony_ci	default:
55d5ac70f0Sopenharmony_ci		return -EINVAL;
56d5ac70f0Sopenharmony_ci	}
57d5ac70f0Sopenharmony_ci	*result = strdup(we.we_wordv[0]);
58d5ac70f0Sopenharmony_ci	wordfree(&we);
59d5ac70f0Sopenharmony_ci	if (*result == NULL)
60d5ac70f0Sopenharmony_ci		return -ENOMEM;
61d5ac70f0Sopenharmony_ci	return 0;
62d5ac70f0Sopenharmony_ci}
63d5ac70f0Sopenharmony_ci
64d5ac70f0Sopenharmony_ci#else /* !HAVE_WORDEX */
65d5ac70f0Sopenharmony_ci
66d5ac70f0Sopenharmony_ci#include <sys/types.h>
67d5ac70f0Sopenharmony_ci#include <unistd.h>
68d5ac70f0Sopenharmony_ci#include <pwd.h>
69d5ac70f0Sopenharmony_ci#include <stdio.h>
70d5ac70f0Sopenharmony_ci#include <stdlib.h>
71d5ac70f0Sopenharmony_ci
72d5ac70f0Sopenharmony_ciint snd_user_file(const char *file, char **result)
73d5ac70f0Sopenharmony_ci{
74d5ac70f0Sopenharmony_ci	int err;
75d5ac70f0Sopenharmony_ci	size_t len;
76d5ac70f0Sopenharmony_ci	char *buf = NULL;
77d5ac70f0Sopenharmony_ci
78d5ac70f0Sopenharmony_ci	assert(file && result);
79d5ac70f0Sopenharmony_ci	*result = NULL;
80d5ac70f0Sopenharmony_ci
81d5ac70f0Sopenharmony_ci	/* expand ~/ if needed */
82d5ac70f0Sopenharmony_ci	if (file[0] == '~' && file[1] == '/') {
83d5ac70f0Sopenharmony_ci		const char *home = getenv("HOME");
84d5ac70f0Sopenharmony_ci		if (home == NULL) {
85d5ac70f0Sopenharmony_ci			struct passwd pwent, *p = NULL;
86d5ac70f0Sopenharmony_ci			uid_t id = getuid();
87d5ac70f0Sopenharmony_ci			size_t bufsize = 1024;
88d5ac70f0Sopenharmony_ci
89d5ac70f0Sopenharmony_ci			buf = malloc(bufsize);
90d5ac70f0Sopenharmony_ci			if (buf == NULL)
91d5ac70f0Sopenharmony_ci				goto out;
92d5ac70f0Sopenharmony_ci
93d5ac70f0Sopenharmony_ci			while ((err = getpwuid_r(id, &pwent, buf, bufsize, &p)) == ERANGE) {
94d5ac70f0Sopenharmony_ci				char *newbuf;
95d5ac70f0Sopenharmony_ci				bufsize += 1024;
96d5ac70f0Sopenharmony_ci				if (bufsize < 1024)
97d5ac70f0Sopenharmony_ci					break;
98d5ac70f0Sopenharmony_ci				newbuf = realloc(buf, bufsize);
99d5ac70f0Sopenharmony_ci				if (newbuf == NULL)
100d5ac70f0Sopenharmony_ci					goto out;
101d5ac70f0Sopenharmony_ci				buf = newbuf;
102d5ac70f0Sopenharmony_ci			}
103d5ac70f0Sopenharmony_ci			home = err ? "" : pwent.pw_dir;
104d5ac70f0Sopenharmony_ci		}
105d5ac70f0Sopenharmony_ci		len = strlen(home) + strlen(&file[2]) + 2;
106d5ac70f0Sopenharmony_ci		*result = malloc(len);
107d5ac70f0Sopenharmony_ci		if (*result)
108d5ac70f0Sopenharmony_ci			snprintf(*result, len, "%s/%s", home, &file[2]);
109d5ac70f0Sopenharmony_ci	} else {
110d5ac70f0Sopenharmony_ci		*result = strdup(file);
111d5ac70f0Sopenharmony_ci	}
112d5ac70f0Sopenharmony_ci
113d5ac70f0Sopenharmony_ciout:
114d5ac70f0Sopenharmony_ci	if (buf)
115d5ac70f0Sopenharmony_ci		free(buf);
116d5ac70f0Sopenharmony_ci
117d5ac70f0Sopenharmony_ci	if (*result == NULL)
118d5ac70f0Sopenharmony_ci		return -ENOMEM;
119d5ac70f0Sopenharmony_ci	return 0;
120d5ac70f0Sopenharmony_ci}
121d5ac70f0Sopenharmony_ci
122d5ac70f0Sopenharmony_ci#endif /* HAVE_WORDEXP */
123