Skip to content

Commit ea57c3d

Browse files
committed
Better logging and command-line parsing
This emulates Xorg's own command-line parser in case the display manager starts to pass additional options to Xorg.
1 parent b6c5810 commit ea57c3d

File tree

1 file changed

+122
-48
lines changed

1 file changed

+122
-48
lines changed

shmoverride/shmoverride.c

+122-48
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <stdio.h>
3030
#include <string.h>
3131
#include <errno.h>
32+
#include <limits.h>
3233

3334
#include <dlfcn.h>
3435
#include <sys/types.h>
@@ -86,8 +87,7 @@ static int xc_hnd;
8687
static xengnttab_handle *xgt;
8788
static char __shmid_filename[SHMID_FILENAME_LEN];
8889
static char *shmid_filename = NULL;
89-
static int idfd = -1;
90-
static char display_str[SHMID_DISPLAY_MAXLEN+1] = "";
90+
static int idfd = -1, display = -1;
9191

9292
static uint8_t *mmap_mfns(struct shm_args_hdr *shm_args) {
9393
uint8_t *map;
@@ -225,64 +225,133 @@ ASM_DEF(int, munmap, void *addr, size_t len)
225225
return real_munmap((void *)rounded_addr, len + (addr_int - rounded_addr));
226226
}
227227

