Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / usr / server / proc / main.c @ 03e9c04a

History | View | Annotate | Download (11.5 KB)

1
/*
2
 * Copyright (c) 2005-2008, Kohsuke Ohtani
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29

    
30
/*
31
 * Process server:
32
 *
33
 * A process server is responsible to handle process ID, group
34
 * ID, signal and fork()/exec() state. Since Prex microkernel
35
 * does not have the concept about process or process group, the
36
 * process server will map each Prex task to POSIX process.
37
 *
38
 * Prex does not support uid (user ID) and gid (group ID) because
39
 * it runs only in a single user mode. The value of uid and gid is
40
 * always returned as 1 for all process. These are handled by the
41
 * library stubs, and it is out of scope in this server.
42
 *
43
 * Important Notice:
44
 * This server is made as a single thread program to reduce many
45
 * locks and to keep the code clean. So, we should not block in
46
 * the kernel for any service. If some service must wait an
47
 * event, it should wait within the library stub in the client
48
 * application.
49
 */
50

    
51
#include <sys/prex.h>
52
#include <sys/param.h>
53
#include <ipc/proc.h>
54
#include <ipc/ipc.h>
55
#include <ipc/exec.h>
56
#include <sys/list.h>
57

    
58
#include <unistd.h>
59
#include <errno.h>
60
#include <stdlib.h>
61
#include <string.h>
62

    
63
#include "proc.h"
64

    
65
/* forward declarations */
66
static int proc_getpid(struct msg *);
67
static int proc_getppid(struct msg *);
68
static int proc_getpgid(struct msg *);
69
static int proc_setpgid(struct msg *);
70
static int proc_getsid(struct msg *);
71
static int proc_setsid(struct msg *);
72
static int proc_fork(struct msg *);
73
static int proc_exit(struct msg *);
74
static int proc_stop(struct msg *);
75
static int proc_waitpid(struct msg *);
76
static int proc_kill(struct msg *);
77
static int proc_exec(struct msg *);
78
static int proc_pstat(struct msg *);
79
static int proc_register(struct msg *);
80
static int proc_setinit(struct msg *);
81
static int proc_trace(struct msg *);
82
static int proc_boot(struct msg *);
83
static int proc_shutdown(struct msg *);
84
static int proc_noop(struct msg *);
85
static int proc_debug(struct msg *);
86

    
87
/*
88
 * Message mapping
89
 */
