+ *end = c;
+ *start = 0;
+ n = printf("%s%d%s", str, id, end);
+ }
+ return n;
+}
+
+static int child_status(int status)
+{
+ return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+}
+
+static int do_rmtacl(int argc, char *argv[], int ops, int (output_func)(char *))
+{
+ pid_t pid = 0;
+ int fd[2], status;
+ FILE *fp;
+ char buf[PIPE_BUF];
+
+ if (output_func) {
+ if (pipe(fd) < 0) {
+ perror("pipe");
+ return -1;
+ }
+
+ if ((pid = fork()) < 0) {
+ perror("fork");
+ close(fd[0]);
+ close(fd[1]);
+ return -1;
+ } else if (!pid) {
+ /* child process redirects its output. */
+ close(fd[0]);
+ close(1);
+ if (dup2(fd[1], 1) < 0) {
+ perror("dup2");
+ close(fd[1]);
+ return -1;
+ }
+ } else {
+ close(fd[1]);
+ }
+ }
+
+ if (!pid) {
+ status = rmtacl_notify(ops);
+ if (status < 0)
+ return -1;
+
+ exit(execvp(argv[0], argv));
+ }
+
+ /* the following is parent process */
+ if ((fp = fdopen(fd[0], "r")) == NULL) {
+ perror("fdopen");
+ kill(pid, SIGKILL);
+ close(fd[0]);
+ return -1;
+ }
+
+ while (fgets(buf, PIPE_BUF, fp) != NULL) {
+ if (output_func(buf) < 0)
+ fprintf(stderr, "WARNING: unexpected error!\n[%s]\n",
+ buf);
+ }
+ fclose(fp);
+ close(fd[0]);
+
+ if (waitpid(pid, &status, 0) < 0) {
+ perror("waitpid");
+ return -1;
+ }
+
+ return child_status(status);
+}
+
+int llapi_lsetfacl(int argc, char *argv[])
+{
+ return do_rmtacl(argc, argv, RMT_LSETFACL, NULL);
+}
+
+int llapi_lgetfacl(int argc, char *argv[])
+{
+ return do_rmtacl(argc, argv, RMT_LGETFACL, NULL);
+}
+
+int llapi_rsetfacl(int argc, char *argv[])
+{
+ return do_rmtacl(argc, argv, RMT_RSETFACL, NULL);
+}
+
+int llapi_rgetfacl(int argc, char *argv[])
+{
+ return do_rmtacl(argc, argv, RMT_RGETFACL, rgetfacl_output);
+}
+
+int llapi_cp(int argc, char *argv[])
+{
+ int rc;
+
+ rc = rmtacl_notify(RMT_RSETFACL);
+ if (rc < 0)
+ return -1;
+
+ exit(execvp(argv[0], argv));
+}
+
+int llapi_ls(int argc, char *argv[])
+{
+ int rc;
+
+ rc = rmtacl_notify(RMT_LGETFACL);
+ if (rc < 0)
+ return -1;
+
+ exit(execvp(argv[0], argv));
+}
+
+/* format must have %s%s, buf must be > 16 */
+static int get_mdtname(const char *name, char *format, char *buf)
+{
+ char suffix[]="-MDT0000";
+ int len = strlen(name);
+
+ if (len > 16) {
+ llapi_err(LLAPI_MSG_ERROR, "bad MDT name |%s|\n", name);
+ return -EINVAL;
+ }
+
+ if ((len > 8) && (strncmp(name + len - 8, "-MDT", 4) == 0))
+ suffix[0] = '\0';
+
+ return sprintf(buf, format, name, suffix);
+}
+
+#define CHANGELOG_FILE "/proc/fs/lustre/mdd/%s%s/changelog"
+
+/* return a file desc to readable changelog */
+int llapi_changelog_open(const char *mdtname, long long startrec)
+{
+ char path[256];
+ int rc, fd;
+
+ if (get_mdtname(mdtname, CHANGELOG_FILE, path) <0)
+ return -EINVAL;
+
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ llapi_err(LLAPI_MSG_ERROR, "error: can't open |%s|\n", path);
+ return -errno;
+ }
+
+ rc = lseek(fd, (off_t)startrec, SEEK_SET);
+ if (rc < 0) {
+ llapi_err(LLAPI_MSG_ERROR, "can't seek rc=%d\n", rc);
+ return -errno;
+ }
+
+ return fd;
+}
+
+int llapi_changelog_clear(const char *mdtname, long long endrec)
+{
+ char path[256];
+ char val[20];
+ int fd, len;
+
+ if (endrec < 0) {
+ llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
+ "can't purge negative records\n");
+ return -EINVAL;
+ }
+
+ if (get_mdtname(mdtname, CHANGELOG_FILE, path) <0)
+ return -EINVAL;
+
+ if ((fd = open(path, O_WRONLY)) < 0) {
+ llapi_err(LLAPI_MSG_ERROR, "error: can't open |%s|\n", path);
+ return errno;
+ }
+
+ snprintf(val, sizeof(val), "%llu", endrec);
+ len = write(fd, val, strlen(val));
+ close(fd);
+ if (len != strlen(val)) {
+ llapi_err(LLAPI_MSG_ERROR, "purge err\n");
+ return errno;
+ }
+
+ return 0;
+}
+
+static int dev_ioctl(struct obd_ioctl_data *data, int dev, int cmd)
+{
+ int rc;
+ static char rawbuf[8192];
+ static char *buf = rawbuf;
+
+ data->ioc_dev = dev;
+ memset(buf, 0, sizeof(rawbuf));
+
+ if ((rc = obd_ioctl_pack(data, &buf, sizeof(rawbuf)))) {
+ llapi_err(LLAPI_MSG_ERROR,
+ "error: ioctl pack (%d) failed: rc %d", cmd, rc);
+ return rc;
+ }
+
+ rc = l_ioctl(OBD_DEV_ID, cmd, buf);
+ if (rc < 0) {
+ /* ioctl returns -1 with errno set */
+ rc = -errno;
+ return rc;
+ }
+
+ if (obd_ioctl_unpack(data, buf, sizeof(rawbuf))) {
+ llapi_err(LLAPI_MSG_ERROR,
+ "error: invalid reply\n");
+ return -EPROTO;
+ }
+ return rc;
+}
+
+/* should we just grep it from proc? */
+static int dev_name2dev(char *name)
+{
+ struct obd_ioctl_data data;
+ int rc;
+
+ memset(&data, 0, sizeof(data));
+ data.ioc_inllen1 = strlen(name) + 1;
+ data.ioc_inlbuf1 = name;
+ rc = dev_ioctl(&data, -1, OBD_IOC_NAME2DEV);
+
+ if (rc < 0) {
+ llapi_err(LLAPI_MSG_ERROR, "Device %s not found %d\n", name,rc);
+ return rc;
+ }
+ return data.ioc_dev;
+}
+
+int llapi_fid2path(char *device, char *fidstr, char *buf, int buflen,
+ __u64 recno, int *linkno)
+{
+ struct lu_fid fid;
+ struct obd_ioctl_data data;
+ int dev, rc;
+
+ while (*fidstr == '[')
+ fidstr++;
+
+ sscanf(fidstr, "0x%llx:0x%x:0x%x", &(fid.f_seq), &(fid.f_oid),
+ &(fid.f_ver));
+ if (!fid_is_sane(&fid)) {
+ llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
+ "bad FID format [%s], should be "DFID"\n",
+ fidstr, (__u64)1, 2, 0);
+ return -EINVAL;