~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/printing/printing_db.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/Netbios implementation.
 
3
   Version 3.0
 
4
   printing backend routines
 
5
   Copyright (C) Andrew Tridgell 1992-2000
 
6
   Copyright (C) Jeremy Allison 2002
 
7
   
 
8
   This program is free software; you can redistribute it and/or modify
 
9
   it under the terms of the GNU General Public License as published by
 
10
   the Free Software Foundation; either version 3 of the License, or
 
11
   (at your option) any later version.
 
12
   
 
13
   This program is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
   GNU General Public License for more details.
 
17
   
 
18
   You should have received a copy of the GNU General Public License
 
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
*/
 
21
 
 
22
#include "includes.h"
 
23
#include "printing.h"
 
24
 
 
25
static struct tdb_print_db *print_db_head;
 
26
 
 
27
/****************************************************************************
 
28
  Function to find or create the printer specific job tdb given a printername.
 
29
  Limits the number of tdb's open to MAX_PRINT_DBS_OPEN.
 
30
****************************************************************************/
 
31
 
 
32
struct tdb_print_db *get_print_db_byname(const char *printername)
 
33
{
 
34
        struct tdb_print_db *p = NULL, *last_entry = NULL;
 
35
        int num_open = 0;
 
36
        char *printdb_path = NULL;
 
37
        bool done_become_root = False;
 
38
 
 
39
        SMB_ASSERT(printername != NULL);
 
40
 
 
41
        for (p = print_db_head, last_entry = print_db_head; p; p = p->next) {
 
42
                /* Ensure the list terminates... JRA. */
 
43
                SMB_ASSERT(p->next != print_db_head);
 
44
 
 
45
                if (p->tdb && strequal(p->printer_name, printername)) {
 
46
                        DLIST_PROMOTE(print_db_head, p);
 
47
                        p->ref_count++;
 
48
                        return p;
 
49
                }
 
50
                num_open++;
 
51
                last_entry = p;
 
52
        }
 
53
 
 
54
        /* Not found. */
 
55
        if (num_open >= MAX_PRINT_DBS_OPEN) {
 
56
                /* Try and recycle the last entry. */
 
57
                if (print_db_head && last_entry) {
 
58
                        DLIST_PROMOTE(print_db_head, last_entry);
 
59
                }
 
60
 
 
61
                for (p = print_db_head; p; p = p->next) {
 
62
                        if (p->ref_count)
 
63
                                continue;
 
64
                        if (p->tdb) {
 
65
                                if (tdb_close(print_db_head->tdb)) {
 
66
                                        DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n",
 
67
                                                                print_db_head->printer_name ));
 
68
                                        return NULL;
 
69
                                }
 
70
                        }
 
71
                        p->tdb = NULL;
 
72
                        p->ref_count = 0;
 
73
                        memset(p->printer_name, '\0', sizeof(p->printer_name));
 
74
                        break;
 
75
                }
 
76
                if (p && print_db_head) {
 
77
                        DLIST_PROMOTE(print_db_head, p);
 
78
                        p = print_db_head;
 
79
                }
 
80
        }
 
81
 
 
82
        if (!p) {
 
83
                /* Create one. */
 
84
                p = SMB_MALLOC_P(struct tdb_print_db);
 
85
                if (!p) {
 
86
                        DEBUG(0,("get_print_db: malloc fail !\n"));
 
87
                        return NULL;
 
88
                }
 
89
                ZERO_STRUCTP(p);
 
90
                DLIST_ADD(print_db_head, p);
 
91
        }
 
92
 
 
93
        if (asprintf(&printdb_path, "%s%s.tdb",
 
94
                                cache_path("printing/"),
 
95
                                printername) < 0) {
 
96
                DLIST_REMOVE(print_db_head, p);
 
97
                SAFE_FREE(p);
 
98
                return NULL;
 
99
        }
 
100
 
 
101
        if (geteuid() != 0) {
 
102
                become_root();
 
103
                done_become_root = True;
 
104
        }
 
105
 
 
106
        p->tdb = tdb_open_log(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT, 
 
107
                0600);
 
