]> code.delx.au - refind/blob - gptsync/os_unix.c
Added documentation on refind-mkdefault script (bootcoup.html and
[refind] / gptsync / os_unix.c
1 /*
2 * gptsync/os_unix.c
3 * Unix OS glue for gptsync
4 *
5 * Copyright (c) 2006 Christoph Pfisterer
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include "gptsync.h"
38
39 #include <stdarg.h>
40
41 #define STRINGIFY(s) #s
42 #define STRINGIFY2(s) STRINGIFY(s)
43 #define PROGNAME_S STRINGIFY2(PROGNAME)
44
45 // variables
46
47 static int fd;
48
49 //
50 // error functions
51 //
52
53 void error(const char *msg, ...)
54 {
55 va_list par;
56 char buf[4096];
57
58 va_start(par, msg);
59 vsnprintf(buf, 4096, msg, par);
60 va_end(par);
61
62 fprintf(stderr, PROGNAME_S ": %s\n", buf);
63 }
64
65 void errore(const char *msg, ...)
66 {
67 va_list par;
68 char buf[4096];
69
70 va_start(par, msg);
71 vsnprintf(buf, 4096, msg, par);
72 va_end(par);
73
74 fprintf(stderr, PROGNAME_S ": %s: %s\n", buf, strerror(errno));
75 }
76
77 //
78 // sector I/O functions
79 //
80
81 // Returns size of disk in blocks (currently bogus)
82 UINT64 disk_size(VOID) {
83 return (UINT64) 0xFFFFFFFF;
84 } // UINT64 disk_size()
85
86 UINTN read_sector(UINT64 lba, UINT8 *buffer)
87 {
88 off_t offset;
89 off_t result_seek;
90 ssize_t result_read;
91
92 offset = lba * 512;
93 result_seek = lseek(fd, offset, SEEK_SET);
94 if (result_seek != offset) {
95 errore("Seek to %llu failed", offset);
96 return 1;
97 }
98
99 result_read = read(fd, buffer, 512);
100 if (result_read < 0) {
101 errore("Data read failed at position %llu", offset);
102 return 1;
103 }
104 if (result_read != 512) {
105 errore("Data read fell short at position %llu", offset);
106 return 1;
107 }
108 return 0;
109 }
110
111 UINTN write_sector(UINT64 lba, UINT8 *buffer)
112 {
113 off_t offset;
114 off_t result_seek;
115 ssize_t result_write;
116
117 offset = lba * 512;
118 result_seek = lseek(fd, offset, SEEK_SET);
119 if (result_seek != offset) {
120 errore("Seek to %llu failed", offset);
121 return 1;
122 }
123
124 result_write = write(fd, buffer, 512);
125 if (result_write < 0) {
126 errore("Data write failed at position %llu", offset);
127 return 1;
128 }
129 if (result_write != 512) {
130 errore("Data write fell short at position %llu", offset);
131 return 1;
132 }
133 return 0;
134 }
135
136 //
137 // keyboard input
138 //
139
140 UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out)
141 {
142 int c;
143
144 printf("%s", prompt);
145 fflush(NULL);
146
147 c = getchar();
148 if (c == EOF)
149 return 1;
150
151 if (c == 'y' || c == 'Y') {
152 printf("Yes\n");
153 *bool_out = TRUE;
154 } else {
155 printf("No\n");
156 *bool_out = FALSE;
157 }
158
159 return 0;
160 }
161
162 //
163 // EFI-style print function
164 //
165
166 void Print(wchar_t *format, ...)
167 {
168 va_list par;
169 char formatbuf[256];
170 char buf[4096];
171 int i;
172
173 for (i = 0; format[i]; i++)
174 formatbuf[i] = (format[i] > 255) ? '?' : (char)(format[i] & 0xff);
175 formatbuf[i] = 0;
176
177 va_start(par, format);
178 vsnprintf(buf, 4096, formatbuf, par);
179 va_end(par);
180
181 printf("%s", buf);
182 }
183
184 //
185 // main entry point
186 //
187
188 int main(int argc, char *argv[])
189 {
190 char *filename;
191 struct stat sb;
192 int filekind;
193 UINT64 filesize;
194 char *reason;
195 int status;
196
197 // argument check
198 if (argc != 2) {
199 fprintf(stderr, "Usage: " PROGNAME_S " <device>\n");
200 return 1;
201 }
202 filename = argv[1];
203
204 // set input to unbuffered
205 fflush(NULL);
206 setvbuf(stdin, NULL, _IONBF, 0);
207
208 // stat check
209 if (stat(filename, &sb) < 0) {
210 errore("Can't stat %.300s", filename);
211 return 1;
212 }
213
214 filekind = 0;
215 filesize = 0;
216 reason = NULL;
217 if (S_ISREG(sb.st_mode))
218 filesize = sb.st_size;
219 else if (S_ISBLK(sb.st_mode))
220 filekind = 1;
221 else if (S_ISCHR(sb.st_mode))
222 filekind = 2;
223 else if (S_ISDIR(sb.st_mode))
224 reason = "Is a directory";
225 else if (S_ISFIFO(sb.st_mode))
226 reason = "Is a FIFO";
227 #ifdef S_ISSOCK
228 else if (S_ISSOCK(sb.st_mode))
229 reason = "Is a socket";
230 #endif
231 else
232 reason = "Is an unknown kind of special file";
233
234 if (reason != NULL) {
235 error("%.300s: %s", filename, reason);
236 return 1;
237 }
238
239 // open file
240 fd = open(filename, O_RDWR);
241 if (fd < 0 && errno == EBUSY) {
242 fd = open(filename, O_RDONLY);
243 #ifndef NOREADONLYWARN
244 if (fd >= 0)
245 printf("Warning: %.300s opened read-only\n", filename);
246 #endif
247 }
248 if (fd < 0) {
249 errore("Can't open %.300s", filename);
250 return 1;
251 }
252
253 // (try to) guard against TTY character devices
254 if (filekind == 2) {
255 if (isatty(fd)) {
256 error("%.300s: Is a TTY device", filename);
257 return 1;
258 }
259 }
260
261 // run sync algorithm
262 status = PROGNAME();
263 printf("\n");
264
265 // close file
266 if (close(fd) != 0) {
267 errore("Error while closing %.300s", filename);
268 return 1;
269 }
270
271 return status;
272 }