~ubuntu-branches/ubuntu/hardy/silo/hardy-updates

« back to all changes in this revision

Viewing changes to first-isofs/isofs.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2007-10-25 09:28:08 UTC
  • mfrom: (15.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20071025092808-1yhj12t7s4zqsfu5
Tags: 1.4.13a+git20070930-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Build with -fno-stack-protector.
  - Change silo.postinst to automatically update the boot block without
    invoking siloconfig and keep asking questions on upgrades.
  - Convert silo.conf to use /dev/disk/by-uuid.
  - Ubuntu maintainer foobar.
  - Fix debian/rules call to dh_installdocs.
  - Drop the requirement of gcc-4.1 and start using default gcc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* CD-SILO : SILO CDROM (ISO-9660) boot block
 
2
   
 
3
   Copyright (C) 1996 Jakub Jelinek
 
4
                 1998 Jan Vondrak
 
5
                 2003 Ben Collins
 
6
   
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 2 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program; if not, write to the Free Software
 
19
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 
20
   USA.  */
 
21
 
 
22
#include <sys/types.h>
 
23
#include <linux/iso_fs.h>
 
24
 
 
25
#include <silo.h>
 
26
#include <rock.h>
 
27
#include <stringops.h>
 
28
 
 
29
 
 
30
#define SECOND_BLK      "/boot/second.b"
 
31
#define SILO_CONF       "/boot/silo.conf"
 
32
#define LOAD_ADDR       0x10000
 
33
 
 
34
struct isofs_inode {
 
35
        unsigned int extent;
 
36
        unsigned int size;
 
37
};
 
38
 
 
39
struct silo_info {
 
40
        char id;
 
41
        char conf_part;
 
42
        char part;
 
43
        char pad;
 
44
        char conf_file[256];
 
45
};
 
46
 
 
47
 
 
48
static struct isofs_inode root_ino;
 
49
static int link_count;
 
50
static char silo_conf[] = SILO_CONF;
 
51
static int fd;
 
52
 
 
53
static int open_namei(const char *pathname, struct isofs_inode *res_inode,
 
54
                      struct isofs_inode *base);
 
55
 
 
56
 
 
57
static int cd_init (void)
 
58
{
 
59
        char iso_bootdevice[1024];
 
60
        char *s = iso_bootdevice;
 
61
 
 
62
        if (prom_vers == PROM_V0) {
 
63
                struct linux_arguments_v0 *ap = *romvec->pv_v0bootargs;
 
64
 
 
65
                *s++ = ap->boot_dev[0];
 
66
                *s++ = ap->boot_dev[1];
 
67
                *s++ = '(';
 
68
                *s++ = (ap->boot_dev_ctrl & 07) + '0';
 
69
                *s++ = ',';
 
70
                // Hopefully it's never > 10
 
71
                *s++ = (ap->boot_dev_unit & 07) + '0';
 
72
                *s++ = ','; 
 
73
                *s++ = '0';
 
74
                *s++ = ')';
 
75
                *s = 0;
 
76
 
 
77
                fd = (*romvec->pv_v0devops.v0_devopen) (iso_bootdevice);
 
78
        } else {
 
79
                if (prom_vers == PROM_P1275)
 
80
                        prom_getproperty (prom_chosen, "bootpath", iso_bootdevice, sizeof(iso_bootdevice));
 
81
                else
 
82
                        strcpy(iso_bootdevice, *romvec->pv_v2bootargs.bootpath);
 
83
 
 
84
                for (; *s && *s != ':'; s++)
 
85
                        /* Do nothing */;
 
86
 
 
87
                if (!*s) {
 
88
                        *s++ = ':'; *s++ = 'a'; *s = 0;
 
89
                } else if (s[1] >= 'a' && s[1] <= 'z' && !s[2])
 
90
                        s[1] = 'a';
 
91
 
 
92
                if (prom_vers == PROM_P1275)
 
93
                        fd = p1275_cmd ("open", 1, iso_bootdevice);
 
94
                else
 
95
                        fd = (*romvec->pv_v2devops.v2_dev_open) (iso_bootdevice);
 
96
        }
 
97
 
 
98
        if (fd == 0 || fd == -1)
 
99
                return 1;
 
100
 
 
101
        return 0;
 
102
}
 
103
 
 
104
static void cd_fini(void)
 
105
{
 
106
        switch (prom_vers) {
 
107
        case PROM_V0:
 
108
                romvec->pv_v0devops.v0_devclose(fd);
 
109
                break;
 
110
 
 
111
        case PROM_V2:
 
112
        case PROM_V3:
 
113
                romvec->pv_v2devops.v2_dev_close(fd);
 
114
                break;
 
115
 
 
116
        case PROM_P1275:
 
117
                p1275_cmd("close", 1, fd);
 
118
                break;
 
119
        };
 
120
}
 
121
 
 
122
static int cd_read_block(unsigned long long offset, int size, void *data)
 
123
{
 
124
        int ret;
 
125
 
 
126
        if (!size)
 
127
                return 0;
 
128
 
 
129
        if (prom_vers == PROM_V0) {
 
130
                /* ISOFS_BLOCK_SIZE / 512 == 4 */
 
131
                size <<= 2;
 
132
                offset <<= 2;
 
133
 
 
134
                ret = (*romvec->pv_v0devops.v0_rdblkdev)
 
135
                                (fd, size, (unsigned)offset, data);
 
136
        } else {
 
137
                static unsigned long long seekp = 0xffffffffffffffffULL;
 
138
 
 
139
                size <<= ISOFS_BLOCK_BITS;
 
140
                offset <<= ISOFS_BLOCK_BITS;
 
141
 
 
142
                if (seekp != offset) {
 
143
                        if (prom_vers == PROM_P1275) {
 
144
                                if (p1275_cmd("seek", P1275_ARG_64B(2) | 3, fd, 0, offset) == -1)
 
145
                                        return -1;
 
146
                        } else {
 
147
                                if ((*romvec->pv_v2devops.v2_dev_seek)
 
148
                                        (fd, (unsigned)(offset >> 32), (unsigned)offset) == -1)
 
149
                                        return -1;
 
150
                        }
 
151
                        seekp = offset;
 
152
                }
 
153
 
 
154
                if (prom_vers == PROM_P1275)
 
155
                        ret = p1275_cmd ("read", 3, fd, data, size);
 
156
                else
 
157
                        ret = (*romvec->pv_v2devops.v2_dev_read) (fd, data, size);
 
158
 
 
159
                seekp += ret;
 
160
        }
 
161
 
 
162
        if (ret != size)
 
163
                ret = -1;
 
164
 
 
165
        return ret;
 
166
}
 
167
 
 
168
static int isonum_733 (char * p)
 
169
{
 
170
        return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)
 
171
                | ((p[2] & 0xff) << 16) | ((p[3] & 0xff) << 24));
 
