~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kdm/backend/bootman.c

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright 2005 Stephan Kulow <coolo@kde.org>
 
4
Copyright 2005 Oswald Buddenhagen <ossi@kde.org>
 
5
 
 
6
Permission to use, copy, modify, distribute, and sell this software and its
 
7
documentation for any purpose is hereby granted without fee, provided that
 
8
the above copyright notice appear in all copies and that both that
 
9
copyright notice and this permission notice appear in supporting
 
10
documentation.
 
11
 
 
12
The above copyright notice and this permission notice shall be included
 
13
in all copies or substantial portions of the Software.
 
14
 
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
16
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
18
IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
19
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
20
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
21
OTHER DEALINGS IN THE SOFTWARE.
 
22
 
 
23
Except as contained in this notice, the name of a copyright holder shall
 
24
not be used in advertising or otherwise to promote the sale, use or
 
25
other dealings in this Software without prior written authorization
 
26
from the copyright holder.
 
27
 
 
28
*/
 
29
 
 
30
/*
 
31
 * xdm - display manager daemon
 
32
 * Author: Keith Packard, MIT X Consortium
 
33
 *
 
34
 * Boot options
 
35
 */
 
36
 
 
37
#include "dm.h"
 
38
#include "dm_error.h"
 
39
 
 
40
#include <string.h>
 
41
#include <unistd.h>
 
42
#include <stdio.h>
 
43
#include <ctype.h>
 
44
 
 
45
static int
 
46
getNull(char ***opts ATTR_UNUSED, int *def ATTR_UNUSED, int *cur ATTR_UNUSED)
 
47
{
 
48
    return BO_NOMAN;
 
49
}
 
50
 
 
51
static int
 
52
setNull(const char *opt ATTR_UNUSED, SdRec *sdr ATTR_UNUSED)
 
53
{
 
54
    return BO_NOMAN;
 
55
}
 
56
 
 
57
static char *
 
58
match(char *obuf, int *blen, const char *key, int klen)
 
59
{
 
60
    char *buf = obuf;
 
61
    if (memcmp(buf, key, klen) || !isspace(buf[klen]))
 
62
        return 0;
 
63
    buf += klen + 1;
 
64
    for (; isspace(*buf); buf++);
 
65
    if (!*buf)
 
66
        return 0;
 
67
    *blen -= buf - obuf;
 
68
    return buf;
 
69
}
 
70
 
 
71
#define GRUB_MENU "/boot/grub/menu.lst"
 
72
 
 
73
static char *grubSetDefault;
 
74
static char *grub;
 
75
 
 
76
static int
 
77
getGrub(char ***opts, int *def, int *cur)
 
78
{
 
79
    FILE *f;
 
80
    char *ptr, *linp;
 
81
    int len;
 
82
    char line[1000];
 
83
 
 
84
    if (!grubSetDefault && !grub &&
 
85
        !(grubSetDefault = locate("grub-set-default")) &&
 
86
        !(grub = locate("grub")))
 
87
        return BO_NOMAN;
 
88
 
 
89
    *def = 0;
 
90
    *cur = -1;
 
91
    *opts = initStrArr(0);
 
92
 
 
93
    if (!(f = fopen(GRUB_MENU, "r")))
 
94
        return errno == ENOENT ? BO_NOMAN : BO_IO;
 
95
    while ((len = fGets(line, sizeof(line), f)) != -1) {
 
96
        for (linp = line; isspace(*linp); linp++, len--);
 
97
        if ((ptr = match(linp, &len, "default", 7))) {
 
98
            *def = atoi(ptr);
 
99
        } else if ((ptr = match(linp, &len, "title", 5))) {
 
100
            for (; isspace(ptr[len - 1]); len--);
 
101
            *opts = addStrArr(*opts, ptr, len);
 
102
        }
 
103
    }
 
104
    fclose(f);
 
105
 
 
106
    return BO_OK;
 
107
}
 
108
 
 
109
static int
 
110
setGrub(const char *opt, SdRec *sdr)
 
111
{
 
112
    FILE *f;
 
113
    char *ptr;
 
114
    int len, i;
 
115
    char line[1000];
 
116
 
 
117
    if (!(f = fopen(GRUB_MENU, "r")))
 
118
        return errno == ENOENT ? BO_NOMAN : BO_IO;
 
119
    for (i = 0; (len = fGets(line, sizeof(line), f)) != -1;)
 
120
        if ((ptr = match(line, &len, "title", 5))) {
 
121
            if (!strcmp(ptr, opt)) {
 
122
                fclose(f);
 
123
                sdr->osindex = i;
 
124
                sdr->bmstamp = mTime(GRUB_MENU);
 
125
                return BO_OK;
 
126
            }
 
127
            i++;
 
128
        }
 
129
    fclose(f);
 
130
    return BO_NOENT;
 
131
}
 
132
 
 
133
static void
 
134
commitGrub(void)
 
135
{
 
136
    if (sdRec.bmstamp != mTime(GRUB_MENU) &&
 
137
            setGrub(sdRec.osname, &sdRec) != BO_OK)
 
138
        return;
 
139
 
 
140
    if (grubSetDefault) {
 
141
        /* The grub-set-default command must be used, which is
 
142
         * not so good because there is no way of setting an
 
143
         * entry for the next boot only. */
 
144
        char index[16];
 
145
        const char *args[] = { grubSetDefault, index, 0 };
 
146
        sprintf(index, "%d", sdRec.osindex);
 
147
        runAndWait((char **)args, environ);
 
148
    } else {
 
149
        /* The grub shell can be used with `savedefault'.
 
150
         * That requires a (widely distributed) patch to grub, e.g.
 
151
         * grub-0.97-once.patch. It won't work with a vanilla grub.*/
 
152
        FILE *f;
 
153
        int pid;
 
154
        static const char *args[] = { 0, "--batch", "--no-floppy", 0 };
 
155
        args[0] = grub;
 
156
        if ((f = pOpen((char **)args, 'w', &pid))) {
 
157
            fprintf(f, "savedefault --default=%d --once\n", sdRec.osindex);
 
158
            pClose(f, &pid);
 
159
        }
 
160
    }
 
161
}
 
162
 
 
163
#define GRUB2_MENU "/boot/grub/grub.cfg"
 
164
 
 
165
static char *grubReboot;
 
166
 
 
167
static int
 
168
getGrub2(char ***opts, int *def, int *cur)
 
169
{
 
170
    FILE *f;
 
171
    char *ptr, *linp;
 
172
    int len, ret = BO_NOMAN, i;
 
173
    char line[1000];
 
174
 
 
175
    if (!grubReboot && !(grubReboot = locate("grub-reboot")))
 
176
        return BO_NOMAN;
 
177
 
 
178
    *def = -1;
 
179
    *cur = -1;
 
180
    *opts = initStrArr(0);
 
181
 
 
182
    if (!(f = fopen(GRUB2_MENU, "r")))
 
183
        return errno == ENOENT ? BO_NOMAN : BO_IO;
 
184
    while ((len = fGets(line, sizeof(line), f)) != -1) {
 
185
        for (linp = line; isspace(*linp); linp++, len--);
 
186
        if ((ptr = match(linp, &len, "set", 3)) && !memcmp(ptr, "default=\"${saved_entry}\"", 24)) {
 
187
            ret = BO_OK;
 
188
        } else if ((ptr = match(linp, &len, "menuentry", 9))) {
 
189
            linp = ptr;
 
190
            if (*linp == '\'') {
 
191
                for (i = 0, linp++; *linp && *linp != '\''; linp++)
 
192
                    ptr[i++] = *linp;
 
193
            } else if (*linp == '"') {
 
194
                for (i = 0, linp++; *linp && *linp != '"'; linp++) {
 
195
                    if (*linp == '\\') {
 
196
                        switch (*(++linp)) {
 
197
                        case 0:
 
198
                            return BO_IO; /* Unexpected end */
 
199
                        case '$':
 
200
                        case '"':
 
201
                        case '\\':
 
202
                            break;
 
203
                        default:
 
204
                            ptr[i++] = '\\';
 
205
                            break;
 
206
                        }
 
207
                    }
 
208
                    ptr[i++] = *linp;
 
209
                }
 
210
            } else {
 
211
                for (i = 0; *linp && !isspace(*linp); linp++) {
 
212
                    if (*linp == '\\' && !*(++linp))
 
213
                        return BO_IO; /* Unexpected end */
 
214
                    ptr[i++] = *linp;
 
215
                }
 
216
            }
 
217
            *opts = addStrArr(*opts, ptr, i);
 
218
        }
 
219
    }
 
220
    fclose(f);
 
221
 
 
222
    return ret;
 
223
}
 
224
 
 
225
static int
 
226
setGrub2(const char *opt, SdRec *sdr)
 
227
{
 
228
    char **opts;
 
229
    int def, cur, ret, i;
 
230
 
 
231
    if ((ret = getGrub2(&opts, &def, &cur)) != BO_OK)
 
232
        return ret;
 
233
    for (i = 0; opts[i]; i++) {
 
234
        if (!strcmp(opts[i], opt)) {
 
235
            sdr->osindex = i;
 
236
            sdr->bmstamp = mTime(GRUB2_MENU);
 
237
            freeStrArr(opts);
 
238
            return BO_OK;
 
239
        }
 
240
    }
 
241
    freeStrArr(opts);
 
242
    return BO_NOENT;
 
243
}
 
244
 
 
245
static void
 
246
commitGrub2(void)
 
247
{
 
248
    if (sdRec.bmstamp != mTime(GRUB2_MENU) &&
 
249
        setGrub2(sdRec.osname, &sdRec) != BO_OK)
 
250
        return;
 
251
 
 
252
    if (grubReboot) {
 
253
        char index[16];
 
254
        const char *args[] = { grubReboot, index, 0 };
 
255
        sprintf(index, "%d", sdRec.osindex);
 
256
        runAndWait((char **)args, environ);
 
257
    }
 
258
}
 
