1 | /* |
2 | This file is part of the KDE libraries |
3 | Copyright (c) 2000 Waldo Bastian <bastian@kde.org> |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Library General Public |
7 | License version 2 as published by the Free Software Foundation. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "config.h" |
21 | #include <config-kstandarddirs.h> |
22 | |
23 | #include <sys/types.h> |
24 | #include <sys/param.h> |
25 | #include <sys/socket.h> |
26 | #include <sys/stat.h> |
27 | #include <sys/un.h> |
28 | |
29 | #include <errno.h> |
30 | #include <string.h> |
31 | #include <stdio.h> |
32 | #include <stdlib.h> |
33 | #include <unistd.h> |
34 | #include <pwd.h> |
35 | #ifdef HAVE_LIMITS_H |
36 | #include <limits.h> |
37 | #endif |
38 | |
39 | int check_tmp_dir(const char *tmp_dir, int check_ownership); |
40 | int create_link(const char *file, const char *tmp_dir); |
41 | int build_link(const char* tmp, const char *tmp_prefix, const char *kde_prefix); |
42 | |
43 | /* checks that tmp_dir exists, otherwise creates it |
44 | * @param check_ownership: if 1, also check that user owns the dir |
45 | * returns 0 on success |
46 | */ |
47 | int check_tmp_dir(const char *tmp_dir, int check_ownership) |
48 | { |
49 | /* reserve some space for an error string + a path name */ |
50 | char errorstring[PATH_MAX+1024]; |
51 | int result; |
52 | struct stat stat_buf; |
53 | result = lstat(tmp_dir, &stat_buf); |
54 | if ((result == -1) && (errno == ENOENT)) |
55 | { |
56 | #ifdef _WIN32 |
57 | result = mkdir(tmp_dir); |
58 | #else |
59 | result = mkdir(tmp_dir, 0700); |
60 | #endif |
61 | if (result == -1) |
62 | { |
63 | snprintf(errorstring, sizeof(errorstring), "Error: cannot create directory \"%s\"" , tmp_dir); |
64 | perror(errorstring); |
65 | return 1; |
66 | } |
67 | result = stat(tmp_dir, &stat_buf); |
68 | } |
69 | if ((result == -1) || ( !S_ISDIR(stat_buf.st_mode) && !S_ISLNK(stat_buf.st_mode) )) |
70 | { |
71 | fprintf(stderr, "Error: \"%s\" is not a directory.\n" , tmp_dir); |
72 | return 1; |
73 | } |
74 | |
75 | if (check_ownership && stat_buf.st_uid != getuid()) |
76 | { |
77 | fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n" , tmp_dir, stat_buf.st_uid, getuid()); |
78 | return 1; |
79 | } |
80 | return 0; |
81 | } |
82 | |
83 | int create_link(const char *file, const char *tmp_dir) |
84 | { |
85 | int result; |
86 | result = check_tmp_dir(tmp_dir, 1); |
87 | if (result) |
88 | { |
89 | return result; |
90 | } |
91 | result = symlink(tmp_dir, file); |
92 | if (result == -1) |
93 | { |
94 | fprintf(stderr, "Error: Can not create link from \"%s\" to \"%s\"\n" , file, tmp_dir); |
95 | return 1; |
96 | } |
97 | #ifndef NDEBUG |
98 | fprintf(stderr,"Created link from \"%s\" to \"%s\"\n" , file, tmp_dir); |
99 | #endif |
100 | return 0; |
101 | } |
102 | |
103 | |
104 | int build_link(const char* tmp, const char *tmp_prefix, const char *kde_prefix) |
105 | { |
106 | struct passwd *pw_ent; |
107 | char kde_tmp_dir[PATH_MAX+1]; |
108 | char user_tmp_dir[PATH_MAX+1]; |
109 | char tmp_buf[PATH_MAX+1]; |
110 | int uid = getuid(); |
111 | const char *home_dir = getenv("HOME" ); |
112 | const char *kde_home = uid ? getenv("KDEHOME" ) : getenv("KDEROOTHOME" ); |
113 | int result; |
114 | struct stat stat_buf; |
115 | |
116 | kde_tmp_dir[0] = 0; |
117 | |
118 | pw_ent = getpwuid(uid); |
119 | if (!pw_ent) |
120 | { |
121 | fprintf(stderr, "Error: Can not find password entry for uid %d.\n" , getuid()); |
122 | return 1; |
123 | } |
124 | |
125 | strncpy(user_tmp_dir, tmp_prefix, PATH_MAX); |
126 | user_tmp_dir[ PATH_MAX ] = '\0'; |
127 | strncat(user_tmp_dir, pw_ent->pw_name, PATH_MAX - strlen(tmp_prefix)); |
128 | |
129 | if (!kde_home || !kde_home[0]) |
130 | { |
131 | kde_home = "~/" KDE_DEFAULT_HOME "/" ; |
132 | } |
133 | |
134 | if (kde_home[0] == '~') |
135 | { |
136 | if (uid == 0) |
137 | { |
138 | home_dir = pw_ent->pw_dir ? pw_ent->pw_dir : "/root" ; |
139 | } |
140 | if (!home_dir || !home_dir[0]) |
141 | { |
142 | fprintf(stderr, "Aborting. $HOME not set!\n" ); |
143 | return 1; |
144 | } |
145 | if (strlen(home_dir) > (PATH_MAX-100)) |
146 | { |
147 | fprintf(stderr, "Aborting. Home directory path too long!\n" ); |
148 | return 1; |
149 | } |
150 | kde_home++; |
151 | strncpy(kde_tmp_dir, home_dir, PATH_MAX); |
152 | kde_tmp_dir[ PATH_MAX ] = '\0'; |
153 | } |
154 | strncat(kde_tmp_dir, kde_home, PATH_MAX - strlen(kde_tmp_dir)); |
155 | |
156 | /** Strip trailing '/' **/ |
157 | if ( kde_tmp_dir[strlen(kde_tmp_dir)-1] == '/') |
158 | kde_tmp_dir[strlen(kde_tmp_dir)-1] = 0; |
159 | |
160 | result = stat(kde_tmp_dir, &stat_buf); |
161 | if ((result == -1) && (errno == ENOENT)) |
162 | { |
163 | #ifdef _WIN32 |
164 | result = mkdir(kde_tmp_dir); |
165 | #else |
166 | result = mkdir(kde_tmp_dir, 0700); |
167 | #endif |
168 | } |
169 | if (result == -1) |
170 | { |
171 | perror("mkdir failed: " ); |
172 | return 1; |
173 | } |
174 | |
175 | strncat(kde_tmp_dir, kde_prefix, PATH_MAX - strlen(kde_tmp_dir)); |
176 | if (gethostname(kde_tmp_dir+strlen(kde_tmp_dir), PATH_MAX - strlen(kde_tmp_dir) - 1) != 0) |
177 | { |
178 | perror("Aborting. Could not determine hostname: " ); |
179 | exit(255); |
180 | } |
181 | kde_tmp_dir[sizeof(kde_tmp_dir)-1] = '\0'; |
182 | |
183 | result = lstat(kde_tmp_dir, &stat_buf); |
184 | if ((result == 0) && (S_ISDIR(stat_buf.st_mode))) |
185 | { |
186 | /* $KDEHOME/tmp is a normal directory. Do nothing. */ |
187 | #ifndef NDEBUG |
188 | fprintf(stderr,"Directory \"%s\" already exists.\n" , kde_tmp_dir); |
189 | #endif |
190 | return 0; |
191 | } |
192 | if ((result == -1) && (errno == ENOENT)) |
193 | { |
194 | #ifndef NDEBUG |
195 | fprintf(stderr,"Creating link %s.\n" , kde_tmp_dir); |
196 | #endif |
197 | result = create_link(kde_tmp_dir, user_tmp_dir); |
198 | if (result == 0) return 0; /* Success */ |
199 | unlink(kde_tmp_dir); |
200 | strncat(user_tmp_dir, "XXXXXX" , PATH_MAX - strlen(user_tmp_dir)); |
201 | #if 0 |
202 | mktemp(user_tmp_dir); /* We want a directory, not a file, so using mkstemp makes no sense and is wrong */ |
203 | #else |
204 | if (mkdtemp(user_tmp_dir)==0) return 1; /*JOWENN: isn't that the better solution ?? */ |
205 | #endif |
206 | return create_link(kde_tmp_dir, user_tmp_dir); |
207 | } |
208 | if ((result == -1) || (!S_ISLNK(stat_buf.st_mode))) |
209 | { |
210 | fprintf(stderr, "Error: \"%s\" is not a link or a directory.\n" , kde_tmp_dir); |
211 | return 1; |
212 | } |
213 | /* kde_tmp_dir is a link. Check whether it points to a valid directory. */ |
214 | result = readlink(kde_tmp_dir, tmp_buf, PATH_MAX); |
215 | if (result == -1) |
216 | { |
217 | fprintf(stderr, "Error: \"%s\" could not be read.\n" , kde_tmp_dir); |
218 | return 1; |
219 | } |
220 | tmp_buf[result] = '\0'; |
221 | #ifndef NDEBUG |
222 | fprintf(stderr,"Link points to \"%s\"\n" , tmp_buf); |
223 | #endif |
224 | if (strncmp(tmp_buf, user_tmp_dir, strlen(user_tmp_dir)) != 0) |
225 | { |
226 | fprintf(stderr, "Error: \"%s\" points to \"%s\" instead of \"%s\".\n" , kde_tmp_dir, tmp_buf, user_tmp_dir); |
227 | unlink(kde_tmp_dir); |
228 | #ifndef NDEBUG |
229 | fprintf(stderr, "Creating link %s.\n" , kde_tmp_dir); |
230 | #endif |
231 | result = create_link(kde_tmp_dir, user_tmp_dir); |
232 | if (result == 0) return 0; /* Success */ |
233 | unlink(kde_tmp_dir); |
234 | strncat(user_tmp_dir, "XXXXXX" , PATH_MAX - strlen(user_tmp_dir)); |
235 | #if 0 |
236 | mktemp(user_tmp_dir); /* We want a directory, not a file, so using mkstemp makes no sense and is wrong */ |
237 | #else |
238 | if (mkdtemp(user_tmp_dir)==0) return 1; /*JOWENN: isn't that the better solution ?? */ |
239 | #endif |
240 | return create_link(kde_tmp_dir, user_tmp_dir); |
241 | } |
242 | result = check_tmp_dir(tmp, 0); |
243 | if (result != 0) return result; /* Failure to create parent dir */ |
244 | result = check_tmp_dir(tmp_buf, 1); |
245 | if (result == 0) return 0; /* Success */ |
246 | unlink(kde_tmp_dir); |
247 | strncat(user_tmp_dir, "XXXXXX" , PATH_MAX - strlen(user_tmp_dir)); |
248 | #if 0 |
249 | mktemp(user_tmp_dir); /* We want a directory, not a file, so using mkstemp makes no sense and is wrong */ |
250 | #else |
251 | if (mkdtemp(user_tmp_dir)==0) return 1; /*JOWENN: isn't that the better solution ?? */ |
252 | #endif |
253 | return create_link(kde_tmp_dir, user_tmp_dir); |
254 | } |
255 | |
256 | int main(int argc, char **argv) |
257 | { |
258 | const char *tmp = 0; |
259 | char *tmp_prefix = 0; |
260 | const char *kde_prefix = 0; |
261 | int res = 0; |
262 | |
263 | if ((argc != 2) || |
264 | ((strcmp(argv[1], "tmp" )!=0) && |
265 | (strcmp(argv[1], "socket" )!=0) && |
266 | (strcmp(argv[1], "cache" )!=0))) |
267 | { |
268 | fprintf(stderr, "Usage: lnusertemp tmp|socket|cache\n" ); |
269 | return 1; |
270 | } |
271 | |
272 | tmp = getenv("KDETMP" ); |
273 | if (!tmp || !tmp[0]) |
274 | tmp = getenv("TMPDIR" ); |
275 | if (!tmp || !tmp[0]) |
276 | tmp = "/tmp" ; |
277 | |
278 | if (strcmp(argv[1], "tmp" ) == 0) |
279 | { |
280 | tmp_prefix = (char *)malloc(strlen(tmp)+strlen("/kde-" )+1); |
281 | strcpy(tmp_prefix, tmp); |
282 | strcat(tmp_prefix, "/kde-" ); |
283 | |
284 | kde_prefix = "/tmp-" ; |
285 | } |
286 | else if (strcmp(argv[1], "socket" ) == 0) |
287 | { |
288 | tmp_prefix = (char *)malloc(strlen(tmp)+strlen("/ksocket-" )+1); |
289 | strcpy(tmp_prefix, tmp ); |
290 | strcat(tmp_prefix, "/ksocket-" ); |
291 | |
292 | kde_prefix = "/socket-" ; |
293 | } |
294 | else if (strcmp(argv[1], "cache" ) == 0) |
295 | { |
296 | tmp = getenv("KDEVARTMP" ); |
297 | if (!tmp || !tmp[0]) |
298 | tmp = "/var/tmp" ; |
299 | |
300 | tmp_prefix = (char *)malloc(strlen(tmp)+strlen("/kdecache-" )+1); |
301 | strcpy(tmp_prefix, tmp ); |
302 | strcat(tmp_prefix, "/kdecache-" ); |
303 | |
304 | kde_prefix = "/cache-" ; |
305 | } |
306 | |
307 | res = build_link(tmp, tmp_prefix, kde_prefix); |
308 | |
309 | free(tmp_prefix); |
310 | |
311 | return res; |
312 | } |
313 | |