172
}
 
173
 
 
174
 
 
175
static int isofs_read_super(void)
 
176
{
 
177
        struct iso_primary_descriptor iso;
 
178
 
 
179
        if (cd_read_block(16, 1, &iso) < 0)
 
180
                return -1;
 
181
 
 
182
        if (memcmp(iso.id, ISO_STANDARD_ID, sizeof (iso.id)))
 
183
                return -1;
 
184
 
 
185
        root_ino.extent = isonum_733 (((struct iso_directory_record *)
 
186
                                (iso.root_directory_record))->extent);
 
187
        root_ino.size =   isonum_733 (((struct iso_directory_record *)
 
188
                                (iso.root_directory_record))->size);
 
189
 
 
190
        return 0;
 
191
}
 
192
 
 
193
 
 
194
static void parse_rr (unsigned char *chr, unsigned char *end,
 
195
                      char *name, char *symlink)
 
196
{
 
197
        int cont_extent = 0, cont_offset = 0, cont_size = 0;
 
198
        struct rock_ridge *rr;
 
199
        int sig;
 
200
        int truncate = 0;
 
201
        int rootflag;
 
202
 
 
203
        *name = 0;
 
204
 
 
205
        while (chr < end) {
 
206
                rr = (struct rock_ridge *)chr;
 
207
                if (rr->len == 0)
 
208
                        goto out;
 
209
 
 
210
                sig = (chr[0] << 8) + chr[1];
 
211
                chr += rr->len;
 
212
 
 
213
                switch (sig) {
 
214
                        case SIG('R','R'):
 
215
                                if ((rr->u.RR.flags[0] &
 
216
                                    (RR_PX | RR_TF | RR_SL | RR_CL | RR_NM | RR_PX | RR_TF)) == 0)
 
217
                                        goto out;
 
218
                                break;
 
219
                        case SIG('N','M'):
 
220
                                if (truncate || rr->u.NM.flags & ~1)
 
221
                                        break;
 
222
 
 
223
                                if ((strlen(name) + rr->len - 5) >= 254) {
 
224
                                        truncate = 1;
 
225
                                        break;
 
226
                                }
 
227
                                strncat(name, rr->u.NM.name, rr->len - 5);
 
228
                                break;
 
229
                        case SIG('S','L'):
 
230
                                {
 
231
                                        int slen;
 
232
                                        struct SL_component * slp;
 
233
                                        struct SL_component * oldslp;
 
234
 
 
235
                                        slen = rr->len - 5;
 
236
                                        slp = &rr->u.SL.link;
 
237
 
 
238
                                        while (slen > 1) {
 
239
                                                rootflag = 0;
 
240
                                                switch (slp->flags & ~1) {
 
241
                                                        case 0:
 
242
                                                                strncat(symlink, slp->text, slp->len);
 
243
                                                                break;
 
244
                                                        case 2:
 
245
                                                                strcat(symlink, ".");
 
246
                                                                break;
 
247
                                                        case 4:
 
248
                                                                strcat(symlink, "..");
 
249
                                                                break;
 
250
                                                        case 8:
 
251
                                                                rootflag = 1;
 
252
                                                                strcat(symlink, "/");
 
253
                                                                break;
 
254
                                                        default:
 
255
                                                                break;
 
256
                                                }
 
257
 
 
258
                                                slen -= slp->len + 2;
 
259
                                                oldslp = slp;
 
260
                                                slp = (struct SL_component *) (((char *) slp) +
 
261
                                                                slp->len + 2);
 
262
 
 
263
                                                if (slen < 2)
 
264
                                                        break;
 
265
 
 
266
                                                if (!rootflag && (oldslp->flags & 1) == 0)
 
267
                                                        strcat (symlink, "/");
 
268
                                        }
 
269
                                }
 
270
                                break;
 
271
                        case SIG('C','E'):
 
272
                                CHECK_CE;
 
273
                                break;
 
274
                        case SIG('P','X'):
 
275
                        case SIG('T','F'):
 
276
                                break;
 
277
                }
 
278
 
 
279
                if (chr >= end && cont_extent) {
 
280
                        char sect_buf[ISOFS_BLOCK_SIZE];
 
281
 
 
282
                        if (cd_read_block(cont_extent, 1, sect_buf) < 0)
 
283
                                return;
 
284
                        parse_rr((unsigned char *)(&sect_buf[cont_offset]),
 
285
                                 (unsigned char *)(&sect_buf[cont_offset +
 
286
                                 cont_size - 3]), name, symlink);
 
287
                }
 
288
        }
 
289
 
 
290
out:
 
291
        return;
 
292
}
 