259
 
 
260
static char *lilo;
 
261
 
 
262
static int
 
263
getLilo(char ***opts, int *def, int *cur)
 
264
{
 
265
    FILE *f;
 
266
    int cdef, pid, len, ret = BO_OK;
 
267
    static const char *args[5] = { 0, "-w", "-v", "-q", 0 };
 
268
    char buf[256], next[256];
 
269
 
 
270
    if (!lilo && !(lilo = locate("lilo")))
 
271
        return BO_NOMAN;
 
272
 
 
273
    args[0] = lilo;
 
274
    if (!(f = pOpen((char **)args, 'r', &pid)))
 
275
        return BO_IO;
 
276
    *opts = 0;
 
277
    next[0] = 0;
 
278
    for (;;) {
 
279
        if ((len = fGets(buf, sizeof(buf), f)) == -1) {
 
280
            ret = BO_NOMAN;
 
281
            goto out;
 
282
        }
 
283
        if (!memcmp(buf, "Images:", 7))
 
284
            break;
 
285
#define Ldeflin "  Default boot command line:"
 
286
        if (!memcmp(buf, Ldeflin, strlen(Ldeflin))) {
 
287
            memcpy(next, buf + strlen(Ldeflin) + 2, len - strlen(Ldeflin) - 3);
 
288
            next[len - strlen(Ldeflin) - 3] = 0;
 
289
        }
 
290
    }
 
291
    cdef = *def = 0;
 
292
    *cur = -1;
 
293
    *opts = initStrArr(0);
 
294
    while ((len = fGets(buf, sizeof(buf), f)) != -1)
 
295
        if (buf[0] == ' ' && buf[1] == ' ' && buf[2] != ' ') {
 
296
            if (buf[len - 1] == '*') {
 
297
                *def = cdef;
 
298
                len--;
 
299
            }
 
300
            for (; buf[len - 1] == ' '; len--);
 
301
            *opts = addStrArr(*opts, buf + 2, len - 2);
 
302
            if (!strcmp((*opts)[cdef], next))
 
303
                *cur = cdef;
 
304
            cdef++;
 
305
        }
 
306
  out:
 
307
    if (pClose(f, &pid)) {
 
308
        if (*opts)
 
309
            freeStrArr(*opts);
 
310
        return BO_IO;
 
311
    }
 
312
    return ret;
 
313
}
 
314
 
 
315
static int
 
316
setLilo(const char *opt, SdRec *sdr ATTR_UNUSED)
 
317
{
 
318
    char **opts;
 
319
    int def, cur, ret, i;
 
320
 
 
321
    if ((ret = getLilo(&opts, &def, &cur)) != BO_OK)
 
322
        return ret;
 
323
    if (!*opt) {
 
324
        opt = 0;
 
325
    } else {
 
326
        for (i = 0; opts[i]; i++)
 
327
            if (!strcmp(opts[i], opt))
 
328
                goto oke;
 
329
        freeStrArr(opts);
 
330
        return BO_NOENT;
 
331
    }
 
332
  oke:
 
333
    freeStrArr(opts);
 
334
    return BO_OK;
 
335
}
 
336
 
 
337
static void
 
338
commitLilo(void)
 
339
{
 
340
    static const char *args[5] = { 0, "-w", "-R", 0, 0 };
 
341
 
 
342
    args[0] = lilo;
 
343
    args[3] = sdRec.osname;
 
344
    runAndWait((char **)args, environ);
 
345
}
 
346
 
 
347
static const struct {
 
348
    int (*get)(char ***, int *, int *);
 
349
    int (*set)(const char *, SdRec *);
 
350
    void (*commit)(void);
 
351
} bootOpts[] = {
 
352
    { getNull, setNull, 0 },
 
353
    { getGrub, setGrub, commitGrub },
 
354
    { getGrub2, setGrub2, commitGrub2 },
 
355
    { getLilo, setLilo, commitLilo },
 
356
};
 
357
 
 
358
int
 
359
getBootOptions(char ***opts, int *def, int *cur)
 
360
{
 
361
    return bootOpts[bootManager].get(opts, def, cur);
 
362
}
 
363
 
 
364
int
 
365
setBootOption(const char *opt, SdRec *sdr)
 
366
{
 
367
    int ret;
 
368
 
 
369
    free(sdr->osname);
 
370
    sdr->osname = 0;
 
371
    if (opt) {
 
372
        if ((ret = bootOpts[bootManager].set(opt, sdr)) != BO_OK)
 
373
            return ret;
 
374
        if (!strDup(&sdr->osname, opt))
 
375
            return BO_IO; /* BO_NOMEM */
 
376
    }
 
377
    return BO_OK;
 
378
}
 
379
 
 
380
void
 
381
commitBootOption(void)
 
382
{
 
383
    if (sdRec.osname) {
 
384
        bootOpts[bootManager].commit();
 
385
/*
 
386
        free(sdRec.osname);
 
387
        sdRec.osname = 0;
 
388
*/
 
389
    }
 
390
}
 
391