Книга: Linux программирование в примерах

14.2.4. Обязательная блокировка

14.2.4. Обязательная блокировка

Большинство коммерческих систем Unix поддерживают в дополнение к вспомогательной обязательную блокировку файлов. Обязательная блокировка работает лишь с fcntl(). Обязательная блокировка файла контролируется установками прав доступа файла, в частности, путем добавления к файлу бита setgid с помощью команды chmod.

$ echo hello, world > myfile /* Создать файл */
$ ls -l myfile /* Отобразить права доступа */
-rw-r--r-- 1 arnold devel 13 Apr 3 17:11 myfile
$ chmod g+s myfile /* Добавить бит setgid */
$ ls -l myfile /* Показать новые права доступа */
-rw-r-Sr-- 1 arnold devel 13 Apr 3 17:11 myfile

Бит права на исполнение группой должен быть оставлен сброшенным. S показывает, что бит setgid установлен, но что бит права на исполнение — нет; если бы были установлены оба бита, была бы использована строчная буква s.

Комбинация установленного бита setgid и сброшенного бита права на исполнение группой обычно бессмысленно. По этой причине, она была выбрана разработчиками System V для обозначения «использования обязательного блокирования». И в самом деле, добавления этого бита достаточно, чтобы заставить коммерческую систему Unix, такую как Solaris, использовать блокировку файлов.

На системах GNU/Linux несколько другая история. Для обязательных блокировок файл должен иметь установленный бит setgid, но этого одного недостаточно. Файловая система, содержащая файл, также должна быть смонтирована с опцией mand в команде mount.

Мы уже рассмотрели файловые системы, разделы диска, монтирование и команду mount, главным образом, в разделе 8.1 «Монтирование и демонтирование файловых систем». Мы можем продемонстрировать обязательную блокировку с помощью небольшой программы и файловой системой для тестирования на гибком диске. Для начала, вот программа:

1  /* ch14-lockall.c --- Демонстрация обязательной блокировки. */
2
3  #include <stdio.h> /* для fprintf(), stderr, BUFSIZ */
4  #include <errno.h> /* объявление errno */
5  #include <fcntl.h> /* для флагов open() */
6  #include <string.h> /* объявление strerror() */
7  #include <unistd.h> /* для ssize_t */
8  #include <sys/types.h>
9  #include <sys/stat.h> /* для mode_t */
10
11 int
12 main(int argc, char **argv)
13 {
14  int fd;
15  int i, j;
16  mode_t rw_mode;
17  static char message[] = "hello, worldn";
18  struct flock lock;
19
20  if (argc != 2) {
21   fprintf(stderr, "usage: %s filen", argv[0]);
22   exit(1);
23  }
24
25  rw_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; / * 0644 */
26  fd = open(argv[1], O_RDWR|O_TRUNC|O_CREAT|O_EXCL, rw_mode);
27  if (fd < 0) {
28   fprintf(stderr, "%s: %s: cannot open for read/write: %sn",
29    argv[0], argv[1], strerror(errno));
30   (void)close(fd);
31   return 1;
32  }
33
34  if (write(fd, message, strlen(message)) != strlen(message)) {
35   fprintf(stderr, "%s: %s: cannot write: %sn",
36    argv[0], argv[1], strerror(errno));
37   (void)close(fd);
38   return 1;
39  }
40
41  rw_mode |= S_ISGID; /* добавить бит обязательной блокировки */
42
43  if (fchmod(fd, rw_mode) < 0) {
44   fprintf(stderr, "%s: %s: cannot change mode to %o: %sn",
45    argv[0], argv[1], rw_mode, strerror(errno));
46   (void)close(fd);
47   return 1;
48  }
49
50  /* заблокировать файл */
51  memset(&lock, '', sizeof(lock));
52  lock.l_whence = SEEK_SET;
53  lock.l_start = 0;
54  lock.l_len =0; /* блокировка всего файла */
55  lock.l_type = F_WRLCK; /* блокировка записи */
56
57  if (fcntl(fd, F_SETLK, &lock) < 0) {
58   fprintf(stderr, "%s: %s: cannot lock the file: %sn",
59    argv[0], argv[1], strerror(errno));
60   (void)close(fd);
61   return 1;
62  }
63
64  pause();
65
66  (void)close(fd);
67
68  return 0;
69 }

Программа устанавливает права доступа и создает файл, указанный в командной строке (строки 25 и 26). Затем она записывает в файл некоторые данные (строка 34). Строка 41 добавляет к правам доступа бит setgid, а строка 43 изменяет их. (Системный вызов fchmod() обсуждался в разделе 5.5.2 «Изменение прав доступа: chmod() и fchmod()».)

Строки 51–55 устанавливают struct flock для блокировки всего файла, а затем блокировка осуществляется реально в строке 57. Выполнив блокировку, программа засыпает, используя системный вызов pause() (см. раздел 10.7 «Сигналы для межпроцессного взаимодействия»). После этого программа закрывает дескриптор файла и завершается. Вот расшифровка с комментариями, демонстрирующая использование обязательной блокировки файлов:

$ fdformat /dev/fd0 /* Форматировать гибкий диск */
Double -sided, 80 tracks, 18 sec/track. Total capacity 1440 kB.
Formatting ... done
Verifying ... done
$ /sbin/mke2fs /dev/fd0 /* Создать файловую систему Linux */
/* ...множество вывода опущено... */
$ su /* Стать root, чтобы использовать mount */
Password: /* Пароль не отображается */
# mount -t ext2 -о mand /dev/fd0 /mnt/floppy /* Смонтировать гибкий
диск, с возможностью блокировок */
# suspend /* Приостановить оболочку root */
[1]+ Stopped su
$ ch14-lockall /mnt/floppy/x & /* Фоновая программа */
[2] 23311 /* содержит блокировку */
$ ls -l /mnt/floppy/x /* Посмотреть файл */
-rw-r-Sr-- 1 arnold devel 13 Apr 6 14:23 /mnt/floppy/x
$ echo something > /mnt/floppy/x /* Попытаться изменить файл */
bash2: /mnt/floppy/x: Resource temporarily unavailable
 /* Возвращается ошибка */
$ kill %2 /* Завершить программу с блокировкой */
$ /* Нажать ENTER */
[2]- Terminated ch14-lockall /mnt/floppy/x /* Программа завершена */
$ echo something > /mnt/floppy/x /* Новая попытка изменения работает */
$ fg /* Вернуться в оболочку root */
su
# umount /mnt/floppy /* Демонтировать гибкий диск */
# exit /* Работа с оболочкой root закончена */
$

Пока выполняется ch14-lockall, она владеет блокировкой. Поскольку это обязательная блокировка, перенаправления ввода/вывода оболочки завершаются неудачей. После завершения ch14-lockall блокировки освобождаются, и перенаправление ввода/вывода достигает цели. Как упоминалось ранее, под GNU/Linux даже root не может аннулировать обязательную блокировку файла.

Немного отклоняясь в сторону, гибкие диски представляют отличный испытательный стенд для изучения того, как использовать инструменты, работающие с файловыми системами. Если вы сделаете что-то, что разрушит данные на гибком диске, это вряд ли будет катастрофическим, тогда как экспериментирование с действующими разделами на обычных жестких дисках значительно более рискованно.

Оглавление книги


Генерация: 1.037. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз