130d9b703SDavid van Moolenbroek /* PFS - Pipe File Server */
230d9b703SDavid van Moolenbroek
330d9b703SDavid van Moolenbroek #include <minix/drivers.h>
430d9b703SDavid van Moolenbroek #include <minix/fsdriver.h>
530d9b703SDavid van Moolenbroek #include <minix/vfsif.h>
6dfc32615SDavid van Moolenbroek #include <minix/rs.h>
730d9b703SDavid van Moolenbroek #include <assert.h>
830d9b703SDavid van Moolenbroek
930d9b703SDavid van Moolenbroek /*
1030d9b703SDavid van Moolenbroek * The following constant defines the number of inodes in PFS, which is
1130d9b703SDavid van Moolenbroek * therefore the maximum number of open pipes and cloned devices that can be
1230d9b703SDavid van Moolenbroek * used in the entire system. If anything, it should be kept somewhat in sync
1330d9b703SDavid van Moolenbroek * with VFS's maximum number of inodes. In the future, inodes could be
1430d9b703SDavid van Moolenbroek * allocated dynamically, but this will require extra infrastructure.
1530d9b703SDavid van Moolenbroek */
1630d9b703SDavid van Moolenbroek #define PFS_NR_INODES 512 /* maximum number of inodes in PFS */
1730d9b703SDavid van Moolenbroek
1830d9b703SDavid van Moolenbroek /* The following bits can be combined in the inode's i_update field. */
1930d9b703SDavid van Moolenbroek #define ATIME 0x1 /* update access time later */
2030d9b703SDavid van Moolenbroek #define MTIME 0x2 /* update modification time later */
2130d9b703SDavid van Moolenbroek #define CTIME 0x4 /* update change time later */
2230d9b703SDavid van Moolenbroek
2330d9b703SDavid van Moolenbroek static struct inode {
2430d9b703SDavid van Moolenbroek ino_t i_num; /* inode number */
2530d9b703SDavid van Moolenbroek
2630d9b703SDavid van Moolenbroek mode_t i_mode; /* file mode and permissions */
2730d9b703SDavid van Moolenbroek uid_t i_uid; /* user ID of the file's owner */
2830d9b703SDavid van Moolenbroek gid_t i_gid; /* group ID of the file's owner */
2930d9b703SDavid van Moolenbroek size_t i_size; /* current file size in bytes */
3030d9b703SDavid van Moolenbroek dev_t i_rdev; /* device number for device nodes */
3130d9b703SDavid van Moolenbroek time_t i_atime; /* file access time */
3230d9b703SDavid van Moolenbroek time_t i_mtime; /* file modification time */
3330d9b703SDavid van Moolenbroek time_t i_ctime; /* file change time */
3430d9b703SDavid van Moolenbroek
3530d9b703SDavid van Moolenbroek char *i_data; /* data buffer, for pipes only */
3630d9b703SDavid van Moolenbroek size_t i_start; /* start of data into data buffer */
3730d9b703SDavid van Moolenbroek
3830d9b703SDavid van Moolenbroek unsigned char i_update; /* which file times to update? */
3930d9b703SDavid van Moolenbroek unsigned char i_free; /* sanity check: is the inode free? */
4030d9b703SDavid van Moolenbroek
4130d9b703SDavid van Moolenbroek LIST_ENTRY(inode) i_next; /* next element in free list */
4230d9b703SDavid van Moolenbroek } inode[PFS_NR_INODES];
4330d9b703SDavid van Moolenbroek
4430d9b703SDavid van Moolenbroek static LIST_HEAD(, inode) free_inodes; /* list of free inodes */
4530d9b703SDavid van Moolenbroek
4630d9b703SDavid van Moolenbroek /*
4730d9b703SDavid van Moolenbroek * Mount the pipe file server.
4830d9b703SDavid van Moolenbroek */
4930d9b703SDavid van Moolenbroek static int
pfs_mount(dev_t __unused dev,unsigned int __unused flags,struct fsdriver_node * node,unsigned int * res_flags)5030d9b703SDavid van Moolenbroek pfs_mount(dev_t __unused dev, unsigned int __unused flags,
5130d9b703SDavid van Moolenbroek struct fsdriver_node * node, unsigned int * res_flags)
5230d9b703SDavid van Moolenbroek {
5330d9b703SDavid van Moolenbroek struct inode *rip;
5430d9b703SDavid van Moolenbroek unsigned int i;
5530d9b703SDavid van Moolenbroek
5630d9b703SDavid van Moolenbroek LIST_INIT(&free_inodes); /* initialize the free list */
5730d9b703SDavid van Moolenbroek
5830d9b703SDavid van Moolenbroek /*
5930d9b703SDavid van Moolenbroek * Initialize the inode table. We walk backwards so that the lowest
6030d9b703SDavid van Moolenbroek * inode numbers end up being used first. Silly? Sure, but aesthetics
6130d9b703SDavid van Moolenbroek * are worth something, too..
6230d9b703SDavid van Moolenbroek */
6330d9b703SDavid van Moolenbroek for (i = PFS_NR_INODES; i > 0; i--) {
6430d9b703SDavid van Moolenbroek rip = &inode[i - 1];
6530d9b703SDavid van Moolenbroek
6630d9b703SDavid van Moolenbroek /* Inode number 0 is reserved. See also pfs_findnode. */
6730d9b703SDavid van Moolenbroek rip->i_num = i;
6830d9b703SDavid van Moolenbroek rip->i_free = TRUE;
6930d9b703SDavid van Moolenbroek
7030d9b703SDavid van Moolenbroek LIST_INSERT_HEAD(&free_inodes, rip, i_next);
7130d9b703SDavid van Moolenbroek }
7230d9b703SDavid van Moolenbroek
7330d9b703SDavid van Moolenbroek /*
7430d9b703SDavid van Moolenbroek * PFS has no root node, and VFS will ignore the returned node details
7530d9b703SDavid van Moolenbroek * anyway. The whole idea is to provide symmetry with other file
7630d9b703SDavid van Moolenbroek * systems, thus keeping libfsdriver simple and free of special cases.
7730d9b703SDavid van Moolenbroek */
7830d9b703SDavid van Moolenbroek memset(node, 0, sizeof(*node));
7930d9b703SDavid van Moolenbroek *res_flags = RES_64BIT;
8030d9b703SDavid van Moolenbroek
8130d9b703SDavid van Moolenbroek return OK;
8230d9b703SDavid van Moolenbroek }
8330d9b703SDavid van Moolenbroek
8430d9b703SDavid van Moolenbroek /*
8530d9b703SDavid van Moolenbroek * Unmount the pipe file server.
8630d9b703SDavid van Moolenbroek */
8730d9b703SDavid van Moolenbroek static void
pfs_unmount(void)8830d9b703SDavid van Moolenbroek pfs_unmount(void)
8930d9b703SDavid van Moolenbroek {
9030d9b703SDavid van Moolenbroek unsigned int i;
9130d9b703SDavid van Moolenbroek
9230d9b703SDavid van Moolenbroek /* Warn about in-use inodes. There's nothing else we can do. */
9330d9b703SDavid van Moolenbroek for (i = 0; i < PFS_NR_INODES; i++)
9430d9b703SDavid van Moolenbroek if (inode[i].i_free == FALSE)
9530d9b703SDavid van Moolenbroek break;
9630d9b703SDavid van Moolenbroek
9730d9b703SDavid van Moolenbroek if (i < PFS_NR_INODES)
9830d9b703SDavid van Moolenbroek printf("PFS: unmounting while busy!\n");
9930d9b703SDavid van Moolenbroek }
10030d9b703SDavid van Moolenbroek
10130d9b703SDavid van Moolenbroek /*
10230d9b703SDavid van Moolenbroek * Find the node with the corresponding inode number. It must be in use.
10330d9b703SDavid van Moolenbroek */
10430d9b703SDavid van Moolenbroek static struct inode *
pfs_findnode(ino_t ino_nr)10530d9b703SDavid van Moolenbroek pfs_findnode(ino_t ino_nr)
10630d9b703SDavid van Moolenbroek {
10730d9b703SDavid van Moolenbroek struct inode *rip;
10830d9b703SDavid van Moolenbroek
10930d9b703SDavid van Moolenbroek /* Inode numbers are 1-based, because inode number 0 is reserved. */
11030d9b703SDavid van Moolenbroek if (ino_nr < 1 || ino_nr > PFS_NR_INODES)
11130d9b703SDavid van Moolenbroek return NULL;
11230d9b703SDavid van Moolenbroek
11330d9b703SDavid van Moolenbroek rip = &inode[ino_nr - 1];
11430d9b703SDavid van Moolenbroek assert(rip->i_num == ino_nr);
11530d9b703SDavid van Moolenbroek
11630d9b703SDavid van Moolenbroek if (rip->i_free == TRUE)
11730d9b703SDavid van Moolenbroek return NULL;
11830d9b703SDavid van Moolenbroek
11930d9b703SDavid van Moolenbroek return rip;
12030d9b703SDavid van Moolenbroek }
12130d9b703SDavid van Moolenbroek
12230d9b703SDavid van Moolenbroek /*
12330d9b703SDavid van Moolenbroek * Create a new, unlinked node. It must be either a pipe or a device file.
12430d9b703SDavid van Moolenbroek */
12530d9b703SDavid van Moolenbroek static int
pfs_newnode(mode_t mode,uid_t uid,gid_t gid,dev_t dev,struct fsdriver_node * node)12630d9b703SDavid van Moolenbroek pfs_newnode(mode_t mode, uid_t uid, gid_t gid, dev_t dev,
12730d9b703SDavid van Moolenbroek struct fsdriver_node * node)
12830d9b703SDavid van Moolenbroek {
12930d9b703SDavid van Moolenbroek struct inode *rip;
13030d9b703SDavid van Moolenbroek char *data;
13130d9b703SDavid van Moolenbroek int isfifo, isdev;
13230d9b703SDavid van Moolenbroek
13330d9b703SDavid van Moolenbroek /* Check the file type. Do we support it at all? */
13430d9b703SDavid van Moolenbroek isfifo = S_ISFIFO(mode);
135*e3b8d4bbSDavid van Moolenbroek isdev = S_ISBLK(mode) || S_ISCHR(mode) || S_ISSOCK(mode);
13630d9b703SDavid van Moolenbroek
13730d9b703SDavid van Moolenbroek if (!isfifo && !isdev)
13830d9b703SDavid van Moolenbroek return EINVAL; /* this means VFS is misbehaving.. */
13930d9b703SDavid van Moolenbroek
14030d9b703SDavid van Moolenbroek /* Is there a free inode? */
14130d9b703SDavid van Moolenbroek if (LIST_EMPTY(&free_inodes))
14230d9b703SDavid van Moolenbroek return ENFILE;
14330d9b703SDavid van Moolenbroek
14430d9b703SDavid van Moolenbroek /* For pipes, we need a buffer. Try to allocate one. */
14530d9b703SDavid van Moolenbroek data = NULL;
14630d9b703SDavid van Moolenbroek if (isfifo && (data = malloc(PIPE_BUF)) == NULL)
14730d9b703SDavid van Moolenbroek return ENOSPC;
14830d9b703SDavid van Moolenbroek
14930d9b703SDavid van Moolenbroek /* Nothing can go wrong now. Take an inode off the free list. */
15030d9b703SDavid van Moolenbroek rip = LIST_FIRST(&free_inodes);
15130d9b703SDavid van Moolenbroek LIST_REMOVE(rip, i_next);
15230d9b703SDavid van Moolenbroek
15330d9b703SDavid van Moolenbroek assert(rip->i_free == TRUE);
15430d9b703SDavid van Moolenbroek rip->i_free = FALSE; /* this is for sanity checks only */
15530d9b703SDavid van Moolenbroek
15630d9b703SDavid van Moolenbroek /* Initialize the inode's fields. */
15730d9b703SDavid van Moolenbroek rip->i_mode = mode;
15830d9b703SDavid van Moolenbroek rip->i_uid = uid;
15930d9b703SDavid van Moolenbroek rip->i_gid = gid;
16030d9b703SDavid van Moolenbroek rip->i_size = 0;
16130d9b703SDavid van Moolenbroek rip->i_update = ATIME | MTIME | CTIME;
16230d9b703SDavid van Moolenbroek if (isdev)
16330d9b703SDavid van Moolenbroek rip->i_rdev = dev;
16430d9b703SDavid van Moolenbroek else
16530d9b703SDavid van Moolenbroek rip->i_rdev = NO_DEV;
16630d9b703SDavid van Moolenbroek rip->i_data = data;
16730d9b703SDavid van Moolenbroek rip->i_start = 0;
16830d9b703SDavid van Moolenbroek
16930d9b703SDavid van Moolenbroek /* Fill in the fields of the response message. */
17030d9b703SDavid van Moolenbroek node->fn_ino_nr = rip->i_num;
17130d9b703SDavid van Moolenbroek node->fn_mode = rip->i_mode;
17230d9b703SDavid van Moolenbroek node->fn_size = rip->i_size;
17330d9b703SDavid van Moolenbroek node->fn_uid = rip->i_uid;
17430d9b703SDavid van Moolenbroek node->fn_gid = rip->i_gid;
17530d9b703SDavid van Moolenbroek node->fn_dev = rip->i_rdev;
17630d9b703SDavid van Moolenbroek
17730d9b703SDavid van Moolenbroek return OK;
17830d9b703SDavid van Moolenbroek }
17930d9b703SDavid van Moolenbroek
18030d9b703SDavid van Moolenbroek /*
18130d9b703SDavid van Moolenbroek * Close a node.
18230d9b703SDavid van Moolenbroek */
18330d9b703SDavid van Moolenbroek static int
pfs_putnode(ino_t ino_nr,unsigned int count)18430d9b703SDavid van Moolenbroek pfs_putnode(ino_t ino_nr, unsigned int count)
18530d9b703SDavid van Moolenbroek {
18630d9b703SDavid van Moolenbroek struct inode *rip;
18730d9b703SDavid van Moolenbroek
18830d9b703SDavid van Moolenbroek if ((rip = pfs_findnode(ino_nr)) == NULL)
18930d9b703SDavid van Moolenbroek return EINVAL;
19030d9b703SDavid van Moolenbroek
19130d9b703SDavid van Moolenbroek /*
19230d9b703SDavid van Moolenbroek * Since the new-node call is the only way to open an inode, and there
19330d9b703SDavid van Moolenbroek * is no way to increase the use count of an already-opened inode, we
19430d9b703SDavid van Moolenbroek * can safely assume that the reference count will only ever be one.
19530d9b703SDavid van Moolenbroek * That also means we are always freeing up the target inode here.
19630d9b703SDavid van Moolenbroek */
19730d9b703SDavid van Moolenbroek if (count != 1)
19830d9b703SDavid van Moolenbroek return EINVAL;
19930d9b703SDavid van Moolenbroek
20030d9b703SDavid van Moolenbroek /* For pipes, free the inode data buffer. */
201129adfebSDavid van Moolenbroek if (rip->i_data != NULL) {
20230d9b703SDavid van Moolenbroek free(rip->i_data);
203129adfebSDavid van Moolenbroek rip->i_data = NULL;
204129adfebSDavid van Moolenbroek }
20530d9b703SDavid van Moolenbroek
20630d9b703SDavid van Moolenbroek /* Return the inode to the free list. */
20730d9b703SDavid van Moolenbroek rip->i_free = TRUE;
20830d9b703SDavid van Moolenbroek
20930d9b703SDavid van Moolenbroek LIST_INSERT_HEAD(&free_inodes, rip, i_next);
21030d9b703SDavid van Moolenbroek
21130d9b703SDavid van Moolenbroek return OK;
21230d9b703SDavid van Moolenbroek }
21330d9b703SDavid van Moolenbroek
21430d9b703SDavid van Moolenbroek /*
21530d9b703SDavid van Moolenbroek * Read from a pipe.
21630d9b703SDavid van Moolenbroek */
21730d9b703SDavid van Moolenbroek static ssize_t
pfs_read(ino_t ino_nr,struct fsdriver_data * data,size_t bytes,off_t __unused pos,int __unused call)21830d9b703SDavid van Moolenbroek pfs_read(ino_t ino_nr, struct fsdriver_data * data, size_t bytes,
21930d9b703SDavid van Moolenbroek off_t __unused pos, int __unused call)
22030d9b703SDavid van Moolenbroek {
22130d9b703SDavid van Moolenbroek struct inode *rip;
22230d9b703SDavid van Moolenbroek int r;
22330d9b703SDavid van Moolenbroek
22430d9b703SDavid van Moolenbroek /* The target node must be a pipe. */
22530d9b703SDavid van Moolenbroek if ((rip = pfs_findnode(ino_nr)) == NULL || !S_ISFIFO(rip->i_mode))
22630d9b703SDavid van Moolenbroek return EINVAL;
22730d9b703SDavid van Moolenbroek
22830d9b703SDavid van Moolenbroek /* We can't read beyond the maximum file position. */
22930d9b703SDavid van Moolenbroek if (bytes > PIPE_BUF)
23030d9b703SDavid van Moolenbroek return EFBIG;
23130d9b703SDavid van Moolenbroek
23230d9b703SDavid van Moolenbroek /* Limit the request to how much is in the pipe. */
23330d9b703SDavid van Moolenbroek if (bytes > rip->i_size)
23430d9b703SDavid van Moolenbroek bytes = rip->i_size;
23530d9b703SDavid van Moolenbroek
23630d9b703SDavid van Moolenbroek /* Copy the data to user space. */
23730d9b703SDavid van Moolenbroek if ((r = fsdriver_copyout(data, 0, rip->i_data + rip->i_start,
23830d9b703SDavid van Moolenbroek bytes)) != OK)
23930d9b703SDavid van Moolenbroek return r;
24030d9b703SDavid van Moolenbroek
24130d9b703SDavid van Moolenbroek /* Update file size and access time. */
24230d9b703SDavid van Moolenbroek rip->i_size -= bytes;
24330d9b703SDavid van Moolenbroek rip->i_start += bytes;
24430d9b703SDavid van Moolenbroek rip->i_update |= ATIME;
24530d9b703SDavid van Moolenbroek
24630d9b703SDavid van Moolenbroek /* Return the number of bytes transferred. */
24730d9b703SDavid van Moolenbroek return bytes;
24830d9b703SDavid van Moolenbroek }
24930d9b703SDavid van Moolenbroek
25030d9b703SDavid van Moolenbroek /*
25130d9b703SDavid van Moolenbroek * Write to a pipe.
25230d9b703SDavid van Moolenbroek */
25330d9b703SDavid van Moolenbroek static ssize_t
pfs_write(ino_t ino_nr,struct fsdriver_data * data,size_t bytes,off_t __unused pos,int __unused call)25430d9b703SDavid van Moolenbroek pfs_write(ino_t ino_nr, struct fsdriver_data * data, size_t bytes,
25530d9b703SDavid van Moolenbroek off_t __unused pos, int __unused call)
25630d9b703SDavid van Moolenbroek {
25730d9b703SDavid van Moolenbroek struct inode *rip;
25830d9b703SDavid van Moolenbroek int r;
25930d9b703SDavid van Moolenbroek
26030d9b703SDavid van Moolenbroek /* The target node must be a pipe. */
26130d9b703SDavid van Moolenbroek if ((rip = pfs_findnode(ino_nr)) == NULL || !S_ISFIFO(rip->i_mode))
26230d9b703SDavid van Moolenbroek return EINVAL;
26330d9b703SDavid van Moolenbroek
26430d9b703SDavid van Moolenbroek /* Check in advance to see if file will grow too big. */
26530d9b703SDavid van Moolenbroek if (rip->i_size + bytes > PIPE_BUF)
26630d9b703SDavid van Moolenbroek return EFBIG;
26730d9b703SDavid van Moolenbroek
26830d9b703SDavid van Moolenbroek /*
26930d9b703SDavid van Moolenbroek * Move any previously remaining data to the front of the buffer.
27030d9b703SDavid van Moolenbroek * Doing so upon writes rather than reads saves on memory moves when
27130d9b703SDavid van Moolenbroek * there are many small reads. Not using the buffer circularly saves
27230d9b703SDavid van Moolenbroek * on kernel calls.
27330d9b703SDavid van Moolenbroek */
27430d9b703SDavid van Moolenbroek if (rip->i_start > 0) {
27530d9b703SDavid van Moolenbroek if (rip->i_size > 0)
27630d9b703SDavid van Moolenbroek memmove(rip->i_data, rip->i_data + rip->i_start,
27730d9b703SDavid van Moolenbroek rip->i_size);
27830d9b703SDavid van Moolenbroek
27930d9b703SDavid van Moolenbroek rip->i_start = 0;
28030d9b703SDavid van Moolenbroek }
28130d9b703SDavid van Moolenbroek
28230d9b703SDavid van Moolenbroek /* Copy the data from user space. */
28330d9b703SDavid van Moolenbroek r = fsdriver_copyin(data, 0, rip->i_data + rip->i_size, bytes);
28430d9b703SDavid van Moolenbroek if (r != OK)
28530d9b703SDavid van Moolenbroek return r;
28630d9b703SDavid van Moolenbroek
28730d9b703SDavid van Moolenbroek /* Update file size and times. */
28830d9b703SDavid van Moolenbroek rip->i_size += bytes;
28930d9b703SDavid van Moolenbroek rip->i_update |= CTIME | MTIME;
29030d9b703SDavid van Moolenbroek
29130d9b703SDavid van Moolenbroek /* Return the number of bytes transferred. */
29230d9b703SDavid van Moolenbroek return bytes;
29330d9b703SDavid van Moolenbroek }
29430d9b703SDavid van Moolenbroek
29530d9b703SDavid van Moolenbroek /*
29630d9b703SDavid van Moolenbroek * Truncate a pipe.
29730d9b703SDavid van Moolenbroek */
29830d9b703SDavid van Moolenbroek static int
pfs_trunc(ino_t ino_nr,off_t start_pos,off_t end_pos)29930d9b703SDavid van Moolenbroek pfs_trunc(ino_t ino_nr, off_t start_pos, off_t end_pos)
30030d9b703SDavid van Moolenbroek {
30130d9b703SDavid van Moolenbroek struct inode *rip;
30230d9b703SDavid van Moolenbroek
30330d9b703SDavid van Moolenbroek /* The target node must be a pipe. */
30430d9b703SDavid van Moolenbroek if ((rip = pfs_findnode(ino_nr)) == NULL || !S_ISFIFO(rip->i_mode))
30530d9b703SDavid van Moolenbroek return EINVAL;
30630d9b703SDavid van Moolenbroek
30730d9b703SDavid van Moolenbroek /* We only support full truncation of pipes. */
30830d9b703SDavid van Moolenbroek if (start_pos != 0 || end_pos != 0)
30930d9b703SDavid van Moolenbroek return EINVAL;
31030d9b703SDavid van Moolenbroek
31130d9b703SDavid van Moolenbroek /* Update file size and times. */
31230d9b703SDavid van Moolenbroek rip->i_size = 0;
31330d9b703SDavid van Moolenbroek rip->i_update |= CTIME | MTIME;
31430d9b703SDavid van Moolenbroek
31530d9b703SDavid van Moolenbroek return OK;
31630d9b703SDavid van Moolenbroek }
31730d9b703SDavid van Moolenbroek
31830d9b703SDavid van Moolenbroek /*
31930d9b703SDavid van Moolenbroek * Return node status.
32030d9b703SDavid van Moolenbroek */
32130d9b703SDavid van Moolenbroek static int
pfs_stat(ino_t ino_nr,struct stat * statbuf)32230d9b703SDavid van Moolenbroek pfs_stat(ino_t ino_nr, struct stat * statbuf)
32330d9b703SDavid van Moolenbroek {
32430d9b703SDavid van Moolenbroek struct inode *rip;
32530d9b703SDavid van Moolenbroek time_t now;
32630d9b703SDavid van Moolenbroek
32730d9b703SDavid van Moolenbroek if ((rip = pfs_findnode(ino_nr)) == NULL)
32830d9b703SDavid van Moolenbroek return EINVAL;
32930d9b703SDavid van Moolenbroek
33030d9b703SDavid van Moolenbroek /* Update the time fields in the inode, if need be. */
33130d9b703SDavid van Moolenbroek if (rip->i_update != 0) {
33230d9b703SDavid van Moolenbroek now = clock_time(NULL);
33330d9b703SDavid van Moolenbroek
33430d9b703SDavid van Moolenbroek if (rip->i_update & ATIME) rip->i_atime = now;
33530d9b703SDavid van Moolenbroek if (rip->i_update & MTIME) rip->i_mtime = now;
33630d9b703SDavid van Moolenbroek if (rip->i_update & CTIME) rip->i_ctime = now;
33730d9b703SDavid van Moolenbroek
33830d9b703SDavid van Moolenbroek rip->i_update = 0;
33930d9b703SDavid van Moolenbroek }
34030d9b703SDavid van Moolenbroek
34130d9b703SDavid van Moolenbroek /* Fill the stat buffer. */
34230d9b703SDavid van Moolenbroek statbuf->st_dev = rip->i_rdev; /* workaround for old socketpair bug */
34330d9b703SDavid van Moolenbroek statbuf->st_mode = rip->i_mode;
34430d9b703SDavid van Moolenbroek statbuf->st_nlink = 0;
34530d9b703SDavid van Moolenbroek statbuf->st_uid = rip->i_uid;
34630d9b703SDavid van Moolenbroek statbuf->st_gid = rip->i_gid;
34730d9b703SDavid van Moolenbroek statbuf->st_rdev = rip->i_rdev;
34830d9b703SDavid van Moolenbroek statbuf->st_size = rip->i_size;
34930d9b703SDavid van Moolenbroek statbuf->st_atime = rip->i_atime;
35030d9b703SDavid van Moolenbroek statbuf->st_mtime = rip->i_mtime;
35130d9b703SDavid van Moolenbroek statbuf->st_ctime = rip->i_ctime;
35230d9b703SDavid van Moolenbroek statbuf->st_blksize = PIPE_BUF;
35330d9b703SDavid van Moolenbroek statbuf->st_blocks = howmany(rip->i_size, S_BLKSIZE);
35430d9b703SDavid van Moolenbroek
35530d9b703SDavid van Moolenbroek return OK;
35630d9b703SDavid van Moolenbroek }
35730d9b703SDavid van Moolenbroek
35830d9b703SDavid van Moolenbroek /*
35930d9b703SDavid van Moolenbroek * Change node permissions.
36030d9b703SDavid van Moolenbroek */
36130d9b703SDavid van Moolenbroek static int
pfs_chmod(ino_t ino_nr,mode_t * mode)36230d9b703SDavid van Moolenbroek pfs_chmod(ino_t ino_nr, mode_t * mode)
36330d9b703SDavid van Moolenbroek {
36430d9b703SDavid van Moolenbroek struct inode *rip;
36530d9b703SDavid van Moolenbroek
36630d9b703SDavid van Moolenbroek if ((rip = pfs_findnode(ino_nr)) == NULL)
36730d9b703SDavid van Moolenbroek return EINVAL;
36830d9b703SDavid van Moolenbroek
36930d9b703SDavid van Moolenbroek /* Update file mode and times. */
37030d9b703SDavid van Moolenbroek rip->i_mode = (rip->i_mode & ~ALLPERMS) | (*mode & ALLPERMS);
37130d9b703SDavid van Moolenbroek rip->i_update |= MTIME | CTIME;
37230d9b703SDavid van Moolenbroek
37330d9b703SDavid van Moolenbroek *mode = rip->i_mode;
37430d9b703SDavid van Moolenbroek return OK;
37530d9b703SDavid van Moolenbroek }
37630d9b703SDavid van Moolenbroek
37730d9b703SDavid van Moolenbroek /*
37830d9b703SDavid van Moolenbroek * Process a signal.
37930d9b703SDavid van Moolenbroek */
38030d9b703SDavid van Moolenbroek static void
pfs_signal(int signo)38130d9b703SDavid van Moolenbroek pfs_signal(int signo)
38230d9b703SDavid van Moolenbroek {
38330d9b703SDavid van Moolenbroek
38430d9b703SDavid van Moolenbroek /* Only check for termination signal, ignore anything else. */
38530d9b703SDavid van Moolenbroek if (signo != SIGTERM) return;
38630d9b703SDavid van Moolenbroek
38730d9b703SDavid van Moolenbroek fsdriver_terminate();
38830d9b703SDavid van Moolenbroek }
38930d9b703SDavid van Moolenbroek
39030d9b703SDavid van Moolenbroek /*
391dfc32615SDavid van Moolenbroek * Initialize PFS.
392dfc32615SDavid van Moolenbroek */
393dfc32615SDavid van Moolenbroek static int
pfs_init(int __unused type,sef_init_info_t * __unused info)394dfc32615SDavid van Moolenbroek pfs_init(int __unused type, sef_init_info_t * __unused info)
395dfc32615SDavid van Moolenbroek {
396dfc32615SDavid van Moolenbroek
397dfc32615SDavid van Moolenbroek /* Drop privileges. */
398dfc32615SDavid van Moolenbroek if (setuid(SERVICE_UID) != 0)
399dfc32615SDavid van Moolenbroek printf("PFS: warning, unable to drop privileges\n");
400dfc32615SDavid van Moolenbroek
401dfc32615SDavid van Moolenbroek return OK;
402dfc32615SDavid van Moolenbroek }
403dfc32615SDavid van Moolenbroek
404dfc32615SDavid van Moolenbroek /*
40530d9b703SDavid van Moolenbroek * Perform SEF initialization.
40630d9b703SDavid van Moolenbroek */
40730d9b703SDavid van Moolenbroek static void
pfs_startup(void)40830d9b703SDavid van Moolenbroek pfs_startup(void)
40930d9b703SDavid van Moolenbroek {
41030d9b703SDavid van Moolenbroek
41130d9b703SDavid van Moolenbroek /* Register initialization callbacks. */
412dfc32615SDavid van Moolenbroek sef_setcb_init_fresh(pfs_init);
4133f82ac6aSCristiano Giuffrida sef_setcb_init_restart(SEF_CB_INIT_RESTART_STATEFUL);
41430d9b703SDavid van Moolenbroek
41530d9b703SDavid van Moolenbroek /* Register signal callbacks. */
41630d9b703SDavid van Moolenbroek sef_setcb_signal_handler(pfs_signal);
41730d9b703SDavid van Moolenbroek
41830d9b703SDavid van Moolenbroek /* Let SEF perform startup. */
41930d9b703SDavid van Moolenbroek sef_startup();
42030d9b703SDavid van Moolenbroek }
42130d9b703SDavid van Moolenbroek
42230d9b703SDavid van Moolenbroek /*
42330d9b703SDavid van Moolenbroek * Function call table for the fsdriver library.
42430d9b703SDavid van Moolenbroek */
42530d9b703SDavid van Moolenbroek static struct fsdriver pfs_table = {
42630d9b703SDavid van Moolenbroek .fdr_mount = pfs_mount,
42730d9b703SDavid van Moolenbroek .fdr_unmount = pfs_unmount,
42830d9b703SDavid van Moolenbroek .fdr_newnode = pfs_newnode,
42930d9b703SDavid van Moolenbroek .fdr_putnode = pfs_putnode,
43030d9b703SDavid van Moolenbroek .fdr_read = pfs_read,
43130d9b703SDavid van Moolenbroek .fdr_write = pfs_write,
43230d9b703SDavid van Moolenbroek .fdr_trunc = pfs_trunc,
43330d9b703SDavid van Moolenbroek .fdr_stat = pfs_stat,
43430d9b703SDavid van Moolenbroek .fdr_chmod = pfs_chmod
43530d9b703SDavid van Moolenbroek };
43630d9b703SDavid van Moolenbroek
43730d9b703SDavid van Moolenbroek /*
43830d9b703SDavid van Moolenbroek * The main routine of this service.
43930d9b703SDavid van Moolenbroek */
44030d9b703SDavid van Moolenbroek int
main(void)44130d9b703SDavid van Moolenbroek main(void)
44230d9b703SDavid van Moolenbroek {
44330d9b703SDavid van Moolenbroek
44430d9b703SDavid van Moolenbroek /* Local startup. */
44530d9b703SDavid van Moolenbroek pfs_startup();
44630d9b703SDavid van Moolenbroek
44730d9b703SDavid van Moolenbroek /* The fsdriver library does the actual work here. */
44830d9b703SDavid van Moolenbroek fsdriver_task(&pfs_table);
44930d9b703SDavid van Moolenbroek
45030d9b703SDavid van Moolenbroek return EXIT_SUCCESS;
45130d9b703SDavid van Moolenbroek }
452