90
struct msg_map {
91
        int        code;
92
        int        (*func)(struct msg *);
93
};
94

    
95
static const struct msg_map procmsg_map[] = {
96
        {PS_GETPID,        proc_getpid},
97
        {PS_GETPPID,        proc_getppid},
98
        {PS_GETPGID,        proc_getpgid},
99
        {PS_SETPGID,        proc_setpgid},
100
        {PS_GETSID,        proc_getsid},
101
        {PS_SETSID,        proc_setsid},
102
        {PS_FORK,        proc_fork},
103
        {PS_EXIT,        proc_exit},
104
        {PS_STOP,        proc_stop},
105
        {PS_WAITPID,        proc_waitpid},
106
        {PS_KILL,        proc_kill},
107
        {PS_EXEC,        proc_exec},
108
        {PS_PSTAT,        proc_pstat},
109
        {PS_REGISTER,        proc_register},
110
        {PS_SETINIT,        proc_setinit},
111
        {PS_TRACE,        proc_trace},
112
        {STD_BOOT,        proc_boot},
113
        {STD_SHUTDOWN,        proc_shutdown},
114
        {STD_DEBUG,        proc_debug},
115
        {0,                proc_noop},
116
};
117

    
118
static struct proc proc0;        /* process data of this server (pid=0) */
119
static struct pgrp pgrp0;        /* process group for first process */
120
static struct session session0;        /* session for first process */
121

    
122
struct proc initproc;                /* process slot for init process (pid=1) */
123
struct proc *curproc;                /* current (caller) process */
124
struct list allproc;                /* list of all processes */
125

    
126
static int
127
proc_getpid(struct msg *msg)
128
{
129
        pid_t pid;
130

    
131
        pid = sys_getpid();
132

    
133
        msg->data[0] = (int)pid;
134
        return 0;
135
}
136

    
137
static int
138
proc_getppid(struct msg *msg)
139
{
140
        pid_t ppid;
141

    
142
        ppid = sys_getppid();
143

    
144
        msg->data[0] = (int)ppid;
145
        return 0;
146
}
147

    
148
static int
149
proc_getpgid(struct msg *msg)
150
{
151
        pid_t pid, pgid;
152
        int error;
153

    
154
        pid = (pid_t)msg->data[0];
155

    
156
        error = sys_getpgid(pid, &pgid);
157
        if (error)
158
                return error;
159

    
160
        msg->data[0] = (int)pgid;
161
        return 0;
162
}
163

    
164
static int
165
proc_setpgid(struct msg *msg)
166
{
167
        pid_t pid, pgid;
168

    
169
        pid = (pid_t)msg->data[0];
170
        pgid = (pid_t)msg->data[1];
171

    
172
        return sys_setpgid(pid, pgid);
173
}
174

    
175
static int
176
proc_getsid(struct msg *msg)
177
{
178
        pid_t pid, sid;
179
        int error;
180

    
181
        pid = (pid_t)msg->data[0];
182

    
183
        error = sys_getsid(pid, &sid);
184
        if (error)
185
                return error;
186

    
187
        msg->data[0] = (int)sid;
188
        return 0;
189
}
190

    
191
static int
192
proc_setsid(struct msg *msg)
193
{
194
        pid_t sid;
195
        int error;
196

    
197
        error = sys_setsid(&sid);
198
        if (error)
199
                return error;
200

    
201
        msg->data[0] = (int)sid;
202
        return 0;
203
}
204

    
205
static int
206
proc_fork(struct msg *msg)
207
{
208
        task_t child;
209
        int vfork;
210
        pid_t pid;
211
        int error;
212

    
213
        child = (task_t)msg->data[0];
214
        vfork = msg->data[1];
215

    
216
        error = sys_fork(child, vfork, &pid);
217
        if (error)
218
                return error;
219

    
220
        msg->data[0] = (int)pid;
221
        return 0;
222
}
223

    
224
static int
225
proc_exit(struct msg *msg)
226
{
227
        int exitcode;
228

    
229
        exitcode = msg->data[0];
230

    
231
        return sys_exit(exitcode);
232
}
233

    
234
static int
235
proc_stop(struct msg *msg)
236
{
237
        int exitcode;
238

    
239
        exitcode = msg->data[0];
240

    
241
        return stop(exitcode);
242
}
243

    
244
static int
245
proc_waitpid(struct msg *msg)
246
{
247
        pid_t pid, pid_child;
248
        int options, status, error;
249

    
250
        pid = (pid_t)msg->data[0];
251
        options = msg->data[1];
252

    
253
        error = sys_waitpid(pid, &status, options, &pid_child);
254
        if (error)
255
                return error;
256

    
257
        msg->data[0] = pid_child;
258
        msg->data[1] = status;
259

    
260
        return 0;
261
}
262

    
263
static int
264
proc_kill(struct msg *msg)
265
{
266
        pid_t pid;
267
        int sig;
268

    
269
        pid = (pid_t)msg->data[0];
270
        sig = msg->data[1];
271

    
272
        return sys_kill(pid, sig);
273
}
274

    
275
/*
276
 * exec() - Update pid to track the mapping with task id.
277
 * The almost all work is done by a exec server for exec()
278
 * emulation. So, there is not so many jobs here...
279
 */
280
static int
281
proc_exec(struct msg *msg)
282
{
283
        task_t orgtask, newtask;
284
        struct proc *p, *parent;
285

    
286
        DPRINTF(("proc: exec pid=%x\n", curproc->p_pid));
287

    
288
        orgtask = (task_t)msg->data[0];
289
        newtask = (task_t)msg->data[1];
290
        if ((p = task_to_proc(orgtask)) == NULL)
291
                return EINVAL;
292

    
293
        p_remove(p);
294
        p->p_task = newtask;
295
        p_add(p);
296
        p->p_invfork = 0;
297
        p->p_stackbase = (void *)msg->data[2];
298

    
299
        if (p->p_flag & P_TRACED) {
300
                DPRINTF(("proc: traced!\n"));
301
                sys_debug(DBGC_TRACE, (void *)newtask);
302
        }
303

    
304
        parent = p->p_parent;
305
        if (parent != NULL && parent->p_vforked)
306
                vfork_end(parent);
307

    
308
        return 0;
309
}
310

    
311
/*
312
 * Get process status.
313
 */
