-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathmsh_cmd_wait.c
More file actions
132 lines (103 loc) · 2.54 KB
/
msh_cmd_wait.c
File metadata and controls
132 lines (103 loc) · 2.54 KB
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
#include <sys/file.h>
#include <sys/ppoll.h>
#include <sys/inotify.h>
#include <string.h>
#include <format.h>
#include <util.h>
#include "msh.h"
#include "msh_cmd.h"
static int check_file(CTX, char* path)
{
struct stat st;
int ret;
if((ret = sys_stat(path, &st)) >= 0)
return 0;
if(ret == -ENOENT)
return 1;
return error(ctx, NULL, path, ret);
}
static int match_event(struct inotify_event* ino, char* name)
{
return !strcmp(name, ino->name);
}
static int watch_ino_for(CTX, int fd, char* name, struct timespec* ts)
{
struct pollfd pfd = { .fd = fd, .events = POLLIN };
int ret, rd;
while(1) {
if((ret = sys_ppoll(&pfd, 1, ts, NULL)) < 0)
return error(ctx, "ppoll", NULL, ret);
if(ret == 0)
return -ETIMEDOUT;
char buf[512];
int len = sizeof(buf);
if((rd = sys_read(fd, buf, len)) < 0)
return error(ctx, "inotify", NULL, rd);
char* end = buf + rd;
char* ptr = buf;
while(ptr < end) {
struct inotify_event* ino = (void*) ptr;
if(match_event(ino, name))
return 0;
ptr += sizeof(*ino) + ino->len;
}
}
}
static void prep_dirname(char* dir, int dlen, char* name, char* base)
{
if(base > name) {
int len = base - name - 1;
if(len > dlen - 1) len = dlen - 1;
memcpy(dir, name, len);
dir[len] = '\0';
} else {
dir[0] = '.';
dir[1] = '\0';
}
}
static int waitfor(CTX, int fd, struct timespec* ts, char* name)
{
char* base = basename(name);
char dir[base - name + 3];
long wd, ret;
prep_dirname(dir, sizeof(dir), name, base);
if((wd = sys_inotify_add_watch(fd, dir, IN_CREATE)) >= 0)
goto got;
else if(wd != -ENOENT)
goto err; /* something's wrong with the parent dir */
else if(!strcmp(dir, "/"))
goto err; /* no point in waiting for / to appear */
if((ret = waitfor(ctx, fd, ts, dir)) < 0)
goto out; /* bad parent dir, or timed out waiting */
if((wd = sys_inotify_add_watch(fd, dir, IN_CREATE)) >= 0)
goto got;
err:
return error(ctx, "inotify", name, wd);
got:
if((ret = check_file(ctx, name)) <= 0)
; /* the file already exists */
else ret = watch_ino_for(ctx, fd, base, ts);
sys_inotify_rm_watch(fd, wd);
out:
return ret;
}
int cmd_waitfor(CTX)
{
char* name;
int timeout;
if((shift_str(ctx, &name)))
return -1;
if(!numleft(ctx))
timeout = 2;
else if(shift_int(ctx, &timeout))
return -1;
struct timespec ts = { timeout, 0 };
int fd, ret;
if((fd = sys_inotify_init1(IN_NONBLOCK)) < 0)
return error(ctx, "inotify", NULL, fd);
ret = waitfor(ctx, fd, &ts, name);
sys_close(fd);
if(ret == -ETIMEDOUT)
return error(ctx, "timeout waiting for", name, 0);
return ret;
}