Linux and UNIX Man Pages

Linux & Unix Commands - Search Man Pages

streamio(7) [osf1 man page]

streamio(7)						 Miscellaneous Information Manual					       streamio(7)

NAME
streamio - STREAMS ioctl commands SYNOPSIS
#include <sys/types.h> #include <sys/stropts.h> int ioctl( int fildes, int command, ... /* arg */); STANDARDS
Interfaces documented on this reference page conform to industry standards as follows: ioctl(): XSH4.2 Refer to the standards(5) reference page for more information about industry standards and associated tags. PARAMETERS
Contains the open file descriptor for the Stream to be operated on. Specifies the STREAM ioctl() command function to be performed on the Stream. Contains additional information that the specified may command need for performing its function. This is usually an integer, or a pointer to a command-specific structure, but can be of any type. DESCRIPTION
The STREAMS ioctl commands perform control operations on Streams. User processes can use these commands on all STREAMS file types. When the Stream head receives a STREAMS ioctl function, it interprets the command parameter and arg parameter, when specified, into an M_IOCTL message. In some cases, the command and arg parameters are passed onto a module or driver in the Stream. The modules or drivers in a Stream can also detect errors. When they do, they send an error message containing an error number to the Stream head. Subsequent calls to the functions will fail with errno set to this number. ioctl Commands The STREAMS ioctl commands are the following: Lets the user process see if the message currently on the Stream head read queue is marked by a downstream module. A message is marked when its b_flag field has MSGMARK ORed in by a module/driver. The arg field specifies how the checking is done when there are multiple marked messages on the queue. The legal values of arg are: Checks if the message is marked. Checks if the message is the last one that is marked on the queue. The command returns a value of 1 if the mark condition is satisfied; otherwise, a 0 (zero) is returned. Checks if the specified priority band is currently writable. The arg parameter specifies the priority band to check. The command returns a value of 0 (zero) if the priority band is being flow controlled; otherwise, a value of 1 is returned. Checks if a certain priority band's message is currently on the Stream head read queue. The arg parameter specifies the priority band being checked. If a message of the priority band is on the Stream head read queue, the command returns a value of 1; otherwise, a value of 0 (zero) is returned. Creates a message from one or more user specified buffers, includes information about another Stream, and sends the message downstream. The message contains a control part and a data part (which is optional). These parts are placed in separate buffers, ctlbuf and databuf, pointed to by arg. These buffers are contained in an strfdinsert structure (defined in the stropts.h header file), whose members are as follows: struct strbuf ctlbuf; struct strbuf databuf; long flags; int fildes; int offset; The strbuf structure pointed to by ctlbuf and databuf has the following members: int maxlen; int len; char *buf The len field of the strbuf structure for ctlbuf must specify the size of a pointer, plus the number of information control bytes to be sent in the message. The fildes field in the strfdinsert structure specifies the file descriptor of the Stream in which the message will be sent. The offset field needs to be properly aligned. This field specifies the number of bytes after the beginning of the control buffer where the I_FDINSERT command will store a pointer. This pointer will be the address of the read queue structure of the device driver for the Stream designated by fildes in the strfdinsert structure. The len field in the strbuf structure for databuf must contain the number of bytes of data information to be sent with the message, or to 0 (zero) if no data part is to be sent. The flags field specifies the type of message to be created. When this field contains 0 (zero), the I_FDINSERT command creates an ordinary message. When the field is set to RS_HIPRI, the I_FDINSERT command creates a high priority message. This command will block for an ordinary message if the named Stream's read queue is full because of internal flow control conditions. It will not block on these conditions for a high priority message. For ordinary messages, the ioctl will not block when the write queue is full and O_NDELAY or O_NONBLOCK (see the open() function) is specified. It will fail instead. Compares the names of all modules cur- rently present on the Stream to the name specified in arg. The command returns a value of 1 value if the module is present and a value of 0 (zero) value if the the module is not present. Flushes the input and output queues of the Stream head and all of the modules and drivers on the Stream, according to the value of arg. The arg parameter value can specify one of the following opera- tions: Flushes write and read queues. Flushes write queues. Flushes read queues. The command has the following effects on pipes: If a pipe does not have pushed modules, then, according to the value of arg, the read queue of the Stream head at either end is flushed. When arg is FLUSHRW and fildes specifies a pipe, the read queues at both ends are flushed. When arg is FLUSHW and fildes specifies a pipe, and the other end of the pipe exists (for example, the other end is not closed), the read queue for the other end of the pipe, and the write queue for this end, are flushed. When arg is FLUSHR and fildes specifies a pipe, both the read queue for the end which issued the I_FLUSH, and the write queue for the other end, are flushed. The pipemod module performs flushing operations on pipes. This module should be the first one pushed on the Stream for a pipe so that it will be located at the midpoint of the pipe. Flushes a band of messages. The band of messages to be flushed is defined in the bandinfo structure pointed to by arg. This structure (in the stropts.h header file) has the following members: unsigned char bi_pri: int bi_flag; The value of the bi_flag field can be FLUSHR, FLUSHW, or FLUSHRW, as described for the I_FLUSH command. Returns the priority of the first message on the Stream head read queue. The arg parameter specifies the priority band being checked. Returns the time delay for closing a Stream (see the I_SETCLTIME ioctl command). The time value is returned in the long pointed to by arg. This value may, or may not, have been set by a previously issued I_SETCLTIME ioctl. Returns the events for which the calling process has reg- istered to receive a SIGPOLL signal. Events are returned as in arg bitmask as defined for the I_SETSIG command. Returns the cur- rent read mode setting of the Stream (see the read() function reference page) in an integer pointed to by arg. Returns the current write mode setting for a Stream in the integer pointed to by arg. The value of the integer returned in arg is SNDZERO as described for the I_SWROPT command. Connects two Streams: the file descriptor of the Stream associated with the multiplexing driver (where fildes is the file descriptor) and the Stream associated with another driver (where arg is the file descriptor). The Stream referred to by arg is connected below the multiplexing driver. The I_LINK ioctl requires a multiplexing driver to send an acknowledgement message (M_IOCACK or M_IOCNAK) to the Stream head about the linking operation. Upon successful completion, the call returns a multiplexor ID number, which is an identifier that is used to disconnect the link (see the I_UNLINK command). If the request fails, a value of -1 is returned. Lets the user process list the names of all the modules present on a Stream. This includes the names up to and including the topmost driver name. If the arg parameter is a null value, the command returns the number of modules, plus the driver, which are present on the Stream referred to by fildes. The user can use this information to allocate enough space for the module and driver names in user space. If the arg parameter is not a null value, its value should point to an str_list structure (in the stropts.h header file), with the following members: int sl_nmods; struct str_mlist *sl_modlist; The str_mlist structure (also in the stropts.h header file) has the following member: char 1_name[FMNAMESZ+1]; The sl_nmods field of the str_list structure indicates the number of entries that the user process has allocated in the array and on return. The sl_modlist field contains the list of module names. The return value for the I_STR ioctl indicates the number of entries that have been filled in the array. Retrieves the name of the module located just below the Stream head, placing it in a null terminated character string pointed to by arg. The Stream is referred to by fildes. The arg parameter should point to a buffer, whose size is at least FMNAMESZ+1 bytes. The <sys/stropts.h> file contains the definition for FMNAMESZ. Counts the bytes in the data blocks of the first message on the Stream head read queue. This command places this value in the location pointed to by arg. The command returns the number of messages on the queue. For example, if the command call results in a value of 0 (zero) in arg, but a return value greater than 0 (zero) is returned by the ioctl() function, the first message on the queue contains 0 (zero) bytes. Allows the user process to look (peek) at the contents of the first message on the Stream head read queue. This is done without taking the message off the queue. The I_PEEK ioctl operates the same way as the getmsg() function, except that it does not remove the message. The arg parameter points to a strpeek structure (in the stropts.h header file) with the following members: struct strbuf ctlbuf; struct strbuf databuf; long flags; The strbuf structure pointed to by ctlbuf and databuf has the following members: int maxlen; int len; char *buf The maxlen field of the strbuf structure must specify the number of bytes of control or data information to be retrieved. The flags field can be set to RS_HIPRI or 0 (zero). If this field is set to RS_HIPRI, the I_PEEK ioctl looks for a high priority message on the queue. If the field is set to 0, the I_PEEK ioctl looks at the first message on the queue. The I_PEEK returns a 1 if a message was retrieved, and returns a value of 0 (zero) if no message was found; it does not wait for a message. Upon successful completion, ctlbuf specifies control information in the control buffer, databuf specifies data information in the data buffer, and flags contains RS_HIPRI or 0 (zero). Connects two Streams: the file descriptor of the Stream associated with the multiplexing driver (where fildes is the file descriptor) and the Stream associated with another driver (where arg is the file descriptor). The Stream referred to by arg is connected via a persistent link below the multiplexing driver. A persistent link is a link that can exist even if the file descriptor fildes referring to the Stream associated with the multiplexing driver is closed. The I_PLINK ioctl requires a multiplexing driver to send an acknowledgement message (M_IOCACK or M_IOCNAK) to the Stream head about the linking operation. On successful completion, the command returns a multiplexor ID number, which is an identifier that is used to disconnect the multi- plexing driver (see the I_PUNLINK command). Otherwise, a -1 is returned. The I_PLINK ioctl can also fail if it is waiting for the multiplexing driver to acknowledge the link request and an error (M_ERROR) message, or hangup (M_HANGUP) message is received at the Stream head for fildes. In addition, an error can be returned in an M_IOCACK or M_IOCNAK message. When these occur, the I_PLINK ioctl will fail with errno set to the value in the message. Removes the module just below the Stream head. The Stream is referred to by the fildes parameter. The arg parameter must be set to the value 0 (zero) in the request. In the case of pipes, the module must be popped from the side on which it was pushed. Disconnects two Streams that are connected via a persistent link, where fildes is the file descriptor of the Stream associated with a multiplexing driver and arg is the multi- plexor ID number returned by the I_PLINK ioctl. If arg is MUXID_ALL (as defined in the stropts.h header file), then all Streams that are connected by persistent links to the Stream referred to by fildes are disconnected. The I_PUNLINK ioctl requires a multiplexing driver to send an acknowledgement message (M_IOCACK or M_IOCNAK) to the Stream head about the unlinking operation. Pushes the module whose name is pointed to by arg on to the Stream, just below the Stream head, then calls the open routine of the module. In the case of pipes, the module is effectively pushed between the Stream head at each end. Gets the file descriptor associated with the message sent by the I_SENDFD command over a Stream pipe. The arg parameter points to a data buffer large enough to hold a strrecvfd structure (in the stropts.h header file), which contains user data. This structure has the following members: int fd; uid_t uid; gid_t gid; char fill[8] The fd field of the strrecvfd structure contains the integer for the file descriptor. The uid and guid fields contain the user ID and group ID of the sending Stream. If the O_ONDELAY or O_NONBOCK flags (see the open() function) are not set, the I_RECVFD ioctl will block until a message is present at the Stream head. If the O_ONDELAY or O_NONBOCK flags are set, the I_RECVFD ioctl will fail if no message is present at the Stream head. If the I_SENDFD command sent the message at the Stream head, the I_RECVFD command allocates a new file descriptor for the file pointer contained in the message. The new file descriptor is placed in the fd field of the strrecvfd structure, and the structure is copied into the data buffer pointed to by arg. Requests the Stream referred to by fildes to send a message M_PASSFP to the Stream head at the other end of a Stream pipe. The file pointer corresponds to the value of arg, which specifies an open file descriptor. The I_SENDFD command changes the arg value into a system file pointer, allocates a message data block, and inserts the file pointer in the block. It also places the user id and group id associated with the calling process are also placed in the block. The mes- sage is then placed directly on the read queue of the Stream head at the other end of the Stream pipe. It does not go through the Stream of the pipe. Lets the user process set the time that the Stream head delays when the Stream is closing and the write queues contain data. The arg parameter contains a pointer to the number of milliseconds to delay, rounded up to the nearest legal value on the system. The default time is 15 seconds. Before Stream modules and drivers are closed, the Stream head will delay for the specified amount of time. This allows the data on the write queues to drain. If data are still present on the writes queues after the delay, the queues are flushed. Tells the Stream head that the user process wants a SIGPOLL signal to be issued by the kernel for a particular event that can occur on a Stream. This command provides support for asynchronous processing in STREAMS. The arg parameter contains a bitmask specifying the particular events that SIGPOLL is to be sent for. The value is the bitwise-OR of any combination of the following constants: Indicates that, when used with S_RDBAND, a priority message has reached the front of the Stream head read queue. (If only S_RDBAND is set, only a SIGPOLL signal will be generated. If S_BANDURG is also set, then a SIGURG signal will be generated.) However, SIGURG is generated instead of SIGPOLL. Specifies that an M_ERROR message has reached the front of the Stream head read queue. The SIGPROC signal is posted to the user. Specifies that an M_HANGUP message has reached the Stream head. The SIGPROC signal is posted, in addition to a SIGHUP signal. Specifies a high priority message has arrived on the readd queue of the Stream head. This bit is set even zero length messages. Specifies that a message, which is not a M_PCPROTO type message, has arrived on the read queue of the Stream head. This bit is set even for zero length messages. The S_INPUT event is maintained for compatibility with SVID 2. Specifies that a STREAMS signal (M_SIG) signal containing the SIGPOLL signal has reached the front of the Stream head read queue. The SIGPROC signal will be posted to the user. If S_MSG is not enabled, SIGPROC will not be sent. Specifies that the write queue of the module just below the Stream head is not full any more. There is room on the queue for the user process to send (write) data to the Stream. Specifies a priority band message (where band is greater than 0 (zero)) has arrived on the read queue of the Stream head. This bit is set even zero length messages. Specifies that an ordinary message has arrived on the read queue of the Stream head. This bit is set even for zero length messages. Specifies that a priority band (where band is greater than 0 (zero)) exists on a queue downstream. The user can send (write)a priority data message on the queue. Specifies that this event is the same as S_OUTPUT. User processes must register explicitly using the I_SETSIG command to receive SIGPOLL (or SIGURG) signals. This is noted by the Stream head. When more than one user process registers to receive the signal for the same event on a Stream, each is signaled when the event occurs. If the value of arg is 0 (zero), the calling process is deregistered and does not receive the signal. A user process can set the arg bitmask to the S_HIPRI value, thus allowing itself to be signaled only of high priority messages. Sets the read mode of the Stream (see the read() reference page) according to the value of arg. The arg value specifies the follow- ing read modes related to data and message boundaries: Byte-stream mode (the default). The read() function completes when the byte count is satisfied, the Stream head read queue is empty, or a zero length message is encountered. In the case of a zero length mes- sage, the message is placed back on the queue, and a subsequent read() returns 0 bytes. Message-discard mode. The read() function completes when the byte count is satisfied, or a message boundary is reached. Any remaining data in the message are discarded. Message-nondiscard mode. The read() function completes when the byte count is satisfied, or a message boundary is reached. Any data remaining in the message are put back on the read queue. If the following value are set in arg, the Stream head treats control (protocol) messages accordingly: The read() function fails, returning EBADMSG, if a control message is at the front of the read queue (the default behavior). The read() function delivers the control portion of the message as data to the user process. The read() function discard the control portion of a message and send the data portion to the user process. Builds a STREAMS ioctl (M_IOCTL) message from the data pointed to by arg and sends the mes- sage downstream to a module or driver. The command allows a user process to send data with an ioctl request, and to receive any information that the downstream recipient of the message returns. The I_STR ioctl blocks until the intended recipient of the M_IOCTL message responds with a positive acknowledgement (M_IOCACK) message or negative acknowledgement (M_IOCNAK) message, or until the request times out (default time = 15 seconds). If the request times out, it fails. Only one I_STR ioctl can be active on a Stream at a time. Other requests must wait until the active request completes at the Stream head. The O_NDELAY and O_NONBLOCK flags (see the open() function) have no effect on the call. User values for the I_STR ioctl request are supplied by a strioctl structure (in the stropts.h header file), to which the arg param- eter points. The members of strioctl structure are the following: int ic_cmd; int ic_timeout; int ic_len; char *ic_dp; The ic_cmd field of the strioctl structure contains the ioctl command to be sent to the downstream module or driver. The ic_timeout field specifies the number of seconds that the I_STR request will wait for an acknowledgement before timing out: Indicates infinite number of seconds. Indicates that the default number of seconds should be used (which is infinite). Indicates that the specified number of seconds should be used. On input, the ic_len field contains the length of the data argument. On return, it contains the number of bytes being returned to the user process, (the buffer pointed to by ic_dp). The buffer pointed to by ic_dp should be large enough to contain the maximum amount of data able to be returned by any module or driver in the Stream. Sets the stream write mode according to the arg parameter value. The legal value for arg is: When set, the Stream head sends a zero length message downstream upon the occurrence of a write of 0 (zero) bytes. When not set, the Stream head does not send a zero length message downstream when a write of 0 bytes occurs, and returns 0 to the user process. Disconnects two Streams, where fildes is the file descriptor of the Stream associated with a multi- plexing driver and arg is the multiplexor identifier number returned by the I_LINK ioctl, which created the multiplexing configura- tion. If arg is MUXID_ALL (defined in the stropts.h header file), all Streams connected to the Stream referred to by fildes are disconnected. The I_UNLINK ioctl requires a multiplexing driver to send an acknowledgement message (M_IOCACK or M_IOCNAK) to the Stream head about the unlinking operation. RETURN VALUES Unless specified differently for a command, the return value for a STREAMS ioctl() call is 0 (zero) on success and -1 (minus one) on fail- ure. ERRORS
A STREAMS ioctl command fails without performing the function and with errno set to [EINVAL] if: The Stream referred to by fildes is linked below a multiplexing driver. The command parameter is not a valid value for the Stream. In addition, if any of the following conditions occur, the STREAMS ioctl commands return the corresponding value: I_ATMARK The arg parameter has an illegal value. I_CANPUT The arg parameter has an illegal value. I_CKBAND The arg parameter has an illegal value. I_FDINSERT The fildes parameter in the strfdinsert structure is an invalid, open file descriptor. The size of the pointer plus offset exceeds the value of the len field for the buffer specified through ctlptr. The offset parameter does not specify a properly aligned loca- tion in the data buffer. The flags parameter contains an undefined value. The arg parameter points, or ctrlbuf or databuf is, outside the allocated address space. The ioctl request failed because a non-priority message was to be created, the O_NDELAY or O_NONBLOCK flag was set, and the Stream's write queue was full because of internal flow control conditions. Buffers could not be allocated for the message that was to be created due to insufficient STREAMS memory resources. A hangup was received on the Stream specified by fildes in the I_FDINSERT ioctl call or on the Stream specified by fildes in the strfdinsert. The value of the len field for the buffer specified through databuf does not fall within the range for the minimum and maximum sizes of packets for the topmost module on the Stream. The value of the len field for the buffer specified through databuf is larger the the maximum allowable size for the data part of a message. The value of the len field for the buffer specified through ctlbuf is larger the the maximum allowable size for the control part of a message. The I_FDINSERT ioctl can also fail if an error (M_ERROR) message was received by the Stream specified by the fildes field in the strfdinsert structure. In this case, errno is set to the error value in the error message. I_FIND The arg parameter does not contain a valid module name. The arg parameter points outside the allocated address space. I_FLUSH Could not allocate buffers for flush operation because of a lack of STREAMS memory resources. The arg parameter is an invalid value. A hangup was received on fildes. I_FLUSHBAND The bi_pr parameter value exceeds the maximum band, or the bi_flag parameter is not FLUSHR, FLUSHW, or FLUSHRW. I_GETBAND No message exists on the Stream head read queue. I_GETSIG User process is not registered to receive the SIGPOLL signal. The arg parameter points outside the allocated address space. GRDOPT The arg parameter is pointing outside the allocated address space. I_LINK Temporarily unable to allocate storage to perform the linking operation. The arg parameter is an invalid, open file descriptor. A hangup was received on fildes. The Stream referred to by fildes does not support multiplexing. The file referred to by arg is not a Stream, or the Stream is already linked under a multiplexor. The link operation would cause a "cycle" in the resulting multiplexing con- figuration. In other words, the driver referred to by the arg parameter is linked into this configuration at multiple places The fildes parameter is the file descriptor of a pipe. The I_LINK ioctl can also fail if it is waiting for the multiplexing driver to acknowledge the link request and an error (M_ERROR) message, or hangup (M_HANGUP) message is received at the Stream head for fildes. In addition, an error can be returned in an M_IOCACK or M_IOCNAK message. When these occur, the I_LINK ioctl will fail with errno set to the value in the message. I_LIST The sl_mods number members is less than 1. Could not allocate buffers. I_LOOK The named module is not present on the Stream. The arg parameter points outside the allocated address space. I_NREAD The arg parameter is pointing outside the allocated address space. I_PEEK The flags parameter is an illegal value. arg points, or ctrlbuf or databuf is, outside the allocated address space. Message to be looked at is not valid for the I_PEEK command. I_PLINK A hangup was received on the Stream referred to by the fildes parameter. A timeout occurred before an acknowledgement message was received at the Stream head. Temporarily unable to allocate storage to perform the linking operation. The arg parameter is an invalid, open file descriptor. The Stream referred to by the fildes parameter does not support multiplexing. The file referred to by the arg parameter is not a Stream, or is already linked under a multiplexing driver. The link operation would cause a "cycle" in the resulting multiplexing configuration. In other words, the driver referred to by the arg parameter is linked into the configuration at multiple places. The fildes parameter is the file descriptor of a pipe. I_POP The named module is not present on the Stream. Error value returned by the module being popped. A hangup was received on fildes. I_PUNLINK A hangup was received on fildes. A timeout occurred before an acknowledgement message was received at the Stream head. Tempo- rarily unable to allocate storage to perform the linking operation. The arg parameter is an invalid multiplexor ID number. fildes is the file descriptor of a pipe. An I_PUNLINK ioctl can also fail if it is waiting for the multiplexor to acknowledge the unlink request and an error (M_ERROR) mes- sage, or hangup (M_HANGUP) is received at the Stream head for fildes. In addition, an error can be returned in an M_IOCACK or M_IOCNAK message. When these occur, the PUNI_LINK ioctl will fail with errno set to the value in the message. I_PUSH An invalid module name was used. The arg parameter points outside the allocated address space. Error value returned by the module being pushed. The push has failed. A hangup was received on fildes. I_RECVFD The O_ONDELAY or O_NONBOCK flag was set, and a message was not present on the Stream head read queue, The arg parameter points outside the allocated address space. The message present on the Stream head read queue did not contain a passed file descriptor. No more file descriptors are permitted to be opened. A hangup was received on fildes. I_SENDFD The sending Stream head could not allocate a message block for the file pointer. The read queue of the receiving Stream head was full and could not accept the message. The arg parameter is an invalid, open file descriptor. The fildes parameter does not refer to a Stream pipe. A hangup was received on fildes. I_SETCLTIME The arg parameter has an illegal value. I_SETSIG The user process is not registered to receive the SIGPOLL signal. A data structure to store the signal request could not be allo- cated. I_SRDOPT The arg parameter contains an illegal value. I_STR The ic_len field is less than 0 (zero) bytes or larger than the maximum allowable size of the data part of a message (ic_dp). The ic_timeout field is less than -1. The arg parameter points, or the buffer area specified by ic_dp or ic_len is, outside the allocated address space. Buffers could not be allocated for the ioctl request because of a lack of STREAMS memory resources. A hangup was received on the Stream referred to by fildes. The ioctl request timed out before an acknowledgement was received. The I_STR ioctl can also fail if the Stream head receives a message indicating an error (M_ERROR) or a hangup (M_HANGUP). In addi- tion, an error can be returned in an M_IOCACK or M_IOCNAK message. In these cases, the ioctl will fail with errno set to the error value in the message. I_SWROPT The arg parameter is an illegal value. I_UNLINK A hangup was received on fildes. A timeout occurred before an acknowledgement message was received at the Stream head. The arg parameter is an invalid multiplexor ID number, or the fildes parameter is already linked under a multiplexing driver. The fildes parameter is the file descriptor of a pipe. An I_UNLINK ioctl can also fail if it is waiting for the multiplexor to acknowledge the unlink request and an error (M_ERROR) mes- sage, or hangup (M_HANGUP) is received at the Stream head for fildes. In addition, an error can be returned in M_IOCACK or M_IOCNAK message. When this occurs, the I_UNLINK ioctl will fail with errno set to the value in the message. FILES
The system file containing all of the structure and constant definitions for STREAMS. The system file that contains type definitions used in STREAMS header files. The system file that contains definitions of the arguments to the STREAMS M_FLUSH message type required by users and STREAMS modules and drivers. RELATED INFORMATION
Functions: close(2), fattach(3), fcntl(2), fdetach(3), getmsg(2), ioctl(2), open(2), poll(2), putmsg(2), read(2), sigaction(2), write(2). Files: signal(4). Standards: standards(5). delim off streamio(7)
Man Page