5333 private links
If you utilize data recovery services, Western Digital will not void the warranty associated with the disk drive you purchased from a Western Digital reseller or distributor. To retain the warranty status of your drive, you should ensure that the service provider you use provides you with written verification, on its company letterhead, that it has performed data recovery or other services on your hard drive. In all other instances, Western Digital's warranty is void if a returned disk drive exhibits a defect attributable to misuse or tampering, improper installation, alteration or to other causes as specified in our warranty policy
Any agreement you may reach with the service provider named below is a matter between you and the service provider. //
- https://www.ontrack.com/en-us/partners/western-digital-recovery
- https://datarecovery.com/westerndigital/
- https://drivesaversdatarecovery.com/home-alt-header-btn/
** In the unlikely event that your data is not recoverable, there is NO charge for our data recovery attempt, and we even ship your device back to you, for free! - https://www.securedatarecovery.com/
If you want to do it with a script or with the CLI, remember that the disk cannot be mounted or otherwise be in use. If you have a few disks to wipe, it will save time in the long run if you use a script like the one shown below. This script wipes the first and last 4096 kilobytes of data from a drive ensuring that any partitioning or MetaData is gone and you can then reuse your drive. Warning, all other data on the drive will become inaccessible!:
#!/bin/sh
echo "What disk do you want"
echo "to wipe? For example - ada1 :"
read disk
echo "OK, in 10 seconds I will destroy all data on $disk!"
echo "Press CTRL+C to abort!"
sleep 10
diskinfo ${disk} | while read disk sectorsize size sectors other
do
# Delete MBR, GPT Primary, ZFS(L0L1)/other partition table.
/bin/dd if=/dev/zero of=/dev/${disk} bs=${sectorsize} count=8192
# Delete GEOM metadata, GPT Secondary(L2L3).
/bin/dd if=/dev/zero of=/dev/${disk} bs=${sectorsize} oseek=`expr $sectors - 8192` count=8192
done
Q:
I've written a script to wipe all disks on any machine that netboots. It works fairly well, but I'd like to add verification of the final "zeroing" pass, and only shutdown the machines if the drive reads all zeros successfully, and otherwise show the error. I'm also trying to both minimize dependencies on ports if possible (currently only using pv(1) to show status), and make the final "read" pass perform quickly (the write passes are already fast).
However, I can't figure out what the best way to do this is. It seems the easiest way is to use another port, security/bcwipe, and run it with bcwipe -bfmz /dev/adaX, which both zeros the disks and verifies the write, but this requires another port. I've looked at other, simpler ways of doing using basic system utilities, like od(1), but then the disks read slowly (about 1/3rd of the speed dd(1) will do with bs=1m). I suspect this is because you can't specify a buffer size for od, and it's reading small chunks. //
dd if=/dev/zero of=/dev/adaX bs=1m
A:
In this particular case I would write a tiny C program for this purpose. The C compiler is in the base system, so you don't need to install additional ports.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#define BLOCKSIZE (128 * 1024)
uint64_t data[(BLOCKSIZE + 7) / 8];
int
main (void)
{
int inbytes, i;
while ((inbytes = read(STDIN_FILENO, data, BLOCKSIZE)) > 0)
for (i = 0; i < (inbytes + 7) / 8; i++)
if (data[i])
exit (1);
if (inbytes < 0) {
perror (NULL);
exit (2);
}
return 0;
}
Save that source code as “testzero.c”.
Then compile it like this: cc -O2 -o testzero testzero.c
That'll give you a binary named “testzero”. Put it somewhere in your $PATH so your shell can find it, or type “./testzero” to run it from the current directory. The program reads a file (or device) from standard input and exits with code 0 if the file is all zeros, so you can use it in a shell script like this:
Code:
if testzero < /dev/ada0; then
echo "allright, disk is zero"
shutdown -p now
else
echo "something went wrong!"
yes | tr -c x '\a' # call attention
fi
Note that I have set the block size to 128 KB, not 1 MB. In my (limited) testing it was faster with 128 KB (actually, as fast as the speed of the physical disk). This may depend on your kernel settings, CPU cache or file system parameters, though. YMMV, so you might want to test different values. If you change it in the source code, don't forget to recompile the program. //
For simplicity, the program reads the file or device from standard input, so there is no reason to parse the argument vector, so I just specified it as “void” instead of the usual “int argc, char *argv[]”. Besides, the compiler issues a warning if you specify argc and argv without actually using them. Note that you could omit the formal parameter completely (i.e. “()” instead of “(void)”), but I think it's a good habit to specify “void” for documentation purposes, so the author's intention is clear. For similar reasons the return type is specified as “int” – actually that wouldn't be necessary because int is the default return type (not void!). In other words: You can just write “main ()” instead of “int main (void)” if you want – both mean exactly the same, but I adhere to the Python motto “explicit is better than implicit”.
Just in case someone wonders: There is no difference (performance-wise) between using standard input vs. opening a file specified on the command line. Just make sure that the shell opens the file directly and passes it to the program (using redirection syntax with “<”). Do not use something like “cat /dev/foo | testzero” because this will create an additional process for the cat command and connect it with a pipe to the testzero command – the pipe may reduce the performance considerably. (NB: The cat command is often abused; I guess that 99% of uses of cat in shell scripts are superfluous, sometimes even harmful.) //
I made a few modifications to his code to report where the error lies if it finds one, but otherwise this does appear to read at the maximum disk speed. Thanks!
Edit: If anyone is interested here's the code after the changes I made. It's also a bit more verbose.
C:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#define BLOCKSIZE (128 * 1024)
uint64_t data[(BLOCKSIZE + 7) / 8];
int main(void) {
int inbytes;
uint64_t intotal = 0;
while((inbytes = read(STDIN_FILENO, data, BLOCKSIZE)) > 0) {
inbytes = (inbytes + 7) >> 3;
for(int i = 0; i < inbytes; i++) {
if(data[i]) {
intotal = (intotal + i) << 3; // Convert back to byte offset
printf("Non-zero byte detected at offset range: %lu to %lu\n", intotal, intotal + 7);
exit(1);
}
}
intotal += inbytes;
}
if(inbytes < 0) {
perror(NULL);
exit(2);
}
printf("Disk is fully zeroed.\n");
return 0;
}
smartctl - Control and Monitor Utility for SMART Disks
SYNOPSIS
smartctl [options] device
DESCRIPTION
smartctl controls the Self-Monitoring, Analysis and Reporting Technology (SMART) system built into most ATA/SATA and SCSI/SAS hard drives and solid-state drives. The purpose of SMART is to monitor the reliability of the hard drive and predict drive failures, and to carry out different types of drive self-tests. smartctl also supports some features not related to SMART. This version of smartctl is compatible with ACS-3, ACS-2, ATA8-ACS, ATA/ATAPI-7 and earlier standards (see REFERENCES below).
In the end, you want something like this:
for i in {1..100}; do cp test.ogg "test$i.ogg"; done
Or, as an alternative
i=0
while (( i++ < 100 )); do
cp test.ogg "test$i.ogg"
done
openssl rand -out sample.txt -base64 805306368
Alternatively, you could use /dev/urandom, but it would be a little slower than OpenSSL:
dd if=/dev/urandom of=sample.txt bs=1G count=1
Personally, I would use bs=64M count=16 or similar:
dd if=/dev/urandom of=sample.txt bs=64M count=16
//
Since, your goal is to create a 1GB file with random content, you could also use yes command instead of dd:
yes [text or string] | head -c [size of file] > [name of file]
Sample usage:
yes 'this is test file' | head -c 100KB > test.file
As you can see, the drive's power-on hours are 520 (which is accurate, as I've had it for under a month), but the two errors say they occurred at 10610 hours and 16878 hours — obviously impossible.
What's happening here? Are the errors real? Worrisome? Could there be some kind of "odometer tampering" going on here by my vendor? //
I think that your suspicion of "odometer tampering" is correct, and it is possible. The recorded errors are likely real and definitely worrisome because they indicate bad sectors upon reading. The disk was likely wiped before making its way to you, so those bad sectors have probably been remapped.
Whoever sold you the hard drive reset the S.M.A.R.T. attributes to make it look like a new hard drive.
Anecdote
On 25 July 2015, I purchased six very similar hard drives from goHardDrive.com. When I checked all the disks, I experienced almost the exact same symptoms:
The point of current / worst attributes like temperature is exactly this: to tell you if the drive has ever been outside its max operating temperature, and thus might have suffered permanent damage.
That's why it says "failed in the past", not "failing now": you did just barely touch the max-temp threshold. Note the attribute display shows "normalized: 50, threshold: 45, worst: 45". (These are 0..200 normalized values like for any other attribute, not raw Celsius temps.)
You also have some bad sectors (uncorrectable sector errors), so whether the brief high temperature caused that or not, it's probably time to ditch that drive.
A better SMART software UI would show you the current and max-ever temp. e.g.
smartctl -a /dev/sda or smartctl -x /dev/sda (-x prints all available SMART and non-SMART data it can get from the drive, including a temperature history log if the drive has one, with an ASCII bar graph.)
smartctl -x includes this for an old WD Green 1TB (WD10EADS) hard drive: