fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / kinit / lnusertemp.c
blob026326da10428a1e6906b4ca6c01aa2341cc36ea
1 /*
2 This file is part of the KDE libraries
3 Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
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.
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.
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.
20 #include "config.h"
21 #include <config-kstandarddirs.h>
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>
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
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);
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
47 int check_tmp_dir(const char *tmp_dir, int check_ownership)
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))
56 #ifdef _WIN32
57 result = mkdir(tmp_dir);
58 #else
59 result = mkdir(tmp_dir, 0700);
60 #endif
61 if (result == -1)
63 snprintf(errorstring, sizeof(errorstring), "Error: cannot create directory \"%s\"", tmp_dir);
64 perror(errorstring);
65 return 1;
67 result = stat(tmp_dir, &stat_buf);
69 if ((result == -1) || ( !S_ISDIR(stat_buf.st_mode) && !S_ISLNK(stat_buf.st_mode) ))
71 fprintf(stderr, "Error: \"%s\" is not a directory.\n", tmp_dir);
72 return 1;
75 if (check_ownership && stat_buf.st_uid != getuid())
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;
80 return 0;
83 int create_link(const char *file, const char *tmp_dir)
85 int result;
86 result = check_tmp_dir(tmp_dir, 1);
87 if (result)
89 return result;
91 result = symlink(tmp_dir, file);
92 if (result == -1)
94 fprintf(stderr, "Error: Can not create link from \"%s\" to \"%s\"\n", file, tmp_dir);
95 return 1;
97 #ifndef NDEBUG
98 fprintf(stderr,"Created link from \"%s\" to \"%s\"\n", file, tmp_dir);
99 #endif
100 return 0;
104 int build_link(const char* tmp, const char *tmp_prefix, const char *kde_prefix)
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;
116 kde_tmp_dir[0] = 0;
118 pw_ent = getpwuid(uid);
119 if (!pw_ent)
121 fprintf(stderr, "Error: Can not find password entry for uid %d.\n", getuid());
122 return 1;
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));
129 if (!kde_home || !kde_home[0])
131 kde_home = "~/" KDE_DEFAULT_HOME "/";
134 if (kde_home[0] == '~')
136 if (uid == 0)
138 home_dir = pw_ent->pw_dir ? pw_ent->pw_dir : "/root";
140 if (!home_dir || !home_dir[0])
142 fprintf(stderr, "Aborting. $HOME not set!\n");
143 return 1;
145 if (strlen(home_dir) > (PATH_MAX-100))
147 fprintf(stderr, "Aborting. Home directory path too long!\n");
148 return 1;
150 kde_home++;
151 strncpy(kde_tmp_dir, home_dir, PATH_MAX);
152 kde_tmp_dir[ PATH_MAX ] = '\0';
154 strncat(kde_tmp_dir, kde_home, PATH_MAX - strlen(kde_tmp_dir));
156 /** Strip trailing '/' **/
157 if ( kde_tmp_dir[strlen(kde_tmp_dir)-1] == '/')
158 kde_tmp_dir[strlen(kde_tmp_dir)-1] = 0;
160 result = stat(kde_tmp_dir, &stat_buf);
161 if ((result == -1) && (errno == ENOENT))
163 #ifdef _WIN32
164 result = mkdir(kde_tmp_dir);
165 #else
166 result = mkdir(kde_tmp_dir, 0700);
167 #endif
169 if (result == -1)
171 perror("mkdir failed: ");
172 return 1;
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)
178 perror("Aborting. Could not determine hostname: ");
179 exit(255);
181 kde_tmp_dir[sizeof(kde_tmp_dir)-1] = '\0';
183 result = lstat(kde_tmp_dir, &stat_buf);
184 if ((result == 0) && (S_ISDIR(stat_buf.st_mode)))
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;
192 if ((result == -1) && (errno == ENOENT))
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);
208 if ((result == -1) || (!S_ISLNK(stat_buf.st_mode)))
210 fprintf(stderr, "Error: \"%s\" is not a link or a directory.\n", kde_tmp_dir);
211 return 1;
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)
217 fprintf(stderr, "Error: \"%s\" could not be read.\n", kde_tmp_dir);
218 return 1;
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)
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);
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);
256 int main(int argc, char **argv)
258 const char *tmp = 0;
259 char *tmp_prefix = 0;
260 const char *kde_prefix = 0;
261 int res = 0;
263 if ((argc != 2) ||
264 ((strcmp(argv[1], "tmp")!=0) &&
265 (strcmp(argv[1], "socket")!=0) &&
266 (strcmp(argv[1], "cache")!=0)))
268 fprintf(stderr, "Usage: lnusertemp tmp|socket|cache\n");
269 return 1;
272 tmp = getenv("KDETMP");
273 if (!tmp || !tmp[0])
274 tmp = getenv("TMPDIR");
275 if (!tmp || !tmp[0])
276 tmp = "/tmp";
278 if (strcmp(argv[1], "tmp") == 0)
280 tmp_prefix = (char *)malloc(strlen(tmp)+strlen("/kde-")+1);
281 strcpy(tmp_prefix, tmp);
282 strcat(tmp_prefix, "/kde-");
284 kde_prefix = "/tmp-";
286 else if (strcmp(argv[1], "socket") == 0)
288 tmp_prefix = (char *)malloc(strlen(tmp)+strlen("/ksocket-")+1);
289 strcpy(tmp_prefix, tmp );
290 strcat(tmp_prefix, "/ksocket-" );
292 kde_prefix = "/socket-";
294 else if (strcmp(argv[1], "cache") == 0)
296 tmp = getenv("KDEVARTMP");
297 if (!tmp || !tmp[0])
298 tmp = "/var/tmp";
300 tmp_prefix = (char *)malloc(strlen(tmp)+strlen("/kdecache-")+1);
301 strcpy(tmp_prefix, tmp );
302 strcat(tmp_prefix, "/kdecache-" );
304 kde_prefix = "/cache-";
307 res = build_link(tmp, tmp_prefix, kde_prefix);
309 free(tmp_prefix);
311 return res;