Làm thế nào để xác minh rằng ổ cứng chứa đầy số không trong Linux?


15

Tôi có ổ cứng chứa đầy số không.

Làm thế nào để kiểm tra xem tất cả các bit trên ổ cứng có phải là số không bằng cách sử dụng bash không?


Có thể chấp nhận được nếu chỉ ghi đè lên toàn bộ ổ đĩa bằng số không? Hay bạn thực sự cần phải xác nhận nội dung hiện tại?
Bob

Tôi muốn xác minh rằng ổ cứng chứa đầy số không.
gkfvbnhjh2

1
Về lý thuyết, có thể có lỗi trong các công cụ vệ sinh dữ liệu làm mất đi một số dữ liệu nguyên vẹn. Tôi sẽ không chắc chắn rằng mọi bit đều bằng không. Vậy làm thế nào để tôi kiểm tra xem hdd có đầy đủ không?
gkfvbnhjh2

Tại sao lại là số không? Bạn sẽ không ngẫu nhiên viết số không và 1, nhiều lần chứ?

13
Bởi vì 1s hẹp hơn 0 - bạn có thể thấy dữ liệu cũ giữa chúng dễ dàng hơn.
ChrisA

Câu trả lời:


28

odsẽ thay thế các hoạt động tương tự *, vì vậy bạn có thể dễ dàng sử dụng nó để quét các byte khác không:

$ sudo od /dev/disk2 | head
0000000    000000  000000  000000  000000  000000  000000  000000  000000
*
234250000

8
Tôi đã thêm | headvào phần cuối của điều đó, để nếu hóa ra ổ đĩa không bằng 0, nó dừng lại sau khi tạo ra đầu ra vừa đủ để hiển thị thực tế, thay vì đổ toàn bộ ổ đĩa vào màn hình.
Wyzard

2
@Wyzard: Ý tưởng tuyệt vời; Tôi sẽ thêm nó vào câu trả lời của tôi.
Gordon Davisson

8

Tôi đã viết một chương trình C ++ ngắn để làm như vậy, nguồn có sẵn ở đây .

Để xây dựng nó:

wget -O iszero.cpp https://gist.github.com/BobVul/5070989/raw/2aba8075f8ccd7eb72a718be040bb6204f70404a/iszero.cpp
g++ -o iszero iszero.cpp

Để chạy nó:

dd if=/dev/sdX 2>/dev/null | ./iszero

Nó sẽ xuất vị trí và giá trị của bất kỳ byte nào khác. Bạn có thể chuyển hướng đầu ra này đến một tệp với >, ví dụ:

dd if=/dev/sdX 2>/dev/null | ./iszero >nonzerochars.txt

Bạn có thể muốn thử thay đổi BUFFER_SIZEđể có hiệu quả tốt hơn. Tôi không chắc giá trị tối ưu có thể là bao nhiêu. Lưu ý rằng điều này cũng ảnh hưởng đến tần suất in tiến trình, điều này sẽ ảnh hưởng đến tốc độ phần nào (đầu ra in ra bàn điều khiển chậm ). Thêm vào 2>/dev/nullđể thoát khỏi đầu ra tiến độ.

Tôi biết rằng đây không phải là sử dụng bash tiêu chuẩn, thậm chí là nội dung, nhưng nó không yêu cầu bất kỳ đặc quyền bổ sung nào. Giải pháp của @Hennes vẫn nhanh hơn (tôi chưa thực sự tối ưu hóa bất cứ điều gì - đây là giải pháp ngây thơ); tuy nhiên, chương trình nhỏ này có thể cho bạn ý tưởng tốt hơn về việc cần gạt của bạn bao nhiêu byte và ở vị trí nào. Nếu bạn tắt đầu ra tiến độ, nó vẫn sẽ nhanh hơn hầu hết các ổ cứng tiêu dùng có thể đọc (> 150 MB / s), vì vậy đó không phải là vấn đề lớn.

Một phiên bản nhanh hơn với đầu ra ít dài hơn có sẵn ở đây . Tuy nhiên, nó vẫn chậm hơn một chút so với giải pháp của @Hennes. Tuy nhiên, cái này sẽ thoát khỏi ký tự khác đầu tiên mà nó gặp phải, vì vậy nó có khả năng nhanh hơn nhiều nếu có một số khác ở gần đầu luồng.


Thêm nguồn vào bài đăng để giữ câu trả lời tốt hơn khép kín:

#include <cstdio>

#define BUFFER_SIZE 1024