314
static int
315
proc_pstat(struct msg *msg)
316
{
317
        task_t task;
318
        struct proc *p;
319

    
320
        DPRINTF(("proc: pstat task=%x\n", msg->data[0]));
321

    
322
        task = (task_t)msg->data[0];
323
        if ((p = task_to_proc(task)) == NULL)
324
                return EINVAL;
325

    
326
        msg->data[0] = (int)p->p_pid;
327
        msg->data[2] = (int)p->p_stat;
328
        if (p->p_parent == NULL)
329
                msg->data[1] = (int)0;
330
        else
331
                msg->data[1] = (int)p->p_parent->p_pid;
332
        return 0;
333
}
334

    
335
/*
336
 * Set init process (pid=1).
337
 */
338
static int
339
proc_setinit(struct msg *msg)
340
{
341

    
342
        DPRINTF(("proc: setinit task=%x\n", msg->hdr.task));
343

    
344
        /* Check client's capability. */
345
        if (task_chkcap(msg->hdr.task, CAP_PROTSERV) != 0)
346
                return EPERM;
347

    
348
        if (initproc.p_stat == SRUN)
349
                return EPERM;
350

    
351
        curproc = &proc0;
352
        newproc(&initproc, 1, msg->hdr.task);
353

    
354
        return 0;
355
}
356

    
357
/*
358
 * Set trace flag
359
 */
360
static int
361
proc_trace(struct msg *msg)
362
{
363
        task_t task = msg->hdr.task;
364
        struct proc *p;
365

    
366
        DPRINTF(("proc: trace task=%x\n", task));
367

    
368
        if ((p = task_to_proc(task)) == NULL)
369
                return EINVAL;
370

    
371
        /* Toggle trace flag */
372
        p->p_flag ^= P_TRACED;
373
        return 0;
374
}
375

    
376
/*
377
 * Register boot task.
378
 */
379
static int
380
proc_register(struct msg *msg)
381
{
382
        struct proc *p;
383

    
384
        DPRINTF(("proc: register task=%x\n", msg->hdr.task));
385

    
386
        /* Check client's capability. */
387
        if (task_chkcap(msg->hdr.task, CAP_PROTSERV) != 0)
388
                return EPERM;
389

    
390
        if ((p = malloc(sizeof(struct proc))) == NULL)
391
                return ENOMEM;
392
        memset(p, 0, sizeof(struct proc));
393

    
394
        curproc = &proc0;
395
        if (newproc(p, 0, msg->hdr.task))
396
                sys_panic("proc: fail to register boot task");
397

    
398
        DPRINTF(("proc: register pid=%d\n", p->p_pid));
399
        return 0;
400
}
401

    
402
/*
403
 * Ready to boot
404
 */
