Tabla de contenido
0. Concepto de llamada al sistema
1. Funciones de llamada al sistema de uso común
2.6 función de enlace simbólico
2.7 función de enlace de lectura
2.9 función de cambio de nombre
3. Funciones relacionadas con el directorio
3.5 función de lectura de directorio
0. Concepto de llamada al sistema
Responsabilidades del sistema operativo
El sistema operativo gestiona todos los recursos y asocia diferentes dispositivos con diferentes programas.
¿Qué es la programación del sistema Linux?
Programe en un entorno de sistema operativo y utilice llamadas al sistema y varias bibliotecas proporcionadas por el sistema operativo para acceder a los recursos del sistema.
La programación del sistema tiene como objetivo principal permitir a los usuarios operar mejor y más cómodamente los dispositivos de hardware, y también proteger los dispositivos de hardware. La esencia de los programas que escribimos es operar dispositivos de hardware, por lo que el sistema operativo proporciona interfaces para operar el hardware.
Descripción general de las llamadas al sistema:
La esencia es operar dispositivos de hardware, pero el sistema operativo Linux tiene un kernel encima del hardware, es decir, solo el kernel puede operar directamente dispositivos de hardware. Si desea operar el kernel, debe llamar a la llamada del sistema de el kernel Si desea operar el kernel, hay tres formas de llamar al sistema:
- El primer tipo: shell, el usuario usa comandos de shell y el intérprete de shell opera las llamadas al sistema del kernel.
- El segundo tipo: función de biblioteca, el usuario opera la llamada al sistema del kernel a través de la interfaz de la función de biblioteca de la capa de aplicación, como fread.
- El tercer tipo: llamada al sistema de la capa de aplicación, que puede operar directamente en la llamada al sistema del kernel.
Las llamadas al sistema son un conjunto de interfaces de funciones "especiales" proporcionadas por el sistema operativo a los programas de usuario.
Las diferentes versiones de Linux proporcionan entre doscientas y trescientas llamadas al sistema.
Los programas de usuario pueden obtener servicios proporcionados por el sistema operativo (kernel) a través de este conjunto de interfaces.
Las llamadas al sistema se pueden dividir aproximadamente en la siguiente lógica funcional:
Control de procesos, comunicación entre procesos, control de sistemas de archivos, control de sistemas, gestión de memoria, gestión de redes, control de sockets, gestión de usuarios.
Valor de retorno de la llamada al sistema:
Normalmente, se utiliza un valor de retorno no negativo para indicar error y un valor 0 para indicar éxito.
La información del error se almacena en la variable global errno y el usuario puede usar la función perror para imprimir la información del error.
Especificaciones seguidas de llamadas al sistema:
En Linux, la interfaz de programación de aplicaciones (API) sigue el estándar POSIX.
Función de E/S de llamada al sistema
Descriptor de archivo:
Los descriptores de archivos son números enteros no negativos. Al abrir un archivo existente o crear un archivo nuevo, el sistema (kernel) devuelve un descriptor de archivo. El descriptor de archivo se utiliza para especificar el archivo abierto.
En las llamadas al sistema (archivo IO), los descriptores de archivos desempeñan un papel en la identificación de archivos. Si desea operar un archivo, debe operar en el descriptor de archivo.
Cuando se ejecuta un programa o se inicia un proceso, el sistema crea automáticamente tres descriptores de archivos.
- #define STDIN_FILENO 0 //Descriptor de archivo de entrada estándar
- #define STDOUT_FILENO 1 //Descriptor de archivo de salida estándar
- #define STDERR_FILENO 2 //Descriptor de archivo de error estándar
Si abre el archivo usted mismo, se devolverá el descriptor del archivo y, por lo general, los descriptores de archivo se crean en orden de pequeño a grande.
1. Funciones de llamada al sistema de uso común
1.1 función abierta
#incluir<sys/types.h>
#incluir<sys/stat.h>
#incluir<fcntl.h>
int open(const char *nombre de ruta, int flags);
int open(const char *nombre de ruta, int flags, modo mode_t);
Función:
Abra el archivo en su nombre. Si el archivo no existe, puede optar por crearlo.
parámetro:
nombre de ruta: la ruta y el nombre del archivo.
flags: indicadores de comportamiento para abrir archivos, opciones requeridas O_RDONLY, O_WRONLY, O_RDWR
modo: Este parámetro solo es válido cuando el archivo no existe, se refiere a especificar los permisos del archivo al crear un nuevo archivo.
valor de retorno:
Éxito: descriptor de archivo
Fallo: -1
descripción detallada de las banderas
requerido:
valor | significado |
O_RDONLY | Abrir como solo lectura |
O_WRONLY | Abrir como solo escritura |
O_RDWR | Abierto para leer y escribir |
Opciones:
valor | significado |
O_CREAR | Si el archivo no existe, cree el archivo, al que debe ir seguido del modo (normalmente 0664) |
O_EXCL | Si también se especifica O_CREAT y el archivo ya existe, se produce un error. |
O_TRUNC | Si el archivo existe, borre su contenido. |
O_APPEND | Al escribir un archivo, los datos se agregan al final del archivo. |
O_NONBLOCK | Para archivos de dispositivos, abrirlos en modo O_NONBLOCK puede realizar E/S sin bloqueo. |
Instrucciones complementarias para el modo:
1) Permisos de archivos finales: modo y ~umask
2) La máscara umask del proceso de shell se puede ver usando el comando umask.
umask: Ver máscara (complemento)
modo umask: establece la máscara, el modo es un número octal
umask -S: ver los permisos de operación predeterminados de cada grupo de usuarios
Comparación de E/S de archivos y permisos de E/S estándar:
E/S estándar | E/S de texto | Significado del permiso |
r | O_RDONLY | Abra el archivo en modo de solo lectura e informe un error si el archivo no existe. |
r+ | O_RDWR | Abra el archivo para lectura y escritura. Si el archivo no existe, se informará un error. |
w | O_WRONLY | O_CREAT | O_TRUNC, 0664 | Abra el archivo solo para escritura, créelo si no existe o bórrelo si existe. |
w+ | O_RDWR | O_CREAT | O_TRUNC, 0664 | Abra el archivo para lectura y escritura. Si el archivo no existe, créelo. Si el archivo existe, bórrelo. |
a | O_WRONLY | O_CREAT |O_APPEND, 0664 | Abra el archivo en modo de solo escritura, créelo si no existe y añádalo si existe. |
un+ | O_RDWR | O_CREAT | O_APPEND, 0664 | Abra el archivo para lectura y escritura. Si el archivo no existe, créelo. Si el archivo existe, añádalo. |
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Failed to open the file");
exit(1);
}
// 在这里可以继续处理打开的文件
close(fd); // 关闭文件
return 0;
}
1.2 perror, función de error
perror
función:#incluir <stdio.h>
void perror(const char *s);
#incluir <errno.h>
Función:
La función perror imprime el mensaje de error correspondiente al código de error actual en el flujo de error estándar (stderr).
parámetro:
s
es una cadena que se puede utilizar para personalizar el prefijo del mensaje de error.valor de retorno:
ninguno
función de error:
#incluir <errno.h>
error nulo (int status, int errnum, const char *formato, ...);
Función:
La función de error imprime un mensaje de error en el flujo de error estándar y lo genera en el formato indicado. Es similar a la función perror, pero proporciona más flexibilidad para personalizar el formato del mensaje de error según sea necesario.
parámetro:
status
: Indica la gravedad del error; normalmente un valor distinto de cero indica un error fatal.
errnum
: Indica un código de error específico, que se puedeerrno
pasar como parámetro mediante variables.
format
: Una cadena de formato, similar al formato de la función printf.Valor de retorno: Ninguno
...
: parámetro adicional opcional utilizado para completar marcadores de posición en la cadena formateada.
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main() {
FILE* file = fopen("nonexistent.txt", "r");
if (file == NULL) {
perror("Failed to open the file");
exit(1);
}
// 在这里可以继续处理打开的文件
fclose(file); // 关闭文件
return 0;
}
1.3 función de cierre
#incluye int close(int fd);
Función:
Cerrar un archivo abierto
parámetro:
fd: descriptor de archivo, valor de retorno de open()
valor de retorno:
Éxito: 0
Fallo: -1 y se establece errno
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Failed to open the file");
exit(1);
}
// 在这里可以继续处理打开的文件
if (close(fd) == -1) {
perror("Failed to close the file");
exit(1);
}
return 0;
}
1.4 función de escritura
#incluir<unistd.h>
ssize_t escribir (int fd, const void *buf, size_t contar);
Función:
Escribe la cantidad especificada de datos en el archivo (fd).
parámetro:
fd: descriptor de archivo
buf: primera dirección de datos
recuento: longitud de los datos escritos (bytes)
valor de retorno:
Éxito: el número de bytes realmente escritos en los datos.
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("example.txt", O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("Failed to open the file");
exit(1);
}
const char* data = "Hello, World!";
ssize_t bytes_written = write(fd, data, strlen(data));
if (bytes_written == -1) {
perror("Failed to write to the file");
exit(1);
}
// 在这里可以继续处理打开的文件
if (close(fd) == -1) {
perror("Failed to close the file");
exit(1);
}
return 0;
}
1.5 función de lectura
#incluir<unistd.h>
ssize_t read(int fd, void *buf, size_t cuenta);
Función:
Lea la cantidad especificada de datos en la memoria (búfer).
parámetro:
fd: descriptor de archivo
buf: primera dirección de memoria
recuento: número de bytes leídos
valor de retorno:
Éxito: el número de bytes realmente leídos
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFFER_SIZE 1024
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Failed to open the file");
exit(1);
}
char buffer[BUFFER_SIZE];
ssize_t bytes_read = read(fd, buffer, BUFFER_SIZE);
if (bytes_read == -1) {
perror("Failed to read from the file");
exit(1);
}
// 在这里可以继续处理读取的数据
if (close(fd) == -1) {
perror("Failed to close the file");
exit(1);
}
return 0;
}
1.6 función de estadística
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int
stat(const char* ruta, struct stat* buf);
int lstat(const char* nombre de ruta, struct stat * buf);
Función:
Obtener información del estado del archivo
. La diferencia entre stat y lstat:
cuando el archivo es un enlace simbólico, lstat devuelve la información del enlace simbólico en sí;
mientras que stat devuelve la información del archivo al que apunta el enlace.
Parámetros:
ruta: nombre de archivo
buf: estructura para guardar la información del archivo
Valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
struct stat st;
if (stat("example.txt", &st) == -1) {
perror("Failed to get file status");
exit(1);
}
// 在这里可以继续处理文件状态信息
return 0;
}
1.7 dup, función dup2
función duplicada
#incluir<unistd.h>
int dup(int viejofd);
Función:
Copie un nuevo descriptor de archivo a través de oldfd. El nuevo descriptor de archivo es el descriptor de archivo más pequeño disponible en la tabla de descriptores de archivo del proceso de llamada. Al final, tanto oldfd como el nuevo descriptor de archivo apuntan al mismo archivo.
parámetro:
oldfd: el descriptor de archivo oldfd que debe copiarse
valor de retorno:
Éxito: nuevo descriptor de archivo
Fallo: -1
función dup2
#incluir<unistd.h>
int dup2(int antiguo, int nuevo);
Función:
Copie un nuevo descriptor de archivo newfd a oldfd. Si tiene éxito, newfd y el valor de retorno de la función son el mismo valor de retorno. Al final, oldfd y el nuevo descriptor de archivo newfd apuntan al mismo archivo.
parámetro:
oldfd: el descriptor de archivo que debe copiarse
newfd: nuevo descriptor de archivo. Este descriptor se puede especificar manualmente con un número legal (0-1023). Si el número especificado ya está ocupado (asociado con un determinado archivo), esta función cerrará automáticamente la desconexión close(). Este número es asociado con un determinado archivo, y luego se utiliza este número legal.
valor de retorno:
Éxito: devolver newfd
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("example.txt", O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("Failed to open the file");
exit(1);
}
// 复制文件描述符
int new_fd = dup(fd);
if (new_fd == -1) {
perror("Failed to duplicate file descriptor");
exit(1);
}
// 在这里可以继续处理文件描述符
if (close(fd) == -1) {
perror("Failed to close the file");
exit(1);
}
if (close(new_fd) == -1) {
perror("Failed to close the duplicated file");
exit(1);
}
return 0;
}
1.8 función fcntl
#incluir<unistd.h>
#incluir<fcntl.h>
int fcntl(int fd, int cmd, .../* arg */);
Función:
Para cambiar la naturaleza de un archivo abierto, fcntl proporciona control sobre el descriptor.
parámetro:
fd: descriptor de archivo para operación
cmd: Cómo operar
arg: para el valor de cmd, fcntl puede aceptar el tercer parámetro int arg
valor de retorno:
Éxito: devuelve algún otro valor
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Failed to open the file");
exit(1);
}
// 获取文件状态标志
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
perror("Failed to get file flags");
exit(1);
}
// 在这里可以继续处理文件状态标志
if (close(fd) == -1) {
perror("Failed to close the file");
exit(1);
}
return 0;
}
2. Otras funciones de E/S
2.1 función de acceso
#incluir<unistd.h>
acceso int (const char *nombre de ruta, modo int);
Función:
Prueba si el archivo especificado tiene un determinado atributo.
parámetro:
nombre de ruta: nombre del archivo
modo: permisos de archivos, 4 tipos de permisos
R_OK: si hay permiso de lectura
W_OK: ¿Tiene permiso de escritura?
X_OK: si existe permiso de ejecución
F_OK: prueba si el archivo existe
valor de retorno:
0: hay algún permiso o el archivo existe
-1: Ninguno o el archivo no existe
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
if (access("example.txt", R_OK) == -1) {
perror("Failed to access the file");
exit(1);
}
// 在这里可以继续处理文件访问权限
return 0;
}
2.2 función chmod
#incluir<sys/stat.h>
int chmod(const char *nombre de ruta, modo mode_t);
Función:
Modificar los permisos de los archivos.
parámetro:
nombre de archivo: nombre de archivo
modo: permiso (número octal)
valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main() {
if (chmod("example.txt", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
perror("Failed to change file mode");
exit(1);
}
// 在这里可以继续处理文件权限
return 0;
}
2.3 función chown
#incluir<unistd.h>
int chown(const char *nombre de ruta, propietario de uid_t, grupo gid_t);
Función:
Modifique el propietario y el grupo del archivo.
parámetro:
nombre de ruta: nombre de archivo o directorio
propietario: ID del propietario del archivo, obtenido al ver /etc/passwd
grupo: El ID del grupo al que pertenece el archivo. Obtenga el ID del grupo de usuarios marcando /etc/passwd.
valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
if (chown("example.txt", 1000, 1000) == -1) {
perror("Failed to change file ownership");
exit(1);
}
// 在这里可以继续处理文件所有者和所属组
return 0;
}
2.4 función truncada
#incluir<unistd.h>
#incluir<sys/types.h>
int truncate(const char *ruta, longitud off_t);
Función:
Modificar el tamaño del archivo.
parámetro:
ruta: nombre del archivo
longitud: tamaño de archivo especificado
a) Más pequeño que el original, eliminar la siguiente parte
b) Más grande que el original, expandiéndose hacia atrás
valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
if (truncate("example.txt", 100) == -1) {
perror("Failed to truncate the file");
exit(1);
}
// 在这里可以继续处理文件截断
return 0;
}
2.5 función de enlace
#incluir<unistd.h>
int link(const char *ruta antigua, const char *nueva ruta);
Función:
Crea un enlace físico.
parámetro:
oldpath: nombre del archivo fuente
nueva ruta: nombre del enlace físico
valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
if (link("example.txt", "example_link.txt") == -1) {
perror("Failed to create hard link");
exit(1);
}
// 在这里可以继续处理硬链接
return 0;
}
2.6 función de enlace simbólico
#incluir<unistd.h>
int enlace simbólico(const char *objetivo, const char *ruta de enlace);
Función:
Crear un enlace suave
parámetro:
destino: nombre del archivo fuente
ruta de enlace: nombre del enlace suave
valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
if (symlink("example.txt", "example_symlink.txt") == -1) {
perror("Failed to create symbolic link");
exit(1);
}
// 在这里可以继续处理符号链接
return 0;
}
2.7 función de enlace de lectura
#incluir<unistd.h>
ssize_t readlink(const char *nombre de ruta, char *buf, size_t bufsize);
Función:
Lea el nombre del archivo correspondiente al enlace suave, no el contenido (esta función solo puede leer archivos de enlace suave).
parámetro:
nombre de ruta: nombre de enlace suave
buf: almacena el nombre del archivo correspondiente al software
bufsize: tamaño del búfer (el número máximo de bytes almacenados en el segundo parámetro)
valor de retorno:
Éxito: >0, lee el número de caracteres en buf
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE 1024
int main() {
char buffer[BUFFER_SIZE];
ssize_t len = readlink("example_symlink.txt", buffer, BUFFER_SIZE - 1);
if (len == -1) {
perror("Failed to read symbolic link");
exit(1);
}
buffer[len] = '\0';
// 在这里可以继续处理读取的符号链接目标
return 0;
}
2.8 función de desvinculación
#incluir<unistd.h>
int unlink(const char *nombre de ruta);
Función:
Eliminar un archivo (archivos de enlace físico y físico).
parámetro:
nombre de ruta: nombre del archivo eliminado
valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
if (unlink("example.txt") == -1) {
perror("Failed to remove the file");
exit(1);
}
// 在这里可以继续处理文件删除
return 0;
}
2.9 función de cambio de nombre
#incluir<stdio.h>
int rename(const char *ruta antigua, const char *nueva ruta);
Función:
Cambie el nombre del archivo de ruta antigua a ruta nueva.
parámetro:
oldpath: nombre de archivo antiguo
nueva ruta: nuevo nombre de archivo
valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
int main() {
if (rename("example.txt", "new_example.txt") == -1) {
perror("Failed to rename the file");
exit(1);
}
// 在这里可以继续处理文件重命名
return 0;
}
3. Funciones relacionadas con el directorio
3.1 función obtenercwd
#incluir<unistd.h>
char *getcwd(char *buf, size_t tamaño);
Función:
buf: Búfer, almacena el directorio de trabajo actual.
tamaño: tamaño del búfer.
valor de retorno:
Éxito: guarde la ubicación del directorio de trabajo del proceso actual en buf
Fallo: NULO
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define PATH_MAX 4096
int main() {
char current_path[PATH_MAX];
if (getcwd(current_path, sizeof(current_path)) == NULL) {
perror("Failed to get the current working directory");
exit(1);
}
// 在这里可以继续处理当前工作目录
return 0;
}
3.2 función chdir
#incluir<unistd.h>
int chdir(const char *ruta);
Función:
Modificar la ruta del proceso actual (aplicación).
parámetro:
ruta: la ruta para cambiar.
valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
if (chdir("/path/to/directory") == -1) {
perror("Failed to change the directory");
exit(1);
}
// 在这里可以继续处理目录切换
return 0;
}
3.3 función abrirdir
#incluir<sys/types.h>
#incluir<direct.h>
DIR *opendir(const char *nombre);
Función:
Abra un directorio.
parámetro:
nombre: nombre del directorio.
valor de retorno:
Éxito: devuelve un puntero a la estructura del directorio.
Fallo: NULO
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main() {
DIR* dir = opendir(".");
if (dir == NULL) {
perror("Failed to open the directory");
exit(1);
}
// 在这里可以继续处理打开的目录
closedir(dir); // 关闭目录
return 0;
}
3.4 función cerrada
#incluir<sys/types.h>
#incluir<direct.h>
int cerradodir(DIR *dirp);
Función:
Cierra el directorio.
parámetro:
dirp: el puntero devuelto por opendir.
valor de retorno:
Éxito: 0
Fallo: -1
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main() {
DIR* dir = opendir(".");
if (dir == NULL) {
perror("Failed to open the directory");
exit(1);
}
// 在这里可以继续处理打开的目录
if (closedir(dir) == -1) {
perror("Failed to close the directory");
exit(1);
}
return 0;
}
3.5 función de lectura de directorio
#incluir<direct.h>
estructura directa *readdir(DIR *dirp);
Función:
dirp: el valor de retorno de opendir.
valor de retorno:
Éxito: puntero de estructura de directorios.
Fallo: NULO
Ejemplo de código:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main() {
DIR* dir = opendir(".");
if (dir == NULL) {
perror("Failed to open the directory");
exit(1);
}
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
// 在这里可以处理每个目录项
}
closedir(dir); // 关闭目录
return 0;
}
Resumir:
Este blog cubre el uso de funciones de llamada al sistema de uso común, incluidas funciones de llamada al sistema en diferentes campos, como control de procesos, control del sistema de archivos, control del sistema, administración de memoria, administración de redes, control de sockets y administración de usuarios. Presentamos las funciones, parámetros y valores de retorno de cada función de llamada al sistema y proporcionamos los ejemplos de código de lenguaje C correspondientes.
Espero que este blog te haya resultado útil y, si tienes alguna pregunta o necesitas más ayuda, no dudes en preguntar. ¡Gracias!