]> git.cameronkatri.com Git - apple_cmds.git/blob - diskdev_cmds/fstyp.tproj/fstyp_udf.c
md5: Don't symlink non working bins, setuid appropriate bins
[apple_cmds.git] / diskdev_cmds / fstyp.tproj / fstyp_udf.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <sys/stat.h>
25 #include <sys/param.h>
26 #include <sys/time.h>
27
28 #include <err.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <fstab.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
39 #include <sys/disk.h>
40
41 #define E_OPENDEV -1
42 #define E_READ -5
43
44 /*
45 * We don't have a (non-C++) standard header for UDF (yet?), so
46 * let's define the basic structures and constants we'll be using.
47 */
48
49 typedef struct UDFVolumeSequenceDescriptor {
50 unsigned char type;
51 unsigned char id[5];
52 unsigned char version;
53 unsigned char data[2041];
54 } udfVSD;
55
56 #define UDFSTART (32*1024) /* First 32k is unused */
57
58 void usage(void);
59 char *rawname(char *name);
60 char *unrawname(char *name);
61 int CheckUDF(int, int);
62 char *blockcheck(char *origname);
63
64 char *progname;
65
66 /*
67 * prefer to use raw device. TODO: suppose block device is valid but
68 * the corresponding raw device is not valid, then we fail. this is
69 * probably no the desired behavior.
70 */
71
72 int
73 main(int argc, char **argv)
74 {
75 char *devname = NULL;
76 int fd, retval;
77
78 retval = 0;
79 fd = -1;
80
81 if ((progname = strrchr(*argv, '/')))
82 ++progname;
83 else
84 progname = *argv;
85
86 if (argc != 2) {
87 usage();
88 } else {
89 devname = blockcheck(argv[1]);
90 if (devname != NULL) {
91 if ((fd = open(devname, O_RDONLY, 0)) < 0) {
92 retval = E_OPENDEV;
93 } else {
94 int bsize;
95 if (ioctl(fd, DKIOCGETBLOCKSIZE, (char*)&bsize) == -1) {
96 #ifdef DEBUG
97 warn("DKIOCGETBLOCKSIZE ioctl failed for %s", devname);
98 #endif
99 bsize = 2048; /* A standard default size */
100 }
101 retval = CheckUDF(fd, bsize) == 1;
102 if (retval == 0 && bsize != 2048) {
103 retval = CheckUDF(fd, 2048) == 1;
104 }
105 }
106 }
107 }
108
109 return retval;
110 }
111
112 static int
113 IsVSD(udfVSD *vsd) {
114 int retval = memcmp(vsd->id, "BEA01", 5)==0 ||
115 memcmp(vsd->id, "BOOT2", 5)==0 ||
116 memcmp(vsd->id, "NSR02", 5)==0 ||
117 memcmp(vsd->id, "NSR03", 5)==0 ||
118 memcmp(vsd->id, "TEA01", 5)==0 ||
119 memcmp(vsd->id, "CDW02", 5)==0 ||
120 memcmp(vsd->id, "CD001", 5)==0;
121 #ifdef DEBUG
122 fprintf(stderr, "IsVSD: Returning %d\n", retval);
123 #endif
124 return retval;
125 }
126
127 /*
128 * This is inspired by the udf25 kext code.
129 * It concludes that a device has a UDF filesystem
130 * if:
131 * 1) It has a Volume Sequence Descriptor;
132 * 2) That VSD has a "BEA01" in it;
133 * 3) That VSD has an "NSR02" or "NSR03" in it before the terminating one.
134 *
135 * It may be necessary to check the AVDP(s), as well.
136 */
137
138 int
139 CheckUDF(int fd, int blockSize) {
140 ssize_t err;
141 char buf[blockSize];
142 off_t curr, max;
143 char found = 0;
144
145 curr = UDFSTART;
146 max = curr + (512 * blockSize);
147 if (lseek(fd, curr, SEEK_SET) == -1) {
148 warn("Cannot seek to %llu", curr);
149 return -1;
150 }
151
152 while (curr < max) {
153 udfVSD *vsd;
154 err = read(fd, buf, sizeof(buf));
155 if (err != sizeof(buf)) {
156 if (err == -1) {
157 warn("Cannot read %zu bytes", sizeof(buf));
158 } else {
159 warn("Cannot read %zd bytes, only read %zd", sizeof(buf), err);
160 }
161 return -1;
162 }
163 vsd = (udfVSD*)buf;
164 if (!IsVSD(vsd)) {
165 break;
166 }
167 if (vsd->type == 0 &&
168 memcmp(vsd->id, "BEA01", 5) == 0 &&
169 vsd->version == 1) {
170 found = 1;
171 break;
172 }
173 curr += blockSize;
174 }
175 if (found == 0)
176 return 0;
177
178 found = 0;
179
180 while (curr < max) {
181 udfVSD *vsd;
182 err = read(fd, buf, sizeof(buf));
183 if (err != sizeof(buf)) {
184 if (err == -1) {
185 warn("Cannot read %zu bytes", sizeof(buf));
186 } else {
187 warn("Cannot read %zu bytes, only read %zd", sizeof(buf), err);
188 }
189 return -1;
190 }
191 vsd = (udfVSD*)buf;
192 if (!IsVSD(vsd)) {
193 break;
194 }
195 if (vsd->type == 0 &&
196 memcmp(vsd->id, "TEA01", 5) == 0 &&
197 vsd->version == 1) {
198 /* we're at the end */
199 break;
200 } else if (memcmp(vsd->id, "NSR02", 5) == 0 ||
201 memcmp(vsd->id, "NSR03", 5) == 0) {
202 found = 1;
203 break;
204 }
205 curr += blockSize;
206 }
207
208 return found;
209 }
210
211 void
212 usage(void)
213 {
214 fprintf(stdout, "usage: %s device\n", progname);
215 return;
216 }
217
218 /* copied from diskdev_cmds/fsck_hfs/utilities.c */
219 char *
220 rawname(char *name)
221 {
222 static char rawbuf[32];
223 char *dp;
224
225 if ((dp = strrchr(name, '/')) == 0)
226 return (0);
227 *dp = 0;
228 (void) strlcpy(rawbuf, name, sizeof(rawbuf));
229 *dp = '/';
230 (void) strlcat(rawbuf, "/r", sizeof(rawbuf));
231 (void) strlcat(rawbuf, &dp[1], sizeof(rawbuf));
232
233 return (rawbuf);
234 }
235
236 /* copied from diskdev_cmds/fsck_hfs/utilities.c */
237 char *
238 unrawname(char *name)
239 {
240 char *dp;
241 struct stat stb;
242 size_t dp_len;
243
244 if ((dp = strrchr(name, '/')) == 0)
245 return (name);
246 if (stat(name, &stb) < 0)
247 return (name);
248 if ((stb.st_mode & S_IFMT) != S_IFCHR)
249 return (name);
250 if (dp[1] != 'r')
251 return (name);
252 dp_len = strlen(&dp[2]) + 1;
253 (void)memmove(&dp[1], &dp[2], dp_len);
254
255 return (name);
256 }
257
258 /*
259 * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
260 * 1) remove "hotroot"
261 * 2) if error, return NULL
262 * 3) if not a char device, return NULL (effectively, this is treated
263 * as error even if accessing the block device might have been OK)
264 */
265 char *
266 blockcheck(char *origname)
267 {
268 struct stat stblock, stchar;
269 char *newname, *raw;
270 int retried = 0;
271
272 newname = origname;
273 retry:
274 if (stat(newname, &stblock) < 0) {
275 perror(newname);
276 fprintf(stderr, "Can't stat %s\n", newname);
277 return NULL;
278 }
279 if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
280 raw = rawname(newname);
281 if (stat(raw, &stchar) < 0) {
282 perror(raw);
283 fprintf(stderr, "Can't stat %s\n", raw);
284 return NULL;
285 }
286 if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
287 return (raw);
288 } else {
289 fprintf(stderr, "%s is not a character device\n", raw);
290 return NULL;
291 }
292 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
293 newname = unrawname(newname);
294 retried++;
295 goto retry;
296 }
297 #ifdef DEBUG
298 else if ((stblock.st_mode & S_IFMT) == S_IFREG) {
299 return strdup(origname);
300 }
301 #endif
302 /* not a block or character device */
303 return NULL;
304 }
305
306