293
 
 
294
 
 
295
static int isofs_lookup (struct isofs_inode *dir, const char *name,
 
296
                         int len, struct isofs_inode *result)
 
297
{
 
298
        char buffer [ISOFS_BLOCK_SIZE];
 
299
        char symlink [512];
 
300
        char namebuf [512];
 
301
        int block, size;
 
302
        struct iso_directory_record *idr;
 
303
        unsigned char *rr;
 
304
 
 
305
        size = dir->size;
 
306
        block = dir->extent;
 
307
 
 
308
        while (size > 0) {
 
309
                int i;
 
310
 
 
311
                if (cd_read_block(block, 1, buffer) < 0)
 
312
                        return -1;
 
313
 
 
314
                size -= ISOFS_BLOCK_SIZE;
 
315
                block++;
 
316
 
 
317
                for (i = 0 ;; ) {
 
318
                        idr = (struct iso_directory_record *) (buffer + i);
 
319
 
 
320
                        if (!idr->length[0])
 
321
                                break;
 
322
 
 
323
                        i += (unsigned char)idr->length[0];
 
324
                        memcpy(namebuf, idr->name, (unsigned char)idr->name_len[0]);
 
325
                        namebuf[(unsigned char)idr->name_len[0]] = 0;
 
326
 
 
327
                        rr = (unsigned char *)(idr + 1);
 
328
                        rr += ((unsigned char)idr->name_len[0]) - sizeof(idr->name);
 
329
 
 
330
                        if (!(idr->name_len[0] & 1))
 
331
                                rr++;
 
332
 
 
333
                        *symlink = 0;
 
334
                        parse_rr(rr, (unsigned char *)(&buffer[i-3]), namebuf, symlink);
 
335
 
 
336
                        if (idr->name_len[0] == 1 && !idr->name[0]) {
 
337
                                namebuf[0] = '.';
 
338
                                namebuf[1] = '\0';
 
339
                        } else if (idr->name_len[0] == 1 && idr->name[0] == 1) {
 
340
                                namebuf[0] = namebuf[1] = '.';
 
341
                                namebuf[2] = '\0';
 
342
                        }
 
343
 
 
344
                        if (strlen(namebuf) == len && !memcmp(name, namebuf, len)) {
 
345
                                if (*symlink) {
 
346
                                        int error;
 
347
                                        
 
348
                                        if (link_count > 5)
 
349
                                                return -1; /* Looping */
 
350
                                        
 
351
                                        link_count++;
 
352
                                        error = open_namei(symlink, result, dir);
 
353
                                        link_count--;
 
354
                                        
 
355
                                        return error;
 
356
                                }
 
357
 
 
358
                                result->extent = isonum_733 (idr->extent);
 
359
                                result->size = isonum_733 (idr->size);
 
360
                                return 0;
 
361
                        }
 
362
 
 
363
                        if (i >= ISOFS_BLOCK_SIZE - sizeof(struct iso_directory_record) +
 
364
                            sizeof(idr->name))
 
365
                                break;
 
366
                }
 
367
        }
 
368
 
 
369
        return -1;
 
370
}
 
