xref: /inferno-os/libinterp/readmod.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include "lib9.h"
2 #include "isa.h"
3 #include "interp.h"
4 #include "kernel.h"
5 #include "dynld.h"
6 
7 Module*
8 readmod(char *path, Module *m, int sync)
9 {
10 	Dir *d;
11 	int fd, n, dynld;
12 	uchar *code;
13 	Module *ans;
14 	ulong length;
15 
16 	if(path[0] == '$') {
17 		if(m == nil)
18 			kwerrstr("module not built-in");
19 		return m;
20 	}
21 
22 	ans = nil;
23 	code = nil;
24 	length = 0;
25 	dynld = 0;
26 
27 	if(sync)
28 		release();
29 
30 	d = nil;
31 	fd = kopen(path, OREAD);
32 	if(fd < 0)
33 		goto done;
34 
35 	if((d = kdirfstat(fd)) == nil)
36 		goto done;
37 
38 	if(m != nil) {
39 		if(d->dev == m->dev && d->type == m->dtype &&
40 		   d->mtime == m->mtime &&
41 		   d->qid.type == m->qid.type && d->qid.path == m->qid.path && d->qid.vers == m->qid.vers) {
42 			ans = m;
43 			goto done;
44 		}
45 	}
46 
47 	if(d->length < 0 || d->length >= 8*1024*1024){
48 		kwerrstr("implausible length");
49 		goto done;
50 	}
51 	if((d->mode&0111) && dynldable(fd)){
52 		dynld = 1;
53 		goto done1;
54 	}
55 	length = d->length;
56 	code = mallocz(length, 0);
57 	if(code == nil)
58 		goto done;
59 
60 	n = kread(fd, code, length);
61 	if(n != length) {
62 		free(code);
63 		code = nil;
64 	}
65 done:
66 	if(fd >= 0)
67 		kclose(fd);
68 done1:
69 	if(sync)
70 		acquire();
71 	if(m != nil && ans == nil)
72 		unload(m);
73 	if(code != nil) {
74 		ans = parsemod(path, code, length, d);
75 		free(code);
76 	}
77 	else if(dynld){
78 		kseek(fd, 0, 0);
79 		ans = newdyncode(fd, path, d);
80 		kclose(fd);
81 	}
82 	free(d);
83 	return ans;
84 }
85