qubes-installer-qubes-os/gptsync/os_unix.c

268 lines
6.1 KiB
C
Raw Normal View History

/*
* gptsync/os_unix.c
* Unix OS glue for gptsync
*
* Copyright (c) 2006 Christoph Pfisterer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Christoph Pfisterer nor the names of the
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gptsync.h"
#include <stdarg.h>
#define STRINGIFY(s) #s
#define STRINGIFY2(s) STRINGIFY(s)
#define PROGNAME_S STRINGIFY2(PROGNAME)
// variables
static int fd;
//
// error functions
//
void error(const char *msg, ...)
{
va_list par;
char buf[4096];
va_start(par, msg);
vsnprintf(buf, 4096, msg, par);
va_end(par);
fprintf(stderr, PROGNAME_S ": %s\n", buf);
}
void errore(const char *msg, ...)
{
va_list par;
char buf[4096];
va_start(par, msg);
vsnprintf(buf, 4096, msg, par);
va_end(par);
fprintf(stderr, PROGNAME_S ": %s: %s\n", buf, strerror(errno));
}
//
// sector I/O functions
//
UINTN read_sector(UINT64 lba, UINT8 *buffer)
{
off_t offset;
off_t result_seek;
ssize_t result_read;
offset = lba * 512;
result_seek = lseek(fd, offset, SEEK_SET);
if (result_seek != offset) {
errore("Seek to %llu failed", offset);
return 1;
}
result_read = read(fd, buffer, 512);
if (result_read < 0) {
errore("Data read failed at position %llu", offset);
return 1;
}
if (result_read != 512) {
errore("Data read fell short at position %llu", offset);
return 1;
}
return 0;
}
UINTN write_sector(UINT64 lba, UINT8 *buffer)
{
off_t offset;
off_t result_seek;
ssize_t result_write;
offset = lba * 512;
result_seek = lseek(fd, offset, SEEK_SET);
if (result_seek != offset) {
errore("Seek to %llu failed", offset);
return 1;
}
result_write = write(fd, buffer, 512);
if (result_write < 0) {
errore("Data write failed at position %llu", offset);
return 1;
}
if (result_write != 512) {
errore("Data write fell short at position %llu", offset);
return 1;
}
return 0;
}
//
// keyboard input
//
UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out)
{
int c;
printf("%s", prompt);
fflush(NULL);
c = getchar();
if (c == EOF)
return 1;
if (c == 'y' || c == 'Y') {
printf("Yes\n");
*bool_out = TRUE;
} else {
printf("No\n");
*bool_out = FALSE;
}
return 0;
}
//
// EFI-style print function
//
void Print(wchar_t *format, ...)
{
va_list par;
char formatbuf[256];
char buf[4096];
int i;
for (i = 0; format[i]; i++)
formatbuf[i] = (format[i] > 255) ? '?' : (char)(format[i] & 0xff);
formatbuf[i] = 0;
va_start(par, format);
vsnprintf(buf, 4096, formatbuf, par);
va_end(par);
printf("%s", buf);
}
//
// main entry point
//
int main(int argc, char *argv[])
{
char *filename;
struct stat sb;
int filekind;
UINT64 filesize;
char *reason;
int status;
// argument check
if (argc != 2) {
fprintf(stderr, "Usage: " PROGNAME_S " <device>\n");
return 1;
}
filename = argv[1];
// set input to unbuffered
fflush(NULL);
setvbuf(stdin, NULL, _IONBF, 0);
// stat check
if (stat(filename, &sb) < 0) {
errore("Can't stat %.300s", filename);
return 1;
}
filekind = 0;
filesize = 0;
reason = NULL;
if (S_ISREG(sb.st_mode))
filesize = sb.st_size;
else if (S_ISBLK(sb.st_mode))
filekind = 1;
else if (S_ISCHR(sb.st_mode))
filekind = 2;
else if (S_ISDIR(sb.st_mode))
reason = "Is a directory";
else if (S_ISFIFO(sb.st_mode))
reason = "Is a FIFO";
#ifdef S_ISSOCK
else if (S_ISSOCK(sb.st_mode))
reason = "Is a socket";
#endif
else
reason = "Is an unknown kind of special file";
if (reason != NULL) {
error("%.300s: %s", filename, reason);
return 1;
}
// open file
fd = open(filename, O_RDWR);
if (fd < 0 && errno == EBUSY) {
fd = open(filename, O_RDONLY);
#ifndef NOREADONLYWARN
if (fd >= 0)
printf("Warning: %.300s opened read-only\n", filename);
#endif
}
if (fd < 0) {
errore("Can't open %.300s", filename);
return 1;
}
// (try to) guard against TTY character devices
if (filekind == 2) {
if (isatty(fd)) {
error("%.300s: Is a TTY device", filename);
return 1;
}
}
// run sync algorithm
status = PROGNAME();
printf("\n");
// close file
if (close(fd) != 0) {
errore("Error while closing %.300s", filename);
return 1;
}
return status;
}