void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; /* update possible left-over symlinks */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev_old)) { const char *name = udev_list_entry_get_name(list_entry); struct udev_list_entry *list_entry_current; int found; /* check if old link name still belongs to this device */ found = 0; udev_list_entry_foreach(list_entry_current, udev_device_get_devlinks_list_entry(dev)) { const char *name_current = udev_list_entry_get_name(list_entry_current); if (strcmp(name, name_current) == 0) { found = 1; break; } } if (found) continue; info(udev, "update old name, '%s' no longer belonging to '%s'\n", name, udev_device_get_devpath(dev)); link_update(dev, name, 0); } }
int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) { const char *name, *devpath; int r; assert(dev); assert(dev_old); r = sd_device_get_devpath(dev, &devpath); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get devpath: %m"); /* update possible left-over symlinks */ FOREACH_DEVICE_DEVLINK(dev_old, name) { const char *name_current; bool found = false; /* check if old link name still belongs to this device */ FOREACH_DEVICE_DEVLINK(dev, name_current) if (streq(name, name_current)) { found = true; break; } if (found) continue; log_device_debug(dev, "Updating old name, '%s' no longer belonging to '%s'", name, devpath); link_update(dev, name, false); } return 0; }
void udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid) { struct udev *udev = udev_device_get_udev(dev); char filename[UTIL_PATH_SIZE]; struct udev_list_entry *list_entry; int err = 0; info(udev, "handling device node '%s', devnum=%s, mode=%#o, uid=%d, gid=%d\n", udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid); if (node_fixup(dev, mode, uid, gid) < 0) return; /* always add /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "%s/%s/%u:%u", udev_get_dev_path(udev), strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); node_symlink(udev, udev_device_get_devnode(dev), filename); /* create/update symlinks, add symlinks to name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) { if (udev_list_entry_get_num(list_entry)) /* simple unmanaged link name */ node_symlink(udev, udev_device_get_devnode(dev), udev_list_entry_get_name(list_entry)); else link_update(dev, udev_list_entry_get_name(list_entry), 1); } }
int udev_node_remove(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; struct stat stats; struct udev_device *dev_check; char filename[UTIL_PATH_SIZE]; int err = 0; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), 0); devnode = udev_device_get_devnode(dev); if (devnode == NULL) goto out; if (stat(devnode, &stats) != 0) { info(udev, "device node '%s' not found\n", devnode); goto out; } if (stats.st_rdev != udev_device_get_devnum(dev)) { info(udev, "device node '%s' points to a different device, skip removal\n", devnode); err = -1; goto out; } dev_check = udev_device_new_from_syspath(udev, udev_device_get_syspath(dev)); if (dev_check != NULL) { /* do not remove device node if the same sys-device is re-created in the meantime */ info(udev, "keeping device node of existing device'%s'\n", devnode); udev_device_unref(dev_check); goto out; } info(udev, "removing device node '%s'\n", devnode); err = util_unlink_secure(udev, devnode); if (err == 0) util_delete_path(udev, devnode); /* remove /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "%s/%s/%u:%u", udev_get_dev_path(udev), strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); unlink(filename); out: return err; }
void udev_node_remove(struct udev_device *dev) { struct udev_list_entry *list_entry; char filename[DEV_NUM_PATH_MAX]; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), false); /* remove /dev/{block,char}/$major:$minor */ xsprintf_dev_num_path(filename, streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", udev_device_get_devnum(dev)); unlink(filename); }
void udev_node_remove(struct udev_device *dev) { struct udev_list_entry *list_entry; char filename[UTIL_PATH_SIZE]; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), false); /* remove /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); unlink(filename); }
int udev_node_remove(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; char partitionname[UTIL_PATH_SIZE]; struct stat stats; int err = 0; int num; /* remove,update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), 0); devnode = udev_device_get_devnode(dev); if (devnode == NULL) return 0; if (stat(devnode, &stats) != 0) { info(udev, "device node '%s' not found\n", devnode); return 0; } if (stats.st_rdev != udev_device_get_devnum(dev)) { info(udev, "device node '%s' points to a different device, skip removal\n", devnode); return -1; } info(udev, "removing device node '%s'\n", devnode); err = util_unlink_secure(udev, devnode); if (err) return err; num = udev_device_get_num_fake_partitions(dev); if (num > 0) { int i; info(udev, "removing all_partitions '%s[1-%i]'\n", devnode, num); if (num > 255) return -1; for (i = 1; i <= num; i++) { snprintf(partitionname, sizeof(partitionname), "%s%d", devnode, i); partitionname[sizeof(partitionname)-1] = '\0'; util_unlink_secure(udev, partitionname); } } util_delete_path(udev, devnode); return err; }
int udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid) { struct udev *udev = udev_device_get_udev(dev); int i; int num; struct udev_list_entry *list_entry; int err = 0; info(udev, "creating device node '%s', devnum=%d:%d, mode=%#o, uid=%d, gid=%d\n", udev_device_get_devnode(dev), major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)), mode, uid, gid); if (udev_node_mknod(dev, NULL, makedev(0,0), mode, uid, gid) != 0) { err = -1; goto exit; } /* create all_partitions if requested */ num = udev_device_get_num_fake_partitions(dev); if (num > 0) { info(udev, "creating device partition nodes '%s[1-%i]'\n", udev_device_get_devnode(dev), num); for (i = 1; i <= num; i++) { char partitionname[UTIL_PATH_SIZE]; dev_t part_devnum; snprintf(partitionname, sizeof(partitionname), "%s%d", udev_device_get_devnode(dev), i); partitionname[sizeof(partitionname)-1] = '\0'; part_devnum = makedev(major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)) + i); udev_node_mknod(dev, partitionname, part_devnum, mode, uid, gid); } } /* create/update symlinks, add symlinks to name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) { if (udev_list_entry_get_flag(list_entry)) /* simple unmanaged link name */ node_symlink(udev, udev_device_get_devnode(dev), udev_list_entry_get_name(list_entry)); else link_update(dev, udev_list_entry_get_name(list_entry), 1); } exit: return err; }
/** * Performs Dijkstra's shortest path algorithm over the set of links provided. * start_node should probably be local IP, but could be anything. */ void shortest_path_graph( uint32_t start_node, links_t *links, links_t *out ) { queue_t *queue; link_from_t *node; link_to_t *link; queue_init( &queue ); /* Add all nodes to the queue. * All nodes apart from the starting node will be added with some large * value, starting node will be entered with value 0. */ d_queue_init( queue, links, start_node ); while ( queue->length ) { uint32_t z_distance; queue_data_t *data= queue_dequeue( queue ); /* Grab the list of neighbours for this IP */ for (node= links->head; node != NULL; node= node->next_node) { if (node->ip == data->ip) break; } if ( node == NULL ) { return; } /* For each vertex adjacent to u, such that it is in 'queue' */ for (link= node->links; link != NULL; link= link->next_link ) { if ( (z_distance= d_queue_contains( queue, link->ip )) != -1 ) { if (data->distance+link->distance< z_distance){ z_distance= data->distance+link->distance; d_queue_add( queue, link->ip, node->ip, z_distance ); } } } /* Add link to output graph */ links_add( out, data->ip2, data->ip ); link_update( out, data->ip2, data->ip, data->distance ); } queue_destroy( &queue ); }
void udev_node_remove(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; struct stat stats; struct udev_device *dev_check; char filename[UTIL_PATH_SIZE]; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), 0); /* remove /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "%s/%s/%u:%u", udev_get_dev_path(udev), strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); unlink(filename); }
void udev_node_add(struct udev_device *dev, bool apply, mode_t mode, uid_t uid, gid_t gid) { char filename[UTIL_PATH_SIZE]; struct udev_list_entry *list_entry; log_debug("handling device node '%s', devnum=%s, mode=%#o, uid=%d, gid=%d\n", udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid); if (node_permissions_apply(dev, apply, mode, uid, gid) < 0) return; /* always add /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); node_symlink(dev, udev_device_get_devnode(dev), filename); /* create/update symlinks, add symlinks to name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), true); }
void udev_node_add(struct udev_device *dev, bool apply, mode_t mode, uid_t uid, gid_t gid, struct udev_list *seclabel_list) { char filename[DEV_NUM_PATH_MAX]; struct udev_list_entry *list_entry; log_debug("handling device node '%s', devnum=%s, mode=%#o, uid="UID_FMT", gid="GID_FMT, udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid); if (node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list) < 0) return; /* always add /dev/{block,char}/$major:$minor */ xsprintf_dev_num_path(filename, streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", udev_device_get_devnum(dev)); node_symlink(dev, udev_device_get_devnode(dev), filename); /* create/update symlinks, add symlinks to name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), true); }
void link_add( links_t *g, uint32_t from, uint32_t to, uint32_t weight ) { links_add( g, from, to ); link_update( g, from, to, weight ); }
/// main loop for time division multiplexing transparent serial /// void tdm_serial_loop(void) { __pdata uint16_t last_t = timer2_tick(); __pdata uint16_t last_link_update = last_t; _canary = 42; for (;;) { __pdata uint8_t len; __pdata uint16_t tnow, tdelta; __pdata uint8_t max_xmit; if (_canary != 42) { panic("stack blown\n"); } if (pdata_canary != 0x41) { panic("pdata canary changed\n"); } // give the AT command processor a chance to handle a command at_command(); // display test data if needed if (test_display) { display_test_output(); test_display = 0; } if (seen_mavlink && feature_mavlink_framing && !at_mode_active) { seen_mavlink = false; MAVLink_report(); } // set right receive channel radio_set_channel(fhop_receive_channel()); // get the time before we check for a packet coming in tnow = timer2_tick(); // see if we have received a packet if (radio_receive_packet(&len, pbuf)) { // update the activity indication received_packet = true; fhop_set_locked(true); // update filtered RSSI value and packet stats statistics.average_rssi = (radio_last_rssi() + 7*(uint16_t)statistics.average_rssi)/8; statistics.receive_count++; // we're not waiting for a preamble // any more transmit_wait = 0; if (len < 2) { // not a valid packet. We always send // two control bytes at the end of every packet continue; } // extract control bytes from end of packet memcpy(&trailer, &pbuf[len-sizeof(trailer)], sizeof(trailer)); len -= sizeof(trailer); if (trailer.window == 0 && len != 0) { // its a control packet if (len == sizeof(struct statistics)) { memcpy(&remote_statistics, pbuf, len); } // don't count control packets in the stats statistics.receive_count--; } else if (trailer.window != 0) { // sync our transmit windows based on // received header sync_tx_windows(len); last_t = tnow; if (trailer.command == 1) { handle_at_command(len); } else if (len != 0 && !packet_is_duplicate(len, pbuf, trailer.resend) && !at_mode_active) { // its user data - send it out // the serial port //printf("rcv(%d,[", len); LED_ACTIVITY = LED_ON; serial_write_buf(pbuf, len); LED_ACTIVITY = LED_OFF; //printf("]\n"); } } continue; } // see how many 16usec ticks have passed and update // the tdm state machine. We re-fetch tnow as a bad // packet could have cost us a lot of time. tnow = timer2_tick(); tdelta = tnow - last_t; tdm_state_update(tdelta); last_t = tnow; // update link status every 0.5s if (tnow - last_link_update > 32768) { link_update(); last_link_update = tnow; } if (lbt_rssi != 0) { // implement listen before talk if (radio_current_rssi() < lbt_rssi) { lbt_listen_time += tdelta; } else { lbt_listen_time = 0; if (lbt_rand == 0) { lbt_rand = ((uint16_t)rand()) % lbt_min_time; } } if (lbt_listen_time < lbt_min_time + lbt_rand) { // we need to listen some more continue; } } // we are allowed to transmit in our transmit window // or in the other radios transmit window if we have // bonus ticks #if USE_TICK_YIELD if (tdm_state != TDM_TRANSMIT && !(bonus_transmit && tdm_state == TDM_RECEIVE)) { // we cannot transmit now continue; } #else if (tdm_state != TDM_TRANSMIT) { continue; } #endif if (transmit_yield != 0) { // we've give up our window continue; } if (transmit_wait != 0) { // we're waiting for a preamble to turn into a packet continue; } if (!received_packet && radio_preamble_detected() || radio_receive_in_progress()) { // a preamble has been detected. Don't // transmit for a while transmit_wait = packet_latency; continue; } // sample the background noise when it is out turn to // transmit, but we are not transmitting, // averaged over around 4 samples statistics.average_noise = (radio_current_rssi() + 3*(uint16_t)statistics.average_noise)/4; if (duty_cycle_wait) { // we're waiting for our duty cycle to drop continue; } // how many bytes could we transmit in the time we // have left? if (tdm_state_remaining < packet_latency) { // none .... continue; } max_xmit = (tdm_state_remaining - packet_latency) / ticks_per_byte; if (max_xmit < PACKET_OVERHEAD) { // can't fit the trailer in with a byte to spare continue; } max_xmit -= PACKET_OVERHEAD; if (max_xmit > max_data_packet_length) { max_xmit = max_data_packet_length; } // ask the packet system for the next packet to send if (send_at_command && max_xmit >= strlen(remote_at_cmd)) { // send a remote AT command len = strlen(remote_at_cmd); memcpy(pbuf, remote_at_cmd, len); trailer.command = 1; send_at_command = false; } else { // get a packet from the serial port memset(pbuf, 0x40, 16); len = packet_get_next(max_xmit-16, pbuf+16) + 16; trailer.command = packet_is_injected(); if (len == 16) len = 0; } if (len > max_data_packet_length) { panic("oversized tdm packet"); } trailer.bonus = (tdm_state == TDM_RECEIVE); trailer.resend = packet_is_resend(); if (tdm_state == TDM_TRANSMIT && len == 0 && send_statistics && max_xmit >= sizeof(statistics)) { // send a statistics packet send_statistics = 0; memcpy(pbuf, &statistics, sizeof(statistics)); len = sizeof(statistics); // mark a stats packet with a zero window trailer.window = 0; trailer.resend = 0; } else { // calculate the control word as the number of // 16usec ticks that will be left in this // tdm state after this packet is transmitted trailer.window = (uint16_t)(tdm_state_remaining - flight_time_estimate(len+sizeof(trailer))); } // set right transmit channel radio_set_channel(fhop_transmit_channel()); memcpy(&pbuf[len], &trailer, sizeof(trailer)); if (len != 0 && trailer.window != 0) { // show the user that we're sending real data LED_ACTIVITY = LED_ON; } if (len == 0) { // sending a zero byte packet gives up // our window, but doesn't change the // start of the next window transmit_yield = 1; } // after sending a packet leave a bit of time before // sending the next one. The receivers don't cope well // with back to back packets transmit_wait = packet_latency; // if we're implementing a duty cycle, add the // transmit time to the number of ticks we've been transmitting if ((duty_cycle - duty_cycle_offset) != 100) { transmitted_ticks += flight_time_estimate(len+sizeof(trailer)); } // start transmitting the packet if (!radio_transmit(len + sizeof(trailer), pbuf, tdm_state_remaining + (silence_period/2)) && len != 0 && trailer.window != 0 && trailer.command == 0) { packet_force_resend(); } if (lbt_rssi != 0) { // reset the LBT listen time lbt_listen_time = 0; lbt_rand = 0; } // set right receive channel radio_set_channel(fhop_receive_channel()); // re-enable the receiver radio_receiver_on(); if (len != 0 && trailer.window != 0) { LED_ACTIVITY = LED_OFF; } } }
/* * routine: * do_like * * purpose: * to propagate ownership and protection changes between * one existing file and another. * * parameters: * file pointer * src/dst indication for who needs to change * whether or not to update statistics (there may be a copy and a like) * * returns: * error mask * * notes: * if we are called from reconcile, we should update * the statistics, but if we were called from do_copy * that routine will do the honors. */ errmask_t do_like(struct file *fp, side_t srcdst, bool_t do_stats) { char *dst; int rc = 0; int do_chown, do_chmod, do_chgrp, do_acls; errmask_t errs = 0; char *errstr = 0; struct base *bp; struct fileinfo *sp; struct fileinfo *dp; struct fileinfo *ip; extern int errno; bp = fp->f_base; /* see if this is a forbidden propagation */ if (srcdst == opt_oneway) { fp->f_flags |= F_CONFLICT; fp->f_problem = gettext(PROB_prohibited); bp->b_unresolved++; return (ERR_UNRESOLVED); } /* get info about source and target files */ if (srcdst == OPT_SRC) { sp = &fp->f_info[ OPT_DST ]; dp = &fp->f_info[ OPT_SRC ]; dst = srcname; } else { sp = &fp->f_info[ OPT_SRC ]; dp = &fp->f_info[ OPT_DST ]; dst = dstname; } ip = &fp->f_info[ OPT_BASE ]; /* figure out what needs fixing */ do_chmod = (sp->f_mode != dp->f_mode); do_chown = (sp->f_uid != dp->f_uid); do_chgrp = (sp->f_gid != dp->f_gid); do_acls = ((fp->f_srcdiffs|fp->f_dstdiffs) & D_FACLS); /* * try to anticipate things that we might not be able to * do, and return appropriate errorst if the calling user * cannot safely perform the requiested updates. */ if (my_uid != 0) { if (do_chown) errstr = gettext(PROB_chown); else if (my_uid != dp->f_uid) { if (do_chmod) errstr = gettext(PROB_chmod); else if (do_acls) errstr = gettext(PROB_chacl); else if (do_chgrp) errstr = gettext(PROB_chgrp); } #ifdef ACL_UID_BUG else if (do_acls && my_gid != dp->f_gid) errstr = gettext(PROB_botch); #endif if (errstr) { need_super = TRUE; /* if the user doesn't care, shine it on */ if (opt_everything == 0) return (0); /* if the user does care, return the error */ rc = -1; goto nogood; } } if (opt_debug & DBG_RECON) { fprintf(stderr, "RECO: do_like %s (", dst); if (do_chmod) fprintf(stderr, "chmod "); if (do_acls) fprintf(stderr, "acls "); if (do_chown) fprintf(stderr, "chown "); if (do_chgrp) fprintf(stderr, "chgrp "); fprintf(stderr, ")\n"); } if (do_chmod) { if (!opt_quiet) fprintf(stdout, "chmod %o %s\n", sp->f_mode, noblanks(dst)); #ifdef DBG_ERRORS /* should we simulate a chmod failure */ if (errno = dbg_chk_error(dst, 'p')) rc = -1; else #endif rc = opt_notouch ? 0 : chmod(dst, sp->f_mode); if (opt_debug & DBG_RECON) fprintf(stderr, "RECO: do_chmod %o -> %d(%d)\n", sp->f_mode, rc, errno); /* update dest and baseline to reflect the change */ if (rc == 0) { dp->f_mode = sp->f_mode; ip->f_mode = sp->f_mode; } else errstr = gettext(PROB_chmod); } /* * see if we need to fix the acls */ if (rc == 0 && do_acls) { if (!opt_quiet) fprintf(stdout, "setfacl %s %s\n", show_acls(sp->f_numacls, sp->f_acls), noblanks(dst)); #ifdef DBG_ERRORS /* should we simulate a set acl failure */ if (errno = dbg_chk_error(dst, 'a')) rc = -1; else #endif rc = opt_notouch ? 0 : set_acls(dst, sp); if (opt_debug & DBG_RECON) fprintf(stderr, "RECO: do_acls %d -> %d(%d)\n", sp->f_numacls, rc, errno); /* update dest and baseline to reflect the change */ if (rc == 0) { dp->f_numacls = sp->f_numacls; dp->f_acls = sp->f_acls; ip->f_numacls = sp->f_numacls; ip->f_acls = sp->f_acls; #ifdef ACL_UID_BUG /* SETFACL changes a file's UID/GID */ if (my_uid != dp->f_uid) { do_chown = 1; dp->f_uid = my_uid; } if (my_gid != dp->f_gid) { do_chgrp = 1; dp->f_gid = my_gid; } #endif } else if (errno == ENOSYS) { /* * if the file system doesn't support ACLs * we should just pretend we never saw them */ fprintf(stderr, gettext(WARN_noacls), dst); ip->f_numacls = 0; sp->f_numacls = 0; dp->f_numacls = 0; rc = 0; } else errstr = gettext(PROB_chacl); } /* * see if we need to fix the ownership */ if (rc == 0 && (do_chown || do_chgrp)) { if (do_chown) fprintf(stdout, "chown %ld %s; ", sp->f_uid, noblanks(dst)); if (do_chgrp) fprintf(stdout, "chgrp %ld %s", sp->f_gid, noblanks(dst)); fprintf(stdout, "\n"); #ifdef DBG_ERRORS /* should we simulate a chown failure */ if (errno = dbg_chk_error(dst, 'O')) rc = -1; else #endif rc = opt_notouch ? 0 : lchown(dst, sp->f_uid, sp->f_gid); if (opt_debug & DBG_RECON) fprintf(stderr, "RECO: do_chown %ld %ld -> %d(%d)\n", sp->f_uid, sp->f_gid, rc, errno); /* update the destination to reflect changes */ if (rc == 0) { dp->f_uid = sp->f_uid; dp->f_gid = sp->f_gid; ip->f_uid = sp->f_uid; ip->f_gid = sp->f_gid; } else { if (errno == EPERM) { need_super = TRUE; if (opt_everything == 0) return (0); } if (rc != 0) errstr = gettext(do_chown ? PROB_chown : PROB_chgrp); } } /* * if we were successful, we should make sure the other links * see the changes. If we were called from do_copy, we don't * want to do the link_updates either because do_copy will * handle them too. */ if (rc == 0 && do_stats) link_update(fp, srcdst); nogood: if (!do_stats) return (errs); if (rc != 0) { fprintf(stderr, gettext(ERR_cannot), errstr, dst); fp->f_problem = errstr; fp->f_flags |= F_CONFLICT; bp->b_unresolved++; errs |= ERR_PERM | ERR_UNRESOLVED; } else { /* * it worked, so update the baseline and statistics */ if (srcdst == OPT_SRC) bp->b_src_misc++; else bp->b_dst_misc++; fp->f_problem = 0; errs |= ERR_RESOLVABLE; } return (errs); }
/* * routine: * do_copy * * purpose: * to propagate a creation or change * * parameters: * file pointer * src/dst indication for who gets the copy * * returns: * error mask * * note: * after any successful operation we update the stat/info * structure for the updated file. This is somewhat redundant * because we will restat at the end of the routine, but these * anticipatory updates help to ensure that the link finding * code will still behave properly in notouch mode (when restats * cannot be done). */ errmask_t do_copy(struct file *fp, side_t srcdst) { char *src, *dst; char cmdbuf[ MAX_PATH + MAX_NAME ]; int mode, maj, min, type; uid_t uid; gid_t gid; int rc; long mtime; int do_chmod = 0; int do_chown = 0; int do_chgrp = 0; int do_unlink = 0; int do_acls = 0; int do_create = 0; char *errstr = "???"; errmask_t errs = 0; struct base *bp; struct file *lp; struct fileinfo *sp, *dp; struct utimbuf newtimes; struct stat statb; bp = fp->f_base; /* see if this is a forbidden propagation */ if (srcdst == opt_oneway) { fp->f_problem = gettext(PROB_prohibited); fp->f_flags |= F_CONFLICT; bp->b_unresolved++; return (ERR_UNRESOLVED); } /* figure out who is the source and who is the destination */ if (srcdst == OPT_SRC) { sp = &fp->f_info[ OPT_DST ]; dp = &fp->f_info[ OPT_SRC ]; src = dstname; dst = srcname; } else { sp = &fp->f_info[ OPT_SRC ]; dp = &fp->f_info[ OPT_DST ]; src = srcname; dst = dstname; } /* note information about the file to be created */ type = sp->f_type; /* type of the new file */ uid = sp->f_uid; /* owner of the new file */ gid = sp->f_gid; /* group of the new file */ mode = sp->f_mode; /* modes for the new file */ mtime = sp->f_modtime; /* modtime (if preserving) */ maj = sp->f_rd_maj; /* major (if it is a device) */ min = sp->f_rd_min; /* minor (if it is a device) */ /* * creating a file does not guarantee it will get the desired * modes, uid and gid. If the file already exists, it will * retain its old ownership and protection. If my UID/GID * are not the desired ones, the new file will also require * manual correction. If the file has the wrong type, we will * need to delete it and recreate it. If the file is not writable, * it is easier to delete it than to chmod it to permit overwrite */ if ((dp->f_type == S_IFREG && sp->f_type == S_IFREG) && (dp->f_mode & 0200)) { /* if the file already exists */ if (dp->f_uid != uid) do_chown = 1; if (dp->f_gid != gid) do_chgrp = 1; if (dp->f_mode != mode) do_chmod = 1; } else { /* if we will be creating a new file */ do_create = 1; if (dp->f_type) do_unlink = 1; if (uid != my_uid) do_chown = 1; if (gid != my_gid) do_chgrp = 1; } /* * if the source has acls, we will surely have to set them for dest */ if (sp->f_numacls) do_acls = 1; /* * for any case other than replacing a normal file with a normal * file, we need to delete the existing file before creating * the new one. */ if (do_unlink) { if (dp->f_type == S_IFDIR) { if (!opt_quiet) fprintf(stdout, "rmdir %s\n", noblanks(dst)); errstr = gettext(PROB_rmdir); #ifdef DBG_ERRORS /* should we simulate a rmdir failure */ if (errno = dbg_chk_error(dst, 'D')) rc = -1; else #endif rc = opt_notouch ? 0 : rmdir(dst); } else { if (!opt_quiet) fprintf(stdout, "rm %s\n", noblanks(dst)); errstr = gettext(PROB_unlink); #ifdef DBG_ERRORS /* should we simulate a unlink failure */ if (errno = dbg_chk_error(dst, 'u')) rc = -1; else #endif rc = opt_notouch ? 0 : unlink(dst); } if (rc != 0) goto cant; /* note that this file no longer exists */ dp->f_type = 0; dp->f_mode = 0; } if (opt_debug & DBG_RECON) { fprintf(stderr, "RECO: do_copy %s %s (", src, dst); if (do_unlink) fprintf(stderr, "unlink "); if (do_chmod) fprintf(stderr, "chmod "); if (do_acls) fprintf(stderr, "acls "); if (do_chown) fprintf(stderr, "chown "); if (do_chgrp) fprintf(stderr, "chgrp "); fprintf(stderr, ")\n"); } /* * how we go about copying a file depends on what type of file * it is that we are supposed to copy */ switch (type) { case S_IFDIR: if (!opt_quiet) { fprintf(stdout, "mkdir %s;", noblanks(dst)); fprintf(stdout, " chmod %o %s;\n", mode, noblanks(dst)); } errstr = gettext(PROB_mkdir); #ifdef DBG_ERRORS /* should we simulate a mkdir failure */ if (errno = dbg_chk_error(dst, 'd')) rc = -1; else #endif rc = opt_notouch ? 0 : mkdir(dst, mode); /* update stat with what we have just created */ if (rc == 0) { dp->f_type = S_IFDIR; dp->f_uid = my_uid; dp->f_gid = my_gid; dp->f_mode = mode; } break; case S_IFLNK: errstr = gettext(PROB_readlink); #ifdef DBG_ERRORS /* should we simulate a symlink read failure */ if (errno = dbg_chk_error(dst, 'r')) rc = -1; else #endif rc = readlink(src, cmdbuf, sizeof (cmdbuf)); if (rc > 0) { cmdbuf[rc] = 0; if (!opt_quiet) { fprintf(stdout, "ln -s %s", noblanks(cmdbuf)); fprintf(stdout, " %s;\n", noblanks(dst)); } errstr = gettext(PROB_symlink); #ifdef DBG_ERRORS /* should we simulate a symlink failure */ if (errno = dbg_chk_error(dst, 'l')) rc = -1; else #endif rc = opt_notouch ? 0 : symlink(cmdbuf, dst); if (rc == 0) dp->f_type = S_IFLNK; } break; case S_IFBLK: case S_IFCHR: if (!opt_quiet) fprintf(stdout, "mknod %s %s %d %d\n", noblanks(dst), (type == S_IFBLK) ? "b" : "c", maj, min); errstr = gettext(PROB_mknod); #ifdef DBG_ERRORS /* should we simulate a mknod failure */ if (errno = dbg_chk_error(dst, 'd')) rc = -1; else #endif rc = opt_notouch ? 0 : mknod(dst, mode|type, makedev(maj, min)); /* update stat with what we have just created */ if (rc == 0) { dp->f_type = type; dp->f_uid = my_uid; dp->f_gid = my_gid; dp->f_mode = 0666; if (dp->f_mode != mode) do_chmod = 1; } break; case S_IFREG: /* * The first thing to do is ascertain whether or not * the alleged new copy might in fact be a new link. * We trust find_link to weigh all the various factors, * so if he says make a link, we'll do it. */ lp = find_link(fp, srcdst); if (lp) { /* figure out name of existing file */ src = full_name(lp, srcdst, OPT_BASE); /* * if file already exists, it must be deleted */ if (dp->f_type) { if (!opt_quiet) fprintf(stdout, "rm %s\n", noblanks(dst)); errstr = gettext(PROB_unlink); #ifdef DBG_ERRORS /* should we simulate a unlink failure */ if (errno = dbg_chk_error(dst, 'u')) rc = -1; else #endif rc = opt_notouch ? 0 : unlink(dst); /* * if we couldn't do the unlink, we must * mark the linkee in conflict as well * so his reference count remains the same * in the baseline and he continues to show * up on the change list. */ if (rc != 0) { lp->f_flags |= F_CONFLICT; lp->f_problem = gettext(PROB_link); goto cant; } } if (!opt_quiet) { fprintf(stdout, "ln %s", noblanks(src)); fprintf(stdout, " %s\n", noblanks(dst)); } errstr = gettext(PROB_link); #ifdef DBG_ERRORS /* should we simulate a link failure */ if (errno = dbg_chk_error(dst, 'l')) rc = -1; else #endif rc = opt_notouch ? 0 : link(src, dst); /* * if this is a link, there is no reason to worry * about ownership and modes, they are automatic */ do_chown = 0; do_chgrp = 0; do_chmod = 0; do_acls = 0; if (rc == 0) { dp->f_type = type; dp->f_uid = uid; dp->f_gid = gid; dp->f_mode = mode; break; } else { /* * if we failed to make a link, we want to * mark the linkee in conflict too, so that * his reference count remains the same in * the baseline, and he shows up on the change * list again next time. */ lp->f_flags |= F_CONFLICT; lp->f_problem = errstr; break; } /* * in some situation we haven't figured out yet * we might want to fall through and try a copy * if the link failed. */ } /* we are going to resolve this by making a copy */ if (!opt_quiet) { fprintf(stdout, "cp %s", noblanks(src)); fprintf(stdout, " %s\n", noblanks(dst)); } rc = opt_notouch ? 0 : copy(src, dst, mode); if (rc != 0) { errs |= rc; if (copy_err_str) errstr = copy_err_str; else errstr = gettext(PROB_copy); /* * The new copy (if it exists at all) is a botch. * If this was a new create or a remove and copy * we should get rid of the botched copy so that * it doesn't show up as two versions next time. */ if (do_create) unlink(dst); } else if (dp->f_mode == 0) { dp->f_type = S_IFREG; dp->f_uid = my_uid; dp->f_gid = my_gid; dp->f_mode = mode; /* FIX: inode number is still wrong */ } /* for normal files we have an option to preserve mod time */ if (rc == 0 && opt_notouch == 0 && opt_mtime) { newtimes.actime = mtime; newtimes.modtime = mtime; /* ignore the error return on this one */ (void) utime(dst, &newtimes); } break; default: errstr = gettext(PROB_deal); rc = -1; } /* * if any of the file's attributes need attention, I should let * do_like take care of them, since it knows all rules for who * can and cannot make what types of changes. */ if (rc == 0 && (do_chmod || do_chown || do_chgrp || do_acls)) { rc = do_like(fp, srcdst, FALSE); errstr = fp->f_problem; errs |= rc; } /* * finish off by re-stating the destination and using that to * update the baseline. If we were completely successful in * our chowns/chmods, stating the destination will confirm it. * If we were unable to make all the necessary changes, stating * the destination will make the source appear to have changed, * so that the differences will continue to reappear as new * changes (inconsistancies). */ if (rc == 0) if (!opt_notouch) { errstr = gettext(PROB_restat); #ifdef DBG_ERRORS /* should we simulate a restat failure */ if (errno = dbg_chk_error(dst, 'R')) rc = -1; else #endif rc = lstat(dst, &statb); if (rc == 0) { note_info(fp, &statb, srcdst); link_update(fp, srcdst); if (do_acls) (void) get_acls(dst, dp); update_info(fp, srcdst); } } else { /* * BOGOSITY ALERT * we are in notouch mode and haven't really * done anything, but if we want link detection * to work and be properly reflected in the * what-I-would-do output for a case where * multiple links are created to a new file, * we have to make the new file appear to * have been created. Since we didn't create * the new file we can't stat it, but if * no file exists, we can't make a link to * it, so we will pretend we created a file. */ if (dp->f_ino == 0 || dp->f_nlink == 0) { dp->f_ino = sp->f_ino; dp->f_nlink = 1; } } cant: if (rc != 0) { fprintf(stderr, gettext(ERR_cannot), errstr, dst); bp->b_unresolved++; fp->f_flags |= F_CONFLICT; fp->f_problem = errstr; if (errs == 0) errs = ERR_PERM; errs |= ERR_UNRESOLVED; } else { /* update the statistics */ if (srcdst == OPT_SRC) bp->b_src_copies++; else bp->b_dst_copies++; errs |= ERR_RESOLVABLE; } return (errs); }
/* * routine: * do_remove * * purpose: * to propagate a deletion * * parameters: * file pointer * src/dst indication for which side gets changed * * returns: * error mask */ errmask_t do_remove(struct file *fp, side_t srcdst) { char *name; int rc; struct base *bp = fp->f_base; errmask_t errs = 0; char *errstr = "???"; /* see if this is a forbidden propagation */ if (srcdst == opt_oneway) { fp->f_problem = gettext(PROB_prohibited); fp->f_flags |= F_CONFLICT; bp->b_unresolved++; return (ERR_UNRESOLVED); } name = (srcdst == OPT_SRC) ? srcname : dstname; if (fp->f_info[0].f_type == S_IFDIR) { if (!opt_quiet) fprintf(stdout, "rmdir %s\n", noblanks(name)); errstr = gettext(PROB_rmdir); #ifdef DBG_ERRORS /* should we simulate a rmdir failure */ if (errno = dbg_chk_error(name, 'D')) rc = -1; else #endif rc = opt_notouch ? 0 : rmdir(name); } else { if (!opt_quiet) fprintf(stdout, "rm %s\n", noblanks(name)); errstr = gettext(PROB_unlink); #ifdef DBG_ERRORS /* should we simulate an unlink failure */ if (errno = dbg_chk_error(name, 'u')) rc = -1; else #endif rc = opt_notouch ? 0 : unlink(name); } if (opt_debug & DBG_RECON) fprintf(stderr, "RECO: do_remove %s -> %d(%d)\n", name, rc, errno); if (rc == 0) { /* tell any other hard links that one has gone away */ fp->f_info[srcdst].f_nlink--; link_update(fp, srcdst); fp->f_flags |= F_REMOVE; if (srcdst == OPT_SRC) fp->f_base->b_src_deletes++; else fp->f_base->b_dst_deletes++; errs |= ERR_RESOLVABLE; } else { fprintf(stderr, gettext(ERR_cannot), errstr, name); fp->f_problem = errstr; fp->f_flags |= F_CONFLICT; bp->b_unresolved++; errs |= ERR_PERM | ERR_UNRESOLVED; } return (errs); }
/* * routine: * do_rename * * purpose: * to propagate a rename * * parameters: * file pointer for the new name * src/dst indication for which side gets changed * * returns: * error mask */ errmask_t do_rename(struct file *fp, side_t srcdst) { int rc; struct file *pp = fp->f_previous; struct base *bp = fp->f_base; errmask_t errs = 0; char *errstr = "???"; char *newname; char *oldname; struct stat statb; /* see if this is a forbidden propagation */ if (srcdst == opt_oneway) { fp->f_problem = gettext(PROB_prohibited); /* if we can't resolve the TO, the FROM is also unresolved */ pp->f_problem = gettext(PROB_prohibited); pp->f_flags |= F_CONFLICT; bp->b_unresolved++; return (ERR_UNRESOLVED); } newname = (srcdst == OPT_SRC) ? srcname : dstname; oldname = full_name(pp, srcdst, OPT_BASE); if (!opt_quiet) fprintf(stdout, "%s %s %s\n", (fp->f_info[0].f_type == S_IFDIR) ? "mvdir" : "mv", noblanks(oldname), noblanks(newname)); #ifdef DBG_ERRORS /* should we simulate a rename failure */ if (errno = dbg_chk_error(oldname, 'm')) rc = -1; else #endif rc = opt_notouch ? 0 : rename(oldname, newname); if (opt_debug & DBG_RECON) fprintf(stderr, "RECO: do_rename %s %s -> %d(%d)\n", oldname, newname, rc, errno); /* if we succeed, update the baseline */ if (rc == 0) if (!opt_notouch) { errstr = gettext(PROB_restat); #ifdef DBG_ERRORS /* should we simulate a restat failure */ if (errno = dbg_chk_error(newname, 'S')) rc = -1; else #endif rc = lstat(newname, &statb); if (rc == 0) { note_info(fp, &statb, srcdst); link_update(fp, srcdst); update_info(fp, srcdst); } } else { /* * BOGOSITY ALERT * in order for link tests to work in notouch * mode we have to dummy up some updated status */ fp->f_info[srcdst].f_ino = pp->f_info[srcdst].f_ino; fp->f_info[srcdst].f_nlink = pp->f_info[srcdst].f_nlink; fp->f_info[srcdst].f_type = pp->f_info[srcdst].f_type; fp->f_info[srcdst].f_size = pp->f_info[srcdst].f_size; fp->f_info[srcdst].f_mode = pp->f_info[srcdst].f_mode; fp->f_info[srcdst].f_uid = pp->f_info[srcdst].f_uid; fp->f_info[srcdst].f_gid = pp->f_info[srcdst].f_gid; update_info(fp, srcdst); } else errstr = gettext(PROB_rename2); if (rc == 0) { pp->f_flags |= F_REMOVE; if (srcdst == OPT_SRC) { bp->b_src_copies++; bp->b_src_deletes++; } else { bp->b_dst_copies++; bp->b_dst_deletes++; } errs |= ERR_RESOLVABLE; } else { fprintf(stderr, gettext(ERR_cannot), errstr, oldname); bp->b_unresolved++; fp->f_flags |= F_CONFLICT; pp->f_flags |= F_CONFLICT; fp->f_problem = errstr; pp->f_problem = gettext(PROB_rename); errs |= ERR_PERM | ERR_UNRESOLVED; } return (errs); }