int main() {
    FILE* file = stdin;
    char buffer[BUFFER_SIZE];
    long long bytes_read = 0;
    long long progress = 0;
    long long nonzero = 0;

    while (bytes_read = fread(buffer, 1, BUFFER_SIZE, file)) {
        for (long long i = 0; i < bytes_read; i++) {
            progress++;
            if (buffer[i] != 0) {
                nonzero++;
                printf("%lld: %x\n", progress, buffer[i]);
            }
        }
        fprintf(stderr, "%lld bytes processed\r", progress);
    }

    fprintf(stderr, "\n");

    int error = 0;
    if (error = ferror(file)) {
        fprintf(stderr, "Error reading file, code: %d\n", error);
        return -1;
    }

    printf("%lld nonzero characters encountered.\n", nonzero);
    return nonzero;
}

Đây là một câu trả lời tuyệt vời, nhưng có cách nào để làm cho kịch bản hoạt động giống như một lệnh thông thường - sử dụng iszero /dev/sdathay vì yêu cầu nó phải được xử lý bằng một cái gì đó như thế iszero < /dev/sdanào không?
Hashim

1
@Hashim Điều này đã được viết ít nhiều là một chương trình vứt đi cách đây khá lâu (ngày nay ít nhất tôi sẽ thực hiện nó bằng một ngôn ngữ kịch bản như Python chứ không phải là C) cách đơn giản nhất, đó là một nơi nào đó dọc theo dòng sản xuất int main(int argc, char *argv[])và sau đó FILE* file = fopen(argv[1], "r");. Hoàn thành đúng cách bao gồm kiểm tra xem đối số có thực sự tồn tại không, kiểm tra lỗi mở thành công (thực hiện ferrorkiểm tra bổ sung sau fopen), v.v., nhưng quá nhiều rắc rối cho chương trình vứt bỏ.
Bob

1
@Hashim Tôi nghi ngờ các hoạt động được véc tơ của SIMD trong numpy sẽ gần với các hướng dẫn được vector hóa trong C. Và giả sử trình biên dịch C đủ thông minh để véc tơ vòng lặp trong chương trình C ngây thơ. Sẽ phải điểm chuẩn để chắc chắn; Thật không may, tôi không có thời gian để làm điều đó ngay bây giờ. Ưu điểm chính của Python (et al.) Là nó thường có sẵn và có thể chạy được mà không cần trình biên dịch, trong khi gcckhông nhất thiết phải có sẵn trên tất cả các bản phân phối Linux mà không cần kéo xuống các gói bổ sung. Sau đó, một lần nữa numpy không phải là một phần của các gói Python tiêu chuẩn ...
Bob

1
@Hashim Nếu bạn biên dịch với -O3-march=nativebạn có thể thấy một số tăng tốc; điều đó sẽ đảm bảo GCC cho phép tự động hóa và sử dụng tốt nhất có sẵn cho CPU hiện tại của bạn (AVX, SSE2 / SSE3, v.v.). Cùng với đó bạn có thể chơi với kích thước bộ đệm; kích thước bộ đệm khác nhau có thể tối ưu hơn với các vòng được véc tơ (tôi sẽ chơi với 1MB +, hiện tại là 1kB).
Bob

1
@Hashim Trên bình luận được chỉnh sửa, trong trường hợp bạn không nhìn thấy. Ngoài ra, nếu bạn muốn thảo luận thêm, bạn có thể ping tôi ( @Bob) trong trò chuyện: chat.stackexchange.com/rooms/118/root-access
Bob

6

Mở rộng câu trả lời của Gordon, pvcung cấp một dấu hiệu cho thấy quá trình này kéo dài bao xa:

$ sudo pv -tpreb /dev/sda | od | head
0000000 000000 000000 000000 000000 000000 000000 000000 000000
*
9.76GiB 0:06:30 [25.3MiB/s] [=================>               ] 59% ETA 0:04:56

Điều này rất hữu ích với một ổ cứng lớn!
Martin Hansen

5

Đây có vẻ là một giải pháp kém hiệu quả, nhưng nếu bạn chỉ phải kiểm tra một lần:

dd if=/dev/sdX | tr --squeeze-repeats "\000" "T"

Sử dụng dd để đọc từ đĩa sdX. (thay thế X bằng ổ đĩa bạn muốn đọc từ đó), sau
đó dịch tất cả các byte không thể in thành một thứ chúng ta có thể xử lý.

Tiếp theo, chúng ta sẽ đếm các byte mà chúng ta có thể xử lý và kiểm tra xem đó có phải là số đúng không (sử dụng wc -ccho điều đó) hoặc chúng ta bỏ qua việc đếm và sử dụng -shoặc --squeeze-repeatsđể nén tất cả nhiều lần xuất hiện trong một char.

Do đó dd if=/dev/sdX | tr --squeeze-repeats "\000" "T"chỉ nên in một chữ T.

