1/* This file is part of Mailfromd.             -*- c -*-
2   Copyright (C) 2006-2021 Sergey Poznyakoff
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 3, or (at your option)
7   any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17MF_BUILTIN_MODULE
18
19#include <sys/utsname.h>
20#include <mflib/status.h>
21
22MF_DEFUN(system, NUMBER, STRING str)
23{
24	MF_RETURN(system(str));
25}
26END
27
28MF_DEFUN(time, NUMBER)
29{
30	time_t t = time(NULL);
31	MF_RETURN(t);
32}
33END
34
35MF_DEFUN(sleep, VOID, NUMBER seconds, OPTIONAL, NUMBER useconds)
36{
37	struct timeval tv;
38
39	tv.tv_sec = seconds;
40	tv.tv_usec = MF_OPTVAL(useconds);
41	/* FIXME: signals? */
42	select(0, NULL, NULL, NULL, &tv);
43}
44END
45
46MF_DEFUN(strftime, STRING, STRING fmt, NUMBER timestamp, OPTIONAL, NUMBER gmt)
47{
48	char buf[1024];
49	time_t t = timestamp;
50	struct tm *tm = MF_OPTVAL(gmt) ? gmtime(&t) : localtime(&t);
51	size_t size = strftime(buf, sizeof(buf), fmt, tm);
52	size_t off;
53	char *s = MF_ALLOC_HEAP(off, size + 1);
54	strcpy(s, buf);
55	MF_RETURN(off, size);
56}
57END
58
59MF_DEFUN(umask, NUMBER, NUMBER mask)
60{
61	mode_t mode = umask(mask);
62	MF_RETURN(mode);
63}
64END
65
66/* Interface to the system uname call.
67
68   Format sequences are:
69   %s   sysname
70   %n   nodename
71   %r   release
72   %v   version
73   %m   machine
74*/
75MF_DEFUN(uname, STRING, STRING fmt)
76{
77	struct utsname ubuf;
78
79	uname(&ubuf);
80	MF_OBSTACK_BEGIN();
81	while (*fmt) {
82		if (*fmt == '%') {
83			switch (*++fmt) {
84			case 's':
85				MF_OBSTACK_GROW(ubuf.sysname,
86						strlen(ubuf.sysname));
87				break;
88			case 'n':
89				MF_OBSTACK_GROW(ubuf.nodename,
90						strlen(ubuf.nodename));
91				break;
92			case 'r':
93				MF_OBSTACK_GROW(ubuf.release,
94						strlen(ubuf.release));
95				break;
96			case 'v':
97				MF_OBSTACK_GROW(ubuf.version,
98						strlen(ubuf.version));
99				break;
100			case 'm':
101				MF_OBSTACK_GROW(ubuf.machine,
102						strlen(ubuf.machine));
103				break;
104			case '%':
105				MF_OBSTACK_1GROW('%');
106				break;
107			default:
108				MF_OBSTACK_1GROW('%');
109				MF_OBSTACK_1GROW(*fmt);
110			}
111			fmt++;
112		} else {
113			MF_OBSTACK_1GROW(*fmt);
114			fmt++;
115		}
116	}
117	MF_OBSTACK_1GROW(0);
118	MF_RETURN_OBSTACK();
119}
120END
121
122static struct builtin_const_trans access_modes[] = {
123	MF_TRANS(R_OK),
124	MF_TRANS(W_OK),
125	MF_TRANS(X_OK),
126	MF_TRANS(F_OK)
127};
128
129MF_DEFUN(access, NUMBER, STRING pathname, NUMBER mode)
130{
131	int c_mode;
132
133	MF_ASSERT(_builtin_const_to_c(access_modes,
134				      MU_ARRAY_SIZE(access_modes),
135				      mode,
136				      &c_mode) == 0,
137		  mfe_failure,
138		  "bad access mode");
139	MF_RETURN(access(pathname, c_mode) == 0);
140}
141END
142
143MF_DEFUN(getenv, STRING, STRING name)
144{
145	char *p = getenv(name);
146	MF_ASSERT(p != NULL,
147		  mfe_not_found,
148		  "%s: environment variable not defined",
149		  name);
150	MF_RETURN(p);
151}
152END
153
154MF_DEFUN(unlink, VOID, STRING name)
155{
156	int rc = unlink(name);
157	MF_ASSERT(rc == 0,
158		  mfe_failure,
159		  "cannot unlink %s: %s", name, mu_strerror(errno));
160}
161END
162
163