1 /*
2
3 Copyright (c) 2003-2013 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31
32 */
33
34 #include <config.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <math.h>
40 #include <sys/types.h>
41 #include <time.h>
42 #include <unistd.h>
43 #include <sys/stat.h>
44 #include <sys/param.h>
45 #include <pwd.h>
46 #include <errno.h>
47 #include <assert.h>
48 #include <fcntl.h>
49
50 #include "uim.h"
51 #include "uim-internal.h"
52 #include "uim-scm.h"
53 #include "uim-scm-abbrev.h"
54 #include "uim-posix.h"
55 #include "uim-notify.h"
56 #include "gettext.h"
57 #include "dynlib.h"
58
59 uim_bool
uim_get_user_name(char * name,int len,int uid)60 uim_get_user_name(char *name, int len, int uid)
61 {
62 struct passwd *pw;
63
64 if (len <= 0)
65 return UIM_FALSE;
66 pw = getpwuid(uid);
67 if (!pw) {
68 name[0] = '\0';
69 return UIM_FALSE;
70 }
71 if (strlcpy(name, pw->pw_name, len) >= (size_t)len) {
72 name[0] = '\0';
73 endpwent();
74 return UIM_FALSE;
75 }
76 endpwent();
77 return UIM_TRUE;
78 }
79
80 static uim_lisp
user_name(void)81 user_name(void)
82 {
83 char name[BUFSIZ];
84
85 if (!uim_get_user_name(name, sizeof(name), getuid()))
86 return uim_scm_f();
87
88 return MAKE_STR(name);
89 }
90
91 uim_bool
uim_get_home_directory(char * home,int len,int uid)92 uim_get_home_directory(char *home, int len, int uid)
93 {
94 struct passwd *pw;
95
96 if (len <= 0)
97 return UIM_FALSE;
98 pw = getpwuid(uid);
99 if (!pw) {
100 home[0] = '\0';
101 return UIM_FALSE;
102 }
103 if (strlcpy(home, pw->pw_dir, len) >= (size_t)len) {
104 home[0] = '\0';
105 endpwent();
106 return UIM_FALSE;
107 }
108 endpwent();
109 return UIM_TRUE;
110 }
111
112 static uim_lisp
home_directory(uim_lisp user_)113 home_directory(uim_lisp user_)
114 {
115 int uid;
116 char home[MAXPATHLEN];
117
118 if (INTP(user_)) {
119 uid = C_INT(user_);
120 } else if (STRP(user_)) {
121 struct passwd *pw;
122
123 pw = getpwnam(REFER_C_STR(user_));
124
125 if (!pw)
126 return uim_scm_f();
127
128 uid = pw->pw_uid;
129 endpwent();
130 } else {
131 return uim_scm_f();
132 }
133
134 if (!uim_get_home_directory(home, sizeof(home), uid)) {
135 char *home_env = getenv("HOME");
136 if (home_env)
137 return MAKE_STR(home_env);
138 return uim_scm_f();
139 }
140
141 return MAKE_STR(home);
142 }
143
144 static uim_bool
uim_check_dir_internal(const char * dir,int need_prepare)145 uim_check_dir_internal(const char *dir, int need_prepare)
146 {
147 struct stat st;
148
149 if (stat(dir, &st) < 0)
150 if (need_prepare)
151 return (mkdir(dir, 0700) < 0) ? UIM_FALSE : UIM_TRUE;
152 else
153 return UIM_FALSE;
154 else {
155 mode_t mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
156 return ((st.st_mode & mode) == mode) ? UIM_TRUE : UIM_FALSE;
157 }
158 }
159
160 /* FIXME: use appropriate name for this API */
161 uim_bool
uim_check_dir(const char * dir)162 uim_check_dir(const char *dir)
163 {
164 int need_prepare = UIM_TRUE;
165
166 return uim_check_dir_internal(dir, need_prepare);
167 }
168
169 static uim_lisp
c_prepare_dir(uim_lisp dir_)170 c_prepare_dir(uim_lisp dir_)
171 {
172 if (!uim_check_dir(REFER_C_STR(dir_))) {
173 return uim_scm_f();
174 }
175 return uim_scm_t();
176 }
177
178 static uim_bool
uim_get_config_path_internal(char * path,int len,int is_getenv,int need_prepare)179 uim_get_config_path_internal(char *path, int len, int is_getenv, int need_prepare)
180 {
181 char home[MAXPATHLEN];
182
183 if (len <= 0)
184 return UIM_FALSE;
185
186 if (!uim_get_home_directory(home, sizeof(home), getuid()) && is_getenv) {
187 char *home_env = getenv("HOME");
188
189 if (!home_env) {
190 path[0] = '\0';
191 return UIM_FALSE;
192 }
193
194 if (strlcpy(home, home_env, sizeof(home)) >= sizeof(home)) {
195 path[0] = '\0';
196 return UIM_FALSE;
197 }
198 }
199
200 if (snprintf(path, len, "%s/.uim.d", home) < 0) {
201 path[0] = '\0';
202 return UIM_FALSE;
203 }
204
205 if (!uim_check_dir_internal(path, need_prepare)) {
206 return UIM_FALSE;
207 }
208
209 return UIM_TRUE;
210 }
211
212 /* FIXME: use appropriate name for this API */
213 uim_bool
uim_get_config_path(char * path,int len,int is_getenv)214 uim_get_config_path(char *path, int len, int is_getenv)
215 {
216 int need_prepare = UIM_TRUE;
217
218 return uim_get_config_path_internal(path, len, is_getenv, need_prepare);
219 }
220
221 static uim_lisp
c_prepare_config_path(uim_lisp is_getenv_)222 c_prepare_config_path(uim_lisp is_getenv_)
223 {
224 char path[MAXPATHLEN];
225 int need_prepare = UIM_TRUE;
226
227 if (!uim_get_config_path_internal(path, sizeof(path), C_BOOL(is_getenv_), need_prepare))
228 return uim_scm_f();
229 return MAKE_STR(path);
230 }
231
232 static uim_lisp
c_get_config_path(uim_lisp is_getenv_)233 c_get_config_path(uim_lisp is_getenv_)
234 {
235 char path[MAXPATHLEN];
236 int need_prepare = UIM_FALSE;
237
238 /* No need to check the existence of path in this function */
239 uim_get_config_path_internal(path, sizeof(path), C_BOOL(is_getenv_), need_prepare);
240
241 return MAKE_STR(path);
242 }
243
244 static uim_lisp
file_stat_mode(uim_lisp filename,mode_t mode)245 file_stat_mode(uim_lisp filename, mode_t mode)
246 {
247 struct stat st;
248 int err;
249
250 err = stat(REFER_C_STR(filename), &st);
251 if (err)
252 return uim_scm_f(); /* intentionally returns #f instead of error */
253
254 return MAKE_BOOL((st.st_mode & mode) == mode);
255 }
256
257 static uim_lisp
file_readablep(uim_lisp filename)258 file_readablep(uim_lisp filename)
259 {
260 return file_stat_mode(filename, S_IRUSR);
261 }
262
263 static uim_lisp
file_writablep(uim_lisp filename)264 file_writablep(uim_lisp filename)
265 {
266 return file_stat_mode(filename, S_IWUSR);
267 }
268
269 static uim_lisp
file_executablep(uim_lisp filename)270 file_executablep(uim_lisp filename)
271 {
272 return file_stat_mode(filename, S_IXUSR);
273 }
274
275 static uim_lisp
file_regularp(uim_lisp filename)276 file_regularp(uim_lisp filename)
277 {
278 return file_stat_mode(filename, S_IFREG);
279 }
280
281 static uim_lisp
file_directoryp(uim_lisp filename)282 file_directoryp(uim_lisp filename)
283 {
284 return file_stat_mode(filename, S_IFDIR);
285 }
286
287 static uim_lisp
file_mtime(uim_lisp filename)288 file_mtime(uim_lisp filename)
289 {
290 struct stat st;
291 int err;
292
293 err = stat(REFER_C_STR(filename), &st);
294 if (err)
295 ERROR_OBJ("stat failed for file", filename);
296
297 return MAKE_INT(st.st_mtime);
298 }
299
300 static uim_lisp
c_unlink(uim_lisp path_)301 c_unlink(uim_lisp path_)
302 {
303 return MAKE_INT(unlink(REFER_C_STR(path_)));
304 }
305
306 static uim_lisp
c_mkdir(uim_lisp path_,uim_lisp mode_)307 c_mkdir(uim_lisp path_, uim_lisp mode_)
308 {
309 return MAKE_INT(mkdir(REFER_C_STR(path_), C_INT(mode_)));
310 }
311
312 static uim_lisp
c_chdir(uim_lisp path_)313 c_chdir(uim_lisp path_)
314 {
315 return MAKE_INT(chdir(REFER_C_STR(path_)));
316 }
317
318 static uim_lisp
c_getenv(uim_lisp str)319 c_getenv(uim_lisp str)
320 {
321 char *val;
322
323 ENSURE_TYPE(str, str);
324
325 val = getenv(REFER_C_STR(str));
326
327 return (val) ? MAKE_STR(val) : uim_scm_f();
328 }
329
330 static uim_lisp
c_setenv(uim_lisp name,uim_lisp val,uim_lisp overwrite)331 c_setenv(uim_lisp name, uim_lisp val, uim_lisp overwrite)
332 {
333 int err;
334
335 err = setenv(REFER_C_STR(name), REFER_C_STR(val), TRUEP(overwrite));
336
337 return MAKE_BOOL(!err);
338 }
339
340 static uim_lisp
c_unsetenv(uim_lisp name)341 c_unsetenv(uim_lisp name)
342 {
343 unsetenv(REFER_C_STR(name));
344
345 return uim_scm_t();
346 }
347
348 static uim_lisp
c_getuid(void)349 c_getuid(void)
350 {
351 return MAKE_INT(getuid());
352 }
353
354 static uim_lisp
c_getgid(void)355 c_getgid(void)
356 {
357 return MAKE_INT(getgid());
358 }
359
360 static uim_lisp
setugidp(void)361 setugidp(void)
362 {
363 assert(uim_scm_gc_any_contextp());
364
365 return MAKE_BOOL(uim_issetugid());
366 }
367
368 static uim_lisp
c_setsid(void)369 c_setsid(void)
370 {
371 return MAKE_INT(setsid());
372 }
373
374 static uim_lisp
time_t_to_uim_lisp(time_t t)375 time_t_to_uim_lisp(time_t t)
376 {
377 char t_str[64];
378
379 snprintf(t_str, sizeof(t_str), "%.32g", (double)t);
380 return MAKE_STR(t_str);
381 }
382
383 static uim_bool
uim_lisp_to_time_t(time_t * t,uim_lisp t_)384 uim_lisp_to_time_t(time_t *t, uim_lisp t_)
385 {
386 const char *t_str = REFER_C_STR(t_);
387 char *end;
388
389 *t = (time_t)strtod(t_str, &end);
390 return *end == '\0';
391 }
392
393 static uim_lisp
c_time(void)394 c_time(void)
395 {
396 time_t now;
397
398 if ((time(&now)) == (time_t) -1)
399 return CONS(MAKE_SYM("error"), MAKE_STR(strerror(errno)));
400 return time_t_to_uim_lisp(now);
401 }
402
403 static uim_lisp
c_difftime(uim_lisp time1_,uim_lisp time0_)404 c_difftime(uim_lisp time1_, uim_lisp time0_)
405 {
406 time_t time1, time0;
407
408 if (!uim_lisp_to_time_t(&time1, time1_))
409 return uim_scm_f();
410 if (!uim_lisp_to_time_t(&time0, time0_))
411 return uim_scm_f();
412 return time_t_to_uim_lisp(difftime(time1, time0));
413 }
414
415
416 static uim_lisp
c_sleep(uim_lisp seconds_)417 c_sleep(uim_lisp seconds_)
418 {
419 return MAKE_INT(sleep((unsigned int)C_INT(seconds_)));
420 }
421
422 static uim_lisp
c_error_string()423 c_error_string()
424 {
425 return MAKE_STR(strerror(errno));
426 }
427
428 void
uim_init_posix_subrs(void)429 uim_init_posix_subrs(void)
430 {
431 uim_scm_init_proc0("user-name", user_name);
432 uim_scm_init_proc1("home-directory", home_directory);
433
434 uim_scm_init_proc1("create/check-directory!", c_prepare_dir);
435 uim_scm_init_proc1("get-config-path!", c_prepare_config_path);
436 uim_scm_init_proc1("get-config-path", c_get_config_path);
437
438 uim_scm_init_proc1("file-readable?", file_readablep);
439 uim_scm_init_proc1("file-writable?", file_writablep);
440 uim_scm_init_proc1("file-executable?", file_executablep);
441 uim_scm_init_proc1("file-regular?", file_regularp);
442 uim_scm_init_proc1("file-directory?", file_directoryp);
443 uim_scm_init_proc1("file-mtime", file_mtime);
444
445 uim_scm_init_proc1("unlink", c_unlink);
446 uim_scm_init_proc2("mkdir", c_mkdir);
447 uim_scm_init_proc1("chdir", c_chdir);
448
449 uim_scm_init_proc0("getuid", c_getuid);
450 uim_scm_init_proc0("getgid", c_getgid);
451 uim_scm_init_proc0("setugid?", setugidp);
452
453 uim_scm_init_proc0("setsid", c_setsid);
454
455 uim_scm_init_proc1("getenv", c_getenv);
456 uim_scm_init_proc3("setenv", c_setenv);
457 uim_scm_init_proc1("unsetenv", c_unsetenv);
458
459 uim_scm_init_proc0("time", c_time);
460 uim_scm_init_proc2("difftime", c_difftime);
461
462 uim_scm_init_proc1("sleep", c_sleep);
463
464 uim_scm_init_proc0("posix-error-string", c_error_string);
465 }
466