Nếu bạn muốn làm điều này thường xuyên thì bạn muốn một cái gì đó hiệu quả hơn.
Nếu bạn muốn làm điều này chỉ một lần thì loại bùn này có thể xác minh rằng cần gạt nước bình thường của bạn đang hoạt động và bạn có thể tin tưởng nó.


Tại sao bạn coi giải pháp này là không hiệu quả? Có một số bộ đệm yêu cầu đọc xa vị trí không phải NUL đầu tiên?
Daniel Beck

Có một vấn đề tiềm năng trong đó một chữ 'T' theo nghĩa đen hiện diện trong hơi nước là ký tự khác không?
Bob

Thật. Đó là một lỗ hổng trong thiết kế. Tôi cũng không sử dụng bash (chính shell), nhưng tôi cho rằng với "Bash", bạn có nghĩa là "Không phải từ bash, từ việc sử dụng bất kỳ dấu nhắc shell và công cụ chế độ văn bản tiêu chuẩn nào".
Hennes

3
@daniel: Một chương trình C đơn giản sẽ có thể đọc tất cả dữ liệu mà không thay đổi mỗi byte đọc. Mà sẽ hiệu quả hơn và thẩm mỹ. Cũng có thể mất nhiều thời gian hơn để viết một chương trình như vậy hơn là chỉ sử dụng các công cụ có sẵn một cách không hiệu quả.
Hennes

3

Để chỉ kiểm tra, bạn sẽ thấy bất kỳ khối nào không khớp với danh sách

sudo badblocks -sv -t 0x00 /dev/sdX

Hoặc sử dụng badblocks để viết chúng cũng như kiểm tra:

sudo badblocks -svw -t 0x00 /dev/sdX

Thử nghiệm phá hủy mặc định là lựa chọn xóa an toàn của tôi

sudo badblocks -svw /dev/sdX

Nếu bất cứ ai cũng có thể lấy bất cứ thứ gì sau khi lấp đầy ổ đĩa bằng 0 và 1 xen kẽ, sau đó bổ sung của họ, sau đó tất cả 1, sau đó tất cả 0, với mỗi lần xác minh nó đã hoạt động, chúc may mắn cho họ!

Làm cho một kiểm tra trước khi triển khai tốt trên các ổ đĩa mới

man badblocks

cho các lựa chọn khác

Không nói là nhanh, nhưng nó hoạt động ...


2

Tốt nhất của cả hai thế giới. Lệnh này sẽ bỏ qua các thành phần xấu:

sudo dd if=/dev/sdX conv=noerror,sync | od | head

Sử dụng kill -USR1 <pid of dd>để xem tiến độ.


0

Một thời gian trước tôi đã tò mò về AIO. Kết quả là một chương trình thử nghiệm mẫu xảy ra để kiểm tra các sector (khối 512 byte) NUL. Bạn có thể thấy đây là một biến thể của trình phát hiện vùng tệp thưa thớt . Tôi nghĩ rằng nguồn nói lên tất cả.

  • Nếu toàn bộ tập tin / ổ đĩa là NULđầu ra trông như thế nào 0000000000-eof. Lưu ý rằng có một mẹo trong chương trình, chức năng fin()không được gọi ở dòng 107 nhằm mục đích đưa ra đầu ra được hiển thị.
  • Không được kiểm tra nhiều, vì vậy có thể chứa lỗi
  • Mã này dài hơn một chút, vì AIOnó không đơn giản như các cách khác,
  • Tuy nhiên AIOcó lẽ là cách nhanh nhất để giữ một đọc bận rộn ổ , bởi vì NULso sánh được thực hiện trong khi khối dữ liệu tiếp theo được đọc trong. (Chúng ta có thể bóp ra một vài mili giây nhiều hơn bằng cách thực hiện chồng chéo AIO, nhưng tôi thực sự không nghĩ rằng đây là giá trị cố gắng.)
  • Nó luôn trả về truenếu tập tin có thể đọc được và mọi thứ đều hoạt động. Nó không trả về falsenếu tập tin không NUL.
  • Nó giả định rằng kích thước tệp là bội số của 512. Có một lỗi trên cung cuối cùng, tuy nhiên trên một tệp hoàn toàn NULnó vẫn hoạt động, vì bộ đệm đã chứa NUL. Nếu ai đó nghĩ rằng điều này cần sửa chữa, trong dòng 95 memcmp(nullblock, buf+off, SECTOR)có thể đọc memcmp(nullblock, buf+off, len-off<SECTOR : len-off : SECTOR). Nhưng sự khác biệt duy nhất là, "báo cáo kết thúc" có lẽ là một chút ngẫu nhiên (không phải cho một tệp hoàn toàn NUL).
  • Việc thay đổi memcmp()cũng khắc phục một sự cố khác trên các nền tảng, không khắc phục được NUL alloc()bộ nhớ, vì mã không thực hiện được. Nhưng điều này chỉ có thể được nhìn thấy bởi các tệp dưới 4 MiB, nhưng checknulcó lẽ là quá mức cần thiết cho một nhiệm vụ nhỏ như vậy;)

