2 * Copyright © 2012-2016 Canonical, Inc
4 * Author: Serge Hallyn <serge.hallyn@ubuntu.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2 of the
12 #define _XOPEN_SOURCE 500
21 #include <sys/types.h>
23 #define min(a,b) (a) < (b) ? (a) : (b)
24 #define max(a,b) (a) > (b) ? (a) : (b)
26 static int verbose = 0;
27 static int convert_uids = 0;
28 static int convert_gids = 0;
32 static uid_t range_uid_max = 0;
33 static uid_t range_uid_min = ~0;
34 static gid_t range_gid_max = 0;
35 static gid_t range_gid_min = ~0;
39 extern const char *__progname;
40 printf("Usage: %s [OPTIONS] directory [src dst range]\n\n", __progname);
41 printf(" -u, --uid convert uids in directory\n");
42 printf(" -g, --gid convert gids in directory\n");
43 printf(" -b, --both convert uids and gids in directory\n");
44 printf(" -r, --range find min,max uid/gid used in directory\n");
45 printf(" -v, --verbose increate verbosity\n\n");
46 printf("Note this program always recursively walks all of directory.\n");
47 printf("If -u,-g, or -b is given, then [src dst range] are required to convert the \n");
48 printf("ids within the range [src..src+range] to [dst..dst+range].\n\n");
49 printf("Examples:\n");
50 printf(" %s -r /path/to/directory # show min/max uid/gid\n", __progname);
51 printf(" %s -b /path/to/directory 0 100000 500 # map uids and gids up\n", __progname);
52 printf(" %s -u /path/to/directory 100000 0 500 # map the uids back down\n", __progname);
55 int ftw_callback(const char *fpath, const struct stat *st,
56 int typeflag, struct FTW *ftw)
62 range_uid_max = max(range_uid_max, st->st_uid);
63 range_uid_min = min(range_uid_min, st->st_uid);
64 range_gid_max = max(range_gid_max, st->st_gid);
65 range_gid_min = min(range_gid_min, st->st_gid);
67 if (convert_uids && st->st_uid >= srcid && st->st_uid < srcid+range)
68 new_uid = (st->st_uid-srcid) + dstid;
69 if (convert_gids && st->st_gid >= srcid && st->st_gid < srcid+range)
70 new_gid = (st->st_gid-srcid) + dstid;
71 if (new_uid != -1 || new_gid != -1) {
72 ret = lchown(&fpath[ftw->base], new_uid, new_gid);
74 fprintf(stderr, "failed to chown %d:%d %s\n",
75 new_uid, new_gid, fpath);
76 /* well, let's keep going */
78 if (!S_ISLNK(st->st_mode)) {
80 fprintf(stderr, "resetting mode to %o on %s\n",
82 ret = chmod(&fpath[ftw->base], st->st_mode);
84 fprintf(stderr, "failed to reset mode %o on %s\n",
86 /* well, let's keep going */
90 printf("u:%07d=%07d g:%07d=%07d m:%#07o %s %s\n",
93 st->st_mode, fpath, &fpath[ftw->base]);
99 int main(int argc, char *argv[])
105 static const struct option long_opts[] = {
106 { "help", no_argument, NULL, 'h' },
107 { "uids", no_argument, NULL, 'u' },
108 { "gids", no_argument, NULL, 'g' },
109 { "both", no_argument, NULL, 'b' },
110 { "range", no_argument, NULL, 'r' },
111 { "verbose", no_argument, NULL, 'v' },
115 while ((opt = getopt_long(argc, argv, "hugbrv", long_opts, NULL)) >= 0) {
117 case 'h': usage(); exit(EXIT_SUCCESS);
118 case 'u': convert_uids = 1; break;
119 case 'g': convert_gids = 1; break;
120 case 'b': convert_uids = convert_gids = 1; break;
121 case 'r': show_range = 1; break;
122 case 'v': verbose++; break;
135 if (convert_uids || convert_gids) {
140 srcid = atoi(argv[1]);
141 dstid = atoi(argv[2]);
142 range = atoi(argv[3]);
145 ret = nftw(base, ftw_callback, 1000, FTW_PHYS|FTW_CHDIR);
147 fprintf(stderr, "Failed to walk path %s %s\n", base, strerror(errno));
153 printf("UIDs %d - %d\n"
155 range_uid_min, range_uid_max,
156 range_gid_min, range_gid_max);