proc-env.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /* Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees.
  2. See file COPYING. */
  3. /*
  4. * Scheme 48/POSIX process environment interface
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include <sys/types.h>
  12. #include <sys/utsname.h>
  13. #include <sys/wait.h>
  14. #include "scheme48.h"
  15. #include "posix.h"
  16. #include "unix.h"
  17. #include "sysdep.h"
  18. extern void s48_init_posix_proc_env(void);
  19. static s48_ref_t posix_get_pid(s48_call_t call, s48_ref_t parent_p),
  20. posix_get_id(s48_call_t call, s48_ref_t user_p, s48_ref_t real_p),
  21. posix_set_id(s48_call_t call, s48_ref_t user_p,
  22. s48_ref_t real_p, s48_ref_t id),
  23. posix_get_groups(s48_call_t call),
  24. posix_get_login(s48_call_t call),
  25. posix_set_sid(s48_call_t call),
  26. posix_sys_name(s48_call_t call, s48_ref_t which),
  27. posix_get_env(s48_call_t call, s48_ref_t name),
  28. posix_set_env(s48_call_t call, s48_ref_t name, s48_ref_t value),
  29. posix_get_env_alist(s48_call_t call),
  30. posix_get_terminal_pathname(s48_call_t call),
  31. posix_tty_name(s48_call_t call, s48_ref_t channel),
  32. posix_is_a_tty(s48_call_t call, s48_ref_t channel);
  33. /*
  34. * Install all exported functions in Scheme48.
  35. */
  36. void
  37. s48_init_posix_proc_env(void)
  38. {
  39. S48_EXPORT_FUNCTION(posix_get_pid);
  40. S48_EXPORT_FUNCTION(posix_get_id);
  41. S48_EXPORT_FUNCTION(posix_set_id);
  42. S48_EXPORT_FUNCTION(posix_get_groups);
  43. S48_EXPORT_FUNCTION(posix_get_login);
  44. S48_EXPORT_FUNCTION(posix_set_sid);
  45. S48_EXPORT_FUNCTION(posix_sys_name);
  46. S48_EXPORT_FUNCTION(posix_get_env);
  47. S48_EXPORT_FUNCTION(posix_set_env);
  48. S48_EXPORT_FUNCTION(posix_get_env_alist);
  49. S48_EXPORT_FUNCTION(posix_get_terminal_pathname);
  50. S48_EXPORT_FUNCTION(posix_tty_name);
  51. S48_EXPORT_FUNCTION(posix_is_a_tty);
  52. }
  53. /*
  54. * Lots of simple little functions.
  55. */
  56. static s48_ref_t
  57. posix_get_pid(s48_call_t call, s48_ref_t parent_p)
  58. {
  59. extern char going;
  60. going = 1 == 0;
  61. return s48_enter_pid(call,
  62. s48_extract_boolean_2(call, parent_p) ?
  63. getppid() :
  64. getpid());
  65. }
  66. static s48_ref_t
  67. posix_set_sid(s48_call_t call)
  68. {
  69. pid_t pid;
  70. RETRY_OR_RAISE_NEG(pid, setsid());
  71. return s48_enter_pid(call, pid);
  72. }
  73. static s48_ref_t
  74. posix_get_id(s48_call_t call, s48_ref_t user_p, s48_ref_t real_p)
  75. {
  76. if (s48_extract_boolean_2(call, user_p))
  77. return s48_enter_uid(call, s48_extract_boolean_2(call, real_p) ? getuid() : geteuid());
  78. else
  79. return s48_enter_gid(call, s48_extract_boolean_2(call, real_p) ? getgid() : getegid());
  80. }
  81. static s48_ref_t
  82. posix_set_id(s48_call_t call, s48_ref_t user_p, s48_ref_t real_p, s48_ref_t id)
  83. {
  84. int status;
  85. if (s48_extract_boolean_2(call, user_p))
  86. RETRY_OR_RAISE_NEG(status,
  87. s48_extract_boolean_2(call, real_p) ?
  88. setuid(s48_extract_uid(call, id)) :
  89. seteuid(s48_extract_uid(call, id)));
  90. else
  91. RETRY_OR_RAISE_NEG(status,
  92. s48_extract_boolean_2(call, real_p) ?
  93. setgid(s48_extract_gid(call, id)) :
  94. setegid(s48_extract_gid(call, id)));
  95. return s48_unspecific_2(call);
  96. }
  97. static s48_ref_t
  98. posix_get_login(s48_call_t call)
  99. {
  100. char *login = getlogin();
  101. return (login == NULL) ? s48_false_2(call) : s48_enter_byte_string_2(call, login);
  102. }
  103. static s48_ref_t
  104. posix_get_env(s48_call_t call, s48_ref_t name)
  105. {
  106. char *value;
  107. value = getenv(s48_extract_byte_vector_readonly_2(call, name));
  108. return (value == NULL) ? s48_false_2(call) : s48_enter_byte_string_2(call, value);
  109. }
  110. static s48_ref_t
  111. posix_set_env(s48_call_t call, s48_ref_t name, s48_ref_t value)
  112. {
  113. int status;
  114. RETRY_OR_RAISE_NEG(status,
  115. setenv(s48_extract_byte_vector_readonly_2(call, name),
  116. s48_extract_byte_vector_readonly_2(call, value), 1));
  117. return s48_unspecific_2(call);
  118. }
  119. /*
  120. * Here we turn an array of strings of the form "name=value" into a list
  121. * of pairs ("name" . "value").
  122. */
  123. static s48_ref_t
  124. posix_get_env_alist(s48_call_t call)
  125. {
  126. extern char **ENVIRON_NAME;
  127. char **c_env = ENVIRON_NAME;
  128. s48_ref_t sch_env = s48_null_2(call);
  129. s48_ref_t name;
  130. for(; *c_env != NULL; c_env++) {
  131. char *entry = *c_env;
  132. s48_ref_t value;
  133. char *name_end = strchr(entry, '=');
  134. name = s48_enter_byte_substring_2(call, entry, name_end - entry);
  135. value = s48_enter_byte_substring_2(call, name_end + 1, strlen(name_end + 1));
  136. sch_env = s48_cons_2(call, s48_cons_2(call, name, value), sch_env); }
  137. return sch_env;
  138. }
  139. /*
  140. * Again we turn an array into a list.
  141. */
  142. static s48_ref_t
  143. posix_get_groups(s48_call_t call)
  144. {
  145. int status, count, i;
  146. gid_t *grouplist;
  147. s48_ref_t groups = s48_null_2(call);
  148. s48_ref_t temp;
  149. count = getgroups(0, (gid_t *)NULL);
  150. grouplist = (gid_t *) malloc(count * sizeof(gid_t));
  151. if (grouplist == NULL)
  152. s48_out_of_memory_error_2(call);
  153. RETRY_NEG(status, getgroups(count, grouplist));
  154. if (status == -1) {
  155. free(grouplist);
  156. s48_os_error_2(call, "posix_get_groups", errno, 0); }
  157. for(i = count - 1; i > -1; i--) {
  158. temp = s48_enter_gid(call, grouplist[i]);
  159. groups = s48_cons_2(call, temp, groups);
  160. }
  161. free(grouplist);
  162. return groups;
  163. }
  164. /*
  165. * uname() - we could define a record for this, but it seems like overkill.
  166. */
  167. static s48_ref_t
  168. posix_sys_name(s48_call_t call, s48_ref_t which)
  169. {
  170. struct utsname names;
  171. char *value;
  172. int status;
  173. RETRY_OR_RAISE_NEG(status, uname(&names));
  174. switch (s48_extract_long_2(call, which)) {
  175. case 0: value = names.sysname; break;
  176. case 1: value = names.nodename; break;
  177. case 2: value = names.release; break;
  178. case 3: value = names.version; break;
  179. default: value = names.machine;
  180. }
  181. return s48_enter_string_latin_1_2(call, value);
  182. }
  183. /*
  184. * Terminals
  185. */
  186. static s48_ref_t
  187. posix_get_terminal_pathname(s48_call_t call)
  188. {
  189. char termid[L_ctermid];
  190. char *status = ctermid(termid);
  191. return (*status == '\0') ? s48_false_2(call) : s48_enter_byte_string_2(call, termid);
  192. }
  193. static s48_ref_t
  194. posix_tty_name(s48_call_t call, s48_ref_t channel)
  195. {
  196. char *name;
  197. name = ttyname(s48_unsafe_extract_long_2(call, s48_channel_os_index_2(call, channel)));
  198. return (name == NULL) ? s48_false_2(call) : s48_enter_byte_string_2(call, name);
  199. }
  200. static s48_ref_t
  201. posix_is_a_tty(s48_call_t call, s48_ref_t channel)
  202. {
  203. return s48_enter_boolean_2(call,
  204. isatty(s48_unsafe_extract_long_2(call,
  205. s48_channel_os_index_2(call, channel))));
  206. }