HTH

/* Output offset of NUL sector spans on disk/partition/file
 *
 * This uses an AIO recipe to speed up reading,
 * so "processing" can take place while data is read into the buffers.
 *
 * usage: ./checknul device_or_file
 *
 * This Works is placed under the terms of the Copyright Less License,
 * see file COPYRIGHT.CLL.  USE AT OWN RISK, ABSOLUTELY NO WARRANTY.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <malloc.h>
#include <aio.h>

#define SECTOR  512
#define SECTORS 40960
#define BUFFERLEN   (SECTOR*SECTORS)

static void
oops(const char *s)
{
  perror(s);
  exit(1);
}

static void *
my_memalign(size_t len)
{
  void      *ptr;
  static size_t pagesize;

  if (!pagesize)
    pagesize = sysconf(_SC_PAGESIZE);
  if (len%pagesize)
    oops("alignment?");
  ptr = memalign(pagesize, len);
  if (!ptr)
    oops("OOM");
  return ptr;
}

static struct aiocb aio;

static void
my_aio_read(void *buf)
{
  int   ret;

  aio.aio_buf = buf;
  ret = aio_read(&aio);
  if (ret<0)
    oops("aio_read");
}

static int
my_aio_wait(void)
{
  const struct aiocb    *cb;
  int           ret;

  cb = &aio;
  ret = aio_suspend(&cb, 1, NULL);
  if (ret<0)
    oops("aio_suspend");
  if (aio_error(&aio))
    return -1;
  return aio_return(&aio);
}

static unsigned long long   nul_last;
static int          nul_was;

static void
fin(void)
{
  if (!nul_was)
    return;
  printf("%010llx\n", nul_last);
  fflush(stdout);
  nul_was   = 0;
}

static void
checknul(unsigned long long pos, unsigned char *buf, int len)
{
  static unsigned char  nullblock[SECTOR];
  int           off;

  for (off=0; off<len; off+=SECTOR)
    if (memcmp(nullblock, buf+off, SECTOR))
      fin();
    else
      {
        if (!nul_was)
          {
            printf("%010llx-", pos+off);
            fflush(stdout);
            nul_was = 1;
          }
        nul_last    = pos+off+SECTOR-1;
      }
}

int
main(int argc, char **argv)
{
  unsigned char *buf[2];
  int       fd;
  int       io, got;

  buf[0] = my_memalign(BUFFERLEN);
  buf[1] = my_memalign(BUFFERLEN);

  if (argc!=2)
    oops("Usage: checknul file");
  if ((fd=open(argv[1], O_RDONLY))<0)
    oops(argv[1]);

  aio.aio_nbytes    = BUFFERLEN;
  aio.aio_fildes    = fd;
  aio.aio_offset    = 0;

  io = 0;
  my_aio_read(buf[io]);
  while ((got=my_aio_wait())>0)
    {
      unsigned long long    pos;

      pos   = aio.aio_offset;

      aio.aio_offset += got;
      my_aio_read(buf[1-io]);

      checknul(pos, buf[io], got);

      io    = 1-io;
    }
  if (got<0)
    oops("read error");
  printf("eof\n");
  close(fd);
  return 0;
}

0

Muốn đăng giải pháp thông minh này từ một câu hỏi tương tự nhưng trước đó, được đăng bởi một người dùng chưa đăng nhập trong một thời gian:

Có một thiết bị /dev/zerotrên hệ thống Linux luôn cung cấp số không khi đọc.

Vì vậy, làm thế nào về việc so sánh ổ cứng của bạn với thiết bị này:

cmp /dev/sdX /dev/zero

Nếu tất cả đều ổn với việc loại bỏ ổ cứng của bạn, nó sẽ chấm dứt với:

cmp: EOF on /dev/sdb

nói với bạn rằng hai tệp giống nhau cho đến khi hết ổ cứng. Nếu có một bit khác không trên ổ cứng cmpsẽ cho bạn biết nó nằm ở đâu trong tệp.

Nếu bạn đã pvcài đặt gói thì:

pv /dev/sdX | cmp /dev/zero

sẽ làm điều tương tự với một thanh tiến trình để giữ cho bạn thích thú trong khi nó kiểm tra ổ đĩa của bạn (EOF bây giờ sẽ ở trên STDIN chứ không phải là sdX).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.