static void print_tags(blkid_dev dev, char *show[], int output) { blkid_tag_iterate iter; const char *type, *value, *devname; int num = 1; if (!dev) return; if (output & OUTPUT_PRETTY_LIST) { pretty_print_dev(dev); return; } devname = blkid_dev_devname(dev); if (output & OUTPUT_DEVICE_ONLY) { printf("%s\n", devname); return; } iter = blkid_tag_iterate_begin(dev); while (blkid_tag_next(iter, &type, &value) == 0) { if (show[0] && !has_item(show, type)) continue; print_value(output, num++, devname, value, type, strlen(value)); } blkid_tag_iterate_end(iter); if (num > 1 && !(output & (OUTPUT_VALUE_ONLY | OUTPUT_UDEV_LIST))) printf("\n"); }
static void pretty_print_dev(blkid_dev dev) { blkid_tag_iterate iter; const char *type, *value, *devname; const char *uuid = "", *fs_type = "", *label = ""; int len, mount_flags; char mtpt[80]; errcode_t retval; if (dev == NULL) { pretty_print_line("device", "fs_type", "label", "mount point", "UUID"); for (len=get_terminal_width()-1; len > 0; len--) fputc('-', stdout); fputc('\n', stdout); return; } devname = blkid_dev_devname(dev); if (access(devname, F_OK)) return; /* Get the uuid, label, type */ iter = blkid_tag_iterate_begin(dev); while (blkid_tag_next(iter, &type, &value) == 0) { if (!strcmp(type, "UUID")) uuid = value; if (!strcmp(type, "TYPE")) fs_type = value; if (!strcmp(type, "LABEL")) label = value; } blkid_tag_iterate_end(iter); /* Get the mount point */ mtpt[0] = 0; retval = ext2fs_check_mount_point(devname, &mount_flags, mtpt, sizeof(mtpt)); if (retval == 0) { if (mount_flags & EXT2_MF_MOUNTED) { if (!mtpt[0]) strcpy(mtpt, "(mounted, mtpt unknown)"); } else if (mount_flags & EXT2_MF_BUSY) strcpy(mtpt, "(in use)"); else strcpy(mtpt, "(not mounted)"); } pretty_print_line(devname, fs_type, label, mtpt, uuid); }
static void print_tags(blkid_dev dev, char *show[], int numtag, int output) { blkid_tag_iterate iter; const char *type, *value; int i, first = 1; if (!dev) return; if (output & OUTPUT_PRETTY_LIST) { pretty_print_dev(dev); return; } if (output & OUTPUT_DEVICE_ONLY) { printf("%s\n", blkid_dev_devname(dev)); return; } iter = blkid_tag_iterate_begin(dev); while (blkid_tag_next(iter, &type, &value) == 0) { if (numtag && show) { for (i=0; i < numtag; i++) if (!strcmp(type, show[i])) break; if (i >= numtag) continue; } if (output & OUTPUT_VALUE_ONLY) { fputs(value, stdout); fputc('\n', stdout); } else { if (first) { printf("%s: ", blkid_dev_devname(dev)); first = 0; } fputs(type, stdout); fputs("=\"", stdout); safe_print(value, -1); fputs("\" ", stdout); } } blkid_tag_iterate_end(iter); if (!first && !(output & OUTPUT_VALUE_ONLY)) printf("\n"); }
static void print_tags(blkid_dev dev, char *show[], int output) { blkid_tag_iterate iter; const char *type, *value, *devname; int num = 1; static int first = 1; if (!dev) return; if (output & OUTPUT_PRETTY_LIST) { pretty_print_dev(dev); return; } devname = blkid_dev_devname(dev); if (output & OUTPUT_DEVICE_ONLY) { printf("%s\n", devname); return; } iter = blkid_tag_iterate_begin(dev); while (blkid_tag_next(iter, &type, &value) == 0) { if (show[0] && !has_item(show, type)) continue; if (num == 1 && !first && (output & (OUTPUT_UDEV_LIST | OUTPUT_EXPORT_LIST))) /* add extra line between output from more devices */ fputc('\n', stdout); print_value(output, num++, devname, value, type, strlen(value)); } blkid_tag_iterate_end(iter); if (num > 1) { if (!(output & (OUTPUT_VALUE_ONLY | OUTPUT_UDEV_LIST | OUTPUT_EXPORT_LIST))) printf("\n"); first = 0; } }
static void print_tags(blkid_dev dev, char *show[], int numtag, int output) { blkid_tag_iterate iter; const char *type, *value; int i, first = 1; if (!dev) return; if (output & OUTPUT_DEVICE_ONLY) { printf("%s\n", blkid_dev_devname(dev)); return; } iter = blkid_tag_iterate_begin(dev); while (blkid_tag_next(iter, &type, &value) == 0) { if (numtag && show) { for (i=0; i < numtag; i++) if (!strcmp(type, show[i])) break; if (i >= numtag) continue; } if (first && !(output & OUTPUT_VALUE_ONLY)) { printf("%s: ", blkid_dev_devname(dev)); first = 0; } if ((output & OUTPUT_VALUE_ONLY)) printf("%s\n", value); else printf("%s=\"%s\" ", type, value); } blkid_tag_iterate_end(iter); if (!first && !(output & OUTPUT_VALUE_ONLY)) printf("\n"); }
/* * Verify that the data in dev is consistent with what is on the actual * block device (using the devname field only). Normally this will be * called when finding items in the cache, but for long running processes * is also desirable to revalidate an item before use. * * If we are unable to revalidate the data, we return the old data and * do not set the BLKID_BID_FL_VERIFIED flag on it. */ blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) { struct stat st; time_t diff, now; char *fltr[2]; int fd; if (!dev) return NULL; now = time(0); diff = now - dev->bid_time; if (stat(dev->bid_name, &st) < 0) { DBG(DEBUG_PROBE, printf("blkid_verify: error %m (%d) while " "trying to stat %s\n", errno, dev->bid_name)); open_err: if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) { /* We don't have read permission, just return cache data. */ DBG(DEBUG_PROBE, printf("returning unverified data for %s\n", dev->bid_name)); return dev; } blkid_free_dev(dev); return NULL; } if (now >= dev->bid_time && #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC (st.st_mtime < dev->bid_time || (st.st_mtime == dev->bid_time && st.st_mtim.tv_nsec / 1000 <= dev->bid_utime)) && #else st.st_mtime <= dev->bid_time && #endif (diff < BLKID_PROBE_MIN || (dev->bid_flags & BLKID_BID_FL_VERIFIED && diff < BLKID_PROBE_INTERVAL))) return dev; #ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC DBG(DEBUG_PROBE, printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t" "time since last check %lu)\n", dev->bid_name, (unsigned long)dev->bid_time, (unsigned long)st.st_mtime, (unsigned long)diff)); #else DBG(DEBUG_PROBE, printf("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\n\t" "time since last check %lu)\n", dev->bid_name, (unsigned long)dev->bid_time, (unsigned long)dev->bid_utime, (unsigned long)st.st_mtime, (unsigned long)st.st_mtim.tv_nsec / 1000, (unsigned long)diff)); #endif if (!cache->probe) { cache->probe = blkid_new_probe(); if (!cache->probe) { blkid_free_dev(dev); return NULL; } } fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC); if (fd < 0) { DBG(DEBUG_PROBE, printf("blkid_verify: error %m (%d) while " "opening %s\n", errno, dev->bid_name)); goto open_err; } if (blkid_probe_set_device(cache->probe, fd, 0, 0)) { /* failed to read the device */ close(fd); blkid_free_dev(dev); return NULL; } blkid_probe_enable_superblocks(cache->probe, TRUE); blkid_probe_set_superblocks_flags(cache->probe, BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE); blkid_probe_enable_partitions(cache->probe, TRUE); blkid_probe_set_partitions_flags(cache->probe, BLKID_PARTS_ENTRY_DETAILS); /* * If we already know the type, then try that first. */ if (dev->bid_type) { blkid_tag_iterate iter; const char *type, *value; fltr[0] = dev->bid_type; fltr[1] = NULL; blkid_probe_filter_superblocks_type(cache->probe, BLKID_FLTR_ONLYIN, fltr); if (!blkid_do_probe(cache->probe)) goto found_type; blkid_probe_invert_superblocks_filter(cache->probe); /* * Zap the device filesystem information and try again */ DBG(DEBUG_PROBE, printf("previous fs type %s not valid, " "trying full probe\n", dev->bid_type)); iter = blkid_tag_iterate_begin(dev); while (blkid_tag_next(iter, &type, &value) == 0) blkid_set_tag(dev, type, 0, 0); blkid_tag_iterate_end(iter); } /* * Probe for all types. */ if (blkid_do_safeprobe(cache->probe)) { /* found nothing or error */ blkid_free_dev(dev); dev = NULL; } found_type: if (dev) { #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC struct timeval tv; if (!gettimeofday(&tv, NULL)) { dev->bid_time = tv.tv_sec; dev->bid_utime = tv.tv_usec; } else #endif dev->bid_time = time(0); dev->bid_devno = st.st_rdev; dev->bid_flags |= BLKID_BID_FL_VERIFIED; cache->bic_flags |= BLKID_BIC_FL_CHANGED; blkid_probe_to_tags(cache->probe, dev); DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n", dev->bid_name, (long long)st.st_rdev, dev->bid_type)); } blkid_reset_probe(cache->probe); blkid_probe_reset_superblocks_filter(cache->probe); close(fd); return dev; }
int get_devinfo(struct s_devinfo *outdev, char *indevname, int min, int maj) { char sysblkdevname[512]; blkid_tag_iterate iter; char sysblkinfo[PATH_MAX]; const char *type, *value; struct stat64 statbuf; struct dirent *dir; char temp[PATH_MAX]; blkid_dev dev; DIR *dirdesc; FILE *finfo; int found; int fd; int i; // init memset(outdev, 0, sizeof(struct s_devinfo)); // defaults values outdev->devtype=BLKDEV_INVALID; snprintf(outdev->label, sizeof(outdev->label), " "); snprintf(outdev->uuid, sizeof(outdev->uuid), "<unknown>"); snprintf(outdev->fsname, sizeof(outdev->fsname), "<unknown>"); // check the name starts with "/dev/" if ((strlen(indevname) < 5) || (memcmp(indevname, "/dev/", 5)!=0)) return -1; // get short name ("/dev/sda1" -> "sda1") snprintf(outdev->devname, sizeof(outdev->devname), "%s", indevname+5); // skip "/dev/" // get long name if there is one (eg: LVM / devmapper) snprintf(outdev->longname, sizeof(outdev->longname), "%s", indevname); if ((dirdesc=opendir("/dev/mapper"))!=NULL) { found=false; while (((dir=readdir(dirdesc)) != NULL) && found==false) { snprintf(temp, sizeof(temp), "/dev/mapper/%s", dir->d_name); if ((stat64(temp, &statbuf)==0) && S_ISBLK(statbuf.st_mode) && (major(statbuf.st_rdev)==maj) && (minor(statbuf.st_rdev)==min)) { snprintf(outdev->longname, sizeof(outdev->longname), "%s", temp); found=true; } } closedir(dirdesc); } // get device basic info (size, major, minor) if (((fd=open64(outdev->longname, O_RDONLY|O_LARGEFILE))<0) || ((outdev->devsize=lseek64(fd, 0, SEEK_END))<0) || (fstat64(fd, &statbuf)!=0) || (!S_ISBLK(statbuf.st_mode)) || (close(fd)<0)) return -1; outdev->rdev=statbuf.st_rdev; outdev->major=major(statbuf.st_rdev); outdev->minor=minor(statbuf.st_rdev); format_size(outdev->devsize, outdev->txtsize, sizeof(outdev->txtsize), 'h'); if (outdev->devsize==1024) // ignore extended partitions return -1; // devname shown in /sys/block (eg for HP-cciss: "cciss/c0d0" -> "cciss!c0d0") snprintf(sysblkdevname, sizeof(sysblkdevname), "%s", outdev->devname); for (i=0; (sysblkdevname[i]!=0) && (i<sizeof(sysblkdevname)); i++) if (sysblkdevname[i]=='/') sysblkdevname[i]='!'; // check if it's a physical disk (there is a "/sys/block/${devname}/device") snprintf(sysblkinfo, sizeof(sysblkinfo), "/sys/block/%s/device", sysblkdevname); if (stat64(sysblkinfo, &statbuf)==0) { outdev->devtype=BLKDEV_PHYSDISK; snprintf(sysblkinfo, sizeof(sysblkinfo), "/sys/block/%s/device/model", sysblkdevname); if ( ((finfo=fopen(sysblkinfo, "rb")) != NULL) && (fread(temp, 1, sizeof(temp), finfo)>0) && fclose(finfo)==0 ) for (i=0; (temp[i]!=0) && (temp[i]!='\r') && (temp[i]!='\n'); i++) outdev->name[i]=temp[i]; } else { outdev->devtype=BLKDEV_FILESYSDEV; } // get blkid infos about the device (label, uuid) blkid_cache cache = NULL; if (blkid_get_cache(&cache, NULL) < 0) return -1; if ((dev=blkid_get_dev(cache, outdev->longname, BLKID_DEV_NORMAL))!=NULL) { iter = blkid_tag_iterate_begin(dev); while (blkid_tag_next(iter, &type, &value)==0) { if (strcmp(type, "LABEL")==0) snprintf(outdev->label, sizeof(outdev->label), "%s", value); else if (strcmp(type, "UUID")==0) snprintf(outdev->uuid, sizeof(outdev->uuid), "%s", value); else if (strcmp(type, "TYPE")==0) snprintf(outdev->fsname, sizeof(outdev->fsname), "%s", value); } blkid_tag_iterate_end(iter); // workaround: blkid < 1.41 don't know ext4 and say it is ext3 instead if (strcmp(outdev->fsname, "ext3")==0) { if (ext3_test(outdev->longname)==true) snprintf(outdev->fsname, sizeof(outdev->fsname), "ext3"); else // cannot run ext4_test(): it would fail on an ext4 when e2fsprogs < 1.41 snprintf(outdev->fsname, sizeof(outdev->fsname), "ext4"); } } blkid_put_cache(cache); // free memory allocated by blkid_get_cache return 0; }
int main (int argc, char ** argv) { struct udev * udev; struct udev_device * dev; char * device = NULL; struct udev_monitor * mon = NULL; fd_set readfds; int fdcount, devnum, errcount = 0; unsigned short int i, major, minor; short int * maxminor; char * notification = NULL; char * icon = NULL; NotifyNotification * netlink; NotifyNotification *** netlinkref; blkid_cache cache = NULL; char *read = NULL; blkid_tag_iterate iter; const char *type, *value, *devname; blkid_dev blkdev; GError * error = NULL; printf("%s: %s v%s (compiled: %s)\n", argv[0], PROGNAME, VERSION, DATE); if(!notify_init("Udev-Block-Notification")) { fprintf(stderr, "%s: Can't create notify.\n", argv[0]); exit(EXIT_FAILURE); } udev = udev_new(); if(!udev) { fprintf(stderr, "%s: Can't create udev.\n", argv[0]); exit(EXIT_FAILURE); } mon = udev_monitor_new_from_netlink(udev, "udev"); udev_monitor_filter_add_match_subsystem_devtype(mon, "block", NULL); udev_monitor_enable_receiving(mon); netlinkref = malloc(256 * sizeof(size_t)); for(i = 0; i < 256; i++) netlinkref[i] = NULL; maxminor = malloc(256 * sizeof(short int)); for(i = 0; i < 256; i++) maxminor[i] = -1; while (1) { FD_ZERO(&readfds); if (mon != NULL) FD_SET(udev_monitor_get_fd(mon), &readfds); fdcount = select(udev_monitor_get_fd(mon) + 1, &readfds, NULL, NULL, NULL); if ((mon != NULL) && FD_ISSET(udev_monitor_get_fd(mon), &readfds)) { dev = udev_monitor_receive_device(mon); if(dev) { device = (char *) udev_device_get_sysname(dev); devnum = udev_device_get_devnum(dev); major = devnum / 256; minor = devnum - (major * 256); switch(udev_device_get_action(dev)[0]) { case 'a': // a: add notification = (char *) malloc(strlen(TEXT_ADD) + strlen(device)); sprintf(notification, TEXT_ADD, device, major, minor); icon = ICON_ADD; break; case 'r': // r: remove notification = (char *) malloc(strlen(TEXT_REMOVE) + strlen(device)); sprintf(notification, TEXT_REMOVE, device, major, minor); icon = ICON_REMOVE; break; case 'm': // m: move notification = (char *) malloc(strlen(TEXT_MOVE) + strlen(device)); sprintf(notification, TEXT_MOVE, device, major, minor); icon = ICON_MOVE; break; case 'c': // c: change notification = (char *) malloc(strlen(TEXT_CHANGE) + strlen(device)); sprintf(notification, TEXT_CHANGE, device, major, minor); icon = ICON_CHANGE; break; default: // we should never get here I think... notification = (char *) malloc(strlen(TEXT_DEFAULT) + strlen(device)); sprintf(notification, TEXT_CHANGE, device, major, minor); icon = ICON_DEFAULT; } blkid_get_cache(&cache, read); blkdev = blkid_get_dev(cache, udev_device_get_devnode(dev), BLKID_DEV_NORMAL); if (blkdev) { iter = blkid_tag_iterate_begin(blkdev); while (blkid_tag_next(iter, &type, &value) == 0) { notification = (char *) realloc(notification, strlen(TEXT_TAG) + strlen(notification) + strlen(type) + strlen(value)); sprintf(notification, TEXT_TAG, notification, type, value); } blkid_tag_iterate_end(iter); blkid_put_cache(cache); } printf("%s: %s\n", argv[0], notification); if (maxminor[major] < minor) { netlinkref[major] = realloc(netlinkref[major], (minor + 1) * sizeof(size_t)); while(maxminor[major] < minor) netlinkref[major][++maxminor[major]] = NULL; } if (netlinkref[major][minor] == NULL) { netlink = notify_notification_new("Udev-Block", notification, icon); netlinkref[major][minor] = netlink; } else { netlink = netlinkref[major][minor]; notify_notification_update(netlink, "Udev-Block", notification, icon); } notify_notification_set_timeout(netlink, NOTIFICATION_TIMEOUT); notify_notification_set_category(netlink, "Udev-Block"); notify_notification_set_urgency (netlink, NOTIFY_URGENCY_NORMAL); while(!notify_notification_show(netlink, &error)) { if (errcount > 1) { fprintf(stderr, "%s: Looks like we can not reconnect to notification daemon... Exiting.\n", argv[0]); exit(EXIT_FAILURE); } else { g_printerr("%s: Error \"%s\" while trying to show notification. Trying to reconnect.\n", argv[0], error->message); errcount++; g_error_free(error); error = NULL; notify_uninit(); usleep(500 * 1000); if(!notify_init("Udev-Block-Notification")) { fprintf(stderr, "%s: Can't create notify.\n", argv[0]); exit(EXIT_FAILURE); } } } errcount = 0; free(notification); udev_device_unref(dev); } // This is not really needed... But we want to make shure not to eat 100% CPU if anything breaks. ;) usleep(500 * 1000); } } udev_unref(udev); return EXIT_SUCCESS; }
static int sl_db_update_filesystem(struct sl_database_connection * db, int host_id, int session_id, const char * path) { struct stat st; int failed = stat(path, &st); if (failed) return failed; struct statfs stfs; failed = statfs(path, &stfs); if (failed) return failed; char * device = blkid_devno_to_devname(st.st_dev); if (device == NULL) { sl_log_write(sl_log_level_notice, sl_log_type_core, "Skip path: { path: %s } because it is not a block device", path); return 0; } char * real_device = realpath(device, NULL); blkid_dev dev = blkid_get_dev(cache, real_device, 0); // find alternative name if (dev == NULL) { char * sys_dev; asprintf(&sys_dev, "/sys/block/%s/dm/name", real_device + 5); int fd = open(sys_dev, O_RDONLY); if (fd > -1) { char buf[64]; ssize_t nb_read = read(fd, buf, 64); buf[nb_read - 1] = '\0'; close(fd); free(real_device); asprintf(&real_device, "/dev/mapper/%s", buf); dev = blkid_get_dev(cache, real_device, 0); } free(sys_dev); } if (dev == NULL) { sl_log_write(sl_log_level_notice, sl_log_type_core, "Skip path: { path: %s } because there is no blkid informations (blkid didn't known filesystem on %s)", path, real_device); free(real_device); free(device); return 0; } sl_log_write(sl_log_level_notice, sl_log_type_core, "Update filesystem: { path: %s }", path); const char * uuid = NULL; const char * label = NULL; const char * type = NULL; blkid_tag_iterate iter = blkid_tag_iterate_begin(dev); const char * key, * value; while (!blkid_tag_next(iter, &key, &value)) { if (!strcmp("UUID", key)) uuid = value; else if (!strcmp("LABEL", key)) label = value; else if (!strcmp("TYPE", key)) type = value; } struct sl_filesystem * fs = sl_filesystem_new(uuid, label, type, st.st_dev, path, stfs.f_bfree, stfs.f_blocks, stfs.f_bsize); blkid_tag_iterate_end(iter); free(device); free(real_device); int s2fs = db->ops->sync_filesystem(db, session_id, fs); if (s2fs < 0) { sl_filesystem_free(fs); return s2fs; } failed = sl_db_update_file(db, host_id, session_id, s2fs, path, NULL, &st); sl_filesystem_free(fs); return failed; }