Exemple #1
0
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;
}
Exemple #3
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);
        }
}
Exemple #4
0
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;
}
Exemple #5
0
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);
}
Exemple #6
0
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;
}
Exemple #9
0
/**
 * 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 );
}
Exemple #10
0
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);
}
Exemple #12
0
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);
}
Exemple #13
0
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 );
}
Exemple #14
0
/// 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;
		}
	}
}
Exemple #15
0
/*
 * 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);
}
Exemple #16
0
/*
 * 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);
}
Exemple #17
0
/*
 * 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);
}
Exemple #18
0
/*
 * 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);
}