108
 
 
109
        if (done_become_root)
 
110
                unbecome_root();
 
111
 
 
112
        if (!p->tdb) {
 
113
                DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n",
 
114
                                        printdb_path ));
 
115
                DLIST_REMOVE(print_db_head, p);
 
116
                SAFE_FREE(printdb_path);
 
117
                SAFE_FREE(p);
 
118
                return NULL;
 
119
        }
 
120
        SAFE_FREE(printdb_path);
 
121
        fstrcpy(p->printer_name, printername);
 
122
        p->ref_count++;
 
123
        return p;
 
124
}
 
125
 
 
126
/***************************************************************************
 
127
 Remove a reference count.
 
128
****************************************************************************/
 
129
 
 
130
void release_print_db( struct tdb_print_db *pdb)
 
131
{
 
132
        pdb->ref_count--;
 
133
        SMB_ASSERT(pdb->ref_count >= 0);
 
134
}
 
135
 
 
136
/***************************************************************************
 
137
 Close all open print db entries.
 
138
****************************************************************************/
 
139
 
 
140
void close_all_print_db(void)
 
141
{
 
142
        struct tdb_print_db *p = NULL, *next_p = NULL;
 
143
 
 
144
        for (p = print_db_head; p; p = next_p) {
 
145
                next_p = p->next;
 
146
 
 
147
                if (p->tdb)
 
148
                        tdb_close(p->tdb);
 
149
                DLIST_REMOVE(print_db_head, p);
 
150
                ZERO_STRUCTP(p);
 
151
                SAFE_FREE(p);
 
152
        }
 
153
}
 
154
 
 
155
 
 
156
/****************************************************************************
 
157
 Fetch and clean the pid_t record list for all pids interested in notify
 
158
 messages. data needs freeing on exit.
 
159
****************************************************************************/
 
160
 
 
161
TDB_DATA get_printer_notify_pid_list(TDB_CONTEXT *tdb, const char *printer_name, bool cleanlist)
 
162
{
 
163
        TDB_DATA data;
 
164
        size_t i;
 
165
 
 
166
        ZERO_STRUCT(data);
 
167
 
 
168
        data = tdb_fetch_bystring( tdb, NOTIFY_PID_LIST_KEY );
 
169
 
 
170
        if (!data.dptr) {
 
171
                ZERO_STRUCT(data);
 
172
                return data;
 
173
        }
 
174
 
 
175
        if (data.dsize % 8) {
 
176
                DEBUG(0,("get_printer_notify_pid_list: Size of record for printer %s not a multiple of 8 !\n", printer_name ));
 
177
                tdb_delete_bystring(tdb, NOTIFY_PID_LIST_KEY );
 
178
                SAFE_FREE(data.dptr);
 
179
                ZERO_STRUCT(data);
 
180
                return data;
 
181
        }
 
182
 
 
183
        if (!cleanlist)
 
184
                return data;
 
185
 
 
186
        /*
 
187
         * Weed out all dead entries.
 
188
         */
 
189
 
 
190
        for( i = 0; i < data.dsize; i += 8) {
 
191
                pid_t pid = (pid_t)IVAL(data.dptr, i);
 
192
 
 
193
                if (pid == sys_getpid())
 
194
                        continue;
 
195
 
 
196
                /* Entry is dead if process doesn't exist or refcount is zero. */
 
197
 
 
198
                while ((i < data.dsize) && ((IVAL(data.dptr, i + 4) == 0) || !process_exists_by_pid(pid))) {
 
199
 
 
200
                        /* Refcount == zero is a logic error and should never happen. */
 
201
                        if (IVAL(data.dptr, i + 4) == 0) {
 
202
                                DEBUG(0,("get_printer_notify_pid_list: Refcount == 0 for pid = %u printer %s !\n",
 
203
                                                        (unsigned int)pid, printer_name ));
 
204
                        }
 
205
 
 
206
                        if (data.dsize - i > 8)
 
207
                                memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8);
 
208
                        data.dsize -= 8;
 
209
                }
 
210
        }
 
211
 
 
212
        return data;
 
213
}
 
214
 
 
215