Lines 31-36
Link Here
|
31 |
#include <sys/wait.h> |
31 |
#include <sys/wait.h> |
32 |
#include <sys/signal.h> |
32 |
#include <sys/signal.h> |
33 |
#include <sys/stat.h> |
33 |
#include <sys/stat.h> |
|
|
34 |
#include <sys/file.h> |
35 |
#include <fcntl.h> |
34 |
#include <limits.h> |
36 |
#include <limits.h> |
35 |
#include <stdio.h> |
37 |
#include <stdio.h> |
36 |
#include <ctype.h> |
38 |
#include <ctype.h> |
Lines 42-47
Link Here
|
42 |
#include <errno.h> |
44 |
#include <errno.h> |
43 |
#include <malloc.h> |
45 |
#include <malloc.h> |
44 |
#include <signal.h> |
46 |
#include <signal.h> |
|
|
47 |
#include <dirent.h> |
48 |
#include <blkid.h> |
45 |
|
49 |
|
46 |
#include "fsprobe.h" |
50 |
#include "fsprobe.h" |
47 |
|
51 |
|
Lines 85-90
char *devices[MAX_DEVICES];
Link Here
|
85 |
char *args[MAX_ARGS]; |
89 |
char *args[MAX_ARGS]; |
86 |
int num_devices, num_args; |
90 |
int num_devices, num_args; |
87 |
|
91 |
|
|
|
92 |
int lockdisk = 0; |
88 |
int verbose = 0; |
93 |
int verbose = 0; |
89 |
int doall = 0; |
94 |
int doall = 0; |
90 |
int noexecute = 0; |
95 |
int noexecute = 0; |
Lines 214-223
static void parse_escape(char *word)
Link Here
|
214 |
*q = 0; |
219 |
*q = 0; |
215 |
} |
220 |
} |
216 |
|
221 |
|
|
|
222 |
static dev_t get_disk(const char *device) |
223 |
{ |
224 |
struct stat st; |
225 |
dev_t disk; |
226 |
|
227 |
if (!stat(device, &st) && |
228 |
!blkid_devno_to_wholedisk(st.st_rdev, NULL, 0, &disk)) |
229 |
return disk; |
230 |
|
231 |
return 0; |
232 |
} |
233 |
|
234 |
static int is_irrotational_disk(dev_t disk) |
235 |
{ |
236 |
char path[PATH_MAX]; |
237 |
FILE *f; |
238 |
int rc, x; |
239 |
|
240 |
rc = snprintf(path, sizeof(path), |
241 |
"/sys/dev/block/%d:%d/queue/rotational", |
242 |
major(disk), minor(disk)); |
243 |
|
244 |
if (rc < 0 || rc + 1 > sizeof(path)) |
245 |
return 0; |
246 |
|
247 |
f = fopen(path, "r"); |
248 |
if (!f) |
249 |
return 0; |
250 |
|
251 |
rc = fscanf(f, "%u", &x); |
252 |
fclose(f); |
253 |
|
254 |
return rc == 1 ? !x : 0; |
255 |
} |
256 |
|
257 |
static void lock_disk(struct fsck_instance *inst) |
258 |
{ |
259 |
dev_t disk = inst->fs->disk ? : get_disk(inst->fs->device); |
260 |
char *diskname; |
261 |
|
262 |
if (!disk || is_irrotational_disk(disk)) |
263 |
return; |
264 |
|
265 |
diskname = blkid_devno_to_devname(disk); |
266 |
if (!diskname) |
267 |
return; |
268 |
|
269 |
if (verbose) |
270 |
printf(_("Locking disk %s ... "), diskname); |
271 |
|
272 |
inst->lock = open(diskname, O_CLOEXEC | O_RDONLY); |
273 |
if (inst->lock >= 0) { |
274 |
int rc = -1; |
275 |
|
276 |
/* inform users that we're waiting on the lock */ |
277 |
if (verbose && |
278 |
(rc = flock(inst->lock, LOCK_EX | LOCK_NB)) != 0 && |
279 |
errno == EWOULDBLOCK) |
280 |
printf(_("(waiting) ")); |
281 |
|
282 |
if (rc != 0 && flock(inst->lock, LOCK_EX) != 0) { |
283 |
close(inst->lock); /* failed */ |
284 |
inst->lock = -1; |
285 |
} |
286 |
} |
287 |
|
288 |
if (verbose) |
289 |
printf("%s.\n", inst->lock >= 0 ? _("success") : _("failed")); |
290 |
|
291 |
free(diskname); |
292 |
return; |
293 |
} |
294 |
|
295 |
static void unlock_disk(struct fsck_instance *inst) |
296 |
{ |
297 |
if (inst->lock >= 0) { |
298 |
/* explicitly unlock, don't rely on close(), maybe some library |
299 |
* (e.g. liblkid) has still open the device. |
300 |
*/ |
301 |
flock(inst->lock, LOCK_UN); |
302 |
close(inst->lock); |
303 |
} |
304 |
} |
305 |
|
217 |
static void free_instance(struct fsck_instance *i) |
306 |
static void free_instance(struct fsck_instance *i) |
218 |
{ |
307 |
{ |
|
|
308 |
if (lockdisk) |
309 |
unlock_disk(i); |
310 |
|
219 |
free(i->prog); |
311 |
free(i->prog); |
220 |
free(i->device); |
|
|
221 |
free(i->base_device); |
312 |
free(i->base_device); |
222 |
free(i); |
313 |
free(i); |
223 |
return; |
314 |
return; |
Lines 240-245
static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
Link Here
|
240 |
fs->passno = passno; |
331 |
fs->passno = passno; |
241 |
fs->flags = 0; |
332 |
fs->flags = 0; |
242 |
fs->next = NULL; |
333 |
fs->next = NULL; |
|
|
334 |
fs->disk = 0; |
335 |
fs->stacked = 0; |
243 |
|
336 |
|
244 |
if (!filesys_info) |
337 |
if (!filesys_info) |
245 |
filesys_info = fs; |
338 |
filesys_info = fs; |
Lines 414-421
static int progress_active(NOARGS)
Link Here
|
414 |
* Execute a particular fsck program, and link it into the list of |
507 |
* Execute a particular fsck program, and link it into the list of |
415 |
* child processes we are waiting for. |
508 |
* child processes we are waiting for. |
416 |
*/ |
509 |
*/ |
417 |
static int execute(const char *type, const char *device, const char *mntpt, |
510 |
static int execute(const char *type, struct fs_info *fs, int interactive) |
418 |
int interactive) |
|
|
419 |
{ |
511 |
{ |
420 |
char *s, *argv[80], prog[80]; |
512 |
char *s, *argv[80], prog[80]; |
421 |
int argc, i; |
513 |
int argc, i; |
Lines 452-458
static int execute(const char *type, const char *device, const char *mntpt,
Link Here
|
452 |
} |
544 |
} |
453 |
} |
545 |
} |
454 |
|
546 |
|
455 |
argv[argc++] = string_copy(device); |
547 |
argv[argc++] = string_copy(fs->device); |
456 |
argv[argc] = 0; |
548 |
argv[argc] = 0; |
457 |
|
549 |
|
458 |
s = find_fsck(prog); |
550 |
s = find_fsck(prog); |
Lines 464-475
static int execute(const char *type, const char *device, const char *mntpt,
Link Here
|
464 |
|
556 |
|
465 |
if (verbose || noexecute) { |
557 |
if (verbose || noexecute) { |
466 |
printf("[%s (%d) -- %s] ", s, num_running, |
558 |
printf("[%s (%d) -- %s] ", s, num_running, |
467 |
mntpt ? mntpt : device); |
559 |
fs->mountpt ? : fs->device); |
468 |
for (i=0; i < argc; i++) |
560 |
for (i=0; i < argc; i++) |
469 |
printf("%s ", argv[i]); |
561 |
printf("%s ", argv[i]); |
470 |
printf("\n"); |
562 |
printf("\n"); |
471 |
} |
563 |
} |
472 |
|
564 |
|
|
|
565 |
|
566 |
inst->fs = fs; |
567 |
inst->lock = -1; |
568 |
|
569 |
if (lockdisk) |
570 |
lock_disk(inst); |
571 |
|
572 |
|
473 |
/* Fork and execute the correct program. */ |
573 |
/* Fork and execute the correct program. */ |
474 |
if (noexecute) |
574 |
if (noexecute) |
475 |
pid = -1; |
575 |
pid = -1; |
Lines 492-499
static int execute(const char *type, const char *device, const char *mntpt,
Link Here
|
492 |
inst->pid = pid; |
592 |
inst->pid = pid; |
493 |
inst->prog = string_copy(prog); |
593 |
inst->prog = string_copy(prog); |
494 |
inst->type = string_copy(type); |
594 |
inst->type = string_copy(type); |
495 |
inst->device = string_copy(device); |
595 |
inst->base_device = base_device(fs->device); |
496 |
inst->base_device = base_device(device); |
|
|
497 |
inst->start_time = time(0); |
596 |
inst->start_time = time(0); |
498 |
inst->next = NULL; |
597 |
inst->next = NULL; |
499 |
|
598 |
|
Lines 597-608
static struct fsck_instance *wait_one(int flags)
Link Here
|
597 |
} else { |
696 |
} else { |
598 |
printf(_("Warning... %s for device %s exited " |
697 |
printf(_("Warning... %s for device %s exited " |
599 |
"with signal %d.\n"), |
698 |
"with signal %d.\n"), |
600 |
inst->prog, inst->device, sig); |
699 |
inst->prog, inst->fs->device, sig); |
601 |
status = EXIT_ERROR; |
700 |
status = EXIT_ERROR; |
602 |
} |
701 |
} |
603 |
} else { |
702 |
} else { |
604 |
printf(_("%s %s: status is %x, should never happen.\n"), |
703 |
printf(_("%s %s: status is %x, should never happen.\n"), |
605 |
inst->prog, inst->device, status); |
704 |
inst->prog, inst->fs->device, status); |
606 |
status = EXIT_ERROR; |
705 |
status = EXIT_ERROR; |
607 |
} |
706 |
} |
608 |
inst->exit_status = status; |
707 |
inst->exit_status = status; |
Lines 641-647
ret_inst:
Link Here
|
641 |
instance_list = inst->next; |
740 |
instance_list = inst->next; |
642 |
if (verbose > 1) |
741 |
if (verbose > 1) |
643 |
printf(_("Finished with %s (exit status %d)\n"), |
742 |
printf(_("Finished with %s (exit status %d)\n"), |
644 |
inst->device, inst->exit_status); |
743 |
inst->fs->device, inst->exit_status); |
645 |
num_running--; |
744 |
num_running--; |
646 |
return inst; |
745 |
return inst; |
647 |
} |
746 |
} |
Lines 698-704
static void fsck_device(struct fs_info *fs, int interactive)
Link Here
|
698 |
type = DEFAULT_FSTYPE; |
797 |
type = DEFAULT_FSTYPE; |
699 |
|
798 |
|
700 |
num_running++; |
799 |
num_running++; |
701 |
retval = execute(type, fs->device, fs->mountpt, interactive); |
800 |
retval = execute(type, fs, interactive); |
702 |
if (retval) { |
801 |
if (retval) { |
703 |
fprintf(stderr, _("%s: Error %d while executing fsck.%s " |
802 |
fprintf(stderr, _("%s: Error %d while executing fsck.%s " |
704 |
"for %s\n"), progname, retval, type, fs->device); |
803 |
"for %s\n"), progname, retval, type, fs->device); |
Lines 924-964
static int ignore(struct fs_info *fs)
Link Here
|
924 |
return 0; |
1023 |
return 0; |
925 |
} |
1024 |
} |
926 |
|
1025 |
|
927 |
/* |
1026 |
static int count_slaves(dev_t disk) |
928 |
* Returns TRUE if a partition on the same disk is already being |
|
|
929 |
* checked. |
930 |
*/ |
931 |
static int device_already_active(char *device) |
932 |
{ |
1027 |
{ |
933 |
struct fsck_instance *inst; |
1028 |
DIR *dir; |
934 |
char *base; |
1029 |
struct dirent *dp; |
|
|
1030 |
char dirname[PATH_MAX]; |
1031 |
int count = 0; |
935 |
|
1032 |
|
936 |
if (force_all_parallel) |
1033 |
snprintf(dirname, sizeof(dirname), |
937 |
return 0; |
1034 |
"/sys/dev/block/%u:%u/slaves/", |
|
|
1035 |
major(disk), minor(disk)); |
938 |
|
1036 |
|
939 |
#ifdef BASE_MD |
1037 |
if (!(dir = opendir(dirname))) |
940 |
/* Don't check a soft raid disk with any other disk */ |
1038 |
return -1; |
941 |
if (instance_list && |
1039 |
|
942 |
(!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) || |
1040 |
while ((dp = readdir(dir)) != 0) { |
943 |
!strncmp(device, BASE_MD, sizeof(BASE_MD)-1))) |
1041 |
#ifdef _DIRENT_HAVE_D_TYPE |
944 |
return 1; |
1042 |
if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK) |
|
|
1043 |
continue; |
945 |
#endif |
1044 |
#endif |
|
|
1045 |
if (dp->d_name[0] == '.' && |
1046 |
((dp->d_name[1] == 0) || |
1047 |
((dp->d_name[1] == '.') && (dp->d_name[2] == 0)))) |
1048 |
continue; |
946 |
|
1049 |
|
947 |
base = base_device(device); |
1050 |
count++; |
948 |
/* |
|
|
949 |
* If we don't know the base device, assume that the device is |
950 |
* already active if there are any fsck instances running. |
951 |
*/ |
952 |
if (!base) |
953 |
return (instance_list != 0); |
954 |
for (inst = instance_list; inst; inst = inst->next) { |
955 |
if (!inst->base_device || !strcmp(base, inst->base_device)) { |
956 |
free(base); |
957 |
return 1; |
958 |
} |
959 |
} |
1051 |
} |
960 |
free(base); |
1052 |
closedir(dir); |
961 |
return 0; |
1053 |
return count; |
|
|
1054 |
} |
1055 |
|
1056 |
/* |
1057 |
* Returns TRUE if a partition on the same disk is already being |
1058 |
* checked. |
1059 |
*/ |
1060 |
static int disk_already_active(struct fs_info *fs) |
1061 |
{ |
1062 |
struct fsck_instance *inst; |
1063 |
|
1064 |
if (force_all_parallel) |
1065 |
return 0; |
1066 |
|
1067 |
if (instance_list && instance_list->fs->stacked) |
1068 |
/* any instance for a stacked device is already running */ |
1069 |
return 1; |
1070 |
|
1071 |
if (!fs->disk) { |
1072 |
fs->disk = get_disk(fs->device); |
1073 |
if (fs->disk) |
1074 |
fs->stacked = count_slaves(fs->disk); |
1075 |
} |
1076 |
|
1077 |
/* |
1078 |
* If we don't know the base device, assume that the device is |
1079 |
* already active if there are any fsck instances running. |
1080 |
* |
1081 |
* Don't check a stacked device with any other disk too. |
1082 |
*/ |
1083 |
if (!fs->disk || fs->stacked) |
1084 |
return (instance_list != 0); |
1085 |
|
1086 |
for (inst = instance_list; inst; inst = inst->next) { |
1087 |
if (!inst->fs->disk || fs->disk == inst->fs->disk) |
1088 |
return 1; |
1089 |
} |
1090 |
return 0; |
962 |
} |
1091 |
} |
963 |
|
1092 |
|
964 |
/* Check all file systems, using the /etc/fstab table. */ |
1093 |
/* Check all file systems, using the /etc/fstab table. */ |
Lines 1038-1044
static int check_all(NOARGS)
Link Here
|
1038 |
* already been spawned, then we need to defer |
1167 |
* already been spawned, then we need to defer |
1039 |
* this to another pass. |
1168 |
* this to another pass. |
1040 |
*/ |
1169 |
*/ |
1041 |
if (device_already_active(fs->device)) { |
1170 |
if (disk_already_active(fs)) { |
1042 |
pass_done = 0; |
1171 |
pass_done = 0; |
1043 |
continue; |
1172 |
continue; |
1044 |
} |
1173 |
} |
Lines 1188-1193
static void PRS(int argc, char *argv[])
Link Here
|
1188 |
} |
1317 |
} |
1189 |
} |
1318 |
} |
1190 |
break; |
1319 |
break; |
|
|
1320 |
case 'l': |
1321 |
lockdisk++; |
1322 |
break; |
1191 |
case 'V': |
1323 |
case 'V': |
1192 |
verbose++; |
1324 |
verbose++; |
1193 |
break; |
1325 |
break; |
Lines 1298-1303
int main(int argc, char *argv[])
Link Here
|
1298 |
if ((num_devices == 1) || (serialize)) |
1430 |
if ((num_devices == 1) || (serialize)) |
1299 |
interactive = 1; |
1431 |
interactive = 1; |
1300 |
|
1432 |
|
|
|
1433 |
if (lockdisk && (doall || num_devices > 1)) { |
1434 |
fprintf(stderr, _("%s: the -l option can be used with one " |
1435 |
"device only -- ignore\n"), progname); |
1436 |
lockdisk = 0; |
1437 |
} |
1438 |
|
1301 |
/* If -A was specified ("check all"), do that! */ |
1439 |
/* If -A was specified ("check all"), do that! */ |
1302 |
if (doall) |
1440 |
if (doall) |
1303 |
return check_all(); |
1441 |
return check_all(); |