371
 
 
372
 
 
373
static int dir_namei(const char *pathname, int *namelen, const char **name,
 
374
                     struct isofs_inode *base, struct isofs_inode *res_inode)
 
375
{
 
376
        char c;
 
377
        const char *thisname;
 
378
        int len;
 
379
        struct isofs_inode this_inode;
 
380
 
 
381
        if ((c = *pathname) == '/') {
 
382
                base = &root_ino;
 
383
                pathname++;
 
384
        }
 
385
 
 
386
        while (1) {
 
387
                thisname = pathname;
 
388
 
 
389
                for (len = 0; (c = *(pathname++)) && (c != '/'); len++)
 
390
                        /* Do nothing */;
 
391
 
 
392
                if (!c)
 
393
                        break;
 
394
 
 
395
                if (isofs_lookup (base, thisname, len, &this_inode))
 
396
                        return -1;
 
397
 
 
398
                base = &this_inode;
 
399
        }
 
400
 
 
401
        *name = thisname;
 
402
        *namelen = len;
 
403
        *res_inode = *base;
 
404
 
 
405
        return 0;
 
406
}
 
407
 
 
408
 
 
409
static int open_namei(const char *pathname,
 
410
                      struct isofs_inode *res_inode,
 
411
                      struct isofs_inode *base)
 
412
{
 
413
        struct isofs_inode dir;
 
414
        const char *basename;
 
415
        int namelen;
 
416
 
 
417
        if (dir_namei(pathname, &namelen, &basename, base, &dir))
 
418
                return -1;
 
419
 
 
420
        if (isofs_lookup(&dir, basename, namelen, res_inode))
 
421
                return -1;
 
422
 
 
423
        return 0;
 
424
}
 