228-
int get_display(void)
228+
static const char* const opts_with_args[] = {
229+
"-a",
230+
"-ardelay",
231+
"-arinterval",
232+
"-audit",
233+
"-auth",
234+
"-background",
235+
"-bgamma",
236+
"-cc",
237+
"-class",
238+
"-config",
239+
"-configdir",
240+
"-cookie",
241+
"-deferglyphs",
242+
"-depth",
243+
"-displayID",
244+
"-displayfd",
245+
"-dpi",
246+
"-f",
247+
"-fc",
248+
"-fn",
249+
"-fp",
250+
"-from",
251+
"-gamma",
252+
"-ggamma",
253+
"-indirect",
254+
"-isolateDevice",
255+
"-keyboard",
256+
"-layout",
257+
"-ld",
258+
"-lf",
259+
"-listen",
260+
"-logfile",
261+
"-ls",
262+
"-maxbigreqsize",
263+
"-modulepath",
264+
"-nolisten",
265+
"-p",
266+
"-pointer",
267+
"-port",
268+
"-query",
269+
"-render",
270+
"-rgamma",
271+
"-s",
272+
"-schedInterval",
273+
"-screen",
274+
"-seat",
275+
"-t",
276+
"-to",
277+
"-weight",
278+
"-x",
279+
"-xkbdir",
280+
"-xkbmap",
281+
"c",
282+
};
283+
284+
static int cmp_strings(const void *a, const void *b) { return strcmp(a, b); }
285+
286+
static int get_display(void)
229287
{
230-
int fd;
231288
ssize_t res;
232-
char ch;
233-
int in_arg = -1;
289+
int fd, rc = -1, display = 0;
234290

235291
fd = open("/proc/self/cmdline", O_RDONLY | O_NOCTTY | O_CLOEXEC);
236292
if (fd < 0) {
237293
perror("cmdline open");
238294
return -1;
239295
}
296+
char *ptr = NULL;
297+
size_t size = 0;
298+
FILE *f = fdopen(fd, "r");
299+
if (!f) {
300+
perror("fdopen()");
301+
close(fd);
302+
return -1;
303+
}
240304

305+
bool skip = false;
241306
while(1) {
242-
res = read(fd, &ch, 1);
243-
if (res < 0) {
307+
errno = 0;
308+
res = getdelim(&ptr, &size, 0, f);
309+
if (res <= 0) {
310+
if (res == -1 && errno == 0)
311+
break;
244312
perror("cmdline read");
245-
return -1;
313+
goto cleanup;
246314
}
247-
if (res == 0)
248-
break;
249-
250-
if (in_arg == 0 && ch != ':')
251-
in_arg = -1;
252-
if (ch == '\0') {
253-
in_arg = 0;
254-
} else if (in_arg >= 0) {
255-
if (in_arg >= SHMID_DISPLAY_MAXLEN)
256-
break;
257-
if (in_arg > 0 && (ch < '0' || ch > '9')) {
258-
if (in_arg == 1) {
259-
fprintf(stderr, "cmdline DISPLAY parsing failed\n");
260-
return -1;
261-
}
262-
in_arg = -1;
263-
continue;
264-
}
265-
display_str[in_arg++] = ch;
266-
display_str[in_arg] = '\0';
315+
size_t length = (size_t)res;
316+
assert(ptr && ptr[length] == '\0');
317+
318+
/* Skip option arguments. Some options take more than one argument,
319+
* but the extra arguments are always optional and display names
320+
* will not be interpreted as arguments to these options. */
321+
if (skip) {
322+
skip = false;
323+
continue;
267324
}
268-
}
269-
close(fd);
270-
271-
if (display_str[0] != ':') {
272-
display_str[0] = ':';
273-
display_str[1] = '0';
274-
display_str[2] = '\0';
275-
} else if (display_str[1] == '\0') {
276-
fprintf(stderr, "cmdline DISPLAY parsing failed\n");
277-
return -1;
278-
}
279325

280-
/* post-processing: drop leading ':' */
281-
res = strlen(display_str);
282-
for (in_arg = 0; in_arg < res; in_arg++)
283-
display_str[in_arg] = display_str[in_arg+1];
326+
/* Check if this is an option that takes a mandatory argument */
327+
if (bsearch(ptr, opts_with_args, sizeof(opts_with_args)/sizeof(opts_with_args[0]),
328+
sizeof(opts_with_args[0]), cmp_strings)) {
329+
skip = true;
330+
continue;
331+
}
284332

285-
return 0;
333+
if (ptr[0] == ':') {
334+
unsigned long l_display = ULONG_MAX;
335+
char *p;
336+
static_assert(ULONG_MAX > INT_MAX, "ULONG_MAX not greater than INT_MAX?");
337+
for (p = ptr + 1;; ++p)
338+
if (*p < '0' || *p > '9')
339+
break;
340+
if (p - ptr > 1 && !*p)
341+
l_display = strtoul(ptr + 1, &p, 10);
342+
if (l_display > INT_MAX || *p) {
343+
fprintf(stderr, "shmoverride: cmdline DISPLAY parsing failed: bad display name %s\n", ptr + 1);
344+
goto cleanup;
345+
}
346+
/* X happily accepts multiple display names and ignores all but the last */
347+
display = (int)l_display;
348+
}
349+
}
350+
rc = display;
351+
cleanup:
352+
free(ptr);
353+
fclose(f);
354+
return rc;
286355
}
287356

288357
static int assign_off(off_t *off) {
@@ -381,12 +450,17 @@ int __attribute__ ((constructor)) initfunc(void)
381450
goto cleanup; // Allow it to run when not under Xen.
382451
}
383452

384-
if (get_display() < 0)
453+
if ((display = get_display()) < 0)
385454
goto cleanup;
386455

387-
snprintf(__shmid_filename, SHMID_FILENAME_LEN,
388-
SHMID_FILENAME_PREFIX "%s", display_str);
456+
static_assert(sizeof __shmid_filename >= SHMID_FILENAME_LEN, "bug");
457+
if ((unsigned int)snprintf(__shmid_filename, SHMID_FILENAME_LEN,
458+
SHMID_FILENAME_PREFIX "%d", display) >= SHMID_FILENAME_LEN) {
459+
fputs("snprintf() failed!\n", stderr);
460+
abort();
461+
}
389462
shmid_filename = __shmid_filename;
463+
fprintf(stderr, "shmoverride: running with shm file %s\n", shmid_filename);
390464

391465
/* Try to lock the shm.id file (don't rely on whether it exists, a previous
392466
* process might have crashed).

0 commit comments

Comments
 (0)