1 /* The customized getenv() function itself. */
3 /* We keep a cached environment for the latest client, with only
4 * the interesting variables picked out. */
5 /* FIXME: We should keep the old clients' environments as well,
6 * in case the app uses stale getenv() pointers! */
16 #include "screenenv.h"
18 /* Just add more if you need. */
19 const static char *grabenv
[] = {
30 /* The cached environment. */
34 char *vars
[sizeof(grabenv
) / sizeof(*grabenv
)];
38 static struct env env0
;
41 /* Parse environment in /proc/.../environ and save it in *env. */
43 int loadenv(pid_t pid
, struct env
*env
)
48 snprintf(envname
, 128, "/proc/%d/environ", pid
);
49 int fd
= open(envname
, O_RDONLY
);
50 if (fd
< 0) return -1;
52 char *envp
= env
->buf_
;
54 char buf
[8192], *bufp
;
57 /* What do we do in this read() iteration; we keep enough context
58 * necessary in the buffer from the previous iteration; if the
59 * variable is not interesting or is too long for our taste, we
60 * just skip to next one. */
61 enum { VARNAME_LOAD
, VALUE_LOAD
, VAR_SKIP
} state
= VARNAME_LOAD
;
67 l
= read(fd
, buf
+ bl
, sizeof(buf
) - bl
);
80 tok
= memchr(bufp
, '=', bl
);
86 memmove(buf
, bufp
, bl
);
91 for (var
= 0; grabenv
[var
]; var
++)
92 if (!strcmp(bufp
, grabenv
[var
]))
94 bl
-= tok
- bufp
; bufp
= tok
;
102 tok
= memchr(bufp
, 0, bl
);
108 bl
-= tok
- bufp
; bufp
= tok
;
109 state
= VARNAME_LOAD
;
112 tok
= memchr(bufp
, 0, bl
);
118 memmove(buf
, bufp
, bl
);
123 int vallen
= tok
- bufp
;
124 if (sizeof(env
->buf_
) - (envp
- env
->buf_
) < vallen
) {
125 /* Environment space full. */
129 memcpy(envp
, bufp
, vallen
);
130 // printf("[%d] `%s'\n", var, envp);
131 env
->vars
[var
] = envp
; envp
+= vallen
;
132 bl
-= tok
- bufp
; bufp
= tok
;
133 state
= VARNAME_LOAD
;
144 /* The getenv() wrapper itself! */
146 __attribute__((visibility("default"))) char *
147 getenv(const char *env
)
149 static char *(*up_getenv
)(const char *);
150 if (__builtin_expect(!up_getenv
, 0))
151 up_getenv
= dlsym(RTLD_NEXT
, "getenv");
153 /* The fast way out, not to hog non-screen processes. */
154 static int in_screen
= -1;
155 if (__builtin_expect(in_screen
< 0, 0))
156 in_screen
= !strcmp(up_getenv("TERM"), "screen");
157 if (__builtin_expect(!in_screen
, 1))
158 return up_getenv(env
);
160 /* TERM=screen - so probably we will get client pid? */
161 pid_t pid
= get_client_pid(getpid());
162 if (__builtin_expect(pid
<= 0, 0))
163 return up_getenv(env
);
165 /* Do we look for a hijacked variable? */
167 for (var
= 0; grabenv
[var
]; var
++)
168 if (__builtin_expect(!strcmp(env
, grabenv
[var
]), 0))
170 if (__builtin_expect(!grabenv
[var
], 1))
171 return up_getenv(env
);
173 /* Should we reload the environment? */
174 if (env0
.pid
!= pid
) {
175 memset(&env0
, 0, sizeof(env0
));
176 if (loadenv(pid
, &env0
) < 0)
177 return up_getenv(env
);
180 return env0
.vars
[var
];
184 void putsn(char *str
)
186 puts(str
? str
: "(null)");
191 putsn(getenv("USER"));
192 putsn(getenv("DISPLAY"));
193 putsn(getenv("TERM"));
194 putsn(getenv("XDG_SESSION_COOKIE"));