1*2912Sartem /*************************************************************************** 2*2912Sartem * CVSID: $Id$ 3*2912Sartem * 4*2912Sartem * util.c - Various utilities 5*2912Sartem * 6*2912Sartem * Copyright (C) 2004 David Zeuthen, <david@fubar.dk> 7*2912Sartem * 8*2912Sartem * Licensed under the Academic Free License version 2.1 9*2912Sartem * 10*2912Sartem * This program is free software; you can redistribute it and/or modify 11*2912Sartem * it under the terms of the GNU General Public License as published by 12*2912Sartem * the Free Software Foundation; either version 2 of the License, or 13*2912Sartem * (at your option) any later version. 14*2912Sartem * 15*2912Sartem * This program is distributed in the hope that it will be useful, 16*2912Sartem * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*2912Sartem * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*2912Sartem * GNU General Public License for more details. 19*2912Sartem * 20*2912Sartem * You should have received a copy of the GNU General Public License 21*2912Sartem * along with this program; if not, write to the Free Software 22*2912Sartem * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23*2912Sartem * 24*2912Sartem **************************************************************************/ 25*2912Sartem 26*2912Sartem #ifdef HAVE_CONFIG_H 27*2912Sartem # include <config.h> 28*2912Sartem #endif 29*2912Sartem 30*2912Sartem #include <stdio.h> 31*2912Sartem #include <stdarg.h> 32*2912Sartem #include <string.h> 33*2912Sartem #include <errno.h> 34*2912Sartem #include <time.h> 35*2912Sartem #include <ctype.h> 36*2912Sartem #include <stdint.h> 37*2912Sartem #include <sys/stat.h> 38*2912Sartem #include <unistd.h> 39*2912Sartem #include <fcntl.h> 40*2912Sartem #include <signal.h> 41*2912Sartem #include <sys/wait.h> 42*2912Sartem #include <sys/file.h> 43*2912Sartem 44*2912Sartem #include <glib.h> 45*2912Sartem #include <dbus/dbus.h> 46*2912Sartem #include <dbus/dbus-glib.h> 47*2912Sartem 48*2912Sartem #include "osspec.h" 49*2912Sartem #include "logger.h" 50*2912Sartem #include "hald.h" 51*2912Sartem #include "hald_runner.h" 52*2912Sartem #include "hald_dbus.h" 53*2912Sartem #include "device_info.h" 54*2912Sartem 55*2912Sartem #include "util.h" 56*2912Sartem 57*2912Sartem gboolean 58*2912Sartem hal_util_remove_trailing_slash (gchar *path) 59*2912Sartem { 60*2912Sartem gchar *c = NULL; 61*2912Sartem 62*2912Sartem if (path == NULL) { 63*2912Sartem return FALSE; 64*2912Sartem } 65*2912Sartem 66*2912Sartem c = strrchr (path, '/'); 67*2912Sartem if (c == NULL) { 68*2912Sartem HAL_WARNING (("Invalid path %s", path)); 69*2912Sartem return 1; 70*2912Sartem } 71*2912Sartem if (*(c+1) == '\0') 72*2912Sartem *c = '\0'; 73*2912Sartem 74*2912Sartem return TRUE; 75*2912Sartem } 76*2912Sartem 77*2912Sartem /** Given a path, /foo/bar/bat/foobar, return the last element, e.g. 78*2912Sartem * foobar. 79*2912Sartem * 80*2912Sartem * @param path Path 81*2912Sartem * @return Pointer into given string 82*2912Sartem */ 83*2912Sartem const gchar * 84*2912Sartem hal_util_get_last_element (const gchar *s) 85*2912Sartem { 86*2912Sartem int len; 87*2912Sartem const gchar *p; 88*2912Sartem 89*2912Sartem len = strlen (s); 90*2912Sartem for (p = s + len - 1; p > s; --p) { 91*2912Sartem if ((*p) == '/') 92*2912Sartem return p + 1; 93*2912Sartem } 94*2912Sartem 95*2912Sartem return s; 96*2912Sartem } 97*2912Sartem 98*2912Sartem /** Given a path, this functions finds the path representing the 99*2912Sartem * parent directory by truncation. 100*2912Sartem * 101*2912Sartem * @param path Path 102*2912Sartem * @return Path for parent or NULL. Must be freed by caller 103*2912Sartem */ 104*2912Sartem gchar * 105*2912Sartem hal_util_get_parent_path (const gchar *path) 106*2912Sartem { 107*2912Sartem guint i; 108*2912Sartem guint len; 109*2912Sartem gchar *parent_path; 110*2912Sartem 111*2912Sartem /* Find parent device by truncating our own path */ 112*2912Sartem parent_path = g_strndup (path, HAL_PATH_MAX); 113*2912Sartem len = strlen (parent_path); 114*2912Sartem for (i = len - 1; parent_path[i] != '/'; --i) { 115*2912Sartem parent_path[i] = '\0'; 116*2912Sartem } 117*2912Sartem parent_path[i] = '\0'; 118*2912Sartem 119*2912Sartem return parent_path; 120*2912Sartem } 121*2912Sartem 122*2912Sartem gchar * 123*2912Sartem hal_util_get_normalized_path (const gchar *path1, const gchar *path2) 124*2912Sartem { 125*2912Sartem int len1; 126*2912Sartem int len2; 127*2912Sartem const gchar *p1; 128*2912Sartem const gchar *p2; 129*2912Sartem gchar buf[HAL_PATH_MAX]; 130*2912Sartem 131*2912Sartem len1 = strlen (path1); 132*2912Sartem len2 = strlen (path2); 133*2912Sartem 134*2912Sartem p1 = path1 + len1; 135*2912Sartem 136*2912Sartem p2 = path2; 137*2912Sartem while (p2 < path2 + len2 && strncmp (p2, "../", 3) == 0) { 138*2912Sartem p2 += 3; 139*2912Sartem 140*2912Sartem while (p1 >= path1 && *(--p1)!='/') 141*2912Sartem ; 142*2912Sartem } 143*2912Sartem 144*2912Sartem if ((p1-path1) < 0) { 145*2912Sartem HAL_ERROR (("Could not normalize '%s' and '%s', return 'NULL'", path1, path2)); 146*2912Sartem return NULL; 147*2912Sartem } 148*2912Sartem 149*2912Sartem strncpy (buf, path1, (p1-path1)); 150*2912Sartem buf[p1-path1] = '\0'; 151*2912Sartem 152*2912Sartem return g_strdup_printf ("%s/%s", buf, p2); 153*2912Sartem } 154*2912Sartem 155*2912Sartem gboolean 156*2912Sartem hal_util_get_int_from_file (const gchar *directory, const gchar *file, gint *result, gint base) 157*2912Sartem { 158*2912Sartem FILE *f; 159*2912Sartem char buf[64]; 160*2912Sartem gchar path[HAL_PATH_MAX]; 161*2912Sartem gboolean ret; 162*2912Sartem 163*2912Sartem f = NULL; 164*2912Sartem ret = FALSE; 165*2912Sartem 166*2912Sartem g_snprintf (path, sizeof (path), "%s/%s", directory, file); 167*2912Sartem 168*2912Sartem f = fopen (path, "rb"); 169*2912Sartem if (f == NULL) { 170*2912Sartem HAL_ERROR (("Cannot open '%s'", path)); 171*2912Sartem goto out; 172*2912Sartem } 173*2912Sartem 174*2912Sartem if (fgets (buf, sizeof (buf), f) == NULL) { 175*2912Sartem HAL_ERROR (("Cannot read from '%s'", path)); 176*2912Sartem goto out; 177*2912Sartem } 178*2912Sartem 179*2912Sartem /* TODO: handle error condition */ 180*2912Sartem *result = strtol (buf, NULL, base); 181*2912Sartem ret = TRUE; 182*2912Sartem 183*2912Sartem out: 184*2912Sartem if (f != NULL) 185*2912Sartem fclose (f); 186*2912Sartem 187*2912Sartem return ret; 188*2912Sartem } 189*2912Sartem 190*2912Sartem gboolean 191*2912Sartem hal_util_set_int_from_file (HalDevice *d, const gchar *key, const gchar *directory, const gchar *file, gint base) 192*2912Sartem { 193*2912Sartem gint value; 194*2912Sartem gboolean ret; 195*2912Sartem 196*2912Sartem ret = FALSE; 197*2912Sartem 198*2912Sartem if (hal_util_get_int_from_file (directory, file, &value, base)) 199*2912Sartem ret = hal_device_property_set_int (d, key, value); 200*2912Sartem 201*2912Sartem return ret; 202*2912Sartem } 203*2912Sartem 204*2912Sartem 205*2912Sartem gboolean 206*2912Sartem hal_util_get_uint64_from_file (const gchar *directory, const gchar *file, guint64 *result, gint base) 207*2912Sartem { 208*2912Sartem FILE *f; 209*2912Sartem char buf[64]; 210*2912Sartem gchar path[HAL_PATH_MAX]; 211*2912Sartem gboolean ret; 212*2912Sartem 213*2912Sartem f = NULL; 214*2912Sartem ret = FALSE; 215*2912Sartem 216*2912Sartem g_snprintf (path, sizeof (path), "%s/%s", directory, file); 217*2912Sartem 218*2912Sartem f = fopen (path, "rb"); 219*2912Sartem if (f == NULL) { 220*2912Sartem HAL_ERROR (("Cannot open '%s'", path)); 221*2912Sartem goto out; 222*2912Sartem } 223*2912Sartem 224*2912Sartem if (fgets (buf, sizeof (buf), f) == NULL) { 225*2912Sartem HAL_ERROR (("Cannot read from '%s'", path)); 226*2912Sartem goto out; 227*2912Sartem } 228*2912Sartem 229*2912Sartem /* TODO: handle error condition */ 230*2912Sartem *result = strtoll (buf, NULL, base); 231*2912Sartem 232*2912Sartem ret = TRUE; 233*2912Sartem 234*2912Sartem out: 235*2912Sartem if (f != NULL) 236*2912Sartem fclose (f); 237*2912Sartem 238*2912Sartem return ret; 239*2912Sartem } 240*2912Sartem 241*2912Sartem gboolean 242*2912Sartem hal_util_set_uint64_from_file (HalDevice *d, const gchar *key, const gchar *directory, const gchar *file, gint base) 243*2912Sartem { 244*2912Sartem guint64 value; 245*2912Sartem gboolean ret; 246*2912Sartem 247*2912Sartem ret = FALSE; 248*2912Sartem 249*2912Sartem if (hal_util_get_uint64_from_file (directory, file, &value, base)) 250*2912Sartem ret = hal_device_property_set_uint64 (d, key, value); 251*2912Sartem 252*2912Sartem return ret; 253*2912Sartem } 254*2912Sartem 255*2912Sartem gboolean 256*2912Sartem hal_util_get_bcd2_from_file (const gchar *directory, const gchar *file, gint *result) 257*2912Sartem { 258*2912Sartem FILE *f; 259*2912Sartem char buf[64]; 260*2912Sartem gchar path[HAL_PATH_MAX]; 261*2912Sartem gboolean ret; 262*2912Sartem gint digit; 263*2912Sartem gint left, right; 264*2912Sartem gboolean passed_white_space; 265*2912Sartem gint num_prec; 266*2912Sartem gsize len; 267*2912Sartem gchar c; 268*2912Sartem guint i; 269*2912Sartem 270*2912Sartem f = NULL; 271*2912Sartem ret = FALSE; 272*2912Sartem 273*2912Sartem g_snprintf (path, sizeof (path), "%s/%s", directory, file); 274*2912Sartem 275*2912Sartem f = fopen (path, "rb"); 276*2912Sartem if (f == NULL) { 277*2912Sartem HAL_ERROR (("Cannot open '%s'", path)); 278*2912Sartem goto out; 279*2912Sartem } 280*2912Sartem 281*2912Sartem if (fgets (buf, sizeof (buf), f) == NULL) { 282*2912Sartem HAL_ERROR (("Cannot read from '%s'", path)); 283*2912Sartem goto out; 284*2912Sartem } 285*2912Sartem 286*2912Sartem left = 0; 287*2912Sartem len = strlen (buf); 288*2912Sartem passed_white_space = FALSE; 289*2912Sartem for (i = 0; i < len && buf[i] != '.'; i++) { 290*2912Sartem if (g_ascii_isspace (buf[i])) { 291*2912Sartem if (passed_white_space) 292*2912Sartem break; 293*2912Sartem else 294*2912Sartem continue; 295*2912Sartem } 296*2912Sartem passed_white_space = TRUE; 297*2912Sartem left *= 16; 298*2912Sartem c = buf[i]; 299*2912Sartem digit = (int) (c - '0'); 300*2912Sartem left += digit; 301*2912Sartem } 302*2912Sartem i++; 303*2912Sartem right = 0; 304*2912Sartem num_prec = 0; 305*2912Sartem for (; i < len; i++) { 306*2912Sartem if (g_ascii_isspace (buf[i])) 307*2912Sartem break; 308*2912Sartem if (num_prec == 2) /* Only care about two digits 309*2912Sartem * of precision */ 310*2912Sartem break; 311*2912Sartem right *= 16; 312*2912Sartem c = buf[i]; 313*2912Sartem digit = (int) (c - '0'); 314*2912Sartem right += digit; 315*2912Sartem num_prec++; 316*2912Sartem } 317*2912Sartem 318*2912Sartem for (; num_prec < 2; num_prec++) 319*2912Sartem right *= 16; 320*2912Sartem 321*2912Sartem *result = left * 256 + (right & 255); 322*2912Sartem ret = TRUE; 323*2912Sartem 324*2912Sartem out: 325*2912Sartem if (f != NULL) 326*2912Sartem fclose (f); 327*2912Sartem 328*2912Sartem return ret; 329*2912Sartem } 330*2912Sartem 331*2912Sartem gboolean 332*2912Sartem hal_util_set_bcd2_from_file (HalDevice *d, const gchar *key, const gchar *directory, const gchar *file) 333*2912Sartem { 334*2912Sartem gint value; 335*2912Sartem gboolean ret; 336*2912Sartem 337*2912Sartem ret = FALSE; 338*2912Sartem 339*2912Sartem if (hal_util_get_bcd2_from_file (directory, file, &value)) 340*2912Sartem ret = hal_device_property_set_int (d, key, value); 341*2912Sartem 342*2912Sartem return ret; 343*2912Sartem } 344*2912Sartem 345*2912Sartem gchar * 346*2912Sartem hal_util_get_string_from_file (const gchar *directory, const gchar *file) 347*2912Sartem { 348*2912Sartem FILE *f; 349*2912Sartem static gchar buf[256]; 350*2912Sartem gchar path[HAL_PATH_MAX]; 351*2912Sartem gchar *result; 352*2912Sartem gsize len; 353*2912Sartem gint i; 354*2912Sartem 355*2912Sartem f = NULL; 356*2912Sartem result = NULL; 357*2912Sartem 358*2912Sartem g_snprintf (path, sizeof (path), "%s/%s", directory, file); 359*2912Sartem 360*2912Sartem f = fopen (path, "rb"); 361*2912Sartem if (f == NULL) { 362*2912Sartem HAL_ERROR (("Cannot open '%s'", path)); 363*2912Sartem goto out; 364*2912Sartem } 365*2912Sartem 366*2912Sartem buf[0] = '\0'; 367*2912Sartem if (fgets (buf, sizeof (buf), f) == NULL) { 368*2912Sartem HAL_ERROR (("Cannot read from '%s'", path)); 369*2912Sartem goto out; 370*2912Sartem } 371*2912Sartem 372*2912Sartem len = strlen (buf); 373*2912Sartem if (len>0) 374*2912Sartem buf[len-1] = '\0'; 375*2912Sartem 376*2912Sartem /* Clear remaining whitespace */ 377*2912Sartem for (i = len - 2; i >= 0; --i) { 378*2912Sartem if (!g_ascii_isspace (buf[i])) 379*2912Sartem break; 380*2912Sartem buf[i] = '\0'; 381*2912Sartem } 382*2912Sartem 383*2912Sartem result = buf; 384*2912Sartem 385*2912Sartem out: 386*2912Sartem if (f != NULL) 387*2912Sartem fclose (f); 388*2912Sartem 389*2912Sartem return result; 390*2912Sartem } 391*2912Sartem 392*2912Sartem gboolean 393*2912Sartem hal_util_set_string_from_file (HalDevice *d, const gchar *key, const gchar *directory, const gchar *file) 394*2912Sartem { 395*2912Sartem gchar *buf; 396*2912Sartem gboolean ret; 397*2912Sartem 398*2912Sartem ret = FALSE; 399*2912Sartem 400*2912Sartem if ((buf = hal_util_get_string_from_file (directory, file)) != NULL) 401*2912Sartem ret = hal_device_property_set_string (d, key, buf); 402*2912Sartem 403*2912Sartem return ret; 404*2912Sartem } 405*2912Sartem 406*2912Sartem void 407*2912Sartem hal_util_compute_udi (HalDeviceStore *store, gchar *dst, gsize dstsize, const gchar *format, ...) 408*2912Sartem { 409*2912Sartem guint i; 410*2912Sartem va_list args; 411*2912Sartem gchar buf[256]; 412*2912Sartem 413*2912Sartem va_start (args, format); 414*2912Sartem g_vsnprintf (buf, sizeof (buf), format, args); 415*2912Sartem va_end (args); 416*2912Sartem 417*2912Sartem g_strcanon (buf, 418*2912Sartem "/_" 419*2912Sartem "abcdefghijklmnopqrstuvwxyz" 420*2912Sartem "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 421*2912Sartem "1234567890", '_'); 422*2912Sartem 423*2912Sartem g_strlcpy (dst, buf, dstsize); 424*2912Sartem if (hal_device_store_find (store, dst) == NULL) 425*2912Sartem goto out; 426*2912Sartem 427*2912Sartem for (i = 0; ; i++) { 428*2912Sartem g_snprintf (dst, dstsize, "%s_%d", buf, i); 429*2912Sartem if (hal_device_store_find (store, dst) == NULL) 430*2912Sartem goto out; 431*2912Sartem } 432*2912Sartem 433*2912Sartem out: 434*2912Sartem ; 435*2912Sartem } 436*2912Sartem 437*2912Sartem 438*2912Sartem gboolean 439*2912Sartem hal_util_path_ascend (gchar *path) 440*2912Sartem { 441*2912Sartem gchar *p; 442*2912Sartem 443*2912Sartem if (path == NULL) 444*2912Sartem return FALSE; 445*2912Sartem 446*2912Sartem p = strrchr (path, '/'); 447*2912Sartem if (p == NULL) 448*2912Sartem return FALSE; 449*2912Sartem 450*2912Sartem *p = '\0'; 451*2912Sartem return TRUE; 452*2912Sartem } 453*2912Sartem 454*2912Sartem static gboolean _grep_can_reuse = FALSE; 455*2912Sartem 456*2912Sartem void 457*2912Sartem hal_util_grep_discard_existing_data (void) 458*2912Sartem { 459*2912Sartem _grep_can_reuse = FALSE; 460*2912Sartem } 461*2912Sartem 462*2912Sartem /** Given a directory and filename, open the file and search for the 463*2912Sartem * first line that starts with the given linestart string. Returns 464*2912Sartem * the rest of the line as a string if found. 465*2912Sartem * 466*2912Sartem * @param directory Directory, e.g. "/proc/acpi/battery/BAT0" 467*2912Sartem * @param file File, e.g. "info" 468*2912Sartem * @param linestart Start of line, e.g. "serial number" 469*2912Sartem * @param reuse Whether we should reuse the file contents 470*2912Sartem * if the file is the same; can be cleared 471*2912Sartem * with hal_util_grep_discard_existing_data() 472*2912Sartem * @return NULL if not found, otherwise the remainder 473*2912Sartem * of the line, e.g. ": 21805" if 474*2912Sartem * the file /proc/acpi/battery/BAT0 contains 475*2912Sartem * this line "serial number: 21805" 476*2912Sartem * The string is only valid until the next 477*2912Sartem * invocation of this function. 478*2912Sartem */ 479*2912Sartem gchar * 480*2912Sartem hal_util_grep_file (const gchar *directory, const gchar *file, const gchar *linestart, gboolean reuse) 481*2912Sartem { 482*2912Sartem static gchar buf[2048]; 483*2912Sartem static unsigned int bufsize; 484*2912Sartem static gchar filename[HAL_PATH_MAX]; 485*2912Sartem static gchar oldfilename[HAL_PATH_MAX]; 486*2912Sartem gchar *result; 487*2912Sartem gsize linestart_len; 488*2912Sartem gchar *p; 489*2912Sartem 490*2912Sartem result = NULL; 491*2912Sartem 492*2912Sartem /* TODO: use reuse and _grep_can_reuse parameters to avoid loading 493*2912Sartem * the file again and again 494*2912Sartem */ 495*2912Sartem 496*2912Sartem if (file != NULL && strlen (file) > 0) 497*2912Sartem snprintf (filename, sizeof (filename), "%s/%s", directory, file); 498*2912Sartem else 499*2912Sartem strncpy (filename, directory, sizeof (filename)); 500*2912Sartem 501*2912Sartem if (_grep_can_reuse && reuse && strcmp (oldfilename, filename) == 0) { 502*2912Sartem /* just reuse old file; e.g. bufsize, buf */ 503*2912Sartem /*HAL_INFO (("hal_util_grep_file: reusing buf for %s", filename));*/ 504*2912Sartem } else { 505*2912Sartem FILE *f; 506*2912Sartem 507*2912Sartem f = fopen (filename, "r"); 508*2912Sartem if (f == NULL) 509*2912Sartem goto out; 510*2912Sartem bufsize = fread (buf, sizeof (char), sizeof (buf) - 1, f); 511*2912Sartem buf[bufsize] = '\0'; 512*2912Sartem fclose (f); 513*2912Sartem 514*2912Sartem /*HAL_INFO (("hal_util_grep_file: read %s of %d bytes", filename, bufsize));*/ 515*2912Sartem } 516*2912Sartem 517*2912Sartem /* book keeping */ 518*2912Sartem _grep_can_reuse = TRUE; 519*2912Sartem strncpy (oldfilename, filename, sizeof(oldfilename)); 520*2912Sartem 521*2912Sartem linestart_len = strlen (linestart); 522*2912Sartem 523*2912Sartem /* analyze buf */ 524*2912Sartem p = buf; 525*2912Sartem do { 526*2912Sartem unsigned int linelen; 527*2912Sartem static char line[256]; 528*2912Sartem 529*2912Sartem for (linelen = 0; p[linelen] != '\n' && p[linelen] != '\0'; linelen++) 530*2912Sartem ; 531*2912Sartem 532*2912Sartem if (linelen < sizeof (line)) { 533*2912Sartem 534*2912Sartem strncpy (line, p, linelen); 535*2912Sartem line[linelen] = '\0'; 536*2912Sartem 537*2912Sartem if (strncmp (line, linestart, linestart_len) == 0) { 538*2912Sartem result = line + linestart_len; 539*2912Sartem goto out; 540*2912Sartem } 541*2912Sartem } 542*2912Sartem 543*2912Sartem p += linelen + 1; 544*2912Sartem 545*2912Sartem } while (p < buf + bufsize); 546*2912Sartem 547*2912Sartem out: 548*2912Sartem return result; 549*2912Sartem } 550*2912Sartem 551*2912Sartem gchar * 552*2912Sartem hal_util_grep_string_elem_from_file (const gchar *directory, const gchar *file, 553*2912Sartem const gchar *linestart, guint elem, gboolean reuse) 554*2912Sartem { 555*2912Sartem gchar *line; 556*2912Sartem gchar *res; 557*2912Sartem static gchar buf[256]; 558*2912Sartem gchar **tokens; 559*2912Sartem guint i, j; 560*2912Sartem 561*2912Sartem res = NULL; 562*2912Sartem tokens = NULL; 563*2912Sartem 564*2912Sartem if (((line = hal_util_grep_file (directory, file, linestart, reuse)) == NULL) || (strlen (line) == 0)) 565*2912Sartem goto out; 566*2912Sartem 567*2912Sartem tokens = g_strsplit_set (line, " \t:", 0); 568*2912Sartem for (i = 0, j = 0; tokens[i] != NULL; i++) { 569*2912Sartem if (strlen (tokens[i]) == 0) 570*2912Sartem continue; 571*2912Sartem if (j == elem) { 572*2912Sartem strncpy (buf, tokens[i], sizeof (buf)); 573*2912Sartem res = buf; 574*2912Sartem goto out; 575*2912Sartem } 576*2912Sartem j++; 577*2912Sartem } 578*2912Sartem 579*2912Sartem out: 580*2912Sartem if (tokens != NULL) 581*2912Sartem g_strfreev (tokens); 582*2912Sartem 583*2912Sartem return res; 584*2912Sartem } 585*2912Sartem 586*2912Sartem gint 587*2912Sartem hal_util_grep_int_elem_from_file (const gchar *directory, const gchar *file, 588*2912Sartem const gchar *linestart, guint elem, guint base, gboolean reuse) 589*2912Sartem { 590*2912Sartem gchar *endptr; 591*2912Sartem gchar *strvalue; 592*2912Sartem int value; 593*2912Sartem 594*2912Sartem value = G_MAXINT; 595*2912Sartem 596*2912Sartem strvalue = hal_util_grep_string_elem_from_file (directory, file, linestart, elem, reuse); 597*2912Sartem if (strvalue == NULL) 598*2912Sartem goto out; 599*2912Sartem 600*2912Sartem value = strtol (strvalue, &endptr, base); 601*2912Sartem if (endptr == strvalue) { 602*2912Sartem value = G_MAXINT; 603*2912Sartem goto out; 604*2912Sartem } 605*2912Sartem 606*2912Sartem out: 607*2912Sartem return value; 608*2912Sartem } 609*2912Sartem 610*2912Sartem /** Get a string value from a formatted text file and assign it to 611*2912Sartem * a property on a device object. 612*2912Sartem * 613*2912Sartem * Example: Given that the file /proc/acpi/battery/BAT0/info contains 614*2912Sartem * the line 615*2912Sartem * 616*2912Sartem * "design voltage: 10800 mV" 617*2912Sartem * 618*2912Sartem * then hal_util_set_string_elem_from_file (d, "battery.foo", 619*2912Sartem * "/proc/acpi/battery/BAT0", "info", "design voltage", 1) will assign 620*2912Sartem * the string "mV" to the property "battery.foo" on d. 621*2912Sartem * 622*2912Sartem * @param d Device object 623*2912Sartem * @param key Property name 624*2912Sartem * @param directory Directory, e.g. "/proc/acpi/battery/BAT0" 625*2912Sartem * @param file File, e.g. "info" 626*2912Sartem * @param linestart Start of line, e.g. "design voltage" 627*2912Sartem * @param elem Element number after linestart to extract 628*2912Sartem * excluding whitespace and ':' characters. 629*2912Sartem * @return TRUE, if, and only if, the value could be 630*2912Sartem * extracted and the property was set 631*2912Sartem */ 632*2912Sartem gboolean 633*2912Sartem hal_util_set_string_elem_from_file (HalDevice *d, const gchar *key, 634*2912Sartem const gchar *directory, const gchar *file, 635*2912Sartem const gchar *linestart, guint elem, gboolean reuse) 636*2912Sartem { 637*2912Sartem gboolean res; 638*2912Sartem gchar *value; 639*2912Sartem 640*2912Sartem res = FALSE; 641*2912Sartem 642*2912Sartem if ((value = hal_util_grep_string_elem_from_file (directory, file, linestart, elem, reuse)) == NULL) 643*2912Sartem goto out; 644*2912Sartem 645*2912Sartem res = hal_device_property_set_string (d, key, value); 646*2912Sartem out: 647*2912Sartem return res; 648*2912Sartem } 649*2912Sartem 650*2912Sartem /** Get an integer value from a formatted text file and assign it to 651*2912Sartem * a property on a device object. 652*2912Sartem * 653*2912Sartem * Example: Given that the file /proc/acpi/battery/BAT0/info contains 654*2912Sartem * the line 655*2912Sartem * 656*2912Sartem * "design voltage: 10800 mV" 657*2912Sartem * 658*2912Sartem * then hal_util_set_int_elem_from_file (d, "battery.foo", 659*2912Sartem * "/proc/acpi/battery/BAT0", "info", "design voltage", 0) will assign 660*2912Sartem * the integer 10800 to the property "battery.foo" on d. 661*2912Sartem * 662*2912Sartem * @param d Device object 663*2912Sartem * @param key Property name 664*2912Sartem * @param directory Directory, e.g. "/proc/acpi/battery/BAT0" 665*2912Sartem * @param file File, e.g. "info" 666*2912Sartem * @param linestart Start of line, e.g. "design voltage" 667*2912Sartem * @param elem Element number after linestart to extract 668*2912Sartem * excluding whitespace and ':' characters. 669*2912Sartem * @return TRUE, if, and only if, the value could be 670*2912Sartem * extracted and the property was set 671*2912Sartem */ 672*2912Sartem gboolean 673*2912Sartem hal_util_set_int_elem_from_file (HalDevice *d, const gchar *key, 674*2912Sartem const gchar *directory, const gchar *file, 675*2912Sartem const gchar *linestart, guint elem, guint base, gboolean reuse) 676*2912Sartem { 677*2912Sartem gchar *endptr; 678*2912Sartem gboolean res; 679*2912Sartem gchar *strvalue; 680*2912Sartem int value; 681*2912Sartem 682*2912Sartem res = FALSE; 683*2912Sartem 684*2912Sartem strvalue = hal_util_grep_string_elem_from_file (directory, file, linestart, elem, reuse); 685*2912Sartem if (strvalue == NULL) 686*2912Sartem goto out; 687*2912Sartem 688*2912Sartem value = strtol (strvalue, &endptr, base); 689*2912Sartem if (endptr == strvalue) 690*2912Sartem goto out; 691*2912Sartem 692*2912Sartem res = hal_device_property_set_int (d, key, value); 693*2912Sartem 694*2912Sartem out: 695*2912Sartem return res; 696*2912Sartem 697*2912Sartem } 698*2912Sartem 699*2912Sartem /** Get a value from a formatted text file, test it against a given 700*2912Sartem * value, and set a boolean property on a device object with the 701*2912Sartem * test result. 702*2912Sartem * 703*2912Sartem * Example: Given that the file /proc/acpi/battery/BAT0/info contains 704*2912Sartem * the line 705*2912Sartem * 706*2912Sartem * "present: yes" 707*2912Sartem * 708*2912Sartem * then hal_util_set_bool_elem_from_file (d, "battery.baz", 709*2912Sartem * "/proc/acpi/battery/BAT0", "info", "present", 0, "yes") will assign 710*2912Sartem * the boolean TRUE to the property "battery.baz" on d. 711*2912Sartem * 712*2912Sartem * If, instead, the line was 713*2912Sartem * 714*2912Sartem * "present: no" 715*2912Sartem * 716*2912Sartem * the value assigned will be FALSE. 717*2912Sartem * 718*2912Sartem * @param d Device object 719*2912Sartem * @param key Property name 720*2912Sartem * @param directory Directory, e.g. "/proc/acpi/battery/BAT0" 721*2912Sartem * @param file File, e.g. "info" 722*2912Sartem * @param linestart Start of line, e.g. "design voltage" 723*2912Sartem * @param elem Element number after linestart to extract 724*2912Sartem * excluding whitespace and ':' characters. 725*2912Sartem * @param expected Value to test against 726*2912Sartem * @return TRUE, if, and only if, the value could be 727*2912Sartem * extracted and the property was set 728*2912Sartem */ 729*2912Sartem gboolean 730*2912Sartem hal_util_set_bool_elem_from_file (HalDevice *d, const gchar *key, 731*2912Sartem const gchar *directory, const gchar *file, 732*2912Sartem const gchar *linestart, guint elem, const gchar *expected, gboolean reuse) 733*2912Sartem { 734*2912Sartem gchar *line; 735*2912Sartem gboolean res; 736*2912Sartem gchar **tokens; 737*2912Sartem guint i, j; 738*2912Sartem 739*2912Sartem res = FALSE; 740*2912Sartem tokens = NULL; 741*2912Sartem 742*2912Sartem if (((line = hal_util_grep_file (directory, file, linestart, reuse)) == NULL) || (strlen (line) == 0)) 743*2912Sartem goto out; 744*2912Sartem 745*2912Sartem tokens = g_strsplit_set (line, " \t:", 0); 746*2912Sartem 747*2912Sartem for (i = 0, j = 0; tokens[i] != NULL; i++) { 748*2912Sartem if (strlen (tokens[i]) == 0) 749*2912Sartem continue; 750*2912Sartem if (j == elem) { 751*2912Sartem hal_device_property_set_bool (d, key, strcmp (tokens[i], expected) == 0); 752*2912Sartem res = TRUE; 753*2912Sartem goto out; 754*2912Sartem } 755*2912Sartem j++; 756*2912Sartem } 757*2912Sartem 758*2912Sartem 759*2912Sartem out: 760*2912Sartem if (tokens != NULL) 761*2912Sartem g_strfreev (tokens); 762*2912Sartem 763*2912Sartem return res; 764*2912Sartem } 765*2912Sartem 766*2912Sartem gchar ** 767*2912Sartem hal_util_dup_strv_from_g_slist (GSList *strlist) 768*2912Sartem { 769*2912Sartem guint j; 770*2912Sartem guint len; 771*2912Sartem gchar **strv; 772*2912Sartem GSList *i; 773*2912Sartem 774*2912Sartem len = g_slist_length (strlist); 775*2912Sartem strv = g_new (char *, len + 1); 776*2912Sartem 777*2912Sartem for (i = strlist, j = 0; i != NULL; i = g_slist_next (i), j++) { 778*2912Sartem strv[j] = g_strdup ((const gchar *) i->data); 779*2912Sartem } 780*2912Sartem strv[j] = NULL; 781*2912Sartem 782*2912Sartem return strv; 783*2912Sartem } 784*2912Sartem 785*2912Sartem /* -------------------------------------------------------------------------------------------------------------- */ 786*2912Sartem 787*2912Sartem typedef struct { 788*2912Sartem HalDevice *d; 789*2912Sartem gchar **programs; 790*2912Sartem gchar **extra_env; 791*2912Sartem guint next_program; 792*2912Sartem 793*2912Sartem HalCalloutsDone callback; 794*2912Sartem gpointer userdata1; 795*2912Sartem gpointer userdata2; 796*2912Sartem 797*2912Sartem } Callout; 798*2912Sartem 799*2912Sartem static void callout_do_next (Callout *c); 800*2912Sartem 801*2912Sartem static void 802*2912Sartem callout_terminated (HalDevice *d, guint32 exit_type, 803*2912Sartem gint return_code, gchar **error, 804*2912Sartem gpointer data1, gpointer data2) 805*2912Sartem { 806*2912Sartem Callout *c; 807*2912Sartem 808*2912Sartem c = (Callout *) data1; 809*2912Sartem callout_do_next (c); 810*2912Sartem } 811*2912Sartem 812*2912Sartem static void 813*2912Sartem callout_do_next (Callout *c) 814*2912Sartem { 815*2912Sartem 816*2912Sartem /* Check if we're done */ 817*2912Sartem if (c->programs[c->next_program] == NULL) { 818*2912Sartem HalDevice *d; 819*2912Sartem gpointer userdata1; 820*2912Sartem gpointer userdata2; 821*2912Sartem HalCalloutsDone callback; 822*2912Sartem 823*2912Sartem d = c->d; 824*2912Sartem userdata1 = c->userdata1; 825*2912Sartem userdata2 = c->userdata2; 826*2912Sartem callback = c->callback; 827*2912Sartem 828*2912Sartem g_strfreev (c->programs); 829*2912Sartem g_strfreev (c->extra_env); 830*2912Sartem g_free (c); 831*2912Sartem 832*2912Sartem callback (d, userdata1, userdata2); 833*2912Sartem 834*2912Sartem } else { 835*2912Sartem hald_runner_run(c->d, c->programs[c->next_program], c->extra_env, 836*2912Sartem HAL_HELPER_TIMEOUT, callout_terminated, 837*2912Sartem (gpointer)c, NULL); 838*2912Sartem c->next_program++; 839*2912Sartem } 840*2912Sartem } 841*2912Sartem 842*2912Sartem static void 843*2912Sartem hal_callout_device (HalDevice *d, HalCalloutsDone callback, gpointer userdata1, gpointer userdata2, 844*2912Sartem GSList *programs, gchar **extra_env) 845*2912Sartem { 846*2912Sartem Callout *c; 847*2912Sartem 848*2912Sartem c = g_new0 (Callout, 1); 849*2912Sartem c->d = d; 850*2912Sartem c->callback = callback; 851*2912Sartem c->userdata1 = userdata1; 852*2912Sartem c->userdata2 = userdata2; 853*2912Sartem c->programs = hal_util_dup_strv_from_g_slist (programs); 854*2912Sartem c->extra_env = g_strdupv (extra_env); 855*2912Sartem c->next_program = 0; 856*2912Sartem 857*2912Sartem callout_do_next (c); 858*2912Sartem } 859*2912Sartem 860*2912Sartem void 861*2912Sartem hal_util_callout_device_add (HalDevice *d, HalCalloutsDone callback, gpointer userdata1, gpointer userdata2) 862*2912Sartem { 863*2912Sartem GSList *programs; 864*2912Sartem gchar *extra_env[2] = {"HALD_ACTION=add", NULL}; 865*2912Sartem 866*2912Sartem if ((programs = hal_device_property_get_strlist (d, "info.callouts.add")) == NULL) { 867*2912Sartem callback (d, userdata1, userdata2); 868*2912Sartem goto out; 869*2912Sartem } 870*2912Sartem 871*2912Sartem HAL_INFO (("Add callouts for udi=%s", d->udi)); 872*2912Sartem 873*2912Sartem hal_callout_device (d, callback, userdata1, userdata2, programs, extra_env); 874*2912Sartem out: 875*2912Sartem ; 876*2912Sartem } 877*2912Sartem 878*2912Sartem void 879*2912Sartem hal_util_callout_device_remove (HalDevice *d, HalCalloutsDone callback, gpointer userdata1, gpointer userdata2) 880*2912Sartem { 881*2912Sartem GSList *programs; 882*2912Sartem gchar *extra_env[2] = {"HALD_ACTION=remove", NULL}; 883*2912Sartem 884*2912Sartem if ((programs = hal_device_property_get_strlist (d, "info.callouts.remove")) == NULL) { 885*2912Sartem callback (d, userdata1, userdata2); 886*2912Sartem goto out; 887*2912Sartem } 888*2912Sartem 889*2912Sartem HAL_INFO (("Remove callouts for udi=%s", d->udi)); 890*2912Sartem 891*2912Sartem hal_callout_device (d, callback, userdata1, userdata2, programs, extra_env); 892*2912Sartem out: 893*2912Sartem ; 894*2912Sartem } 895*2912Sartem 896*2912Sartem void 897*2912Sartem hal_util_callout_device_preprobe (HalDevice *d, HalCalloutsDone callback, gpointer userdata1, gpointer userdata2) 898*2912Sartem { 899*2912Sartem GSList *programs; 900*2912Sartem gchar *extra_env[2] = {"HALD_ACTION=preprobe", NULL}; 901*2912Sartem 902*2912Sartem if ((programs = hal_device_property_get_strlist (d, "info.callouts.preprobe")) == NULL) { 903*2912Sartem callback (d, userdata1, userdata2); 904*2912Sartem goto out; 905*2912Sartem } 906*2912Sartem 907*2912Sartem HAL_INFO (("Preprobe callouts for udi=%s", d->udi)); 908*2912Sartem 909*2912Sartem hal_callout_device (d, callback, userdata1, userdata2, programs, extra_env); 910*2912Sartem out: 911*2912Sartem ; 912*2912Sartem } 913*2912Sartem 914*2912Sartem gchar * 915*2912Sartem hal_util_strdup_valid_utf8 (const char *str) 916*2912Sartem { 917*2912Sartem char *endchar; 918*2912Sartem char *newstr; 919*2912Sartem unsigned int count = 0; 920*2912Sartem 921*2912Sartem if (str == NULL) 922*2912Sartem return NULL; 923*2912Sartem 924*2912Sartem newstr = g_strdup (str); 925*2912Sartem 926*2912Sartem while (!g_utf8_validate (newstr, -1, (const char **) &endchar)) { 927*2912Sartem *endchar = '?'; 928*2912Sartem count++; 929*2912Sartem } 930*2912Sartem 931*2912Sartem if (strlen(newstr) == count) 932*2912Sartem return NULL; 933*2912Sartem else 934*2912Sartem return newstr; 935*2912Sartem } 936*2912Sartem 937*2912Sartem void 938*2912Sartem hal_util_hexdump (const void *mem, unsigned int size) 939*2912Sartem { 940*2912Sartem unsigned int i; 941*2912Sartem unsigned int j; 942*2912Sartem unsigned int n; 943*2912Sartem const char *buf = (const char *) mem; 944*2912Sartem 945*2912Sartem n = 0; 946*2912Sartem printf ("Dumping %d=0x%x bytes\n", size, size); 947*2912Sartem while (n < size) { 948*2912Sartem 949*2912Sartem printf ("0x%04x: ", n); 950*2912Sartem 951*2912Sartem j = n; 952*2912Sartem for (i = 0; i < 16; i++) { 953*2912Sartem if (j >= size) 954*2912Sartem break; 955*2912Sartem printf ("%02x ", buf[j]); 956*2912Sartem j++; 957*2912Sartem } 958*2912Sartem 959*2912Sartem for ( ; i < 16; i++) { 960*2912Sartem printf (" "); 961*2912Sartem } 962*2912Sartem 963*2912Sartem printf (" "); 964*2912Sartem 965*2912Sartem j = n; 966*2912Sartem for (i = 0; i < 16; i++) { 967*2912Sartem if (j >= size) 968*2912Sartem break; 969*2912Sartem printf ("%c", isprint(buf[j]) ? buf[j] : '.'); 970*2912Sartem j++; 971*2912Sartem } 972*2912Sartem 973*2912Sartem printf ("\n"); 974*2912Sartem 975*2912Sartem n += 16; 976*2912Sartem } 977*2912Sartem } 978*2912Sartem 979*2912Sartem gboolean 980*2912Sartem hal_util_is_mounted_by_hald (const char *mount_point) 981*2912Sartem { 982*2912Sartem int i; 983*2912Sartem FILE *hal_mtab; 984*2912Sartem int hal_mtab_len; 985*2912Sartem int num_read; 986*2912Sartem char *hal_mtab_buf; 987*2912Sartem char **lines; 988*2912Sartem gboolean found; 989*2912Sartem 990*2912Sartem hal_mtab = NULL; 991*2912Sartem hal_mtab_buf = NULL; 992*2912Sartem found = FALSE; 993*2912Sartem 994*2912Sartem /*HAL_DEBUG (("examining /media/.hal-mtab for %s", mount_point));*/ 995*2912Sartem 996*2912Sartem hal_mtab = fopen ("/media/.hal-mtab", "r"); 997*2912Sartem if (hal_mtab == NULL) { 998*2912Sartem HAL_ERROR (("Cannot open /media/.hal-mtab")); 999*2912Sartem goto out; 1000*2912Sartem } 1001*2912Sartem if (fseek (hal_mtab, 0L, SEEK_END) != 0) { 1002*2912Sartem HAL_ERROR (("Cannot seek to end of /media/.hal-mtab")); 1003*2912Sartem goto out; 1004*2912Sartem } 1005*2912Sartem hal_mtab_len = ftell (hal_mtab); 1006*2912Sartem if (hal_mtab_len < 0) { 1007*2912Sartem HAL_ERROR (("Cannot determine size of /media/.hal-mtab")); 1008*2912Sartem goto out; 1009*2912Sartem } 1010*2912Sartem rewind (hal_mtab); 1011*2912Sartem 1012*2912Sartem hal_mtab_buf = g_new0 (char, hal_mtab_len + 1); 1013*2912Sartem num_read = fread (hal_mtab_buf, 1, hal_mtab_len, hal_mtab); 1014*2912Sartem if (num_read != hal_mtab_len) { 1015*2912Sartem HAL_ERROR (("Cannot read from /media/.hal-mtab")); 1016*2912Sartem goto out; 1017*2912Sartem } 1018*2912Sartem fclose (hal_mtab); 1019*2912Sartem hal_mtab = NULL; 1020*2912Sartem 1021*2912Sartem /*HAL_DEBUG (("hal_mtab = '%s'\n", hal_mtab_buf));*/ 1022*2912Sartem 1023*2912Sartem lines = g_strsplit (hal_mtab_buf, "\n", 0); 1024*2912Sartem g_free (hal_mtab_buf); 1025*2912Sartem hal_mtab_buf = NULL; 1026*2912Sartem 1027*2912Sartem /* find the entry we're going to unmount */ 1028*2912Sartem for (i = 0; lines[i] != NULL && !found; i++) { 1029*2912Sartem char **line_elements; 1030*2912Sartem 1031*2912Sartem /*HAL_DEBUG ((" line = '%s'", lines[i]));*/ 1032*2912Sartem 1033*2912Sartem if ((lines[i])[0] == '#') 1034*2912Sartem continue; 1035*2912Sartem 1036*2912Sartem line_elements = g_strsplit (lines[i], "\t", 6); 1037*2912Sartem if (g_strv_length (line_elements) == 6) { 1038*2912Sartem /* 1039*2912Sartem HAL_DEBUG ((" devfile = '%s'", line_elements[0])); 1040*2912Sartem HAL_DEBUG ((" uid = '%s'", line_elements[1])); 1041*2912Sartem HAL_DEBUG ((" session id = '%s'", line_elements[2])); 1042*2912Sartem HAL_DEBUG ((" fs = '%s'", line_elements[3])); 1043*2912Sartem HAL_DEBUG ((" options = '%s'", line_elements[4])); 1044*2912Sartem HAL_DEBUG ((" mount_point = '%s'", line_elements[5])); 1045*2912Sartem HAL_DEBUG ((" (comparing against '%s')", mount_point)); 1046*2912Sartem */ 1047*2912Sartem 1048*2912Sartem if (strcmp (line_elements[5], mount_point) == 0) { 1049*2912Sartem found = TRUE; 1050*2912Sartem /*HAL_INFO (("device at '%s' is indeed mounted by HAL's Mount()", mount_point));*/ 1051*2912Sartem } 1052*2912Sartem 1053*2912Sartem } 1054*2912Sartem 1055*2912Sartem g_strfreev (line_elements); 1056*2912Sartem } 1057*2912Sartem 1058*2912Sartem g_strfreev (lines); 1059*2912Sartem 1060*2912Sartem out: 1061*2912Sartem if (hal_mtab != NULL) 1062*2912Sartem fclose (hal_mtab); 1063*2912Sartem if (hal_mtab_buf != NULL) 1064*2912Sartem g_free (hal_mtab_buf); 1065*2912Sartem 1066*2912Sartem return found; 1067*2912Sartem } 1068*2912Sartem 1069*2912Sartem void 1070*2912Sartem hal_util_branch_claim (HalDeviceStore *store, HalDevice *root, dbus_bool_t claimed, 1071*2912Sartem const char *service, int uid) 1072*2912Sartem { 1073*2912Sartem GSList *children; 1074*2912Sartem GSList *i; 1075*2912Sartem HalDevice *d; 1076*2912Sartem 1077*2912Sartem if (claimed) { 1078*2912Sartem hal_device_property_set_bool (root, "info.claimed", claimed); 1079*2912Sartem hal_device_property_set_string (root, "info.claimed.service", service); 1080*2912Sartem hal_device_property_set_int (root, "info.claimed.uid", uid); 1081*2912Sartem } else { 1082*2912Sartem hal_device_property_remove (root, "info.claimed"); 1083*2912Sartem hal_device_property_remove (root, "info.claimed.service"); 1084*2912Sartem hal_device_property_remove (root, "info.claimed.uid"); 1085*2912Sartem } 1086*2912Sartem 1087*2912Sartem 1088*2912Sartem children = hal_device_store_match_multiple_key_value_string (store, 1089*2912Sartem "info.parent", root->udi); 1090*2912Sartem 1091*2912Sartem for (i = children; i != NULL; i = g_slist_next (i)) { 1092*2912Sartem d = HAL_DEVICE (i->data); 1093*2912Sartem hal_util_branch_claim (store, d, claimed, service, uid); 1094*2912Sartem } 1095*2912Sartem 1096*2912Sartem g_slist_free (children); 1097*2912Sartem } 1098