425
 
 
426
 
 
427
char *cd_main (struct linux_romvec *promvec, void *cifh, void *cifs)
 
428
{
 
429
        struct isofs_inode inode;
 
430
        unsigned char *dest = (unsigned char *)LOAD_ADDR;
 
431
        struct silo_info *sinfo;
 
432
 
 
433
        prom_init(promvec, cifh, cifs);
 
434
 
 
435
        prom_putchar('S');
 
436
 
 
437
        if (cd_init())
 
438
                prom_halt();
 
439
 
 
440
        if (isofs_read_super())
 
441
                prom_halt();
 
442
 
 
443
        link_count = 0;
 
444
 
 
445
        if (open_namei(SECOND_BLK, &inode, &root_ino))
 
446
                prom_halt();
 
447
 
 
448
        prom_putchar('I');
 
449
 
 
450
        if (cd_read_block(inode.extent, (inode.size + (ISOFS_BLOCK_SIZE - 1)) /
 
451
            ISOFS_BLOCK_SIZE, dest) < 0)
 
452
                prom_halt();
 
453
 
 
454
        dest += 0x800;
 
455
 
 
456
        sinfo = (struct silo_info *)&dest[0x08];
 
457
 
 
458
        if (sinfo->id != 'L')
 
459
                prom_halt();
 
460
 
 
461
        memset(sinfo, 0, sizeof(*sinfo));
 
462
        sinfo->id = 'L';
 
463
        sinfo->conf_part = 1;
 
464
        strcpy(sinfo->conf_file, silo_conf);
 
465
 
 
466
        cd_fini();
 
467
 
 
468
        prom_putchar(sinfo->id);
 
469
 
 
470
        return (char *)dest;
 
471
}
 
472
 
 
473
 
 
474
/* Utility functions */
 
475
int memcmp(const void *cs, const void *ct, size_t count)
 
476
{
 
477
        const unsigned char *su1, *su2;
 
478
        signed char res = 0;
 
479
 
 
480
        for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
 
481
                if ((res = *su1 - *su2) != 0)
 
482
                        break;
 
483
        return res;
 
484
}
 
485
 
 
486
void *memcpy(void *dest, const void *src, size_t count)
 
487
{
 
488
        char *tmp = (char *) dest, *s = (char *) src;
 
489
        while (count--)
 
490
                *tmp++ = *s++;
 
491
        return dest;
 
492
}
 
493
 
 
494
int strlen(const char *s)
 
495
{
 
496
        const char *sc;
 
497
        for (sc = s; *sc != '\0'; ++sc)
 
498
                /* Do nothing */;
 
499
        return sc - s;
 
500
}
 
501
 
 
502
char *strcat(char *dest, const char *src)
 
503
{
 
504
        char *tmp = dest;
 
505
        while (*dest) dest++;
 
506
        while ((*dest++ = *src++) != '\0');
 
507
        return tmp;
 
508
}
 
509
 
 
510
char *strncat(char *dest, const char *src, size_t n)
 
511
{
 
512
        char *tmp = dest;
 
513
        while (*dest) dest++;
 
514
        while (n && (*dest++ = *src++) != '\0') n--;
 
515
        if (!n) *dest = 0;
 
516
        return tmp;
 
517
}
 
518
 
 
519
int strcmp(const char *cs, const char *ct)
 
520
{
 
521
        register signed char __res;
 
522
        while (1)
 
523
                if ((__res = *cs - *ct++) != 0 || !*cs++)
 
524
                        break;
 
525
        return __res;
 
526
}
 
527
 
 
528
void *memset(void *s,int c,size_t count)
 
529
{
 
530
        char *xs = (char *) s;
 
531
        while (count--)
 
532
                *xs++ = c;
 
533
        return s;
 
534
}
 
535
 
 
536
char *strcpy(char *dest, const char *src)
 
537
{
 
538
        char *tmp = dest;
 
539
        while ((*dest++ = *src++) != '\0');
 
540
        return tmp;
 
541
}