1 /*
2  * system.h - Gauche system interface
3  *
4  *   Copyright (c) 2000-2020  Shiro Kawai  <shiro@acm.org>
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *   1. Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *
13  *   2. Redistributions in binary form must reproduce the above copyright
14  *      notice, this list of conditions and the following disclaimer in the
15  *      documentation and/or other materials provided with the distribution.
16  *
17  *   3. Neither the name of the authors nor the names of its contributors
18  *      may be used to endorse or promote products derived from this
19  *      software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef GAUCHE_SYSTEM_H
35 #define GAUCHE_SYSTEM_H
36 
37 /* This file provides some OS abstraction layer for Gauche. */
38 
39 /*==============================================================
40  * System call wrapper
41  */
42 
43 /* Our rule of thumb is that we always restart system calls
44  * when it is interrupted prematurely.  The following macro
45  * hides restarting.
46  */
47 
48 #define SCM_SYSCALL3(result, expr, check)                       \
49   do {                                                          \
50     (result) = (expr);                                          \
51     if ((check) && (errno == EINTR || errno == EPIPE)) {        \
52       ScmVM *vm__ = Scm_VM();                                   \
53       int epipe__ = (errno == EPIPE);                           \
54       errno = 0;                                                \
55       SCM_SIGCHECK(vm__);                                       \
56       if (epipe__) {                                            \
57         errno = EPIPE;                                          \
58         break;                                                  \
59       }                                                         \
60     } else {                                                    \
61       break;                                                    \
62     }                                                           \
63   } while (1)
64 
65 #define SCM_SYSCALL(result, expr) \
66   SCM_SYSCALL3(result, expr, (result < 0))
67 
68 /*==============================================================
69  * Utility functions
70  */
71 
72 /* Some commonly-used utilities */
73 
74 SCM_EXTERN int Scm_GetPortFd(ScmObj port_or_fd, int needfd);
75 
76 SCM_EXTERN off_t  Scm_IntegerToOffset(ScmObj i);
77 SCM_EXTERN ScmObj Scm_OffsetToInteger(off_t o);
78 
79 /*==============================================================
80  * Filesystem
81  */
82 
83 SCM_EXTERN ScmObj Scm_ReadDirectory(ScmString *pathname);
84 SCM_EXTERN ScmObj Scm_GetCwd(void);
85 
86 #define SCM_PATH_ABSOLUTE       (1L<<0)
87 #define SCM_PATH_EXPAND         (1L<<1)
88 #define SCM_PATH_CANONICALIZE   (1L<<2)
89 #define SCM_PATH_FOLLOWLINK     (1L<<3) /* not supported yet */
90 SCM_EXTERN ScmObj Scm_NormalizePathname(ScmString *pathname, int flags);
91 SCM_EXTERN ScmObj Scm_TmpDir(void);
92 SCM_EXTERN ScmObj Scm_DirName(ScmString *filename);
93 SCM_EXTERN ScmObj Scm_BaseName(ScmString *filename);
94 
95 /* struct stat */
96 #ifdef GAUCHE_WINDOWS
97 typedef struct __stat64 ScmStat;
98 #else  /*!GAUCHE_WINDOWS*/
99 typedef struct stat ScmStat;
100 #endif /*!GAUCHE_WINDOWS*/
101 
102 typedef struct ScmSysStatRec {
103     SCM_HEADER;
104     ScmStat statrec;
105 } ScmSysStat;
106 
107 SCM_CLASS_DECL(Scm_SysStatClass);
108 #define SCM_CLASS_SYS_STAT    (&Scm_SysStatClass)
109 #define SCM_SYS_STAT(obj)     ((ScmSysStat*)(obj))
110 #define SCM_SYS_STAT_P(obj)   (SCM_XTYPEP(obj, SCM_CLASS_SYS_STAT))
111 #define SCM_SYS_STAT_STAT(obj) (&SCM_SYS_STAT(obj)->statrec)
112 
113 SCM_EXTERN ScmObj Scm_MakeSysStat(void); /* returns empty SysStat */
114 
115 /*==============================================================
116  * Time
117  */
118 
119 /* time_t
120  * NB: POSIX defines time_t to be a type to represent number of seconds
121  * since Epoch.  It may be a structure.  In Gauche we just convert it
122  * to a number.
123  */
124 SCM_EXTERN ScmObj Scm_MakeSysTime(time_t time);
125 SCM_EXTERN time_t Scm_GetSysTime(ScmObj val);
126 
127 SCM_EXTERN void Scm_GetTimeOfDay(u_long *sec, u_long *usec);
128 SCM_EXTERN long Scm_CurrentMicroseconds();
129 SCM_EXTERN int  Scm_ClockGetTimeMonotonic(u_long *sec, u_long *nsec);
130 SCM_EXTERN int  Scm_ClockGetResMonotonic(u_long *sec, u_long *nsec);
131 
132 /* Gauche also has a <time> object, as specified in SRFI-18, SRFI-19
133  * and SRFI-21.  It can be constructed from the basic system interface
134  * such as sys-time or sys-gettimeofday.
135  */
136 typedef struct ScmTimeRec {
137     SCM_HEADER;
138     ScmObj type;       /* 'time-utc by default.  see SRFI-19 */
139     int64_t sec;       /* seconds */
140     long nsec;         /* nanoseconds */
141 } ScmTime;
142 
143 SCM_CLASS_DECL(Scm_TimeClass);
144 #define SCM_CLASS_TIME        (&Scm_TimeClass)
145 #define SCM_TIME(obj)         ((ScmTime*)obj)
146 #define SCM_TIMEP(obj)        SCM_XTYPEP(obj, SCM_CLASS_TIME)
147 
148 SCM_EXTERN ScmObj Scm_CurrentTime(void);
149 SCM_EXTERN ScmObj Scm_MakeTime(ScmObj type, long sec, long nsec);
150 SCM_EXTERN ScmObj Scm_MakeTime64(ScmObj type, int64_t sec, long nsec);
151 SCM_EXTERN ScmObj Scm_IntSecondsToTime(long sec);
152 SCM_EXTERN ScmObj Scm_Int64SecondsToTime(int64_t sec);
153 SCM_EXTERN ScmObj Scm_RealSecondsToTime(double sec);
154 SCM_EXTERN ScmObj Scm_TimeToSeconds(ScmTime *t);
155 
156 /* struct timespec compatibility handling.  MinGW32 runtime v3.21, at least, has
157    incompatible struct timespec. */
158 #if defined(HAVE_STRUCT_TIMESPEC) && (!defined(GAUCHE_WINDOWS) || defined(__MINGW64_VERSION_MAJOR))
159 typedef struct timespec ScmTimeSpec;
160 #else  /*!(defined(HAVE_STRUCT_TIMESPEC) && (!defined(GAUCHE_WINDOWS) || defined(__MINGW64_VERSION_MAJOR)))*/
161 typedef struct ScmTimeSpecRec {
162     time_t tv_sec;
163     long   tv_nsec;
164 } ScmTimeSpec;
165 #endif /*!(defined(HAVE_STRUCT_TIMESPEC) && (!defined(GAUCHE_WINDOWS) || defined(__MINGW64_VERSION_MAJOR)))*/
166 
167 SCM_EXTERN ScmTimeSpec *Scm_GetTimeSpec(ScmObj t, ScmTimeSpec *spec);
168 
169 /* sched_yield */
170 SCM_EXTERN void   Scm_YieldCPU(void);
171 
172 /* struct tm */
173 typedef struct ScmSysTmRec {
174     SCM_HEADER;
175     struct tm tm;
176 } ScmSysTm;
177 
178 SCM_CLASS_DECL(Scm_SysTmClass);
179 #define SCM_CLASS_SYS_TM      (&Scm_SysTmClass)
180 #define SCM_SYS_TM(obj)       ((ScmSysTm*)(obj))
181 #define SCM_SYS_TM_P(obj)     (SCM_XTYPEP(obj, SCM_CLASS_SYS_TM))
182 #define SCM_SYS_TM_TM(obj)    SCM_SYS_TM(obj)->tm
183 
184 SCM_EXTERN ScmObj Scm_MakeSysTm(struct tm *);
185 
186 SCM_EXTERN int    Scm_NanoSleep(const ScmTimeSpec *req,
187                                 ScmTimeSpec *rem);
188 
189 #if !HAVE_UTIMENSAT
190 int utimensat(int, const char*, const ScmTimeSpec*, int);
191 #  if !defined(AT_FDCWD)
192 #  define AT_FDCWD -1
193 #  endif
194 #  if !defined(UTIME_NOW)
195 #  define UTIME_NOW -1
196 #  endif
197 #  if !defined(UTIME_OMIT)
198 #  define UTIME_OMIT -1
199 #  endif
200 #endif /*!HAVE_UTIMENSAT*/
201 
202 /*==============================================================
203  * Groups and users
204  */
205 
206 /* struct group */
207 typedef struct ScmSysGroupRec {
208     SCM_HEADER;
209     ScmObj name;
210     ScmObj gid;
211     ScmObj passwd;
212     ScmObj mem;
213 } ScmSysGroup;
214 
215 SCM_CLASS_DECL(Scm_SysGroupClass);
216 #define SCM_CLASS_SYS_GROUP    (&Scm_SysGroupClass)
217 #define SCM_SYS_GROUP(obj)     ((ScmSysGroup*)(obj))
218 #define SCM_SYS_GROUP_P(obj)   (SCM_XTYPEP(obj, SCM_CLASS_SYS_GROUP))
219 
220 SCM_EXTERN ScmObj Scm_GetGroupById(gid_t gid);
221 SCM_EXTERN ScmObj Scm_GetGroupByName(ScmString *name);
222 
223 /* struct passwd */
224 typedef struct ScmSysPasswdRec {
225     SCM_HEADER;
226     ScmObj name;
227     ScmObj passwd;
228     ScmObj uid;
229     ScmObj gid;
230     ScmObj gecos;
231     ScmObj dir;
232     ScmObj shell;
233     ScmObj pwclass;
234 } ScmSysPasswd;
235 
236 SCM_CLASS_DECL(Scm_SysPasswdClass);
237 #define SCM_CLASS_SYS_PASSWD    (&Scm_SysPasswdClass)
238 #define SCM_SYS_PASSWD(obj)     ((ScmSysPasswd*)(obj))
239 #define SCM_SYS_PASSWD_P(obj)   (SCM_XTYPEP(obj, SCM_CLASS_SYS_PASSWD))
240 
241 SCM_EXTERN ScmObj Scm_GetPasswdById(uid_t uid);
242 SCM_EXTERN ScmObj Scm_GetPasswdByName(ScmString *name);
243 
244 /*==============================================================
245  * Program execution
246  */
247 
248 SCM_EXTERN int    Scm_IsSugid(void);
249 
250 /* flags for Scm_SysExec */
251 enum {
252     SCM_EXEC_WITH_FORK = (1L<<0), /* fork() before exec(), i.e. spawn(). */
253     SCM_EXEC_DETACHED = (1L<<1)   /* try to detach from process group.
254                                      good for daemoninzing. */
255 };
256 
257 SCM_EXTERN ScmObj Scm_SysExec(ScmString *file, ScmObj args,
258                               ScmObj iomap, ScmSysSigset *mask,
259                               ScmString *dir, int flags);
260 SCM_EXTERN int   *Scm_SysPrepareFdMap(ScmObj iomap);
261 SCM_EXTERN void   Scm_SysSwapFds(int *fds);
262 
263 SCM_EXTERN void   Scm_SysKill(ScmObj process, int signal);
264 SCM_EXTERN ScmObj Scm_SysWait(ScmObj process, int options);
265 
266 /*==============================================================
267  * Select
268  */
269 
270 /* select */
271 #ifdef HAVE_SELECT
272 typedef struct ScmSysFdsetRec {
273     SCM_HEADER;
274     int maxfd;
275     fd_set fdset;
276 } ScmSysFdset;
277 
278 SCM_CLASS_DECL(Scm_SysFdsetClass);
279 #define SCM_CLASS_SYS_FDSET     (&Scm_SysFdsetClass)
280 #define SCM_SYS_FDSET(obj)      ((ScmSysFdset*)(obj))
281 #define SCM_SYS_FDSET_P(obj)    (SCM_XTYPEP(obj, SCM_CLASS_SYS_FDSET))
282 
283 SCM_EXTERN ScmObj Scm_SysSelect(ScmObj rfds, ScmObj wfds, ScmObj efds,
284                                 ScmObj timeout);
285 SCM_EXTERN ScmObj Scm_SysSelectX(ScmObj rfds, ScmObj wfds, ScmObj efds,
286                                  ScmObj timeout);
287 #else  /*!HAVE_SELECT*/
288 /* dummy definitions */
289 typedef struct ScmHeaderRec ScmSysFdset;
290 #define SCM_SYS_FDSET(obj)      (obj)
291 #define SCM_SYS_FDSET_P(obj)    (FALSE)
292 #endif /*!HAVE_SELECT*/
293 
294 /*==============================================================
295  * Miscellaneous
296  */
297 
298 SCM_EXTERN int    Scm_Mkstemp(char *tmpl);
299 SCM_EXTERN ScmObj Scm_SysMkstemp(ScmString *tmpl);
300 SCM_EXTERN ScmObj Scm_SysMkdtemp(ScmString *tmpl);
301 SCM_EXTERN ScmObj Scm_Environ(void);
302 SCM_EXTERN const char *Scm_GetEnv(const char *name);
303 SCM_EXTERN void Scm_SetEnv(const char *name, const char *value, int overwrite);
304 SCM_EXTERN void Scm_UnsetEnv(const char *name);
305 SCM_EXTERN void Scm_ClearEnv(void);
306 SCM_EXTERN int  Scm_AvailableProcessors(void);
307 
308 /*==============================================================
309  * Windows-specific utility functions
310  */
311 
312 #if defined(GAUCHE_WINDOWS)
313 /* special object to wrap windows handle */
314 SCM_EXTERN ScmObj Scm_MakeWinHandle(HANDLE h, ScmObj type);
315 SCM_EXTERN int    Scm_WinHandleP(ScmObj obj, ScmObj type);
316 SCM_EXTERN HANDLE Scm_WinHandle(ScmObj h, ScmObj type);
317 
318 SCM_EXTERN ScmObj Scm_MakeWinProcess(HANDLE h);
319 SCM_EXTERN int    Scm_WinProcessP(ScmObj p);
320 SCM_EXTERN pid_t  Scm_WinProcessPID(ScmObj p);
321 SCM_EXTERN HANDLE Scm_WinProcess(ScmObj p);
322 
323 SCM_EXTERN ScmObj Scm_WinGetPipeName(HANDLE h);
324 #endif /* GAUCHE_WINDOWS */
325 
326 #endif /* GAUCHE_SYSTEM_H */
327 
328