1/** \file
2 *  \brief inheritance of file descriptors
3 */
4
5/*
6 * Copyright (c) 2010, 2012, ETH Zurich.
7 * All rights reserved.
8 *
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/socket.h>
18
19#include <unistd.h>
20#include <fcntl.h>
21
22#include <barrelfish/barrelfish.h>
23#include <barrelfish/spawn_client.h>
24
25#include "testdesc.h"
26
27/* Copying the actual handles is hard.
28 * We could try a deep copy, but really we should come up with a serialised
29 * format for each type.  It also involves implementing the underlying
30 * resources such that the descriptors can actually be used in the new
31 * dispatcher.
32 */
33
34static size_t copy_file_fd(void *dest, lpaddr_t offset, struct fd_store *fds)
35{
36    size_t size = sizeof(void *);
37
38    printf("FILE\n\thandle: %p\n", fds->handle);
39
40    /* This following isn't correct at all - we're just copying the value of
41     * the pointer, which is useless in the new dispatcher */
42
43    printf("copying %zu bytes from %p to %p\n", size, &fds->handle, dest);
44    memcpy(dest, &fds->handle, size);
45    fds->handle = (void*)(offset);
46    printf("fd %d fixed handle is: %p\n", fds->num, fds->handle);
47
48    return size;
49}
50
51
52static size_t copy_unixsock_fd(void *dest, lpaddr_t offset,
53                                 struct fd_store *fds)
54{
55    // shallow copy. doesn't really help us.
56
57    struct _unix_socket *ush;
58    size_t size;
59
60    ush = fds->handle;
61    printf("adding UNIX socket (%p)\n\ttype: %x protocol: %x\n\tpassive: %d "
62           "nonblkng: %d\n",
63           fds->handle, ush->type, ush->protocol, ush->passive, ush->nonblocking);
64    size = sizeof(struct _unix_socket);
65
66    printf("copying %zu bytes from %p to %p\n", size, fds->handle, dest);
67    memcpy(dest, fds->handle, size);
68    fds->handle = (void*)(offset);
69    printf("fd %d fixed handle is: %p\n", fds->num, fds->handle);
70
71    return size;
72}
73
74
75/**
76 * \brief Setup inherited file descriptors
77 *
78 */
79static errval_t spawn_setup_fds(struct capref *frame)
80{
81    errval_t err;
82    void *fdspg;
83
84    // Create frame (actually multiple pages) for fds
85    err = frame_alloc(frame, FDS_SIZE, NULL);
86    if (err_is_fail(err)) {
87        return err_push(err, SPAWN_ERR_CREATE_FDSPG);
88    }
89
90    // map it in so we can write to it
91    err = vspace_map_one_frame(&fdspg, FDS_SIZE, *frame, NULL, NULL);
92    if (err_is_fail(err)) {
93        return err_push(err, SPAWN_ERR_MAP_FDSPG_TO_SELF);
94    }
95
96    /* Layout of FD page:
97     * int num_fds
98     * struct fd_store fdtab[num_fds]
99     * uint8_t buf[] // store of actual handle data.  entries in fdtab above
100     *               // point here (relative offset from the beginning of buf).
101     * TODO: add the actual handle data!
102     */
103    int *num_fds = (int *)fdspg;
104    *num_fds = 0;
105    struct fd_store *fdtab = (struct fd_store *)(num_fds + 1);
106
107    /* first copy all the fd table entries */
108    struct fdtab_entry *fde;
109    struct fd_store *fds;
110    int i;
111    for (i = MIN_FD; i < MAX_FD; i++) {
112        fde = fdtab_get(i);
113        if (fde->type != FDTAB_TYPE_AVAILABLE) {
114            fds = &fdtab[*num_fds];
115            fds->num = i;
116            fds->type = fde->type;
117            fds->handle = fde->handle;
118            printf("added fd %d to fdtabs[%d]: %p as fd_store (%p: num: %d, "
119                    "type: %d, (unfixed)handle: %p)\n",
120                    i, *num_fds, &fdtab[*num_fds], fds, fds->num, fds->type,
121                    fds->handle);
122            (*num_fds)++;
123        }
124    }
125
126    /* then copy all the handle data to the buffer */
127    char *buf = (char *)&fdtab[*num_fds];
128    char *dest = buf;
129    genpaddr_t offset;
130    size_t size;
131    for (i = 0; i < *num_fds; i++) {
132        fds =  &fdtab[i];
133        offset = (genpaddr_t)(dest - buf);
134        switch (fds->type) {
135        case FDTAB_TYPE_FILE:
136            size = copy_file_fd(dest, offset, fds);
137            break;
138        case FDTAB_TYPE_UNIX_SOCKET:
139            size = copy_unixsock_fd(dest, offset, fds);
140            break;
141        default:
142            // nothing to copy
143            size = 0;
144            break;
145        }
146        dest += size;
147    }
148
149    // unmap frame
150    err = vspace_unmap(fdspg);
151
152    return err;
153}
154
155
156static errval_t spawn_child(struct capref fdcap)
157
158{
159    errval_t err;
160
161    char *argv[2] = { "testdesc-child", NULL };
162
163    struct capref new_domain;
164
165    coreid_t core = 0;
166
167    // allocate inheritcn
168    struct capref inheritcn_cap;
169    err = alloc_inheritcn_with_caps(&inheritcn_cap, fdcap,
170                                    NULL_CAP, NULL_CAP);
171
172    err = spawn_program_with_caps(core, argv[0], argv, NULL, inheritcn_cap,
173                                  NULL_CAP, SPAWN_FLAGS_NEW_DOMAIN, &new_domain);
174
175    if (err_is_fail(err)) {
176        DEBUG_ERR(err, "failed spawn on core %d", core);
177        return err;
178    }
179
180    return SYS_ERR_OK;
181
182}
183
184int main(int argc, char *argv[])
185{
186    errval_t err;
187
188    printf("Test inheritance of file descriptors\n");
189
190    // create some file handles
191    int fd = open("test file", O_CREAT);
192    printf("opened a file with fd: %d\n", fd);
193
194    fd = socket(AF_UNIX, SOCK_STREAM, 0);
195    printf("opened a socket with fd: %d\n", fd);
196
197    struct capref fdcap;
198    err = spawn_setup_fds(&fdcap);
199    if (err_is_fail(err)) {
200        DEBUG_ERR(err, "could not setup fds!\n");
201        return EXIT_FAILURE;
202    }
203
204    err = spawn_child(fdcap);
205    if (err_is_fail(err)) {
206        DEBUG_ERR(err, "could not spawn child!\n");
207        return EXIT_FAILURE;
208    }
209
210    return EXIT_SUCCESS;
211}
212