405
static int
406
proc_boot(struct msg *msg)
407
{
408
        object_t obj;
409
        struct bind_msg m;
410

    
411
        DPRINTF(("proc: boot\n"));
412

    
413
        /* Check client's capability. */
414
        if (task_chkcap(msg->hdr.task, CAP_PROTSERV) != 0)
415
                return EPERM;
416

    
417
        /*
418
         * Request exec server to bind an appropriate
419
         * capability for us.
420
         */
421
        if (object_lookup("!exec", &obj) != 0)
422
                sys_panic("proc: no exec found");
423
        m.hdr.code = EXEC_BINDCAP;
424
        strlcpy(m.path, "/boot/proc", sizeof(m.path));
425
        msg_send(obj, &m, sizeof(m));
426

    
427
        return 0;
428
}
429

    
430
static int
431
proc_shutdown(struct msg *msg)
432
{
433

    
434
        DPRINTF(("proc: shutdown\n"));
435
        return 0;
436
}
437

    
438
static int
439
proc_noop(struct msg *msg)
440
{
441

    
442
        return 0;
443
}
444

    
445
static int
446
proc_debug(struct msg *msg)
447
{
448
#ifdef DEBUG_PROC
449
        struct proc *p;
450
        list_t n;
451
        char stat[][5] = { "    ", "RUN ", "ZOMB", "STOP" };
452

    
453
        dprintf("<Process Server>\n");
454
        dprintf("Dump process\n");
455
        dprintf(" pid    ppid   pgid   sid    stat task\n");
456
        dprintf(" ------ ------ ------ ------ ---- --------\n");
457

    
458
        for (n = list_first(&allproc); n != &allproc;
459
             n = list_next(n)) {
460
                p = list_entry(n, struct proc, p_link);
461
                dprintf(" %6d %6d %6d %6d %s %08x\n", p->p_pid,
462
                        p->p_parent->p_pid, p->p_pgrp->pg_pgid,
463
                        p->p_pgrp->pg_session->s_leader->p_pid,
464
                        stat[p->p_stat], p->p_task);
465
        }
466
        dprintf("\n");
467
#endif
468
        return 0;
469
}
470

    
471
static void
472
proc_init(void)
473
{
474

    
475
        list_init(&allproc);
476
        tty_init();
477
        table_init();
478
}
479

    
480

    
481
/*
482
 * Initialize process 0.
483
 */
484
static void
485
proc0_init(void)
486
{
487
        struct proc *p;
488
        struct pgrp *pg;
489
        struct session *sess;
490

    
491
        p = &proc0;
492
        pg = &pgrp0;
493
        sess = &session0;
494

    
495
        pg->pg_pgid = 0;
496
        list_init(&pg->pg_members);
497
        pg_add(pg);
498

    
499
        pg->pg_session = sess;
500
        sess->s_refcnt = 1;
501
        sess->s_leader = p;
502
        sess->s_ttyhold = 0;
503

    
504
        p->p_parent = 0;
505
        p->p_pgrp = pg;
506
        p->p_stat = SRUN;
507
        p->p_exitcode = 0;
508
        p->p_pid = 0;
509
        p->p_task = task_self();
510
        p->p_vforked = 0;
511
        p->p_invfork = 0;
512

    
513
        list_init(&p->p_children);
514
        p_add(p);
515
        list_insert(&pg->pg_members, &p->p_pgrp_link);
516
}
517

    
518
/*
519
 * Main routine for process service.
520
 */
521
int
522
main(int argc, char *argv[])
523
{
524
        static struct msg msg;
525
        const struct msg_map *map;
526
        object_t obj;
527
        int error;
528

    
529
        sys_log("Starting process server\n");
530

    
531
        /* Boost thread priority. */
532
        thread_setpri(thread_self(), PRI_PROC);
533

    
534
        /* Initialize process and pgrp structures. */
535
        proc_init();
536

    
537
        /* Create process 0 (process server). */
538
        proc0_init();
539

    
540
        /* Create an object to expose our service. */
541
        if ((error = object_create("!proc", &obj)) != 0)
542
                sys_panic("proc: fail to create object");
543

    
544
        /*
545
         * Message loop
546
         */
547
        for (;;) {
548
                /*
549
                 * Wait for an incoming request.
550
                 */
551
                error = msg_receive(obj, &msg, sizeof(msg));
552
                if (error)
553
                        continue;
554

    
555
                DPRINTF(("proc: msg code=%x task=%x\n",
556
                         msg.hdr.code, msg.hdr.task));
557

    
558
                error = EINVAL;
559
                map = &procmsg_map[0];
560
                while (map->code != 0) {
561
                        if (map->code == msg.hdr.code) {
562

    
563
                                /* Get current process */
564
                                curproc = task_to_proc(msg.hdr.task);
565
                                error = (*map->func)(&msg);
566
                                break;
567
                        }
568
                        map++;
569
                }
570
                /*
571
                 * Reply to the client.
572
                 */
573
                msg.hdr.status = error;
574
                msg_reply(obj, &msg, sizeof(msg));
575
#ifdef DEBUG_PROC
576
                if (error) {
577
                        DPRINTF(("proc: msg code=%x error=%d\n",
578
                                 map->code, error));
579
                }
580
#endif
581
        }
582
}