fcntl()--Perform File Control Command


  Syntax
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>

 int fcntl(int descriptor,
          int command,
          ...)  
  Service Program Name: QP0LLIB1

  Default Public Authority: *USE

  Threadsafe: Conditional; see Usage Notes

The fcntl() function performs various actions on open descriptors, such as obtaining or changing the attributes of a file or socket descriptor.


Parameters

descriptor
(Input)  The descriptor on which the control command is to be performed, such as having its attributes retrieved or changed.

command
(Input)  The command that is to be performed on the descriptor.

...
(Input) A variable number of optional parameters that is dependent on the command. Only some of the commands use this parameter.

The fcntl() commands that are supported are:



Flags

There are several types of flags associated with each open object. Flags for an object are represented by symbols defined in the <fcntl.h> header file. The following file status flags can be associated with an object:

The following file access mode flags can be associated with a file:

A mask can be used to extract flags:

The following descriptor flags can be associated with a descriptor:

See spawn()--Spawn Process and spawnp()--Spawn Process with Path for additional information about FD_CLOEXEC.


File locking

A local or remote job can use fcntl() to lock out other local or remote jobs from a part of a file. By locking out other jobs, the job can read or write to that part of the file without interference from others. File locking can ensure data integrity when several jobs have a file accessed concurrently. For more information about remote locking, see information about the network lock manager and the network status monitor in the IBM® i Network File System SupportLink to PDF manual.

All locks obtained using fcntl() are advisory only. Jobs can use advisory locks to inform each other that they want to protect parts of a file, but advisory locks do not prevent input and output on the locked parts. If a job has appropriate permissions on a file, it can perform whatever I/O it chooses, regardless of what advisory locks are set. Therefore, advisory locking is only a convention, and it works only when all jobs respect the convention.

Another type of lock, called a mandatory lock, can be set by a remote personal computer application. Mandatory locks restrict I/O on the locked parts. A read fails when reading a part that is locked with a mandatory write lock. A write fails when writing a part that is locked with a mandatory read or mandatory write lock.

Two different structures are used to control locking operations: struct flock and struct flock64 (both defined in the <fcntl.h> header file). You can use struct flock64 with the F_GETLK64, F_SETLK64, and F_SETLKW64 commands to control locks on large files (files greater than 2GB minus 1 byte). The struct flock structure has the following members:

When you develop in C-based languages and this function is compiled with _LARGE_FILES defined, the struct flock data type will be mapped to a struct flock64 data type. To use the struct flock64 data type explicitly, it is necessary to compile the function with _LARGE_FILE_API defined.

The struct flock64 structure has the following members:

You can set locks by specifying F_SETLK or F_SETLK64 as the command argument for fcntl(). Such a function call requires a third argument pointing to a struct flock structure (or struct flock64 in the case of F_SETLK64), as in this example:

   struct flock lock_it;
   lock_it.l_type = F_RDLCK;
   lock_it.l_whence = SEEK_SET;
   lock_it.l_start = 0;
   lock_it.l_len = 100;
   fcntl(file_descriptor,F_SETLK,&lock_it);

This example sets up a flock structure describing a read lock on the first 100 bytes of a file, and then calls fcntl() to establish the lock. You can unlock this lock by setting l_type to F_UNLCK and making the same call. If an F_SETLK operation cannot set a lock, it returns immediately with an error saying that the lock cannot be set.

The F_SETLKW and F_SETLKW64 operations are similar to F_SETLK and F_SETLK64, except that they wait until the lock can be set. For example, if you want to establish an exclusive lock and some other job already has a lock established on an overlapping part of the file, fcntl() waits until the other process has removed its lock.

F_SETLKW and F_SETLKW64 operations can encounter deadlocks when job A is waiting for job B to unlock a region and job B is waiting for job A to unlock a different region. If the system detects that an F_SETLKW or F_SETLKW64 might cause a deadlock, fcntl() fails with errno set to [EDEADLK].

With the F_SETLK64, F_SETLKW64, and F_GETLK64 operations, the maximum offset that can be specified is the largest value that can be held in an 8-byte, signed integer.

A job can determine locking information about a file by using F_GETLK and F_GETLK64 as the command argument for fcntl(). In this case, the call to fcntl() should specify a third argument pointing to a flock structure. The structure should describe the lock operation you want. When fcntl() returns, the structure indicated by the flock pointer is changed to show the first lock that would prevent the proposed lock operation from taking place. The returned structure shows the type of lock that is set, the part of the file that is locked, and the job ID of the job that holds the lock. In the returned structure:

If there are no locks that prevent the proposed lock operation, the returned structure has F_UNLCK in l_type and is otherwise unchanged.

If fcntl() attempts to operate on a large file (one larger than 2GB minus 1 byte) with the F_SETLK, F_GETLK, or FSETLKW commands, the API fails with [EOVERFLOW]. To work with large files, compile with the _LARGE_FILE_API macro defined (when you develop in C-based languages) and use the F_SETLK64, F_GETLK64, or FSETLKW64 commands. When you develop in C-based languages, it is also possible to work with large files by compiling the source with the _LARGE_FILES macro label defined. Note that the file must have been opened for large file access (either the open64() API was used or the open() API was used with the O_LARGEFILE flag defined in the oflag parameter).

An application that uses the F_SETLK or F_SETLKW commands may try to lock or unlock a file that has been extended beyond 2GB minus 1 byte by another application. If the value of l_len is set to 0 on the lock or unlock request, the byte range held or released will go to the end of the file rather than ending at offset 2GB minus 2.

An application that uses the F_SETLK or F_SETLKW commands also may try to lock or unlock a file that has been extended beyond offset 2GB minus 2 with l_len NOT set to 0. If this application attempts to lock or unlock the byte range up to offset 2GB minus 2 and l_len is not 0, the unlock request will unlock the file only up to offset 2GB minus 2 rather than to the end of the file.

A job can have several locks on a file at the same time, but only one type of lock can be set on a given byte. Therefore, if a job puts a new lock on a part of a file that it had locked previously, the job has only one lock on that part of the file. The type of the lock is the one specified in the most recent locking operation.

Locks can start and extend beyond the current end of a file, but cannot start or extend ahead of the beginning of a file.

All of the locks a job has on a file are removed when the job closes any descriptor that refers to the locked file.

The maximum starting offset that can be specified by using the fnctl() API is 263 - 1, the largest number that can be represented by a signed 8-byte integer. Mandatory locks set by a personal computer application or by a user of the DosSetFileLocks64() API may lock a byte range that is greater than 263 - 1.

An application that uses the F_SETLK64 or F_SETLKW64 commands can lock the offset range that is beyond 263 - 1 by locking offset 263 - 1. When offset 263 - 1 is locked, it implicitly locks to the end of the file. The end of the file is the largest number than can be represented by an 8-byte unsigned integer or 264 - 1. This implicit lock may inhibit the personal computer application from setting mandatory locks in the range not explicitly accessable by the fcntl() API.

Any lock set using the fcntl() API that locks offset 263 - 1 will have a length of 0.

An application that uses the F_GETLK64 may encounter a mandatory lock set by a personal computer application, which locks a range of offsets greater than 263 - 1. This lock conflict will have a starting offset equal to or less than 263 - 1 and a length of 0.


Authorities

No authorization is required.


Return Value



Error Conditions

If fcntl() is not successful, errno usually indicates one of the following errors. Under some conditions, errno could indicate an error other than those listed here.

If interaction with a file server is required to access the object, errno could also indicate one of the following errors:



Error Messages

The following messages may be sent from this function:



Usage Notes

  1. This function will fail with error code [ENOTSAFE] when all the following conditions are true:

    • Where multiple threads exist in the job.
    • The object on which this function is operating resides in a file system that is not threadsafe. Only the following file systems are threadsafe for this function:

      • "Root" (/)
      • QOpenSys
      • User-defined
      • QNTC
      • QSYS.LIB
      • Independent ASP QSYS.LIB
      • QOPT
      • Network File System
      • QFileSvr.400

  2. If F_DUPFD is specified as the fcntl() command, this function will fail with error code [EBADF] when fildes is a scan descriptor that was passed to one of the scan-related exit programs. See Integrated File System Scan on Open Exit Programs and Integrated File System Scan on Close Exit Programs for more information.

  3. If the fcntl() command is called by a thread executing one of the scan-related exit programs (or any of its created threads), it will fail with error code [ENOTSUP] if F_SETLK, F_SETLK64, F_SETLKW or F_SETLKW64 is specified. See Integrated File System Scan on Open Exit Programs and Integrated File System Scan on Close Exit Programs for more information.
  4. QSYS.LIB and Independent ASP QSYS.LIB File System Differences

    The following fcntl() commands are not supported:

    • F_GETLK
    • F_SETLK
    • F_SETLKW

    Using any of these commands results in an [ENOSYS] error.

    The following fcntl() commands are not supported if the file was opened with O_TEXTDATA:

    • F_GETCVT
    • F_SETCVT

    Using any of these commands results in an [ENOTSUP] error.

  5. Network File System Differences

    Reading and writing to a file with the Network File System relies on byte-range locking to guarantee data integrity. To prevent data inconsistency, use the fcntl() API to get and release these locks. For more information about remote locking, see information about the network lock manager and the network status monitor in the i5/OS Network File System SupportLink to PDF manual.

  6. This function will fail with the [EOVERFLOW] error if the command is F_GETLK, F_SETLK, or F_SETLKW and the offset or the length exceeds offset 2 GB minus 2.

  7. When you develop in C-based languages and an application is compiled with the _LARGE_FILES macro defined, the struct flock data type will be mapped to a struct flock64 data type. To use the struct flock64 data type explicitly, it is necessary to compile the function with the _LARGE_FILE_API defined.

  8. In several cases, similar function can be obtained by using ioctl().

  9. Network File System Differences

    Local access to remote files through the Network File System may produce unexpected results due to conditions at the server. Once a file is open, subsequent requests to perform operations on the file can fail because file attributes are checked at the server on each request. If permissions on the file are made more restrictive at the server to the file is unlinked or made unavailable by the server for another client, your operation on an open file descriptor will fail when the local Network File System receives these updates. The local Network File System also impacts operations that retrieve file attributes. Recent changes at the server may not be available at your client yet, and old values may be returned from operations (several options on the Add Mounted File System (ADDMFS) command determine the time between refresh operations of local data).



  10. If the portion of the file prior to the position retrieved by F_GETCVT is changed before a corresponding F_SETCVT call, then subsequent read and write operations would produce unexpected results. For example, if the file pointer were at offset 50 when F_GETCVT was called, and changes were made to any of the first 50 bytes before F_SETCVT was called, the restored conversion information would be incorrect.

  11. No changes should be made to the contents of a CVTSP returned by the F_GETCVT function. Any changes to the CVTSP specified with F_SETCVT may invalidate the CVTSP resulting in a return of error number [EINVAL] or cause data integrity issues.

  12. If O_TEXTDATA or O_CCSID were not specified when opening the descriptor, use lseek() to obtain or change the file offset instead of using F_GETCVT and F_SETCVT.

  13. A different descriptor may be used with F_SETCVT than was used when F_GETCVT was called if the descriptors were opened on the same file with the same oflags and CCSIDs. If the descriptors were not opened with the same oflags and CCSIDs, F_SETCVT may return error number [EINVAL] or cause data integrity issues.

Related Information


Example

The following example uses fcntl().

Note: By using the code examples, you agree to the terms of the Code license and disclaimer information.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
  int flags;
  int append_flag;
  int nonblock_flag;
  int access_mode;
  int file_descriptor; /* File Descriptor */
  char *text1 = "abcdefghij";
  char *text2 = "0123456789";
  char read_buffer[25];

  memset(read_buffer, '\0', 25);

  /* create a new file */
  file_descriptor = creat("testfile",S_IRWXU);
  write(file_descriptor, text1, 10);
  close(file_descriptor);

  /* open the file with read/write access */
  file_descriptor = open("testfile", O_RDWR);
  read(file_descriptor, read_buffer,24);
  printf("first read is \'%s\'\n",read_buffer);

  /* reset file pointer to the beginning of the file */
  lseek(file_descriptor, 0, SEEK_SET);
  /* set append flag to prevent overwriting existing text */
  fcntl(file_descriptor, F_SETFL, O_APPEND);
  write(file_descriptor, text2, 10);
  lseek(file_descriptor, 0, SEEK_SET);
  read(file_descriptor, read_buffer,24);
  printf("second read is \'%s\'\n",read_buffer);

  close(file_descriptor);
  unlink("testfile");

  return 0;
}

Output:

first read is 'abcdefghij'
second read is 'abcdefghij0123456789'


API introduced: V3R1

[ Back to top | UNIX-Type APIs | APIs by category ]