1*9608SLin.Guo@Sun.COM /*************************************************************************** 2*9608SLin.Guo@Sun.COM * 3*9608SLin.Guo@Sun.COM * probe-xkb.c : Probe for keyboard device information 4*9608SLin.Guo@Sun.COM * 5*9608SLin.Guo@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 6*9608SLin.Guo@Sun.COM * Use is subject to license terms. 7*9608SLin.Guo@Sun.COM * 8*9608SLin.Guo@Sun.COM * Licensed under the Academic Free License version 2.1 9*9608SLin.Guo@Sun.COM * 10*9608SLin.Guo@Sun.COM **************************************************************************/ 11*9608SLin.Guo@Sun.COM 12*9608SLin.Guo@Sun.COM #ifdef HAVE_CONFIG_H 13*9608SLin.Guo@Sun.COM #include <config.h> 14*9608SLin.Guo@Sun.COM #endif 15*9608SLin.Guo@Sun.COM 16*9608SLin.Guo@Sun.COM #include <errno.h> 17*9608SLin.Guo@Sun.COM #include <string.h> 18*9608SLin.Guo@Sun.COM #include <strings.h> 19*9608SLin.Guo@Sun.COM #include <ctype.h> 20*9608SLin.Guo@Sun.COM #include <stdlib.h> 21*9608SLin.Guo@Sun.COM #include <stdio.h> 22*9608SLin.Guo@Sun.COM #include <sys/ioctl.h> 23*9608SLin.Guo@Sun.COM #include <sys/stropts.h> 24*9608SLin.Guo@Sun.COM #include <fcntl.h> 25*9608SLin.Guo@Sun.COM #include <unistd.h> 26*9608SLin.Guo@Sun.COM #include <priv.h> 27*9608SLin.Guo@Sun.COM 28*9608SLin.Guo@Sun.COM #include <sys/kbd.h> 29*9608SLin.Guo@Sun.COM #include <sys/kbio.h> 30*9608SLin.Guo@Sun.COM 31*9608SLin.Guo@Sun.COM #include <libhal.h> 32*9608SLin.Guo@Sun.COM #include <logger.h> 33*9608SLin.Guo@Sun.COM 34*9608SLin.Guo@Sun.COM #define MAXLINELEN 256 35*9608SLin.Guo@Sun.COM #define COMMENTCHAR '#' 36*9608SLin.Guo@Sun.COM #define KBD_DEFAULT_DEVICE "/dev/kbd" 37*9608SLin.Guo@Sun.COM #define XKBTABLE_PATH "/usr/X11/lib/X11/xkb/xkbtable.map" 38*9608SLin.Guo@Sun.COM 39*9608SLin.Guo@Sun.COM static int global_linenumber = 0; 40*9608SLin.Guo@Sun.COM static char line[MAXLINELEN + 1]; 41*9608SLin.Guo@Sun.COM 42*9608SLin.Guo@Sun.COM static void 43*9608SLin.Guo@Sun.COM drop_privileges() 44*9608SLin.Guo@Sun.COM { 45*9608SLin.Guo@Sun.COM priv_set_t *pPrivSet = NULL; 46*9608SLin.Guo@Sun.COM priv_set_t *lPrivSet = NULL; 47*9608SLin.Guo@Sun.COM 48*9608SLin.Guo@Sun.COM /* 49*9608SLin.Guo@Sun.COM * Start with the 'basic' privilege set and then remove any 50*9608SLin.Guo@Sun.COM * of the 'basic' privileges that will not be needed. 51*9608SLin.Guo@Sun.COM */ 52*9608SLin.Guo@Sun.COM if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) { 53*9608SLin.Guo@Sun.COM HAL_INFO(("Error in setting the priv")); 54*9608SLin.Guo@Sun.COM return; 55*9608SLin.Guo@Sun.COM } 56*9608SLin.Guo@Sun.COM 57*9608SLin.Guo@Sun.COM /* Clear privileges we will not need from the 'basic' set */ 58*9608SLin.Guo@Sun.COM (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY); 59*9608SLin.Guo@Sun.COM (void) priv_delset(pPrivSet, PRIV_PROC_INFO); 60*9608SLin.Guo@Sun.COM (void) priv_delset(pPrivSet, PRIV_PROC_SESSION); 61*9608SLin.Guo@Sun.COM (void) priv_delset(pPrivSet, PRIV_PROC_EXEC); 62*9608SLin.Guo@Sun.COM (void) priv_delset(pPrivSet, PRIV_PROC_FORK); 63*9608SLin.Guo@Sun.COM 64*9608SLin.Guo@Sun.COM (void) priv_addset(pPrivSet, PRIV_SYS_DEVICES); 65*9608SLin.Guo@Sun.COM (void) priv_addset(pPrivSet, PRIV_FILE_DAC_READ); 66*9608SLin.Guo@Sun.COM 67*9608SLin.Guo@Sun.COM /* Set the permitted privilege set. */ 68*9608SLin.Guo@Sun.COM if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) { 69*9608SLin.Guo@Sun.COM return; 70*9608SLin.Guo@Sun.COM } 71*9608SLin.Guo@Sun.COM 72*9608SLin.Guo@Sun.COM /* Clear the limit set. */ 73*9608SLin.Guo@Sun.COM if ((lPrivSet = priv_allocset()) == NULL) { 74*9608SLin.Guo@Sun.COM return; 75*9608SLin.Guo@Sun.COM } 76*9608SLin.Guo@Sun.COM 77*9608SLin.Guo@Sun.COM priv_emptyset(lPrivSet); 78*9608SLin.Guo@Sun.COM 79*9608SLin.Guo@Sun.COM if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) { 80*9608SLin.Guo@Sun.COM return; 81*9608SLin.Guo@Sun.COM } 82*9608SLin.Guo@Sun.COM 83*9608SLin.Guo@Sun.COM priv_freeset(lPrivSet); 84*9608SLin.Guo@Sun.COM priv_freeset(pPrivSet); 85*9608SLin.Guo@Sun.COM } 86*9608SLin.Guo@Sun.COM 87*9608SLin.Guo@Sun.COM static int 88*9608SLin.Guo@Sun.COM get_kbd_layout_type(char *device_file, int *kbd_type, int *kbd_layout) 89*9608SLin.Guo@Sun.COM { 90*9608SLin.Guo@Sun.COM int ret = 1; 91*9608SLin.Guo@Sun.COM int fd = -1; 92*9608SLin.Guo@Sun.COM 93*9608SLin.Guo@Sun.COM if ((fd = open(device_file, O_RDONLY | O_NONBLOCK)) < 0) { 94*9608SLin.Guo@Sun.COM HAL_DEBUG(("Cannot open %s: %s", device_file, strerror(errno))); 95*9608SLin.Guo@Sun.COM goto out; 96*9608SLin.Guo@Sun.COM } 97*9608SLin.Guo@Sun.COM 98*9608SLin.Guo@Sun.COM /* 99*9608SLin.Guo@Sun.COM * For usb keyboard devices, we need to first push "usbkbm" module upon 100*9608SLin.Guo@Sun.COM * the stream. 101*9608SLin.Guo@Sun.COM */ 102*9608SLin.Guo@Sun.COM if (strstr(device_file, "hid") != NULL) { 103*9608SLin.Guo@Sun.COM if (ioctl(fd, I_FIND, "usbkbm") == 0) { 104*9608SLin.Guo@Sun.COM (void) ioctl(fd, I_PUSH, "usbkbm"); 105*9608SLin.Guo@Sun.COM HAL_DEBUG(("usbkbm module has been pushed %s", strerror(errno))); 106*9608SLin.Guo@Sun.COM } 107*9608SLin.Guo@Sun.COM } 108*9608SLin.Guo@Sun.COM 109*9608SLin.Guo@Sun.COM if (ioctl(fd, KIOCTYPE, kbd_type) < 0) { 110*9608SLin.Guo@Sun.COM HAL_DEBUG(("get keyboard type failed %s: %s", 111*9608SLin.Guo@Sun.COM device_file, strerror(errno))); 112*9608SLin.Guo@Sun.COM goto out; 113*9608SLin.Guo@Sun.COM } 114*9608SLin.Guo@Sun.COM if (ioctl(fd, KIOCLAYOUT, kbd_layout) < 0) { 115*9608SLin.Guo@Sun.COM HAL_DEBUG(("get keyboard layout failed %s: %s", 116*9608SLin.Guo@Sun.COM device_file, strerror(errno))); 117*9608SLin.Guo@Sun.COM goto out; 118*9608SLin.Guo@Sun.COM } 119*9608SLin.Guo@Sun.COM 120*9608SLin.Guo@Sun.COM ret = 0; 121*9608SLin.Guo@Sun.COM 122*9608SLin.Guo@Sun.COM out: if (fd >= 0) { 123*9608SLin.Guo@Sun.COM close(fd); 124*9608SLin.Guo@Sun.COM } 125*9608SLin.Guo@Sun.COM 126*9608SLin.Guo@Sun.COM return (ret); 127*9608SLin.Guo@Sun.COM } 128*9608SLin.Guo@Sun.COM 129*9608SLin.Guo@Sun.COM /* Skips over the white space character in the string. */ 130*9608SLin.Guo@Sun.COM static char * 131*9608SLin.Guo@Sun.COM skipwhite(char *ptr) 132*9608SLin.Guo@Sun.COM { 133*9608SLin.Guo@Sun.COM while ((*ptr == ' ') || (*ptr == '\t')) { 134*9608SLin.Guo@Sun.COM ptr++; 135*9608SLin.Guo@Sun.COM } 136*9608SLin.Guo@Sun.COM 137*9608SLin.Guo@Sun.COM /* This should not occur. but .. */ 138*9608SLin.Guo@Sun.COM if (*ptr == '\n') { 139*9608SLin.Guo@Sun.COM ptr = '\0'; 140*9608SLin.Guo@Sun.COM } 141*9608SLin.Guo@Sun.COM 142*9608SLin.Guo@Sun.COM return (ptr); 143*9608SLin.Guo@Sun.COM } 144*9608SLin.Guo@Sun.COM 145*9608SLin.Guo@Sun.COM static char * 146*9608SLin.Guo@Sun.COM getaline(FILE *fp) 147*9608SLin.Guo@Sun.COM { 148*9608SLin.Guo@Sun.COM char *ptr; 149*9608SLin.Guo@Sun.COM char *tmp; 150*9608SLin.Guo@Sun.COM int index; 151*9608SLin.Guo@Sun.COM int c; 152*9608SLin.Guo@Sun.COM 153*9608SLin.Guo@Sun.COM while (1) { 154*9608SLin.Guo@Sun.COM ptr = fgets(line, MAXLINELEN, fp); 155*9608SLin.Guo@Sun.COM if (!ptr) { 156*9608SLin.Guo@Sun.COM (void) fclose(fp); 157*9608SLin.Guo@Sun.COM return (NULL); 158*9608SLin.Guo@Sun.COM } 159*9608SLin.Guo@Sun.COM 160*9608SLin.Guo@Sun.COM global_linenumber++; 161*9608SLin.Guo@Sun.COM 162*9608SLin.Guo@Sun.COM /* Comment line */ 163*9608SLin.Guo@Sun.COM if (ptr[0] == COMMENTCHAR) { 164*9608SLin.Guo@Sun.COM continue; 165*9608SLin.Guo@Sun.COM } 166*9608SLin.Guo@Sun.COM 167*9608SLin.Guo@Sun.COM /* Blank line */ 168*9608SLin.Guo@Sun.COM if (ptr[0] == '\n') { 169*9608SLin.Guo@Sun.COM continue; 170*9608SLin.Guo@Sun.COM } 171*9608SLin.Guo@Sun.COM 172*9608SLin.Guo@Sun.COM if ((tmp = strchr(ptr, '#')) != NULL) { 173*9608SLin.Guo@Sun.COM *tmp = '\0'; 174*9608SLin.Guo@Sun.COM } 175*9608SLin.Guo@Sun.COM 176*9608SLin.Guo@Sun.COM if (ptr[strlen(ptr) - 1] == '\n') { 177*9608SLin.Guo@Sun.COM /* get rid of '\n' */ 178*9608SLin.Guo@Sun.COM ptr[strlen(ptr) - 1] = '\0'; 179*9608SLin.Guo@Sun.COM } 180*9608SLin.Guo@Sun.COM 181*9608SLin.Guo@Sun.COM ptr = skipwhite(ptr); 182*9608SLin.Guo@Sun.COM if (*ptr) { 183*9608SLin.Guo@Sun.COM break; 184*9608SLin.Guo@Sun.COM } 185*9608SLin.Guo@Sun.COM } 186*9608SLin.Guo@Sun.COM return (ptr); 187*9608SLin.Guo@Sun.COM } 188*9608SLin.Guo@Sun.COM 189*9608SLin.Guo@Sun.COM static int 190*9608SLin.Guo@Sun.COM sun_find_xkbnames(int kb_type, int kb_layout, char **xkb_keymap, 191*9608SLin.Guo@Sun.COM char **xkb_model, char **xkb_layout) 192*9608SLin.Guo@Sun.COM { 193*9608SLin.Guo@Sun.COM const char *type, *layout; 194*9608SLin.Guo@Sun.COM char *keymap, *defkeymap = NULL; 195*9608SLin.Guo@Sun.COM char *model, *defmodel = NULL; 196*9608SLin.Guo@Sun.COM char *xkblay, *defxkblay = NULL; 197*9608SLin.Guo@Sun.COM FILE *fp; 198*9608SLin.Guo@Sun.COM int found_error = 0, found_keytable = 0; 199*9608SLin.Guo@Sun.COM int ret = 1; 200*9608SLin.Guo@Sun.COM 201*9608SLin.Guo@Sun.COM if ((fp = fopen(XKBTABLE_PATH, "r")) == NULL) { 202*9608SLin.Guo@Sun.COM return (ret); 203*9608SLin.Guo@Sun.COM } 204*9608SLin.Guo@Sun.COM 205*9608SLin.Guo@Sun.COM global_linenumber = 0; 206*9608SLin.Guo@Sun.COM while (getaline(fp)) { 207*9608SLin.Guo@Sun.COM if ((type = strtok(line, " \t\n")) == NULL) { 208*9608SLin.Guo@Sun.COM found_error = 1; 209*9608SLin.Guo@Sun.COM } 210*9608SLin.Guo@Sun.COM 211*9608SLin.Guo@Sun.COM if ((layout = strtok(NULL, " \t\n")) == NULL) { 212*9608SLin.Guo@Sun.COM found_error = 1; 213*9608SLin.Guo@Sun.COM } 214*9608SLin.Guo@Sun.COM 215*9608SLin.Guo@Sun.COM if ((keymap = strtok(NULL, " \t\n")) == NULL) { 216*9608SLin.Guo@Sun.COM found_error = 1; 217*9608SLin.Guo@Sun.COM } 218*9608SLin.Guo@Sun.COM 219*9608SLin.Guo@Sun.COM /* These two are optional entries */ 220*9608SLin.Guo@Sun.COM model = strtok(NULL, " \t\n"); 221*9608SLin.Guo@Sun.COM if ((model == NULL) || (*model == COMMENTCHAR)) { 222*9608SLin.Guo@Sun.COM model = xkblay = NULL; 223*9608SLin.Guo@Sun.COM } else { 224*9608SLin.Guo@Sun.COM xkblay = strtok(NULL, " \t\n"); 225*9608SLin.Guo@Sun.COM if ((xkblay != NULL) && (*xkblay == COMMENTCHAR)) { 226*9608SLin.Guo@Sun.COM xkblay = NULL; 227*9608SLin.Guo@Sun.COM } 228*9608SLin.Guo@Sun.COM } 229*9608SLin.Guo@Sun.COM 230*9608SLin.Guo@Sun.COM if (found_error) { 231*9608SLin.Guo@Sun.COM found_error = 0; 232*9608SLin.Guo@Sun.COM continue; 233*9608SLin.Guo@Sun.COM } 234*9608SLin.Guo@Sun.COM 235*9608SLin.Guo@Sun.COM /* record default entry if/when found */ 236*9608SLin.Guo@Sun.COM if (*type == '*') { 237*9608SLin.Guo@Sun.COM if (defkeymap == NULL) { 238*9608SLin.Guo@Sun.COM defkeymap = keymap; 239*9608SLin.Guo@Sun.COM defmodel = model; 240*9608SLin.Guo@Sun.COM defxkblay = xkblay; 241*9608SLin.Guo@Sun.COM } 242*9608SLin.Guo@Sun.COM } else if (atoi(type) == kb_type) { 243*9608SLin.Guo@Sun.COM if (*type == '*') { 244*9608SLin.Guo@Sun.COM if (defkeymap == NULL) { 245*9608SLin.Guo@Sun.COM defkeymap = keymap; 246*9608SLin.Guo@Sun.COM defmodel = model; 247*9608SLin.Guo@Sun.COM defxkblay = xkblay; 248*9608SLin.Guo@Sun.COM } 249*9608SLin.Guo@Sun.COM } else if (atoi(layout) == kb_layout) { 250*9608SLin.Guo@Sun.COM found_keytable = 1; 251*9608SLin.Guo@Sun.COM break; 252*9608SLin.Guo@Sun.COM } 253*9608SLin.Guo@Sun.COM } 254*9608SLin.Guo@Sun.COM } 255*9608SLin.Guo@Sun.COM 256*9608SLin.Guo@Sun.COM (void) fclose(fp); 257*9608SLin.Guo@Sun.COM 258*9608SLin.Guo@Sun.COM if (!found_keytable) { 259*9608SLin.Guo@Sun.COM keymap = defkeymap; 260*9608SLin.Guo@Sun.COM model = defmodel; 261*9608SLin.Guo@Sun.COM xkblay = defxkblay; 262*9608SLin.Guo@Sun.COM } 263*9608SLin.Guo@Sun.COM 264*9608SLin.Guo@Sun.COM if ((keymap != NULL) && (strcmp(keymap, "-") != 0)) { 265*9608SLin.Guo@Sun.COM *xkb_keymap = keymap; 266*9608SLin.Guo@Sun.COM } 267*9608SLin.Guo@Sun.COM if ((model != NULL) && (strcmp(model, "-") != 0)) { 268*9608SLin.Guo@Sun.COM *xkb_model = model; 269*9608SLin.Guo@Sun.COM } 270*9608SLin.Guo@Sun.COM if ((xkblay != NULL) && (strcmp(xkblay, "-") != 0)) { 271*9608SLin.Guo@Sun.COM *xkb_layout = xkblay; 272*9608SLin.Guo@Sun.COM } 273*9608SLin.Guo@Sun.COM 274*9608SLin.Guo@Sun.COM return (0); 275*9608SLin.Guo@Sun.COM } 276*9608SLin.Guo@Sun.COM 277*9608SLin.Guo@Sun.COM int 278*9608SLin.Guo@Sun.COM main(int argc, char *argv[]) 279*9608SLin.Guo@Sun.COM { 280*9608SLin.Guo@Sun.COM int ret = 1; 281*9608SLin.Guo@Sun.COM char *udi; 282*9608SLin.Guo@Sun.COM char *device_file; 283*9608SLin.Guo@Sun.COM LibHalContext *ctx = NULL; 284*9608SLin.Guo@Sun.COM LibHalChangeSet *cs = NULL; 285*9608SLin.Guo@Sun.COM DBusError error; 286*9608SLin.Guo@Sun.COM int kbd_type, kbd_layout; 287*9608SLin.Guo@Sun.COM char *xkbkeymap = NULL, *xkbmodel = NULL, *xkblayout = NULL; 288*9608SLin.Guo@Sun.COM 289*9608SLin.Guo@Sun.COM if ((udi = getenv("UDI")) == NULL) { 290*9608SLin.Guo@Sun.COM goto out; 291*9608SLin.Guo@Sun.COM } 292*9608SLin.Guo@Sun.COM 293*9608SLin.Guo@Sun.COM if ((device_file = getenv("HAL_PROP_INPUT_DEVICE")) == NULL) { 294*9608SLin.Guo@Sun.COM goto out; 295*9608SLin.Guo@Sun.COM } 296*9608SLin.Guo@Sun.COM 297*9608SLin.Guo@Sun.COM drop_privileges(); 298*9608SLin.Guo@Sun.COM setup_logger(); 299*9608SLin.Guo@Sun.COM 300*9608SLin.Guo@Sun.COM dbus_error_init(&error); 301*9608SLin.Guo@Sun.COM if ((ctx = libhal_ctx_init_direct(&error)) == NULL) { 302*9608SLin.Guo@Sun.COM goto out; 303*9608SLin.Guo@Sun.COM } 304*9608SLin.Guo@Sun.COM 305*9608SLin.Guo@Sun.COM if ((cs = libhal_device_new_changeset(udi)) == NULL) { 306*9608SLin.Guo@Sun.COM HAL_DEBUG(("Cannot allocate changeset")); 307*9608SLin.Guo@Sun.COM goto out; 308*9608SLin.Guo@Sun.COM } 309*9608SLin.Guo@Sun.COM 310*9608SLin.Guo@Sun.COM HAL_DEBUG(("Doing probe-xkb for %s (udi=%s)", device_file, udi)); 311*9608SLin.Guo@Sun.COM 312*9608SLin.Guo@Sun.COM if (get_kbd_layout_type(device_file, &kbd_type, &kbd_layout)) { 313*9608SLin.Guo@Sun.COM goto out; 314*9608SLin.Guo@Sun.COM } 315*9608SLin.Guo@Sun.COM 316*9608SLin.Guo@Sun.COM /* 317*9608SLin.Guo@Sun.COM * For some usb keyboard that is not self-identifying, get keyboard's 318*9608SLin.Guo@Sun.COM * layout and type from system default keyboard device--/dev/kbd. 319*9608SLin.Guo@Sun.COM */ 320*9608SLin.Guo@Sun.COM if ((kbd_layout == 0) && (strstr(device_file, "hid") != NULL)) { 321*9608SLin.Guo@Sun.COM if (get_kbd_layout_type(KBD_DEFAULT_DEVICE, 322*9608SLin.Guo@Sun.COM &kbd_type, &kbd_layout)) { 323*9608SLin.Guo@Sun.COM goto out; 324*9608SLin.Guo@Sun.COM } 325*9608SLin.Guo@Sun.COM } 326*9608SLin.Guo@Sun.COM 327*9608SLin.Guo@Sun.COM if (sun_find_xkbnames(kbd_type, kbd_layout, 328*9608SLin.Guo@Sun.COM &xkbkeymap, &xkbmodel, &xkblayout)) { 329*9608SLin.Guo@Sun.COM goto out; 330*9608SLin.Guo@Sun.COM } 331*9608SLin.Guo@Sun.COM 332*9608SLin.Guo@Sun.COM libhal_changeset_set_property_string(cs, 333*9608SLin.Guo@Sun.COM "input.x11_options.XkbModel", xkbmodel); 334*9608SLin.Guo@Sun.COM libhal_changeset_set_property_string(cs, 335*9608SLin.Guo@Sun.COM "input.x11_options.XkbLayout", xkblayout); 336*9608SLin.Guo@Sun.COM 337*9608SLin.Guo@Sun.COM libhal_device_commit_changeset(ctx, cs, &error); 338*9608SLin.Guo@Sun.COM 339*9608SLin.Guo@Sun.COM ret = 0; 340*9608SLin.Guo@Sun.COM 341*9608SLin.Guo@Sun.COM out: 342*9608SLin.Guo@Sun.COM if (cs != NULL) { 343*9608SLin.Guo@Sun.COM libhal_device_free_changeset(cs); 344*9608SLin.Guo@Sun.COM } 345*9608SLin.Guo@Sun.COM 346*9608SLin.Guo@Sun.COM if (ctx != NULL) { 347*9608SLin.Guo@Sun.COM libhal_ctx_shutdown(ctx, &error); 348*9608SLin.Guo@Sun.COM libhal_ctx_free(ctx); 349*9608SLin.Guo@Sun.COM if (dbus_error_is_set(&error)) { 350*9608SLin.Guo@Sun.COM dbus_error_free(&error); 351*9608SLin.Guo@Sun.COM } 352*9608SLin.Guo@Sun.COM } 353*9608SLin.Guo@Sun.COM return (ret); 354*9608SLin.Guo@Sun.COM } 355