proc-env.c 6.4 KB

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