links

lynx-like text mode web browser
git clone anongit@rnpnr.xyz:links.git
Log | Files | Refs | Feed | README | LICENSE

os_dep.c (10689B)


      1 /* os_dep.c
      2  * (c) 2002 Mikulas Patocka
      3  * This file is a part of the Links program, released under GPL.
      4  */
      5 
      6 #include <fcntl.h>
      7 #include <limits.h>
      8 #include <sys/ioctl.h>
      9 #include <sys/socket.h>
     10 #include <unistd.h>
     11 
     12 #include "links.h"
     13 
     14 int page_size = 4096;
     15 
     16 int
     17 is_safe_in_shell(unsigned char c)
     18 {
     19 	return c == '@' || c == '+' || c == '-' || c == '.' || c == ','
     20 	       || c == '=' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
     21 	       || c == '_' || (c >= 'a' && c <= 'z');
     22 }
     23 
     24 static inline int
     25 is_safe_in_file(unsigned char c)
     26 {
     27 	return !(c < ' ' || c == '"' || c == '*' || c == '/' || c == ':'
     28 	         || c == '<' || c == '>' || c == '\\' || c == '|' || c >= 0x80);
     29 }
     30 
     31 static inline int
     32 is_safe_in_url(unsigned char c)
     33 {
     34 	return is_safe_in_shell(c) || c == ':' || c == '/' || c >= 0x80;
     35 }
     36 
     37 void
     38 check_shell_security(unsigned char **cmd)
     39 {
     40 	unsigned char *c = *cmd;
     41 	while (*c) {
     42 		if (!is_safe_in_shell(*c))
     43 			*c = '_';
     44 		c++;
     45 	}
     46 }
     47 
     48 void
     49 check_filename(unsigned char **file)
     50 {
     51 	unsigned char *c = *file;
     52 	while (*c) {
     53 		if (!is_safe_in_file(*c))
     54 			*c = '_';
     55 		c++;
     56 	}
     57 }
     58 
     59 int
     60 check_shell_url(unsigned char *url)
     61 {
     62 	while (*url) {
     63 		if (!is_safe_in_url(*url))
     64 			return -1;
     65 		url++;
     66 	}
     67 	return 0;
     68 }
     69 
     70 unsigned char *
     71 escape_path(char *path)
     72 {
     73 	unsigned char *result;
     74 	size_t i;
     75 	if (strchr(path, '"'))
     76 		return stracpy(cast_uchar path);
     77 	for (i = 0; path[i]; i++)
     78 		if (!is_safe_in_url(path[i]))
     79 			goto do_esc;
     80 	return stracpy(cast_uchar path);
     81 do_esc:
     82 	result = stracpy(cast_uchar "\"");
     83 	add_to_strn(&result, cast_uchar path);
     84 	add_to_strn(&result, cast_uchar "\"");
     85 	return result;
     86 }
     87 
     88 static int
     89 get_e(const char *env)
     90 {
     91 	const char *v;
     92 	if ((v = getenv(env)))
     93 		return atoi(v);
     94 	return 0;
     95 }
     96 
     97 void
     98 init_page_size(void)
     99 {
    100 	long getpg = -1;
    101 	if (getpg < 0)
    102 		getpg = getpagesize();
    103 	if (getpg > 0 && !(getpg & (getpg - 1)))
    104 		page_size = (int)getpg;
    105 }
    106 
    107 void
    108 do_signal(int sig, void (*handler)(int))
    109 {
    110 	errno = 0;
    111 	while (signal(sig, handler) == SIG_ERR && errno == EINTR)
    112 		errno = 0;
    113 }
    114 
    115 void
    116 ignore_signals(void)
    117 {
    118 	do_signal(SIGPIPE, SIG_IGN);
    119 #ifdef SIGXFSZ
    120 	do_signal(SIGXFSZ, SIG_IGN);
    121 #endif
    122 }
    123 
    124 uttime
    125 get_absolute_time(void)
    126 {
    127 	struct timeval tv;
    128 	int rs;
    129 	EINTRLOOP(rs, gettimeofday(&tv, NULL));
    130 	if (rs)
    131 		fatal_exit("gettimeofday failed: %d", errno);
    132 	return (uttime)tv.tv_sec * 1000 + (unsigned)tv.tv_usec / 1000;
    133 }
    134 
    135 uttime
    136 get_time(void)
    137 {
    138 #if defined(CLOCK_MONOTONIC_RAW) || defined(CLOCK_MONOTONIC)
    139 	struct timespec ts;
    140 	int rs;
    141 	#if defined(CLOCK_MONOTONIC_RAW)
    142 	EINTRLOOP(rs, clock_gettime(CLOCK_MONOTONIC_RAW, &ts));
    143 	if (!rs)
    144 		return (uttime)ts.tv_sec * 1000
    145 		       + (unsigned)ts.tv_nsec / 1000000;
    146 	#endif
    147 	#if defined(CLOCK_MONOTONIC)
    148 	EINTRLOOP(rs, clock_gettime(CLOCK_MONOTONIC, &ts));
    149 	if (!rs)
    150 		return (uttime)ts.tv_sec * 1000
    151 		       + (unsigned)ts.tv_nsec / 1000000;
    152 	#endif
    153 #endif
    154 	return get_absolute_time();
    155 }
    156 
    157 static unsigned char *clipboard = NULL;
    158 
    159 void
    160 os_free_clipboard(void)
    161 {
    162 	free(clipboard);
    163 	clipboard = NULL;
    164 }
    165 
    166 /* Terminal size */
    167 
    168 static void (*terminal_resize_callback)(int, int);
    169 
    170 #ifdef SIGWINCH
    171 static void
    172 sigwinch(void *s)
    173 {
    174 	int cur_xsize, cur_ysize;
    175 	get_terminal_size(&cur_xsize, &cur_ysize);
    176 	terminal_resize_callback(cur_xsize, cur_ysize);
    177 }
    178 #endif
    179 
    180 void
    181 handle_terminal_resize(void (*fn)(int, int), int *x, int *y)
    182 {
    183 	terminal_resize_callback = fn;
    184 	get_terminal_size(x, y);
    185 #if defined(SIGWINCH)
    186 	install_signal_handler(SIGWINCH, sigwinch, NULL, 0);
    187 #endif
    188 }
    189 
    190 void
    191 unhandle_terminal_resize(void)
    192 {
    193 #if defined(SIGWINCH)
    194 	install_signal_handler(SIGWINCH, NULL, NULL, 0);
    195 #endif
    196 }
    197 
    198 void
    199 get_terminal_size(int *x, int *y)
    200 {
    201 	int rs = -1;
    202 #ifdef TIOCGWINSZ
    203 	struct winsize ws;
    204 	EINTRLOOP(rs, ioctl(1, TIOCGWINSZ, &ws));
    205 #endif
    206 	if ((rs == -1
    207 #ifdef TIOCGWINSZ
    208 	     || !(*x = ws.ws_col)
    209 #endif
    210 	         )
    211 	    && !(*x = get_e("COLUMNS"))) {
    212 		*x = 80;
    213 	}
    214 	if ((rs == -1
    215 #ifdef TIOCGWINSZ
    216 	     || !(*y = ws.ws_row)
    217 #endif
    218 	         )
    219 	    && !(*y = get_e("LINES"))) {
    220 		*y = 24;
    221 	}
    222 }
    223 
    224 static void
    225 new_fd_cloexec(int fd)
    226 {
    227 	int rs;
    228 	EINTRLOOP(rs, fcntl(fd, F_SETFD, FD_CLOEXEC));
    229 }
    230 
    231 static void
    232 new_fd_bin(int fd)
    233 {
    234 	new_fd_cloexec(fd);
    235 }
    236 
    237 /* Pipe */
    238 
    239 void
    240 set_nonblock(int fd)
    241 {
    242 #ifdef O_NONBLOCK
    243 	int rs;
    244 	EINTRLOOP(rs, fcntl(fd, F_SETFL, O_NONBLOCK));
    245 #elif defined(FIONBIO)
    246 	int rs;
    247 	int on = 1;
    248 	EINTRLOOP(rs, ioctl(fd, FIONBIO, &on));
    249 #endif
    250 }
    251 
    252 static int
    253 cleanup_fds(void)
    254 {
    255 #ifdef ENFILE
    256 	if (errno == ENFILE)
    257 		return abort_background_connections();
    258 #endif
    259 #ifdef EMFILE
    260 	if (errno == EMFILE)
    261 		return abort_background_connections();
    262 #endif
    263 	return 0;
    264 }
    265 
    266 int
    267 c_pipe(int fd[2])
    268 {
    269 	int r;
    270 	do {
    271 		EINTRLOOP(r, pipe(fd));
    272 		if (!r)
    273 			new_fd_bin(fd[0]), new_fd_bin(fd[1]);
    274 	} while (r == -1 && cleanup_fds());
    275 	return r;
    276 }
    277 
    278 int
    279 c_dup(int oh)
    280 {
    281 	int h;
    282 	do {
    283 		EINTRLOOP(h, dup(oh));
    284 		if (h != -1)
    285 			new_fd_cloexec(h);
    286 	} while (h == -1 && cleanup_fds());
    287 	return h;
    288 }
    289 
    290 int
    291 c_socket(int d, int t, int p)
    292 {
    293 	int h = socket(d, t, p);
    294 
    295 	if (h == -1)
    296 		die("socket()\n");
    297 
    298 	if (fcntl(h, F_SETFD, FD_CLOEXEC) == -1)
    299 		die("c_socket(): fcntl()\n");
    300 
    301 	return h;
    302 }
    303 
    304 int
    305 c_accept(int sh, struct sockaddr *addr, socklen_t *addrlen)
    306 {
    307 	int h;
    308 	do {
    309 		EINTRLOOP(h, accept(sh, addr, addrlen));
    310 		if (h != -1)
    311 			new_fd_cloexec(h);
    312 	} while (h == -1 && cleanup_fds());
    313 	return h;
    314 }
    315 
    316 int
    317 c_open(unsigned char *path, int flags)
    318 {
    319 	int h;
    320 	do {
    321 		EINTRLOOP(h, open(cast_const_char path, flags));
    322 		if (h != -1)
    323 			new_fd_bin(h);
    324 	} while (h == -1 && cleanup_fds());
    325 	return h;
    326 }
    327 
    328 int
    329 c_open3(unsigned char *path, int flags, int mode)
    330 {
    331 	int h;
    332 	do {
    333 		EINTRLOOP(h, open(cast_const_char path, flags, mode));
    334 		if (h != -1)
    335 			new_fd_bin(h);
    336 	} while (h == -1 && cleanup_fds());
    337 	return h;
    338 }
    339 
    340 DIR *
    341 c_opendir(unsigned char *path)
    342 {
    343 	DIR *d;
    344 	do {
    345 		ENULLLOOP(d, opendir(cast_const_char path));
    346 		if (d) {
    347 			int h;
    348 			EINTRLOOP(h, dirfd(d));
    349 			if (h != -1)
    350 				new_fd_cloexec(h);
    351 		}
    352 	} while (!d && cleanup_fds());
    353 	return d;
    354 }
    355 
    356 /* Exec */
    357 
    358 int
    359 is_screen(void)
    360 {
    361 	static int xt = -1;
    362 	if (xt == -1)
    363 		xt = !!getenv("STY");
    364 	return xt;
    365 }
    366 
    367 int
    368 is_xterm(void)
    369 {
    370 	static int xt = -1;
    371 	if (xt == -1)
    372 		xt = getenv("DISPLAY") && *(char *)getenv("DISPLAY");
    373 	return xt;
    374 }
    375 
    376 void
    377 close_fork_tty(void)
    378 {
    379 	struct terminal *t = NULL;
    380 	struct list_head *lt;
    381 	struct download *d = NULL;
    382 	struct list_head *ld;
    383 	struct connection *c = NULL;
    384 	struct list_head *lc;
    385 	struct k_conn *k = NULL;
    386 	struct list_head *lk;
    387 	int rs;
    388 	EINTRLOOP(rs, close(signal_pipe[0]));
    389 	EINTRLOOP(rs, close(signal_pipe[1]));
    390 	if (terminal_pipe[1] != -1)
    391 		EINTRLOOP(rs, close(terminal_pipe[1]));
    392 	foreach (struct terminal, t, lt, terminals) {
    393 		if (t->fdin > 0)
    394 			EINTRLOOP(rs, close(t->fdin));
    395 		if (t->handle_to_close >= 0)
    396 			EINTRLOOP(rs, close(t->handle_to_close));
    397 	}
    398 	foreach (struct download, d, ld, downloads)
    399 		if (d->handle > 0)
    400 			EINTRLOOP(rs, close(d->handle));
    401 	foreach (struct connection, c, lc, queue) {
    402 		if (c->sock1 >= 0)
    403 			EINTRLOOP(rs, close(c->sock1));
    404 		if (c->sock2 >= 0)
    405 			EINTRLOOP(rs, close(c->sock2));
    406 	}
    407 	foreach (struct k_conn, k, lk, keepalive_connections)
    408 		EINTRLOOP(rs, close(k->conn));
    409 }
    410 
    411 unsigned char *
    412 os_conv_to_external_path(unsigned char *file, unsigned char *prog)
    413 {
    414 	return stracpy(file);
    415 }
    416 
    417 unsigned char *
    418 os_fixup_external_program(unsigned char *prog)
    419 {
    420 	return stracpy(prog);
    421 }
    422 
    423 /* UNIX */
    424 int
    425 exe(char *path, int fg)
    426 {
    427 #ifdef SIGCHLD
    428 	do_signal(SIGCHLD, SIG_DFL);
    429 #endif
    430 	do_signal(SIGPIPE, SIG_DFL);
    431 #ifdef SIGXFSZ
    432 	do_signal(SIGXFSZ, SIG_DFL);
    433 #endif
    434 #ifdef SIGTSTP
    435 	do_signal(SIGTSTP, SIG_DFL);
    436 #endif
    437 #ifdef SIGCONT
    438 	do_signal(SIGCONT, SIG_DFL);
    439 #endif
    440 #ifdef SIGWINCH
    441 	do_signal(SIGWINCH, SIG_DFL);
    442 #endif
    443 	return system(path);
    444 }
    445 
    446 /* clipboard -> links */
    447 unsigned char *
    448 get_clipboard_text(struct terminal *term)
    449 {
    450 	if (!clipboard)
    451 		return NULL;
    452 	return stracpy(clipboard);
    453 }
    454 
    455 /* links -> clipboard */
    456 void
    457 set_clipboard_text(struct terminal *term, unsigned char *data)
    458 {
    459 	free(clipboard);
    460 	clipboard = stracpy(data);
    461 }
    462 
    463 int
    464 clipboard_support(struct terminal *term)
    465 {
    466 	return 0;
    467 }
    468 
    469 void
    470 set_window_title(unsigned char *title)
    471 {
    472 	/* !!! FIXME */
    473 }
    474 
    475 unsigned char *
    476 get_window_title(void)
    477 {
    478 	/* !!! FIXME */
    479 	return NULL;
    480 }
    481 
    482 /* Threads */
    483 
    484 int
    485 start_thread(void (*fn)(void *, int), void *ptr, int l, int counted)
    486 {
    487 	int p[2];
    488 	pid_t f;
    489 	int rs;
    490 	if (c_pipe(p) < 0)
    491 		return -1;
    492 	EINTRLOOP(f, fork());
    493 	if (!f) {
    494 		close_fork_tty();
    495 		EINTRLOOP(rs, close(p[0]));
    496 		fn(ptr, p[1]);
    497 		EINTRLOOP(rs, (int)write(p[1], "x", 1));
    498 		EINTRLOOP(rs, close(p[1]));
    499 		_exit(0);
    500 	}
    501 	if (f == -1) {
    502 		EINTRLOOP(rs, close(p[0]));
    503 		EINTRLOOP(rs, close(p[1]));
    504 		return -1;
    505 	}
    506 	EINTRLOOP(rs, close(p[1]));
    507 	return p[0];
    508 }
    509 
    510 static void
    511 exec_new_links(struct terminal *term, unsigned char *xterm, unsigned char *exe,
    512                unsigned char *param)
    513 {
    514 	unsigned char *str;
    515 	str = stracpy(cast_uchar "");
    516 	if (*xterm) {
    517 		add_to_strn(&str, xterm);
    518 		add_to_strn(&str, cast_uchar " ");
    519 	}
    520 	add_to_strn(&str, exe);
    521 	add_to_strn(&str, cast_uchar " ");
    522 	add_to_strn(&str, param);
    523 	exec_on_terminal(term, str, cast_uchar "", 2);
    524 	free(str);
    525 }
    526 
    527 static unsigned char *
    528 links_xterm(void)
    529 {
    530 	unsigned char *xterm;
    531 	if (!(xterm = cast_uchar getenv("LINKS_XTERM"))) {
    532 		xterm = cast_uchar "xterm -e";
    533 	}
    534 	return xterm;
    535 }
    536 
    537 static int
    538 open_in_new_xterm(struct terminal *term, unsigned char *exe,
    539                   unsigned char *param)
    540 {
    541 	exec_new_links(term, links_xterm(), exe, param);
    542 	return 0;
    543 }
    544 
    545 static int
    546 open_in_new_screen(struct terminal *term, unsigned char *exe,
    547                    unsigned char *param)
    548 {
    549 	exec_new_links(term, cast_uchar "screen", exe, param);
    550 	return 0;
    551 }
    552 
    553 static const struct {
    554 	int env;
    555 	int (*open_window_fn)(struct terminal *term, unsigned char *,
    556 	                      unsigned char *);
    557 	unsigned char *text;
    558 	unsigned char *hk;
    559 } oinw[] = {
    560 	{ENV_XWIN,    open_in_new_xterm,  TEXT_(T_XTERM),  TEXT_(T_HK_XTERM) },
    561 	{ ENV_SCREEN, open_in_new_screen, TEXT_(T_SCREEN), TEXT_(T_HK_SCREEN)},
    562 };
    563 
    564 struct open_in_new *
    565 get_open_in_new(int environment)
    566 {
    567 	int i;
    568 	struct open_in_new *oin = NULL;
    569 	int noin = 0;
    570 	if (anonymous)
    571 		return NULL;
    572 	for (i = 0; i < (int)array_elements(oinw); i++)
    573 		if ((environment & oinw[i].env) == oinw[i].env) {
    574 			if ((unsigned)noin
    575 			    > INT_MAX / sizeof(struct open_in_new) - 2)
    576 				overalloc();
    577 			oin = xrealloc(oin,
    578 			               (noin + 2) * sizeof(struct open_in_new));
    579 			oin[noin].text = oinw[i].text;
    580 			oin[noin].hk = oinw[i].hk;
    581 			oin[noin].open_window_fn = &oinw[i].open_window_fn;
    582 			noin++;
    583 			oin[noin].text = NULL;
    584 			oin[noin].hk = NULL;
    585 			oin[noin].open_window_fn = NULL;
    586 		}
    587 	return oin;
    588 }
    589 
    590 void
    591 os_detach_console(void)
    592 {
    593 #if !defined(NO_FORK_ON_EXIT)
    594 	pid_t rp;
    595 	EINTRLOOP(rp, fork());
    596 	if (!rp)
    597 		reinit_child();
    598 	if (rp > 0)
    599 		_exit(0);
    600 #endif
    601 }