summaryrefslogtreecommitdiff
path: root/os.h
blob: 23e94f291a2956ff1618bdc5467385b533d43df3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/// \file
/// a bunch of OS-dependent functions
#ifndef OS_H_
#define OS_H_

#include "base.h"

typedef enum {
	FS_NON_EXISTENT,
	FS_FILE,
	FS_DIRECTORY,
	FS_OTHER
} FsType;

enum {
	FS_PERMISSION_READ = 0x01,
	FS_PERMISSION_WRITE = 0x02,
};
/// permission bits
typedef u8 FsPermission;

typedef struct {
	FsType type;
	char name[];
} FsDirectoryEntry;

/// returns what kind of thing this is.
FsType fs_path_type(const char *path);
/// get which permissions user has for file
FsPermission fs_path_permission(const char *path);
/// Does this file exist? Returns false for directories.
bool fs_file_exists(const char *path);
/// returns size of file or -1 on error
int64_t fs_file_size(const char *path);
/// Returns a `NULL`-terminated array of the files/directories in this directory, or `NULL` on error.
///
/// When you're done with the entries, call \ref fs_dir_entries_free (or call free on each entry, then on the whole array).
/// NOTE: The files/directories aren't returned in any particular order!
FsDirectoryEntry **fs_list_directory(const char *dirname);
/// Create the directory specified by `path`
///
/// \returns
/// 1  if the directory was created successfully\n
/// 0  if the directory already exists\n
/// -1 if the path already exists, but it's not a directory, or if there's another error (e.g. don't have permission to create directory).
int fs_mkdir(const char *path);
/// Puts the current working directory into `buf`, including a null-terminator, writing at most `buflen` bytes.
///
/// \returns
/// 1  if the working directory was inserted into buf successfully\n
/// 0  if buf is too short to hold the cwd\n
/// -1 if we can't get the cwd for whatever reason.
int os_get_cwd(char *buf, size_t buflen);
/// Unlike ISO C rename() function, this will overwrite `newname` if it exists.
///
/// \returns
/// >= 0 if successful\n
/// < 0 on error
int os_rename_overwrite(const char *oldname, const char *newname);
/// get last modification time of file
struct timespec time_last_modified(const char *filename);
/// get time since some arbitrary point
struct timespec time_get(void);
/// sleep for a certain number of nanoseconds
void time_sleep_ns(u64 ns);

/// runs xdg-open or equivalent on the given path, which can be a URL.
///
/// \returns `true` on success.
bool open_with_default_application(const char *path);
/// equivalent to POSIX function `chdir`, but returns `true` on success and `false` on failure.
bool change_directory(const char *path);

/// free the entries generated by \ref fs_list_directory.
static void fs_dir_entries_free(FsDirectoryEntry **entries) {
	for (int i = 0; entries[i]; ++i)
		free(entries[i]);
	free(entries);
}

/// get current time in seconds since some arbitrary point
static double time_get_seconds(void) {
	struct timespec t = time_get();
	return (double)t.tv_sec
		+ (double)t.tv_nsec * 1e-9;
}

/// sleep for seconds
static void time_sleep_seconds(double s) {
	if (s <= 0) return;
	time_sleep_ns((u64)(s * 1000000000));
}

/// a process
typedef struct Process Process;

/// zero everything except what you're using
typedef struct {
	bool separate_stderr;
	const char *working_directory;
	/// for forwards compatibility
	char _reserved[256];
} ProcessSettings;

typedef struct {
	/// string like "exited with code 9"
	char message[62];
	/// it might be possible that both `signalled` and `exited` are false,
	/// if something weird happens.
	bool signalled;
	bool exited;
	/// only relevant if `exited = true`
	int exit_code;
	/// only relevant if `signalled = true`
	int signal;
} ProcessExitInfo;

/// get process ID of this process
int process_get_id(void);
/// execute the given command (like if it was passed to `system()`), creating a new \ref Process object.
///
/// returns a valid process object on failure, but it will have an error, according to \ref process_geterr
Process *process_run_ex(const char *command, const ProcessSettings *settings);
/// like \ref process_run_ex, but with the default settings
Process *process_run(const char *command);
/// returns the error last error produced, or NULL if there was no error.
const char *process_geterr(Process *process);
/// write to stdin
///
/// \returns -2 on error,\n
///  -1 if the read end of the pipe was closed,\n
/// or a non-negative number indicating the number of bytes written.
long long process_write(Process *process, const char *data, size_t size);
/// read from stdout+stderr.
///
/// \returns
/// -2 on error\n
/// -1 on end of file\n
/// 0 if no data is available right now\n
/// or a positive number indicating the number of bytes read to `data` (at most `size`)\n
/// This does a nonblocking read.
long long process_read(Process *process, char *data, size_t size);
/// like \ref process_read, but reads stderr.
///
/// this function ALWAYS RETURNS -2 if `separate_stderr` is not specified in the \ref ProcessSettings.
///   if `separate_stderr` is false, then both stdout and stderr will be sent via \ref process_read.
long long process_read_stderr(Process *process, char *data, size_t size);
/// Checks if the process has exited.
///
/// \returns
/// -1 if the process returned a non-zero exit code, or got a signal.\n
/// 1  if the process exited successfully\n
/// 0  if the process hasn't exited.\n
/// If the process has exited, `*info` will be filled out with details.
/// if the process is no longer running, `*process` will be freed and set to NULL.
int process_check_status(Process **process, ProcessExitInfo *info);
/// kills process if still running
///
/// this also frees any resources used by `*process`.
/// `*process` will be set to NULL.
void process_kill(Process **process);


typedef struct Socket Socket;

/// create TCP socket with address and port.
///
/// currently only supports IPv4.
/// if you pass `NULL` for `address`, `127.0.0.1` will be used.
Socket *socket_connect_tcp(const char *address, u16 port);
/// get last error from socket
///
/// returns `""` if there is no error.
const char *socket_get_error(Socket *socket);
/// read from socket.
///
/// \returns
///  -2 on error\n
///  -1 on end of file\n
///   0 if no data is available right now\n
/// or a positive number indicating the number of bytes read to `data` (at most `size`)
///
/// This does a nonblocking read.
long long socket_read(Socket *socket, char *data, size_t size);
/// write to socket
///
/// \returns -2 on error\n
///  -1 if the read end of the socket was closed\n
/// or a non-negative number indicating the number of bytes written.
long long socket_write(Socket *socket, const char *data, size_t size);
/// close socket
///
/// if `*psocket` is `NULL`, this does nothing.
///
/// sets `*psocket` to `NULL`.
void socket_close(Socket **psocket);

#endif // OS_H_