summaryrefslogtreecommitdiff
path: root/emulators/qemu-devel/files/patch-zb3-bsd-user-sson004c
blob: 2101ab2bdd1652e6d6809b389807ecd11d9ead2b (plain) (blame)
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
diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c
index dcf6f66..83ff852 100644
--- a/bsd-user/bsdload.c
+++ b/bsd-user/bsdload.c
@@ -154,19 +154,77 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
     return sp;
 }
 
+static int
+is_there(const char *candidate)
+{
+	struct stat fin;
+
+	/* XXX work around access(2) false positives for superuser */
+	if (access(candidate, X_OK) == 0 &&
+	    stat(candidate, &fin) == 0 &&
+	    S_ISREG(fin.st_mode) &&
+	    (getuid() != 0 ||
+	     (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+		return (1);
+	}
+	return (0);
+}
+
+static int
+find_in_path(char *path, const char *filename, char *retpath, size_t rpsize)
+{
+	const char *d;
+	int found;
+
+	if (strchr(filename, '/') != NULL)
+	    return (is_there(filename) ? 0 : -1);
+	found = 0;
+	while ((d = strsep(&path, ":")) != NULL) {
+		if (*d == '\0')
+			d = ".";
+		if (snprintf(retpath, rpsize, "%s/%s", d,
+		    filename) >= (int)rpsize)
+			continue;
+		if (is_there((const char *)retpath)) {
+			found = 1;
+			break;
+		}
+	}
+	return (found);
+}
+
 int loader_exec(const char * filename, char ** argv, char ** envp,
              struct target_pt_regs * regs, struct image_info *infop,
 	     struct bsd_binprm *bprm)
 {
     int retval;
     int i;
+    char *p, *path, fullpath[PATH_MAX];
+    ssize_t pathlen;
 
     bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES /*-sizeof(unsigned int) XXX */;
     for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
             bprm->page[i] = NULL;
-    retval = open(filename, O_RDONLY);
+
+    /* Find target executable in path, if not already fullpath. */
+    if ((p = getenv("PATH")) != NULL) {
+	    pathlen = strlen(p) + 1;
+	    path = malloc(pathlen);
+	    if (NULL == path) {
+		    fprintf(stderr, "Out of memory\n");
+		    return (-1);
+	    }
+	    memcpy(path, p, pathlen);
+	    if (find_in_path(path, filename, fullpath, sizeof(fullpath)))
+		retval = open(fullpath, O_RDONLY);
+	    else
+		retval = open(filename, O_RDONLY);
+
+    } else
+	    retval = open(filename, O_RDONLY);
     if (retval < 0)
         return retval;
+
     bprm->fd = retval;
     bprm->filename = (char *)filename;
     bprm->argc = count(argv);
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 99b94c1..9b526b3 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -1022,7 +1022,7 @@ void cpu_loop(CPUMIPSState *env)
 		switch(trapnr) {
 		case EXCP_SYSCALL: /* syscall exception */
 			syscall_num = env->active_tc.gpr[2]; /* v0 */
-			env->active_tc.PC += 4;
+			env->active_tc.PC += TARGET_INSN_SIZE;
 			if (syscall_num >= SYS_MAXSYSCALL) {
 				ret = -TARGET_ENOSYS;
 			} else {
@@ -1094,7 +1094,11 @@ void cpu_loop(CPUMIPSState *env)
 				 */
 				break;
 			}
-			/* XXX need to handle ERESTART */
+			if (-TARGET_ERESTART == ret) {
+				/* Backup the pc to point at the swi. */
+				env->active_tc.PC -= TARGET_INSN_SIZE;
+				break;
+			}
 			if ((unsigned int)ret >= (unsigned int)(-1133)) {
 				env->active_tc.gpr[7] = 1;
 				ret = -ret;
diff --git a/bsd-user/mips/target_vmparam.h b/bsd-user/mips/target_vmparam.h
index 6eca54f..abdb1dc 100644
--- a/bsd-user/mips/target_vmparam.h
+++ b/bsd-user/mips/target_vmparam.h
@@ -33,6 +33,8 @@ struct target_ps_strings {
 
 #define TARGET_SZSIGCODE 0
 
+#define	TARGET_INSN_SIZE 4
+
 #else
 
 #define	TARGET_USRSTACK 0
diff --git a/bsd-user/mips64/target_vmparam.h b/bsd-user/mips64/target_vmparam.h
index 3fe93fb..3a3bb6e 100644
--- a/bsd-user/mips64/target_vmparam.h
+++ b/bsd-user/mips64/target_vmparam.h
@@ -31,6 +31,8 @@ struct target_ps_strings {
 
 #define TARGET_PS_STRINGS  (TARGET_USRSTACK - sizeof(struct target_ps_strings))
 
+#define	TARGET_INSN_SIZE 4
+
 #else
 
 #define	TARGET_USRSTACK	 0
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index c4e8440..a26d40a 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -122,8 +122,9 @@ int
 host_to_target_signal(int sig)
 {
 
-	if (sig >= _NSIG)
+	if (sig < 0 || sig >= _NSIG)
 		return (sig);
+
 	return (host_to_target_signal_table[sig]);
 }
 
@@ -598,11 +599,13 @@ do_sigaction(int sig, const struct target_sigaction *act,
 			 if (k->_sa_handler == TARGET_SIG_IGN) {
 				 act1.sa_sigaction = (void *)SIG_IGN;
 			 } else if (k->_sa_handler == TARGET_SIG_DFL) {
-				  if (fatal_signal(sig))
+				  if (fatal_signal(sig)) {
+					  act1.sa_flags = SA_SIGINFO;
 					  act1.sa_sigaction =
 					      host_signal_handler;
-				  else
+				  } else {
 					  act1.sa_sigaction = (void *)SIG_DFL;
+				  }
 			 } else {
 				act1.sa_flags = SA_SIGINFO;
 				act1.sa_sigaction = host_signal_handler;
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 0f337e2..490227c 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -3120,6 +3120,15 @@ do_lock_umutex(abi_ulong target_addr, uint32_t id, struct timespec *ts,
 			0, ts));
 	}
 
+	if (NULL == ts) {
+		/*
+		 * In the case of no timeout do a restart on this syscall,
+		 * if interrupted.
+		 */
+		if (-TARGET_EINTR == ret)
+			ret = -TARGET_ERESTART;
+	}
+
 	return (0);
 }