xref: /minix3/minix/fs/pfs/pfs.c (revision e3b8d4bb58a799dc7fd563ac39bf3015762af03b)
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